├── test ├── Data-Structure │ └── list_test │ │ ├── Data-Structure │ │ └── dynamic_array_test │ │ ├── CMakeLists.txt │ │ └── main.c ├── misc │ └── bf_runner │ │ ├── bf_code.bf │ │ ├── CMakeLists.txt │ │ └── main.c ├── digest │ ├── MD4 │ │ ├── CMakeLists.txt │ │ └── main.c │ ├── MD5 │ │ ├── CMakeLists.txt │ │ └── main.c │ └── SHA2 │ │ ├── CMakeLists.txt │ │ └── main.c ├── Encoding │ ├── hex │ │ ├── CMakeLists.txt │ │ └── main.c │ ├── base64 │ │ ├── CMakeLists.txt │ │ └── main.c │ └── morse │ │ ├── CMakeLists.txt │ │ └── main.c └── Encrypt │ ├── RC4 │ ├── CMakeLists.txt │ └── main.c │ ├── tea │ ├── CMakeLists.txt │ └── main.c │ └── SM4 │ ├── CMakeLists.txt │ └── main.c ├── include ├── encode │ ├── hex.h │ ├── morse.h │ ├── encode_pre_init.h │ └── base64.h ├── adt │ ├── adt_pre_init.h │ ├── list.h │ ├── dynamic_array.h │ └── queue.h ├── encrypt │ ├── pkcspad.h │ ├── rc4.h │ ├── encrypt_pre_init.h │ ├── tea.h │ └── sm4.h ├── digest │ ├── md4.h │ ├── digest_pre_init.h │ ├── sha2.h │ └── md5.h └── misc │ ├── bitwise_utils.h │ ├── bf.h │ └── endian.h ├── CMakeLists.txt ├── docs ├── encode │ ├── hex.md │ └── base64.md ├── design.md ├── encrypt │ └── tea.md └── 代码规范1.0.md ├── README.md └── src ├── encode ├── hex.c ├── morse.c └── base64.c ├── encrypt ├── pkcspad.c ├── rc4.c ├── sm4.c └── tea.c ├── misc └── bf_runner │ └── bf.c ├── adt ├── dynamic_array.c ├── queue.c └── list.c └── digest ├── md4.c ├── md5.c └── sha2.c /test/Data-Structure/list_test/Data-Structure/dynamic_array_test: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/misc/bf_runner/bf_code.bf: -------------------------------------------------------------------------------- 1 | +++++ +++++ [->++ +++++ +++<] >++++ .---. +++++ ++..+ ++.<+ +++++ ++[-> ----- ---<] >---- ----- ----- -.<++ +++++ ++[-> +++++ ++++< ]>+++ +++.- ----- --.++ +.--- ---.- ----- --.< -------------------------------------------------------------------------------- /test/digest/MD4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encode_hex_test) 4 | 5 | include_directories("../../../include") 6 | 7 | set( 8 | source_file_path 9 | ../../../src 10 | ) 11 | 12 | add_executable( 13 | md4_test 14 | main.c 15 | ${source_file_path}/digest/md4.c 16 | ${source_file_path}/encode/hex.c 17 | ) -------------------------------------------------------------------------------- /test/digest/MD5/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encode_hex_test) 4 | 5 | include_directories("../../../include") 6 | 7 | set( 8 | source_file_path 9 | ../../../src 10 | ) 11 | 12 | add_executable( 13 | md5_test 14 | main.c 15 | ${source_file_path}/digest/md5.c 16 | ${source_file_path}/encode/hex.c 17 | ) -------------------------------------------------------------------------------- /test/digest/SHA2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encode_hex_test) 4 | 5 | include_directories("../../../include") 6 | 7 | set( 8 | source_file_path 9 | ../../../src 10 | ) 11 | 12 | add_executable( 13 | sha2_test 14 | main.c 15 | ${source_file_path}/digest/sha2.c 16 | ${source_file_path}/encode/hex.c 17 | ) -------------------------------------------------------------------------------- /test/Encoding/hex/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encode_hex_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | hex_test 14 | main.c 15 | ${source_file_path}/encode/hex.c 16 | ) -------------------------------------------------------------------------------- /test/Encrypt/RC4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encrypt_rc4_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | rc4_test 14 | main.c 15 | ${source_file_path}/encrypt/rc4.c 16 | ) -------------------------------------------------------------------------------- /test/Encrypt/tea/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encrypt_tea_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | tea_test 14 | main.c 15 | ${source_file_path}/encrypt/tea.c 16 | ) -------------------------------------------------------------------------------- /test/Encoding/base64/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encode_b64_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | base64_test 14 | main.c 15 | ${source_file_path}/encode/base64.c 16 | ) -------------------------------------------------------------------------------- /test/Encoding/morse/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encode_morse_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | morse_test 14 | main.c 15 | ${source_file_path}/encode/morse.c 16 | ) -------------------------------------------------------------------------------- /test/Data-Structure/list_test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(adt_list_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | adt_list_test 14 | main.c 15 | ${source_file_path}/adt/list.c 16 | ) -------------------------------------------------------------------------------- /test/misc/bf_runner/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(misc_bf_runner_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | bf_runner_test 14 | main.c 15 | ${source_file_path}/misc/bf_runner/bf.c 16 | ) -------------------------------------------------------------------------------- /test/Encrypt/SM4/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(encrypt_sm4_test) 4 | 5 | include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../../include") 6 | 7 | set( 8 | source_file_path 9 | ${CMAKE_CURRENT_SOURCE_DIR}/../../../src/ 10 | ) 11 | 12 | add_executable( 13 | sm4_test 14 | main.c 15 | ${source_file_path}/encrypt/sm4.c 16 | ../../../src/encrypt/pkcspad.c 17 | ) -------------------------------------------------------------------------------- /test/Encoding/morse/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | char input[1024]; 6 | char res[1024]; 7 | puts("input code: "); 8 | gets_s(input, sizeof(input)); 9 | morse_decode(input, res, sizeof(res)); 10 | printf("%s\n", res); 11 | 12 | puts("input string: "); 13 | gets_s(input, sizeof(input)); 14 | morse_encode(input, res, sizeof(res)); 15 | printf("%s\n", res); 16 | return 0; 17 | } -------------------------------------------------------------------------------- /test/Data-Structure/list_test/main.c: -------------------------------------------------------------------------------- 1 | #include "adt/list.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | list_t *list = list_create(NULL, NULL); 8 | for (int i = 0;i < 10;++i) { 9 | int *data = (int *)malloc(sizeof(int)); 10 | *data = i*2; 11 | list_push_back(list, data); 12 | } 13 | 14 | list_node_t *cur; 15 | list_for_each(list, cur) { 16 | printf("%d ", *(int *)cur->data); 17 | } 18 | list_destroy(list); 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /test/Encoding/base64/main.c: -------------------------------------------------------------------------------- 1 | #include "encode/base64.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main() { 8 | char table[] = "0123456789XYZabcdefghijklABCDEFGHIJKLMNOPQRSTUVWmnopqrstuvwxyz+/="; 9 | base64_encoder *b64 = new_base64((uint8_t *) table); 10 | char input[] = "hello"; 11 | byte output[100]; 12 | 13 | base64_encode(b64, input, strlen(input), output); 14 | puts(output); 15 | base64_decode(b64, output, strlen(output), input); 16 | puts(input); 17 | free_base64(b64); 18 | 19 | return 0; 20 | } -------------------------------------------------------------------------------- /include/encode/hex.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file hex.h 3 | * @brief This is a header file that contains the declaration of hex encoding and decoding functions. 4 | * @author WAHAHA 5 | * @category encode-algorithm 6 | * @date 2024 7 | */ 8 | 9 | #ifndef _ENCODE_HEX_H_ 10 | #define _ENCODE_HEX_H_ 11 | 12 | /* pre-initialization of encode */ 13 | #include 14 | 15 | /* hex transform */ 16 | status hex_to_bytes(const char *hex, size_t in_len, byte *bytes, size_t *out_len); 17 | 18 | status bytes_to_hex(const byte *bytes, size_t in_len, char *hex, size_t *out_len); 19 | 20 | #endif // _ENCODE_HEX_H_ -------------------------------------------------------------------------------- /test/Encrypt/RC4/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | rc4_encipher *rc4 = new_rc4(); 6 | byte key[] = "Thi5_1S_key?"; 7 | byte enc[] = { 8 | 0xf, 0x3c, 0x41, 0x75, 0x72, 0x42, 0x53, 0x6, 0x5d, 0x4c, 0x32, 0x1d, 0x2a, 0x5c, 0x49, 9 | 0x26, 0x22, 0x4b, 0x69, 0x22 10 | }; 11 | byte dec[21]={0}; 12 | rc4_init(rc4, key, strlen((char *) key), 128); 13 | rc4_crypt(rc4, enc, 20, dec); 14 | puts((char *) dec); 15 | memset(enc, 0, 21); 16 | rc4_crypt(rc4, dec, 20, enc); 17 | for(int i=0;i<20;i++) 18 | printf("%x ",enc[i]); 19 | 20 | return 0; 21 | } -------------------------------------------------------------------------------- /test/Encoding/hex/main.c: -------------------------------------------------------------------------------- 1 | #include "encode/hex.h" 2 | 3 | #include 4 | #include 5 | 6 | int main() { 7 | char text[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+{}[]|\\:;\"'<>,.?/~`"; 8 | size_t text_len, hex_len; 9 | byte hex[256] = {0}; 10 | 11 | /* bytes to hex */ 12 | bytes_to_hex(text, strlen(text), hex, &hex_len); 13 | for (int i = 0; i < hex_len; ++i) 14 | printf("%2X", hex[i]); 15 | putchar('\n'); 16 | /* hex to bytes */ 17 | memset(text, 0, strlen(text)); 18 | hex_to_bytes(hex, hex_len, text, &text_len); 19 | for (int i = 0; i < text_len; ++i) 20 | putchar(text[i]); 21 | 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(Serendipity) 3 | 4 | # test executable file path 5 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin) 6 | 7 | # set include path 8 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 9 | 10 | # Data-Structure 11 | add_subdirectory(test/Data-Structure/list_test) 12 | 13 | # Encoding 14 | add_subdirectory(test/Encoding/base64) 15 | add_subdirectory(test/Encoding/hex) 16 | add_subdirectory(test/Encoding/morse) 17 | 18 | # Digest 19 | add_subdirectory(test/digest/MD5) 20 | add_subdirectory(test/digest/MD4) 21 | add_subdirectory(test/digest/SHA2) 22 | 23 | # Encrypt 24 | add_subdirectory(test/Encrypt/tea) 25 | add_subdirectory(test/Encrypt/rc4) 26 | add_subdirectory(test/Encrypt/SM4) 27 | 28 | # Misc 29 | add_subdirectory(test/Misc/bf_runner) -------------------------------------------------------------------------------- /include/adt/adt_pre_init.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file adt_pre_init.h 3 | * @brief This is a header file that contains the declaration of pre-initialization of ADT. 4 | * @author WAHAHA 5 | * @category data-structure 6 | * @date 2024 7 | */ 8 | 9 | #ifndef ADT_PRE_INIT_H 10 | #define ADT_PRE_INIT_H 11 | 12 | #include 13 | 14 | /* declare extended boolean type */ 15 | #ifndef SERENDIPITY_BOOL 16 | #define SERENDIPITY_BOOL 17 | 18 | typedef int status; 19 | #define true 1 20 | #define false 0 21 | #define error (-1) // user's usage error 22 | #define failed (-2) // system's failure 23 | 24 | #endif 25 | 26 | 27 | /* define assert macro */ 28 | #ifndef ASSERT 29 | #define ASSERT(expr,code) \ 30 | if(!(expr)) { \ 31 | printf("[%s]:%s:%d is failed! error code: %d\r\n", \ 32 | __FILE__,__FUNCTION__,__LINE__,code); \ 33 | return code; \ 34 | } 35 | #endif 36 | 37 | #endif // ADT_PRE_INIT_H -------------------------------------------------------------------------------- /include/encrypt/pkcspad.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: pkcspad.h 3 | * @description: This is a header file that contains the declaration of PKCSPAD algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/3/19 2:29 6 | * @LastEditTime: 2024/3/19 2:29 7 | * @FilePath: Serendipity/include/encrypt/pkcspad.h 8 | * @category: encrypt-algorithm 9 | */ 10 | 11 | #ifndef SERENDIPITY_PKCSPAD_H 12 | #define SERENDIPITY_PKCSPAD_H 13 | 14 | #include 15 | 16 | /* macro of PKCS padding size */ 17 | #define PKCS5_BLOCK_SIZE 8 18 | 19 | #define pkcs7_pad_len(data_len, block_size) (block_size - (data_len % block_size)) 20 | #define pkcs5_pad_len(data_len) (PKCS5_BLOCK_SIZE - (data_len % PKCS5_BLOCK_SIZE)) 21 | 22 | /* PKCS7 padding and unpadding */ 23 | byte *pkcs7_pad(const byte *data, size_t data_len, size_t block_size); 24 | 25 | byte *pkcs7_unpad(const byte *data, size_t data_len, size_t block_size); 26 | 27 | /* PKCS5 padding and unpadding */ 28 | byte *pkcs5_pad(const byte *data, size_t data_len); 29 | 30 | byte *pkcs5_unpad(const byte *data, size_t data_len); 31 | 32 | #endif //SERENDIPITY_PKCSPAD_H 33 | -------------------------------------------------------------------------------- /include/encode/morse.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: morse.h 3 | * @description: This is a header file that contains the declaration of the Morse code encoding function. 4 | * @author: WAHAHA 5 | * @Date: 2024/9/5 下午1:38 6 | * @FilePath: Serendipity/include/encode/morse.h 7 | * @category: encode 8 | */ 9 | 10 | #ifndef SERENDIPITY_MORSE_H 11 | #define SERENDIPITY_MORSE_H 12 | 13 | #include 14 | #include 15 | 16 | // Morse Code Struct 17 | typedef struct morse_tree_node_s { 18 | int ascii; 19 | struct morse_tree_node_s *left; 20 | struct morse_tree_node_s *right; 21 | } morse_tree_node_t; 22 | 23 | typedef struct morse_ctx_s { 24 | morse_tree_node_t *root; // morse tree root 25 | const char **morse_table_ascii; // morse to ascii 26 | char error_char; // error char 27 | int error_flag; // error flag 28 | } morse_ctx_t; 29 | 30 | // Decode Morse code to ASCII 31 | status morse_decode(const char *str, char *buffer, size_t buffer_size); 32 | // Encode ASCII to Morse code 33 | status morse_encode(const char *str, char *buffer, size_t buffer_size); 34 | 35 | #endif //SERENDIPITY_MORSE_H 36 | -------------------------------------------------------------------------------- /test/digest/MD5/main.c: -------------------------------------------------------------------------------- 1 | #include "digest/md5.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | byte data0[] = "Hello, world!"; 9 | byte data1[] = "abcdefghijklmnopqrstuvwxyz"; 10 | byte data2[] = "12345678901234567890"; 11 | 12 | char expected0[] = "6cd3556deb0da54bca060b4c39479839"; 13 | char expected1[] = "c3fcd3d76192e4007dfb496cca67e13b"; 14 | char expected2[] = "fd85e62d9beb45428771ec688418b271"; 15 | 16 | size_t data_bit_size0 = strlen((char *) data0) * 8; 17 | size_t data_bit_size1 = strlen((char *) data1) * 8; 18 | size_t data_bit_size2 = strlen((char *) data2) * 8; 19 | 20 | char digest[33] = {0}; 21 | 22 | md5(data0, data_bit_size0, digest); 23 | if (strcmp(digest, expected0) != 0) { 24 | printf("data0: failed\n"); 25 | } else { 26 | printf("data0: passed\n"); 27 | } 28 | 29 | md5(data1, data_bit_size1, digest); 30 | if (strcmp(digest, expected1) != 0) { 31 | printf("data1: failed\n"); 32 | } else { 33 | printf("data1: passed\n"); 34 | } 35 | 36 | md5(data2, data_bit_size2, digest); 37 | if (strcmp(digest, expected2) != 0) { 38 | printf("data2: failed\n"); 39 | } else { 40 | printf("data2: passed\n"); 41 | } 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /test/digest/MD4/main.c: -------------------------------------------------------------------------------- 1 | #include "digest/md4.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | int main() { 8 | byte data0[] = "Hello, world!"; 9 | byte data1[] = "abcdefghijklmnopqrstuvwxyz"; 10 | byte data2[] = "12345678901234567890"; 11 | 12 | char expected0[] = "0abe9ee1f376caa1bcecad9042f16e73"; 13 | char expected1[] = "d79e1c308aa5bbcdeea8ed63df412da9"; 14 | char expected2[] = "3fee688b3e2a76a7eb5f78e840ebd67d"; 15 | 16 | size_t data_bit_size0 = strlen((char *) data0) * 8; 17 | size_t data_bit_size1 = strlen((char *) data1) * 8; 18 | size_t data_bit_size2 = strlen((char *) data2) * 8; 19 | 20 | char digest[33] = {0}; 21 | 22 | md4(data0, data_bit_size0, digest); 23 | if (strcmp(digest, expected0) != 0) { 24 | printf("data0: failed\n"); 25 | } else { 26 | printf("data0: passed\n"); 27 | } 28 | 29 | md4(data1, data_bit_size1, digest); 30 | if (strcmp(digest, expected1) != 0) { 31 | printf("data1: failed\n"); 32 | } else { 33 | printf("data1: passed\n"); 34 | } 35 | 36 | md4(data2, data_bit_size2, digest); 37 | if (strcmp(digest, expected2) != 0) { 38 | printf("data2: failed\n"); 39 | } else { 40 | printf("data2: passed\n"); 41 | } 42 | 43 | 44 | return 0; 45 | } -------------------------------------------------------------------------------- /include/digest/md4.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: md5.h 3 | * @description: This is a header file that contains the declaration of MD4 algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/4/11 14:52 6 | * @LastEditTime: 2024/4/11 14:52 7 | * @FilePath: Serendipity/include/digest/md4.h 8 | * @category: digest-algorithm 9 | */ 10 | 11 | #ifndef SERENDIPITY_MD4_H 12 | #define SERENDIPITY_MD4_H 13 | 14 | /* pre-initialization of digest */ 15 | #include "digest/digest_pre_init.h" 16 | 17 | /* basic md4 data size */ 18 | #define MD4_DIGEST_SIZE 16 19 | 20 | /* md4 auxiliary functions */ 21 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 22 | #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) 23 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 24 | 25 | #define FF(a, b, c, d, mi, s) \ 26 | (a = ( CYCLE_SHL_SIZE_NBIT(a + F(b, c, d) + mi, s, uint32_t))) 27 | #define GG(a, b, c, d, mj, s) \ 28 | (a = ( CYCLE_SHL_SIZE_NBIT(a + G(b, c, d) + mj + 0x5A827999, s, uint32_t))) 29 | #define HH(a, b, c, d, mj, s) \ 30 | (a = ( CYCLE_SHL_SIZE_NBIT(a + H(b, c, d) + mj + 0x6ED9EBA1, s, uint32_t))) 31 | 32 | /* md4 function */ 33 | static uint32_t *md4_padding(const byte *data, size_t data_bit_count, size_t *block_size); 34 | 35 | status md4(const byte *data, size_t data_bit_size, char *digest); 36 | 37 | #endif //SERENDIPITY_MD4_H 38 | -------------------------------------------------------------------------------- /include/misc/bitwise_utils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: bitwise_utils.h 3 | * @description: This header file contains utility functions or macros for bit operations. 4 | * @author: WAHAHA 5 | * @Date: 2024/4/7 10:00 6 | * @FilePath: Serendipity/include/misc/bitwise_utils.h 7 | * @category: misc 8 | */ 9 | 10 | #ifndef SERENDIPITY_BITWISE_UTILS_H 11 | #define SERENDIPITY_BITWISE_UTILS_H 12 | 13 | /** 14 | * Bit manipulation macros: setting, clearing, getting 15 | * a specific bit, and getting the number of bits of 16 | * a type. 17 | */ 18 | #define SET_BIT(x, i) (x |= (1 << i)) 19 | #define CLEAR_BIT(x, i) (x &= ~(1 << i)) 20 | #define GET_BIT(x, i) ((x >> i) & 1) 21 | #define BITS_OF(type) (sizeof(type)<<3) 22 | 23 | /** 24 | * The following macros should be used for unsigned numbers 25 | * to avoid arithmetic shifts 26 | */ 27 | 28 | /* shift left and right */ 29 | #define SHL_NBIT(data, bits) ((data)<<(bits)) 30 | #define SHR_NBIT(data, bits) ((data)>>(bits)) 31 | 32 | /* cycle shift left and right */ 33 | #define CYCLE_SHL_SIZE_NBIT(data, bits, type) \ 34 | (((data) << (bits)) | ((data) >> (BITS_OF(type) - (bits)))) 35 | #define CYCLE_SHR_SIZE_NBIT(data, bits, type) \ 36 | (((data) >> (bits)) | ((data) << (BITS_OF(type) - (bits)))) 37 | 38 | #endif //SERENDIPITY_BITWISE_UTILS_H 39 | -------------------------------------------------------------------------------- /include/encrypt/rc4.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: rc4.h 3 | * @description: This is a header file that contains the declaration of the RC4 encryption algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024-03-05 14:15:32 6 | * @LastEditTime: 2024-03-05 14:45:28 7 | * @FilePath: \Serendipity\include\encrypt\rc4.h 8 | * @category: encrypt-algorithm 9 | */ 10 | 11 | #ifndef SERENDIPITY_RC4_H 12 | #define SERENDIPITY_RC4_H 13 | 14 | /* pre-initialization of encrypt */ 15 | #include 16 | #include 17 | 18 | /* RC4 macros */ 19 | #define RC4_DEFAULT_SBOX_LEN 256 20 | 21 | /* RC4 encipher */ 22 | typedef struct rc4_encipher { 23 | byte *sbox; // the sbox of RC4 24 | byte *key; // the key of RC4 25 | int key_len; // the length of the key 26 | int sbox_len; // The length of each instance's own sbox 27 | status initialized; // the status of the RC4 28 | } rc4_encipher; 29 | 30 | /* rc4_encipher object */ 31 | rc4_encipher *new_rc4(); 32 | 33 | status free_rc4(rc4_encipher *rc4); 34 | 35 | /* RC4 functions */ 36 | status rc4_init(rc4_encipher *rc4, const byte *key, int key_len, int sbox_len); 37 | 38 | static status rc4_generate_sbox(rc4_encipher *rc4); 39 | 40 | status rc4_crypt(rc4_encipher *rc4, const byte *in_data, int data_len, byte *out_data); 41 | 42 | 43 | #endif // SERENDIPITY_RC4_H -------------------------------------------------------------------------------- /include/encrypt/encrypt_pre_init.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: encrypt_pre_init.h 3 | * @description: This is a header file that contains the declaration of pre-initialization of encrypt algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024-02-29 17:32:55 6 | * @LastEditTime: 2024-03-05 13:45:09 7 | * @FilePath: \Serendipity\include\encrypt\encrypt_pre_init.h 8 | * @category: encrypt-algorithm 9 | */ 10 | 11 | #ifndef ENCRYPT_PRE_INIT 12 | #define ENCRYPT_PRE_INIT 13 | 14 | #include 15 | #include 16 | 17 | /* declare byte type */ 18 | typedef uint8_t byte; 19 | 20 | /* declare extended boolean type */ 21 | #ifndef SERENDIPITY_BOOL 22 | #define SERENDIPITY_BOOL 23 | 24 | typedef int status; 25 | #define true 1 26 | #define false 0 27 | #define error (-1) // user's usage error 28 | #define failed (-2) // system's failure 29 | 30 | #endif 31 | 32 | /* define assert macro */ 33 | #ifndef ASSERT 34 | 35 | #include 36 | 37 | #define ASSERT(expr, code) \ 38 | if(!(expr)) { \ 39 | printf("[%s]:%s:%d is failed! error code: %d\r\n", \ 40 | __FILE__,__FUNCTION__,__LINE__,code); \ 41 | return code; \ 42 | } 43 | #endif 44 | 45 | 46 | #endif // ENCRYPT_PRE_INIT -------------------------------------------------------------------------------- /include/digest/digest_pre_init.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: digest_pre_init.h 3 | * @description: This is a header file that contains the declaration of pre-initialization of digest. 4 | * @author: WAHAHA 5 | * @Date: 2024-02-28 11:06:35 6 | * @LastEditTime: 2024-03-04 15:22:36 7 | * @FilePath: \Serendipity\include\digest\digest_pre_init.h 8 | * @category: digest-algorithm 9 | */ 10 | 11 | #ifndef DIGEST_PRE_INIT_H 12 | #define DIGEST_PRE_INIT_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | /* declare byte type */ 19 | typedef uint8_t byte; 20 | 21 | /* declare extended boolean type */ 22 | #ifndef SERENDIPITY_BOOL 23 | #define SERENDIPITY_BOOL 24 | 25 | typedef int status; 26 | #define true 1 // correct execution 27 | #define false 0 // The data to be processed or initialized is incorrect 28 | #define error (-1) // user's usage error 29 | #define failed (-2) // system's failure 30 | 31 | #endif 32 | 33 | /* define assert macro */ 34 | #ifndef ASSERT 35 | #define ASSERT(expr, code) \ 36 | if(!(expr)) { \ 37 | printf("[%s]:%s:%d is failed! error code: %d\r\n", \ 38 | __FILE__,__FUNCTION__,__LINE__,code); \ 39 | return code; \ 40 | } 41 | #endif 42 | 43 | #endif // DIGEST_PRE_INIT_H -------------------------------------------------------------------------------- /include/encode/encode_pre_init.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: encode_pre_init.h 3 | * @description: This is a header file that contains the declaration of pre-initialization of encode. 4 | * @author: WAHAHA 5 | * @Date: 2024-02-28 11:06:35 6 | * @LastEditTime: 2024-03-04 15:22:36 7 | * @FilePath: \Serendipity\include\encode\encode_pre_init.h 8 | * @category: encode-algorithm 9 | */ 10 | 11 | #ifndef ENCODE_PRE_INIT_H 12 | #define ENCODE_PRE_INIT_H 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | /* declare byte type */ 19 | typedef uint8_t byte; 20 | 21 | /* declare extended boolean type */ 22 | #ifndef SERENDIPITY_BOOL 23 | #define SERENDIPITY_BOOL 24 | 25 | typedef int status; 26 | #define true 1 // correct execution 27 | #define false 0 // The data to be processed or initialized is incorrect 28 | #define error (-1) // user's usage error 29 | #define failed (-2) // system's failure 30 | 31 | #endif 32 | 33 | /* define assert macro */ 34 | #ifndef ASSERT 35 | #define ASSERT(expr, code) \ 36 | if(!(expr)) { \ 37 | printf("[%s]:%s:%d is failed! error code: %d\r\n", \ 38 | __FILE__,__FUNCTION__,__LINE__,code); \ 39 | return code; \ 40 | } 41 | #endif 42 | 43 | #endif // ENCODE_PRE_INIT_H -------------------------------------------------------------------------------- /include/encode/base64.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file base64.h 3 | * @brief This is a header file that contains the declaration of base64 encode and decode algorithm. 4 | * @author WAHAHA 5 | * @category encode-algorithm 6 | * @date 2024 7 | */ 8 | 9 | #ifndef ENCODE_BASE64_H 10 | #define ENCODE_BASE64_H 11 | 12 | /* pre-initialization of encode */ 13 | #include 14 | 15 | /* base64 data */ 16 | static byte *base64_default_table = (unsigned char*)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 17 | 18 | /* base64 encoder */ 19 | typedef struct base64_encoder { 20 | byte* b64_table; 21 | /** 22 | * The characters in b64_table may not be ASCII characters, 23 | * so we need to use 256 24 | */ 25 | byte* reverse_table; 26 | int output_len; 27 | } base64_encoder; 28 | 29 | /* base64 encoder constructor and destructor */ 30 | base64_encoder *new_base64(const byte *b64_table); 31 | status free_base64(base64_encoder *encoder); 32 | 33 | /* base64 table operations */ 34 | static status generate_reverse_table(const byte *b64_table, byte *reverse_table); 35 | status base64_change_table(base64_encoder *encoder, const byte *b64_table); 36 | 37 | /* base64 operations */ 38 | status base64_reset(base64_encoder *encoder); 39 | status base64_encode(base64_encoder *encoder, const byte *input, int in_len, 40 | byte *output); 41 | status base64_decode(base64_encoder *encoder, const byte *input, int in_len, 42 | byte *output); 43 | 44 | #endif // ENCODE_BASE64_H -------------------------------------------------------------------------------- /test/Encrypt/SM4/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | sm4_encipher* sm4 = new_sm4(); 8 | byte key[16] = { 9 | 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 10 | 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef 11 | }; 12 | sm4_init(sm4, key); 13 | 14 | byte data[] = "hello world!"; 15 | byte* pad_data = pkcs7_pad(data, strlen((char*)data), 16); 16 | int data_len = strlen(data); 17 | int pad_data_len = strlen(data) + pkcs7_pad_len(data_len, 16); 18 | 19 | byte* out_data = (byte*)malloc(sizeof(byte) * (pad_data_len)); 20 | 21 | printf("origin data: "); 22 | for (int i = 0; i < data_len; i++) 23 | printf("%02x ", data[i]); 24 | printf("(%s)\n",(char*)data); 25 | 26 | sm4_crypt(sm4, pad_data, pad_data_len, out_data, SM4_ENCRYPT); 27 | printf("SM4 encrypt data: "); 28 | for (int i = 0; i < pad_data_len; i++) { 29 | printf("%02x ", out_data[i]); 30 | } 31 | sm4_crypt(sm4, out_data, pad_data_len, pad_data, SM4_DECRYPT); 32 | 33 | memset(data, 0, sizeof(pad_data)); 34 | putchar('\n'); 35 | printf("SM4 decrypt data: "); 36 | for (int i = 0; i < data_len; i++) { 37 | printf("%02x ", pad_data[i]); 38 | } 39 | putchar('('); 40 | for (int i = 0; i < data_len; i++) { 41 | printf("%c", pad_data[i]); 42 | } 43 | putchar(')'); 44 | free_sm4(sm4); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /test/Encrypt/tea/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | /* uint32_t key[] = { 1,2,3,4 }; 8 | tea_encipher *tea = new_tea(0x12345678, key, 31); 9 | char plain[100] = "Hello world!"; 10 | 11 | printf("XTEA encrypt test:\n"); 12 | printf("plain: %s\n",plain); 13 | 14 | int len = (strlen(plain) / sizeof(uint32_t)) + (strlen(plain) % sizeof(uint32_t) != 0); 15 | len += len % 2; 16 | tea->n = len; 17 | uint32_t enc[len]; 18 | xtea_encrypt(tea, (uint32_t *)plain, enc); 19 | printf("ciper: "); 20 | for (int i = 0; i < len; i++) { 21 | printf("%x ", enc[i]); 22 | } 23 | 24 | printf("\n"); 25 | memset(plain, 0, sizeof(plain)); 26 | xtea_decrypt(tea, enc, (uint32_t *)plain); 27 | printf("decrypt from ciper: %s\n", plain); */ 28 | uint32_t key[4] = { 29 | 22,33,44,55 30 | }; 31 | uint32_t del = -0x543210DD; 32 | tea_encipher *tea = new_tea(del, key, 32); 33 | tea->n = 10; 34 | char c[] = { 35 | 0x20,0x69,0xb3,0xe4,0xd0,0x24,0x69,0x93,0x44,0xd1,0x16,0xa8,0xf5,0xd5,0x82,0xaa, 36 | 0xda,0xf0,0x79,0x36,0x06,0xfd,0x32,0x7f,0xd3,0xc0,0x60,0x34,0x39,0x49,0x21,0xb7, 37 | 0xa2,0x69,0x72,0xe5,0xfa,0x51,0x6a,0x83 38 | }; 39 | uint32_t * ciper = (uint32_t *)c; 40 | uint32_t plain[10]; 41 | tea_decrypt(tea, ciper, plain); 42 | for (int i = 0;i < 10;++i) 43 | for (int j = 0;j < 4;++j) 44 | putchar(((char *)(&plain[i]))[j]); 45 | return 0; 46 | } -------------------------------------------------------------------------------- /docs/encode/hex.md: -------------------------------------------------------------------------------- 1 | # Base64 编码/解码模块 2 | 3 | 这个模块提供了`十六进制字符串`与`字节串`之间的转换. 4 | 5 | `十六进制`字符串应满足以下要求: 6 | 7 | - 总长度为2的倍数,即每2个字符对应的十六进制数编码1个字节的数据. 8 | - 每个字符应为合法的十六进制数. 9 | 10 | caller应该在调用该模块的函数之前自行分配好内存(缓冲区)用于接收处理结果. 11 | 12 | ## 依赖 13 | 14 | 该模块依赖于`encode/encode_pre_init.h`. 15 | 16 | # API参考 17 | 18 | ## hex_to_bytes 19 | 20 | 该函数用于将`十六进制字符串`转换为`字节串`. 21 | 22 | 函数原型: 23 | 24 | ```c 25 | status hex_to_bytes(const char *hex, size_t in_len, byte *bytes, size_t *out_len); 26 | ``` 27 | 28 | - hex: 一个只读的C风格字符串,即待转换的十六进制字符串. 29 | - in_len: 一个无符号整数,即期望处理的十六进制字符串的长度,该长度(应该)为2的倍数. 30 | - bytes: 一个指针,指向一个缓冲区,用于存储转换的结果,即一个字节串. 31 | - out_len: 一个指针,指向一个无符号整型变量,该变量用于接受成功转换的字节数. 32 | 33 | 注意: 34 | 35 | - 函数会处理十六进制字符串的前`in_len`个字符,一直处理到第一个错误出现的位置之前,`*out_len`保存成功转换的字节数. 36 | - caller应该确保`bytes`参数指向的缓冲区足够大,以容纳所有成功转换的字节,至多应该为`in_len`的一半. 37 | - 由于结果是`字节串`,而非`字符串`,因此该函数不(应该)负责在转换结果后面添加`\0`结束符. 38 | - 返回结果是一个整数,代表了函数的运行结果,`1`为全部成功转换,`0`为部分成功转换,`-1`为调用错误. 39 | 40 | ## bytes_to_hex 41 | 42 | 该函数用于将`字节串`转换为`十六进制字符串`. 43 | 44 | 函数原型: 45 | 46 | ```c 47 | status bytes_to_hex(const byte *bytes, size_t in_len, char *hex, size_t *out_len); 48 | ``` 49 | 50 | - bytes: 一个指针,指向一个只读的待转换字节串. 51 | - in_len: 一个无符号整数,即期望处理的字节串的长度. 52 | - hex: 一个指针,指向一个缓冲区,用于存储转换的结果,即一个十六进制字符串. 53 | - out_len: 一个指针,指向一个无符号整型变量,该变量用于接受转换后的十六进制字符串的长度. 54 | 55 | 注意: 56 | 57 | - 函数会处理字节串的前`in_len`个字节,`*out_len`保存成功转换的十六进制字符串的长度. 58 | - caller应该确保`hex`参数指向的缓冲区足够大,以容纳所有成功转换的字节,至多应该为`in_len`的二倍再加1. 59 | - 由于结果是`字符串`,因此该函数会在转换结果后面添加一个`\0`结束符,hex指向的缓冲区需要避免该字节的溢出. 60 | - 返回结果是一个整数,代表了函数的运行结果,`1`为全部成功转换,`-1`为调用错误. 61 | 62 | -------------------------------------------------------------------------------- /test/misc/bf_runner/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "misc/bf.h" 3 | 4 | const char* code_file_name = "D:/Data/code/cpp/Serendipity/test/misc/bf_runner/bf_code.bf"; 5 | 6 | void get_code(char** code, int* len) { 7 | FILE* code_file = fopen(code_file_name, "r"); 8 | if (code_file == NULL) { 9 | printf("[ERROR] Failed to open code file %s\n", code_file_name); 10 | return; 11 | } 12 | fseek(code_file, 0, SEEK_END); 13 | *len = ftell(code_file); 14 | *code = malloc(*len + 1); 15 | fseek(code_file, 0, SEEK_SET); 16 | fread(*code, 1, *len, code_file); 17 | (*code)[*len] = '\0'; 18 | fclose(code_file); 19 | } 20 | 21 | int main() { 22 | /* Initialize BF environment */ 23 | unsigned char* input = NULL; 24 | unsigned char* output = malloc(1024); 25 | char* code = NULL; 26 | int len = 0; 27 | get_code(&code, &len); 28 | if (code == NULL) { 29 | printf("[ERROR] Failed to read BF code\n"); 30 | } 31 | 32 | bf_ctx_t* ctx = new_ctx(input, output); 33 | ctx_bind_code(ctx, code, len); 34 | 35 | /* Run BF code */ 36 | printf("[INFO] Running BF code...\n"); 37 | 38 | int result = run_bf(ctx); 39 | printf("[INFO] Output data:\n"); 40 | const size_t output_len = ctx->output_ptr; 41 | for (size_t i = 0; i < output_len; i++) { 42 | printf("%c", ctx->output[i]); 43 | } 44 | printf("\n"); 45 | 46 | printf("[INFO] BF code exits with code %d\n", result); 47 | 48 | /* Free resources */ 49 | free(code); 50 | free_ctx(ctx); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /include/misc/bf.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: load.h 3 | * @description: This is a header file that contains the declaration of bf 4 | * @author: WAHAHA 5 | * @Date: 2024/8/7 下午12:45 6 | * @FilePath: bf_runner/load.h 7 | * @category: misc-bf_runner 8 | */ 9 | 10 | #ifndef BF_RUNNER_BF_H 11 | #define BF_RUNNER_BF_H 12 | 13 | #include 14 | 15 | #define KB (1024) 16 | #define MB (1024 * KB) 17 | #define GB (1024 * MB) 18 | 19 | #define MAX_MEM_SIZE (1024 * KB) 20 | #define BF_STATUS_RUNNING 0 21 | #define BF_STATUS_ERROR 1 22 | #define BF_STATUS_FINISHED 2 23 | 24 | typedef unsigned char byte; 25 | 26 | typedef struct bf_ctx_s { 27 | byte* array; 28 | char* code; // read all code from file 29 | size_t arr_size; 30 | size_t code_len; 31 | size_t ptr; 32 | size_t code_ptr; 33 | int status; // 0: running, 1: error, 2: finished 34 | size_t output_ptr; 35 | size_t input_ptr; 36 | byte* input; 37 | byte* output; 38 | } bf_ctx_t; 39 | 40 | // context operations 41 | bf_ctx_t* new_ctx(unsigned char* input,unsigned char* output); 42 | bf_ctx_t* copy_ctx(const bf_ctx_t* old_ctx); 43 | void free_ctx(bf_ctx_t* ctx); 44 | void ctx_bind_code(bf_ctx_t* ctx, char* code, const int len); 45 | 46 | // run bf code 47 | int run_bf(bf_ctx_t* ctx); 48 | void interpret_command(bf_ctx_t* ctx, char command); 49 | 50 | // vm commands 51 | void vm_add_ptr(bf_ctx_t* ctx); 52 | void vm_sub_ptr(bf_ctx_t* ctx); 53 | void vm_add_val(bf_ctx_t* ctx); 54 | void vm_sub_val(bf_ctx_t* ctx); 55 | void vm_output(bf_ctx_t* ctx); 56 | void vm_input(bf_ctx_t* ctx); 57 | void vm_loop_start(bf_ctx_t* ctx); 58 | 59 | #endif //BF_RUNNER_BF_H 60 | -------------------------------------------------------------------------------- /include/encrypt/tea.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file tea.c 3 | * @brief This is a header file that contains the declaration of TEA encryption algorithm. 4 | * @author WAHAHA 5 | * @category encrypt-algorithm 6 | * @date 2024 7 | */ 8 | 9 | 10 | #ifndef ENCRYPT_TEA 11 | #define ENCRYPT_TEA 12 | 13 | /* pre-initialization of encrypt */ 14 | #include 15 | #include 16 | 17 | /* TEA encipher */ 18 | typedef struct tea_encipher { 19 | uint32_t delta; 20 | int rounds; // not available for XXTEA 21 | int n; // the count of blocks 22 | uint32_t key[4]; 23 | } tea_encipher; 24 | 25 | tea_encipher *new_tea(uint32_t delta, const uint32_t key[4], int rounds); 26 | 27 | status free_tea(tea_encipher *tea); 28 | 29 | /* common TEA encryption */ 30 | status tea_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 31 | 32 | status tea_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain); 33 | 34 | static status tea_block_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 35 | 36 | static status tea_block_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain); 37 | 38 | /* XTEA encryption */ 39 | status xtea_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 40 | 41 | status xtea_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain); 42 | 43 | static status xtea_block_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 44 | 45 | static status xtea_block_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain); 46 | 47 | /* XXTEA encryption */ 48 | status xxtea_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 49 | 50 | status xxtea_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain); 51 | 52 | #endif // ENCRYPT_TEA -------------------------------------------------------------------------------- /include/adt/list.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file list.h 3 | * @brief This is a header file that contains the declaration of list data structure. 4 | * @author WAHAHA 5 | * @category data-structure 6 | * @date 2024 7 | */ 8 | 9 | #ifndef ADT_LIST_H 10 | #define ADT_LIST_H 11 | 12 | /* pre-initialization of ADT */ 13 | #include "adt/adt_pre_init.h" 14 | 15 | /* list node structure */ 16 | typedef struct list_node_s { 17 | void *data; 18 | struct list_node_s *next; 19 | } list_node_t; 20 | 21 | /* list structure */ 22 | typedef struct list_s { 23 | list_node_t *head; 24 | list_node_t *tail; 25 | size_t size; 26 | int (*compare)(const void *, const void *); 27 | void (*destructor)(void *); 28 | } list_t; 29 | 30 | /* macro for list operations */ 31 | #define list_size(list) ((list)->size) 32 | #define list_empty(list) ((list)->size == 0) 33 | #define list_front(list) ((list)->head->data) 34 | #define list_back(list) ((list)->tail->data) 35 | #define list_for_each(list, cur) \ 36 | for (cur = (list)->head; cur != NULL; cur = cur->next) 37 | 38 | 39 | /* list operations */ 40 | list_t *list_create(int (*compare)(const void *, const void *), 41 | void (*destroy)(void *)); 42 | status list_destroy(list_t *list); 43 | status list_insert(list_t *list, size_t index, void *data); 44 | status list_remove(list_t *list, size_t index, void **data); 45 | status list_push_front(list_t *list, void *data); 46 | status list_push_back(list_t *list, void *data); 47 | 48 | /* get the status of list */ 49 | // size_t list_size(list_t *list); 50 | // status list_empty(list_t *list); 51 | 52 | /* get the data of list */ 53 | // void *list_front(list_t *list); 54 | // void *list_back(list_t *list); 55 | void *list_get(list_t *list, size_t index); 56 | 57 | #endif // ADT_LIST_H -------------------------------------------------------------------------------- /docs/design.md: -------------------------------------------------------------------------------- 1 | # 介绍 2 | 3 | 本项目基于C语言开发,旨在为CTFer编写C环境下的一个简单易用,且高效健壮的常用工具库,以便于CTFer在比赛中可以快速使用C编写出高效的代码,提高比赛效率. 4 | 5 | 由于CTF题目的特殊性,很多加密,编码算法并不是标准的,所以本项目会尽可能为各个模块接口增加灵活性,以便于CTFer可以根据题目的特殊性进行定制化的修改. 6 | 例如`TEA`系列算法的`Deltea值`, `Base64`算法的`自定义编码表`,`RC4`算法的`SBOX大小`等等. 7 | 8 | # 项目包含 9 | 10 | 预计至少有以下几个分类: 11 | 12 | - 常用数据结构的ADT实现 13 | - 常用加密算法的实现 14 | - 常用编码算法的实现 15 | 16 | # 项目结构 17 | 18 | 基本的目录结构如下: 19 | 20 | ```plaintext 21 | Serendipity 22 | ├─docs 23 | ├─include 24 | │ ├─adt 25 | │ ├─encode 26 | │ └─encrypt 27 | ├─src 28 | │ ├─adt 29 | │ ├─encode 30 | │ └─encrypt 31 | ├─test 32 | │ ├─Data-Structure 33 | │ │ │ ... 34 | │ ├─Encoding 35 | │ │ │ ... 36 | │ └─Encrypt 37 | │ │ ... 38 | │ CMakelists.txt 39 | │ LICENSE 40 | │ README.md 41 | ``` 42 | 43 | 其中: 44 | 45 | - `docs`目录存放项目的文档 46 | - `include`目录存放项目的头文件 47 | - `src`目录存放项目的源文件 48 | - `test`目录存放项目的测试文件,使用`cmake`进行构建 49 | - 顶层的`CMakelists.txt`文件用于构建整个项目(开发阶段用于构建测试文件,发布阶段用于构建库文件) 50 | - `LICENSE`文件存放项目的开源协议 51 | - `README.md`文件存放项目的基本信息 52 | 53 | 新加入的模块应该按照上述的目录结构进行组织,将模块的头文件放在`include`目录下,将模块的源文件放在`src`目录下,将模块的测试文件放在`test`目录下. 54 | 在`test`目录下对应文件夹的`CMakelists.txt`文件中添加新的测试文件,在顶层的`CMakelists.txt`文件中添加该模块的构建目录. 55 | 56 | # 文件包含关系 57 | - 头文件路径应该从`include`内的子目录开始,例如`adt/list.h`,而不是`include/adt/list.h` 58 | - 每个模块的头文件应该包含该模块私有的全局变量/常量的定义并声明所有函数接口; 59 | - 每个模块的头文件除了依赖模块外,不应该包含其他模块的头文件. 60 | - 每个模块的源文件应该包含该模块对应的头文件,其他依赖模块的头文件应该在对应的头文件中包含,在源文件中不应该包含其他模块的头文件. 61 | 62 | 换言之,除了必要的依赖模块外,每个模块应该是独立的,不应该依赖于其他模块. 63 | 例如: 64 | 65 | `SM4`模块依赖于`Pkcspad`模块,则`SM4`模块的头文件中应该包含`Pkcspad`模块的头文件; 66 | 67 | `SM4`模块的源文件中应该包含`SM4`模块的头文件,而无需包含`Pkcspad`模块的头文件. 68 | 69 | # 分支管理 70 | ## 主分支-main 71 | - 主分支为`main`分支,用于发布稳定版本 72 | - 该分支在发布新版本时,会打上对应的版本号的tag 73 | 74 | ## 开发分支-dev 75 | - 开发分支为`dev`分支,用于开发新功能 76 | - 新代码的提交应该提交到该分支 77 | 78 | # release版本 79 | - 每个版本预计会编译成一套动态库和静态库,并发布到release中 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 项目目的 2 | 本项目基于C语言开发,旨在为CTFer编写C环境下的一个简单易用,且高效健壮的常用工具库,以简化exp的编写等,库预计包含以下部分: 3 | 4 | - 一些常用的编码转换,例如Base系列等编码 5 | - CTF中常见加密算法的加解密,并且支持自定义关键值 6 | - 一些其他加密或编码转换,例如栅栏密码,摩斯电码等,甚至有Brainf**k的解释器 7 | - 构建一套基本数据结构库,以减少重复造轮子 8 | 9 | # 为什么要有这个项目 10 | CTF比赛中,经常需要编写脚本代码来处理题目数据,生成flag,使用python语言一般即可满足大部分的需求, 11 | 但是,不是所有人都擅长(或喜欢)使用Python等语言高效解决这些问题,有人可能更愿意(希望)使用C语言解决问题. 12 | 13 | 本项目希望为CTFer提供一个基于C语言的工具库,让C语言也能够快速解决问题,同时希望能够提高工具的灵活性. 14 | 15 | 另一方面,C语言更为底层,操作起来更为自由,使用C语言作为基础也有可能使问题的解决更为灵活. 16 | 17 | # 该项目有何特点 18 | 现在互联网上有着庞大的工具资源,任何一个领域都有着极其优秀的C语言工具库, 19 | 但是,这些库往往是为了解决更为专业严谨的问题,而不是为了解决CTF中的问题. 20 | 21 | 因此,这些库的接口往往会比较复杂,想要即写即用,往往需要花费大量的时间去阅读文档,学习使用方法. 22 | 23 | 另一方面,很多CTF题目基于的算法等并不是标准的,往往经过了一些变形,这就需要我们能够灵活的调整库的接口. 24 | 与其手动修改整个算法内部的逻辑,不如直接提供一个接口,让使用者可以自由的调整. 25 | 26 | 本项目并不追求异常卓越的性能,而是追求简单易用,高效健壮,并且尽可能的提供灵活的接口. 27 | 项目的编写者即为使用者,我希望能够让这个库更加符合CTFer的使用习惯. 28 | 29 | 欢迎广大CTFer提出宝贵意见,及时批评指正,共同完善这个项目. 30 | 31 | # 安装 32 | // 正在施工... 33 | 34 | # 使用 35 | // 正在施工... 36 | 37 | # 功能支持列表 38 | - 数据结构ADT 39 | - [x] dynamic_array 40 | - [x] list 41 | - [x] queue 42 | - [ ] stack 43 | - 摘要算法Digest 44 | - [ ] MD2 45 | - [ ] MD3 46 | - [x] MD4 47 | - [x] MD5 48 | - [x] SHA2-224 49 | - [x] SHA2-256 50 | - [x] SHA2-384 51 | - [x] SHA2-512 52 | - [x] SHA2-512/224 53 | - [x] SHA2-512/256 54 | - [ ] CRC32 55 | - [ ] CRC64 56 | - 编码转换Encode 57 | - [x] Base64(支持编码表的自定义) 58 | - [ ] Base32(支持编码表的自定义) 59 | - [x] HEX_string to Byte_array 60 | - [x] Morse Code 61 | - 加密算法Encrypt 62 | - [x] RC4(支持SBOX盒大小的自定义) 63 | - [x] 国密 SM4 64 | - [x] TEA,XTEA,XXTEA(支持各个关键key值的自定义) 65 | - [ ] AES 66 | - [ ] DES 67 | - [ ] Blowfish 68 | - 其他算法Other 69 | - [x] Brain f**k 解释器 70 | - 其他附加工具 71 | - [x] 大小端序转换宏 72 | - [x] 二进制位操作宏 73 | 74 | # 如何贡献 75 | - 主分支:main, 用于发布稳定版本(待发布) 76 | - 开发分支:dev, 用于开发新功能 77 | 78 | // 2024-3-22: 79 | 本项目正在初步开发阶段,main中无可行版本,仅放置README文档作为引导 80 | 请前往dev分支查看最新进展 81 | 82 | # 联系我(们) 83 | QQ交流群: 342568232 -------------------------------------------------------------------------------- /include/adt/dynamic_array.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dynamic_array.h 3 | * @brief dynamic array implementation 4 | * @author inrootshell 5 | * @category data-structure 6 | * @date 2024-3-25 7 | */ 8 | 9 | #ifndef DYNAMIC_ARRAY_H_ 10 | #define DYNAMIC_ARRAY_H_ 11 | 12 | //#include "adt_pre_init.h" 13 | #include 14 | #include 15 | #include 16 | 17 | #ifndef _FN_IN_OUT_ 18 | # define _FN_IN_OUT_ 19 | # define _Fn_In_ 20 | # define _Fn_Out_ 21 | #endif 22 | 23 | #ifndef DYNAMICARRAY_T 24 | # define DYNAMICARRAY_T 25 | typedef struct dynamic_array 26 | { 27 | void** dynamic_array; 28 | int array_capacity; 29 | int array_size; 30 | }dynamic_array_t, *dynamicarray_ptr_t; 31 | #endif 32 | 33 | typedef int status; 34 | 35 | 36 | /* 37 | *@function name:initialize_dynamic_array 38 | *@arguments:initialize dynamic array size 39 | *@return type:dynamicarray_ptr_t 40 | *@return value:success return a pointer failed return NULL 41 | */ 42 | extern dynamicarray_ptr_t initialize_dynamic_array(int _Fn_In_ initial_capacity_size); 43 | 44 | /* 45 | *@function name:insert_array_element 46 | *@arguments:dynamic array pointer, insert position and insert data 47 | *@return type:status 48 | *@return value:success return 1 failed return -1 49 | */ 50 | extern status insert_array_element(dynamicarray_ptr_t _Fn_In_ dynamic_array, int _Fn_In_ insert_position, void* _Fn_In_ insert_data); 51 | 52 | /* 53 | *@function name:delete_array_element 54 | *@arguments:dynamic array pointer, delete position and reseved data pointer 55 | *@return type:status 56 | *@return value:success return 1 failed return -1 57 | */ 58 | extern status delete_array_element(dynamicarray_ptr_t _Fn_In_ dynamic_array, int _Fn_In_ delete_position, void** _Fn_Out_ reserved); 59 | 60 | /* 61 | *@function name:print_array_element 62 | *@arguments:dynamic array pointer, back call function print_func 63 | *@return type:void 64 | *@return value:void 65 | */ 66 | extern status print_array_element(dynamicarray_ptr_t _Fn_In_ dynamic_array, void (*print_func)(void* print_data)); 67 | 68 | /* 69 | *@function name:free_dynamic_array 70 | *@arguments:dynamic array pointer 71 | *@return type:status 72 | *@return value:success return 1 failed return -1 73 | */ 74 | extern status free_dynamic_array(dynamicarray_ptr_t _Fn_In_ dynamic_array); 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /include/digest/sha2.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: sha2.h 3 | * @description: This is a header file that contains the declaration of SHA-2 algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/4/16 14:48 6 | * @FilePath: Serendipity/include/digest/sha2.h 7 | * @category: digest-algorithm 8 | */ 9 | 10 | /**************************************************************** 11 | * Module Name: SHA-2 12 | * Description: This module provides the implementation of SHA-2 algorithm. 13 | * Inclusive functions: 14 | * SHA-224, SHA-256, SHA-384 15 | * SHA-512, SHA-512/224, SHA-512/256 16 | * RFC Reference: https://www.rfc-editor.org/info/rfc6234 17 | * NIST Reference: https://csrc.nist.gov/pubs/fips/180-4/upd1/final 18 | ***************************************************************/ 19 | 20 | #ifndef SERENDIPITY_SHA2_H 21 | #define SERENDIPITY_SHA2_H 22 | 23 | /* pre-initialization of digest */ 24 | #include "digest/digest_pre_init.h" 25 | 26 | /* basic sha2 data size */ 27 | #define SHA224_DIGEST_SIZE 28 28 | #define SHA256_DIGEST_SIZE 32 29 | #define SHA384_DIGEST_SIZE 48 30 | #define SHA512_DIGEST_SIZE 64 31 | #define SHA512_224_DIGEST_SIZE 28 32 | #define SHA512_256_DIGEST_SIZE 32 33 | 34 | /* 128-bit word structure */ 35 | typedef struct { 36 | uint64_t high, low; 37 | } uint128_t; 38 | /* 128-bit word operations */ 39 | static uint128_t uint128_add_uint64(uint128_t a, uint64_t b); 40 | 41 | /* SHA-2 mode */ 42 | typedef enum { 43 | SHA224 = 0, 44 | SHA256, 45 | SHA384, 46 | SHA512, 47 | SHA512_224, 48 | SHA512_256 49 | } SHA2_MODE; 50 | 51 | /* SHA-2 Context */ 52 | typedef struct { 53 | SHA2_MODE mode; // SHA-2 mode 54 | uint32_t buffer_len; // buffer length 55 | uint32_t data_len; // data length 56 | uint64_t bit_len; // bit length 57 | uint128_t total_len; // bit length for 512-bit hash 58 | union { 59 | uint32_t s32[8]; // 32-bit hash value 60 | uint64_t s64[8]; // 64-bit hash value 61 | } state; 62 | union { 63 | byte buf32[64]; // 32-bit buffer 64 | byte buf64[128]; // 64-bit buffer 65 | } buffer; 66 | } sha2_ctx; 67 | 68 | /* sha2 functions */ 69 | status sha2_init(sha2_ctx *ctx, SHA2_MODE mode); 70 | status sha2_update(sha2_ctx *ctx, const byte *data, size_t data_len); 71 | status sha2_final(sha2_ctx *ctx, byte *digest); 72 | 73 | /* sha2 transform functions */ 74 | static void sha224_256_transform(sha2_ctx *ctx, const byte *data); 75 | static void sha384_512_transform(sha2_ctx *ctx, const byte *data); 76 | 77 | #endif //SERENDIPITY_SHA2_H 78 | -------------------------------------------------------------------------------- /include/digest/md5.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: md5.h 3 | * @description: This is a header file that contains the declaration of MD5 algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/4/7 9:36 6 | * @LastEditTime: 2024/4/7 9:36 7 | * @FilePath: Serendipity/include/digest/md5.h 8 | * @category: digest-algorithm 9 | */ 10 | 11 | #ifndef SERENDIPITY_MD5_H 12 | #define SERENDIPITY_MD5_H 13 | 14 | /* pre-initialization of digest */ 15 | #include "digest/digest_pre_init.h" 16 | 17 | /* basic md5 data size */ 18 | #define MD5_DIGEST_SIZE 16 19 | 20 | /* md5 data */ 21 | /* // The table that is used to calculate the md5 22 | * static const uint32_t T[64] = { 23 | 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 24 | 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 25 | 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 26 | 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 27 | 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 28 | 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 29 | 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 30 | 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 31 | 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 32 | 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 33 | 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 34 | 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 35 | 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 36 | 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 37 | 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 38 | 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 39 | };*/ 40 | 41 | /* md5 auxiliary functions */ 42 | #define F(x, y, z) (((x) & (y)) | ((~x) & (z))) 43 | #define G(x, y, z) (((x) & (z)) | ((y) & (~z))) 44 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 45 | #define I(x, y, z) ((y) ^ ((x) | (~z))) 46 | 47 | #define FF(a, b, c, d, mj, s, ti) \ 48 | (a = b + ( CYCLE_SHL_SIZE_NBIT(a + F(b, c, d) + mj + ti, s, uint32_t))) 49 | #define GG(a, b, c, d, mj, s, ti) \ 50 | (a = b + ( CYCLE_SHL_SIZE_NBIT(a + G(b, c, d) + mj + ti, s, uint32_t))) 51 | #define HH(a, b, c, d, mj, s, ti) \ 52 | (a = b + ( CYCLE_SHL_SIZE_NBIT(a + H(b, c, d) + mj + ti, s, uint32_t))) 53 | #define II(a, b, c, d, mj, s, ti) \ 54 | (a = b + ( CYCLE_SHL_SIZE_NBIT(a + I(b, c, d) + mj + ti, s, uint32_t))) 55 | 56 | /* md5 function */ 57 | static uint32_t *md5_padding(const byte *data, size_t data_bit_count, size_t *block_size); 58 | 59 | status md5(const byte *data, size_t data_bit_size, char *digest); 60 | 61 | #endif //SERENDIPITY_MD5_H 62 | -------------------------------------------------------------------------------- /src/encode/hex.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: hex.c 3 | * @description: hex transform implementation 4 | * @author: WAHAHA 5 | * @Date: 2024-02-29 13:06:25 6 | * @LastEditTime: 2024-03-04 12:29:16 7 | * @FilePath: \Serendipity\src\encode\hex.c 8 | * @category: encode-algorithm 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | * @Funticon name: hex_to_bytes 17 | * @description: transform hex string to bytes 18 | * @Author: WAHAHA 19 | * @Date: 2024-03-04 12:25:50 20 | * @Note: The function will process until the first error occurs. 21 | * @Note: return 1: all hex characters are correct. 22 | * @Note: return 0: part of hex characters are incorrect. 23 | * @Note: return -1: parameter error. 24 | * @return {status} 25 | */ 26 | status hex_to_bytes(const char *hex, size_t in_len, byte *bytes, size_t *out_len) { 27 | ASSERT(hex != NULL && bytes != NULL && out_len != NULL, error); 28 | ASSERT(in_len % 2 == 0, error); 29 | 30 | /* init the buffer */ 31 | memset(bytes, 0, in_len / 2); 32 | 33 | for (size_t i = 0; i < in_len; i++) { 34 | char c = hex[i]; 35 | byte value; 36 | if (c >= '0' && c <= '9') { 37 | value = c - '0'; 38 | } else if (c >= 'a' && c <= 'f') { 39 | value = c - 'a' + 10; 40 | } else if (c >= 'A' && c <= 'F') { 41 | value = c - 'A' + 10; 42 | } else { 43 | printf("hex_to_bytes error: incorrect hex character\r\n"); 44 | bytes[i / 2] = 0; // reset the value 45 | *out_len = (i - (i & 1)) / 2; // set the correct length 46 | return false; 47 | } 48 | /* shift the value to the correct position */ 49 | bytes[i / 2] += value << (4 * (1 - (i & 1))); 50 | } 51 | *out_len = in_len / 2; // set the correct length 52 | return true; 53 | } 54 | 55 | /** 56 | * @Funticon name: bytes_to_hex 57 | * @description: transform bytes to hex string 58 | * @Author: WAHAHA 59 | * @Date: 2024-03-04 12:28:53 60 | * @Note: None 61 | * @return {status} 62 | */ 63 | status bytes_to_hex(const byte *bytes, size_t in_len, char *hex, size_t *out_len) { 64 | ASSERT(bytes != NULL && hex != NULL && out_len != NULL, error); 65 | ASSERT(in_len > 0, error); 66 | 67 | const char *hex_table = "0123456789abcdef"; 68 | 69 | *out_len = in_len * 2; 70 | size_t out_idx = 0; 71 | for (size_t i = 0; i < in_len; ++i) { 72 | hex[out_idx++] = hex_table[bytes[i] >> 4]; 73 | hex[out_idx++] = hex_table[bytes[i] & 0x0f]; 74 | } 75 | hex[out_idx] = '\0'; 76 | return true; 77 | } 78 | -------------------------------------------------------------------------------- /docs/encode/base64.md: -------------------------------------------------------------------------------- 1 | # Base64 编码/解码模块 2 | 3 | 这个模块提供了将数据进行 Base64 编码和解码的功能. 4 | 5 | 不仅支持标准的base64编码,而且支持自定义表,表中可以不是合法的ASCII字符,即字符数值范围支持`0~255`,而不是`0~127`. 6 | 7 | ## 依赖 8 | 9 | 该模块依赖于`encode/encode_pre_init.h`. 10 | 11 | # 数据类型参考 12 | 13 | ## base64_encoder 14 | 15 | ```c 16 | typedef struct base64_encoder { 17 | byte* b64_table; 18 | byte* reverse_table; 19 | int output_len; 20 | } base64_encoder; 21 | ``` 22 | 23 | - base64_encoder是base64模块所使用的"编码器"类型. 24 | - b64_table: 该编码器实例所使用的"base64表". 25 | - reverse_table: 该编码器实例所使用的"base64表"所对应的"逆表",用于解码. 26 | 27 | 应该使用`new_base64`函数来创建一个`base64_encoder`实例;对应地,使用`free_base64`函数将其释放. 28 | 29 | # API参考 30 | 31 | ## new_base64 32 | 33 | 该函数创建一个"编码器"实例,并返回其指针. 34 | 35 | 函数原型: 36 | 37 | ```c 38 | base64_encoder *new_base64(const byte *b64_table); 39 | ``` 40 | 41 | - b64_table: 一个只读的长为64字节的byte字符串,来指定该"编码器"所使用的`Base64表`,如果想要使用`标准base64`编码,则传入`NULL`. 42 | - 返回一个`base64_encoder *`,指向创建的`base64_encoder`实例,如果调用失败,返回`NULL`. 43 | 44 | ## free_base64 45 | 46 | 该函数销毁一个"编码器"实例. 47 | 48 | 函数原型: 49 | 50 | ```c 51 | status free_base64(base64_encoder *encoder); 52 | ``` 53 | 54 | - encoder: 一个`base64_encoder *`的参数,指向需要销毁的`base64_encoder`实例,如果为NULL,返回值为`error`. 55 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 56 | 57 | ## base64_change_table 58 | 59 | 该函数修改一个"编码器"所使用的`base64表`. 60 | 61 | 函数原型: 62 | 63 | ```c 64 | status base64_change_table(base64_encoder *encoder, const byte *b64_table); 65 | ``` 66 | 67 | - encoder: 一个`base64_encoder *`的参数,指向要处理的`base64_encoder`实例. 68 | - b64_table: 一个长为64字节的byte字符串,来指定要使用的新`Base64表`,该不允许为`NULL`. 69 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 70 | 71 | ## base64_reset 72 | 73 | 该函数将一个"编码器"重置为标准状态,即使用默认`base64表`,并将`output`成员的值重置. 74 | 75 | 函数原型: 76 | 77 | ```c 78 | status base64_reset(base64_encoder *encoder); 79 | ``` 80 | 81 | - encoder: 一个`base64_encoder *`的参数,指向要处理的`base64_encoder`实例. 82 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 83 | 84 | ## base64_encode 85 | 86 | 该函数进行`base64编码`的操作,将输入的数据进行编码. 87 | 88 | 函数原型: 89 | 90 | ```c 91 | status base64_encode(base64_encoder *encoder, const byte *input, int in_len, byte *output); 92 | ``` 93 | 94 | - encoder: 接受一个`base64_encoder *`的参数,指向要使用的`base64_encoder`实例,该实例`应该`被提前设置好. 95 | - input: 接受一个只读的byte指针,指向待编码的字节数据. 96 | - in_len: input参数指向的数据的长度,单位是`字节`. 97 | - output: 指向一个缓冲区,用于存储生成的编码数据. 98 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 99 | 100 | ## base64_decode 101 | 102 | 该函数进行`base64解码`的操作,将输入的数据进行解码. 103 | 104 | ```c 105 | status base64_decode(base64_encoder *encoder, const byte *input, int in_len, byte *output); 106 | ``` 107 | 108 | - encoder: 接受一个`base64_encoder *`的参数,指向要使用的`base64_encoder`实例,该实例`应该`被提前设置好. 109 | - input: 接受一个只读的byte指针,指向待解码的字节数据. 110 | - in_len: input参数指向的数据的长度,单位是`字节`. 111 | - output: 指向一个缓冲区,用于存储生成的解码数据. 112 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. -------------------------------------------------------------------------------- /src/encrypt/pkcspad.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: pkcspad.c 3 | * @description: This is a source file that contains the implementation of PKCSPAD algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/3/19 2:29 6 | * @LastEditTime: 2024/3/19 2:29 7 | * @FilePath: Serendipity/src/encrypt/pkcspad.c 8 | * @category: encrypt-algorithm 9 | */ 10 | 11 | #include 12 | //#include 13 | #include 14 | #include 15 | 16 | /** 17 | * @Funticon name: pkcs7_pad 18 | * @description: padding the data with PKCS7 19 | * @Author: WAHAHA 20 | * @Date: 2024-3-21 15:34:37 21 | * @Note: This function will return a new memory block,which should be freed by the caller. 22 | * @param {byte} *data 23 | * @param {size_t} data_len 24 | * @param {size_t} block_size 25 | * @return {byte *} 26 | */ 27 | byte *pkcs7_pad(const byte *data, size_t data_len, size_t block_size) { 28 | if (data == NULL) 29 | return NULL; 30 | 31 | byte pad_value = pkcs7_pad_len(data_len, block_size); 32 | size_t pad_data_len = data_len + pad_value; 33 | byte *output = (byte *) malloc(sizeof(byte) * pad_data_len); 34 | if (output == NULL) 35 | return NULL; 36 | 37 | memcpy(output, data, data_len); 38 | memset(output + data_len, pad_value, pad_value); 39 | 40 | return output; 41 | } 42 | 43 | /** 44 | * @Funticon name: pkck7_unpad 45 | * @description: unpadding the data with PKCS7 46 | * @Author: WAHAHA 47 | * @Date: 2024-3-21 15:36:26 48 | * @Note: This function will return a new memory block,which should be freed by the caller. 49 | * @param {byte} *data 50 | * @param {size_t} data_len 51 | * @param {size_t} block_size 52 | * @return {byte *} 53 | */ 54 | byte *pkcs7_unpad(const byte *data, size_t data_len, size_t block_size) { 55 | if (data == NULL) 56 | return NULL; 57 | 58 | byte pad_value = data[data_len - 1]; 59 | /* check the padding value */ 60 | if (pad_value >= block_size) 61 | return NULL; 62 | 63 | size_t unpad_data_len = data_len - pad_value; 64 | byte *output = (byte *) malloc(sizeof(byte) * unpad_data_len); 65 | if (output == NULL) 66 | return NULL; 67 | 68 | memcpy(output, data, unpad_data_len); 69 | 70 | return output; 71 | } 72 | 73 | /** 74 | * @Funticon name: pkcs5_pad 75 | * @description: padding the data with PKCS5 76 | * @Author: WAHAHA 77 | * @Date: 2024-3-21 16:1:26 78 | * @Note: This function will return a new memory block,which should be freed by the caller. 79 | * @param {byte} *data 80 | * @param {size_t} data_len 81 | * @return {byte *} 82 | */ 83 | byte *pkcs5_pad(const byte *data, size_t data_len){ 84 | return pkcs7_pad(data, data_len, PKCS5_BLOCK_SIZE); 85 | } 86 | 87 | /** 88 | * @Funticon name: pkcs5_unpad 89 | * @description: unpadding the data with PKCS5 90 | * @Author: WAHAHA 91 | * @Date: 2024-3-21 16:4:35 92 | * @Note: This function will return a new memory block,which should be freed by the caller. 93 | * @param {byte} *data 94 | * @param {size_t} data_len 95 | * @return {byte *} 96 | */ 97 | byte *pkcs5_unpad(const byte *data, size_t data_len){ 98 | return pkcs7_unpad(data, data_len, PKCS5_BLOCK_SIZE); 99 | } -------------------------------------------------------------------------------- /include/adt/queue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file dynamic_array.h 3 | * @brief dynamic array implementation 4 | * @author inrootshell 5 | * @category data-structure 6 | * @date 2024-4-11 7 | */ 8 | 9 | #ifndef QUEUE_H_ //If no queue header file is defined 10 | 11 | #define QUEUE_H_ //definition queue header file flag 12 | 13 | //#include "adt_pre_init.h" 14 | #include //include standard c header file 15 | #include 16 | #include 17 | #include 18 | 19 | #ifndef SEQQUEUE_T //If the linear queue type is not defined 20 | 21 | #define SEQQUEUE_T 1 //defined flag 22 | 23 | typedef int status; 24 | 25 | typedef struct _seqqueue_t //define linaer queue structure 26 | { 27 | void** queue_array; //An array that stores queue data 28 | int queue_max_size; //The maximum size of the queue 29 | int queue_header; //The head of the line 30 | int queue_tail; //Tail pointer 31 | }seqqueue_t, *seqqueue_ptr_t; //structure type alias 32 | 33 | #endif //end define 34 | 35 | /* 36 | *@function name:initialize_queue 37 | *@arguments:initialize queue size 38 | *@return type:seqqueue_ptr_t 39 | *@return value:success return a pointer failed return NULL 40 | */ 41 | 42 | extern seqqueue_ptr_t initialize_queue(unsigned int initialize_queue_size); 43 | 44 | /* 45 | *@function name:enter_queue 46 | *@arguments:Queue pointers and data pointers 47 | *@return type:status 48 | *@return value:success return 1 argments error return -1 function error return 0 49 | */ 50 | 51 | extern status enter_queue(seqqueue_ptr_t queue, void* new_data); 52 | 53 | /* 54 | *@function name:out_queue 55 | *@arguments:Queue pointers and reserved pointers 56 | *@return type:status 57 | *@return value:success return 1 argments error return -1 function error return 0 58 | */ 59 | extern status out_queue(seqqueue_ptr_t queue, void** reserved_data); 60 | 61 | /* 62 | *@function name:print_queue 63 | *@arguments:Queue pointer and callback function pointer 64 | *@return type:status 65 | *@return value:success print return 1 fail return 0 66 | */ 67 | extern status print_queue(seqqueue_ptr_t queue, void (*print_back)(void* print_data)); 68 | 69 | /* 70 | *@function name:print_back 71 | *@arguments:print data 72 | *@return type:void 73 | *@return value:void 74 | */ 75 | 76 | extern void print_back(void* print_data); 77 | 78 | /* 79 | *@function name:get_queue_header 80 | *@arguments:queue pointer 81 | *@return type:void* 82 | *@return value:queue pointer is null return null else return queue head element 83 | */ 84 | 85 | extern void* get_queue_header(seqqueue_ptr_t queue); 86 | 87 | /* 88 | *@function name:get_queue_tail 89 | *@arguments:queue pointer 90 | *@return type:void* 91 | *@return value:queue pointer is null return null else return queue tail element 92 | */ 93 | 94 | extern void* get_queue_tail(seqqueue_ptr_t queue); 95 | 96 | /* 97 | *@function name: 98 | *@arguments:queue pointer 99 | *@return type:int 100 | *@return value:queue pointer is null return 0 else return queue current size 101 | */ 102 | 103 | extern int get_queue_current_size(seqqueue_ptr_t queue); 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /docs/encrypt/tea.md: -------------------------------------------------------------------------------- 1 | # TEA 加密/解密模块 2 | 3 | 该模块实现了`TEA`,`XTEA`,`XXTEA`三种加密算法,并支持如下自定义: 4 | - 三种加密自定义`delta`值. 5 | - `TEA`,`XTEA`自定义加密轮次`round`. 6 | 7 | ## 依赖 8 | 9 | 该模块依赖于`encrypt/encrypt_pre_init.h`. 10 | 11 | # 数据类型参考 12 | 13 | ## tea_encipher 14 | 15 | ```C 16 | typedef struct tea_encipher { 17 | uint32_t delta; 18 | int rounds; // not available for XXTEA 19 | int n; // the count of blocks 20 | uint32_t key[4]; 21 | } tea_encipher; 22 | ``` 23 | 24 | - tea_encipher是tea模块所使用的"加密器"类型. 25 | - delta: TEA系加密所使用的delta值,可以设置为默认值. 26 | - rounds: `TEA`和`XTEA`的加密轮次,默认为32. 27 | - n: 需要加密/解密的分组数,一个分组为`32-bits`. 28 | 29 | 应该使用`new_tea`函数来创建一个`tea_encipher`实例;对应地,使用`free_tea`函数将其释放. 30 | `TEA`,`XTEA`,`XXTEA`均使用相同`tea_encipher*`类型的"加密器"参数,其中无关参数`rounds`对`XXTEA`的加密/解密无影响. 31 | 32 | `tea_encipher`结构体的成员也可以直接设置其值进行修改,以达到复用等效果. 33 | 34 | # API参考 35 | 36 | ## new_tea 37 | 38 | 该函数创建一个`tea_encipher`实例,并返回其指针. 39 | 40 | 函数原型: 41 | ```C 42 | tea_encipher *new_tea(uint32_t delta, const uint32_t key[4], int rounds); 43 | ``` 44 | 45 | - delta: 一个无符号的32位整数,来指定`DELTA`值,如果该参数为零,则使用默认`DELTA`值. 46 | - key: 一个长为4的32位整数数组,用于指定`密钥`. 即TEA系加密的`128-bits`密钥. 47 | - rounds: 一个整数,用于指定加密轮次,当该加密器用于`XXTEA`时,`round`参数无效. 48 | - 返回一个`tea_encipher *`,指向创建的`tea_encipher`实例,如果调用失败,返回`NULL`. 49 | 50 | ## free_tea 51 | 52 | 该函数销毁一个`tea_encipher`实例. 53 | 函数原型: 54 | 55 | ```C 56 | status free_tea(tea_encipher *tea); 57 | ``` 58 | 59 | - tea: 一个`tea_encipher *`的参数,指向需要销毁的`tea_encipher`实例,如果为NULL,返回值为`error`. 60 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 61 | 62 | ## tea_encrypt 63 | 64 | 该函数对输入的数据进行`TEA`加密. 65 | 函数原型: 66 | ```C 67 | status tea_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 68 | ``` 69 | 70 | 其中: 71 | - tea: 一个`tea_encrypt`的指针,指向一个`tea_encrypt`实例. 其信息指定特定的加密过程. 72 | - plain: 一个只读的`uint32_t`指针,指向待加密的若干分组,分组个数必须是偶数. 73 | - cipher: 一个`uint32_t`指针,指向caller分配好的内存段,用于存储加密结果. 74 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 75 | 注意: 76 | - 在调用该函数之前,`tea->n`必须被设置为待处理数据的分组数. 77 | ## tea_decrypt 78 | 79 | 该函数对输入的数据进行`TEA`解密. 80 | 函数原型: 81 | ```C 82 | status tea_decrypt(tea_encipher *tea,const uint32_t *cipher, uint32_t *plain); 83 | ``` 84 | 85 | 其中: 86 | - tea: 一个`tea_encrypt`的指针,指向一个`tea_encrypt`实例. 其信息指定特定的解密过程. 87 | - cipher: 一个只读的`uint32_t`指针,指向待解密的若干分组,分组个数必须是偶数. 88 | - plain: 一个`uint32_t`指针,指向caller分配好的内存段,用于存储解密结果. 89 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 90 | 注意: 91 | - 在调用该函数之前,`tea->n`必须被设置为待处理数据的分组数. 92 | 93 | ## xtea_encrypt 94 | 95 | 该函数对输入的数据进行`XTEA`加密. 96 | 函数原型: 97 | ```C 98 | status xtea_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 99 | ``` 100 | 101 | 其中: 102 | - tea: 一个`tea_encrypt`的指针,指向一个`tea_encrypt`实例. 其信息指定特定的加密过程. 103 | - plain: 一个只读的`uint32_t`指针,指向待加密的若干分组,分组个数必须是偶数. 104 | - cipher: 一个`uint32_t`指针,指向caller分配好的内存段,用于存储加密结果. 105 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 106 | 注意: 107 | - 在调用该函数之前,`tea->n`必须被设置为待处理数据的分组数. 108 | ## xtea_decrypt 109 | 110 | 该函数对输入的数据进行`XTEA`解密. 111 | 函数原型: 112 | ```C 113 | status xtea_decrypt(tea_encipher *tea,const uint32_t *cipher, uint32_t *plain); 114 | ``` 115 | 116 | 其中: 117 | - tea: 一个`tea_encrypt`的指针,指向一个`tea_encrypt`实例. 其信息指定特定的解密过程. 118 | - cipher: 一个只读的`uint32_t`指针,指向待解密的若干分组,分组个数必须是偶数. 119 | - plain: 一个`uint32_t`指针,指向caller分配好的内存段,用于存储解密结果. 120 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 121 | 注意: 122 | - 在调用该函数之前,`tea->n`必须被设置为待处理数据的分组数. 123 | 124 | ## xxtea_encrypt 125 | 126 | 该函数对输入的数据进行`XXTEA`加密. 127 | 函数原型: 128 | ```C 129 | status xxtea_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher); 130 | ``` 131 | 132 | 其中: 133 | - tea: 一个`tea_encrypt`的指针,指向一个`tea_encrypt`实例. 其信息指定特定的加密过程. 134 | - plain: 一个只读的`uint32_t`指针,指向待加密的若干分组,分组个数必须是偶数. 135 | - cipher: 一个`uint32_t`指针,指向caller分配好的内存段,用于存储加密结果. 136 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 137 | 注意: 138 | - 在调用该函数之前,`tea->n`必须被设置为待处理数据的分组数,并且不能为零. 139 | - 对于`XXTEA`,`tea->rounds`没有作用,但其值是否被设置并无影响. 140 | ## xxtea_decrypt 141 | 142 | 该函数对输入的数据进行`XXTEA`解密. 143 | 函数原型: 144 | ```C 145 | status tea_decrypt(tea_encipher *tea,const uint32_t *cipher, uint32_t *plain); 146 | ``` 147 | 148 | 其中: 149 | - tea: 一个`tea_encrypt`的指针,指向一个`tea_encrypt`实例. 其信息指定特定的解密过程. 150 | - cipher: 一个只读的`uint32_t`指针,指向待解密的若干分组,分组个数必须是偶数. 151 | - plain: 一个`uint32_t`指针,指向caller分配好的内存段,用于存储解密结果. 152 | - 返回值为`status`,等价于`int`,成功返回`1`,失败返回`非1`. 153 | 注意: 154 | - 在调用该函数之前,`tea->n`必须被设置为待处理数据的分组数,并且不能为零. 155 | - 对于`XXTEA`,`tea->rounds`没有作用,但其值是否被设置并无影响. 156 | -------------------------------------------------------------------------------- /include/misc/endian.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: endian.h 3 | * @description: This header file contains macros for endian conversion. 4 | * @author: WAHAHA 5 | * @Date: 2024/3/28 14:38 6 | * @LastEditTime: 2024/3/28 14:38 7 | * @FilePath: Serendipity/include/misc/endian.h 8 | * @category: misc 9 | */ 10 | 11 | #ifndef SERENDIPITY_ENDIAN_H 12 | #define SERENDIPITY_ENDIAN_H 13 | 14 | /* 15 | * Convert 4 bytes of data to uint32_t in big-endian or little-endian 16 | */ 17 | /* big-endian */ 18 | // u: uint32_t, b: unsigned char * 19 | #define BE_BYTES_TO_UINT32(u, b) \ 20 | ((u) = (uint32_t)((b)[0]) << 24 \ 21 | | (uint32_t)((b)[1]) << 16 \ 22 | | (uint32_t)((b)[2]) << 8 \ 23 | | (uint32_t)((b)[3]) \ 24 | ) 25 | 26 | // b: unsigned char *, u: uint32_t 27 | #define BE_UINT32_TO_BYTES(b, u) \ 28 | do { \ 29 | (b)[0] = (unsigned char)((u) >> 24); \ 30 | (b)[1] = (unsigned char)((u) >> 16); \ 31 | (b)[2] = (unsigned char)((u) >> 8); \ 32 | (b)[3] = (unsigned char)( u ); \ 33 | } while(0) 34 | 35 | // b: unsigned char *, u: uint64_t 36 | #define BE_BYTES_TO_UINT64(b, u) \ 37 | ((u) = (uint64_t)((b)[0]) << 56 \ 38 | | (uint64_t)((b)[1]) << 48 \ 39 | | (uint64_t)((b)[2]) << 40 \ 40 | | (uint64_t)((b)[3]) << 32 \ 41 | | (uint64_t)((b)[4]) << 24 \ 42 | | (uint64_t)((b)[5]) << 16 \ 43 | | (uint64_t)((b)[6]) << 8 \ 44 | | (uint64_t)((b)[7]) \ 45 | ) 46 | 47 | // u: uint64_t, b: unsigned char * 48 | #define BE_UINT64_TO_BYTES(b, u) \ 49 | do { \ 50 | (b)[0] = (unsigned char)((u) >> 56); \ 51 | (b)[1] = (unsigned char)((u) >> 48); \ 52 | (b)[2] = (unsigned char)((u) >> 40); \ 53 | (b)[3] = (unsigned char)((u) >> 32); \ 54 | (b)[4] = (unsigned char)((u) >> 24); \ 55 | (b)[5] = (unsigned char)((u) >> 16); \ 56 | (b)[6] = (unsigned char)((u) >> 8); \ 57 | (b)[7] = (unsigned char)( u ); \ 58 | } while(0) 59 | 60 | /* little-endian */ 61 | // u: uint32_t, b: unsigned char * 62 | #define LE_BYTES_TO_UINT32(u, b) \ 63 | ((u) = (uint32_t)((b)[3]) << 24 \ 64 | | (uint32_t)((b)[2]) << 16 \ 65 | | (uint32_t)((b)[1]) << 8 \ 66 | | (uint32_t)((b)[0]) \ 67 | ) 68 | 69 | // b: unsigned char *, u: uint32_t 70 | #define LE_UINT32_TO_BYTES(b, u) \ 71 | do { \ 72 | (b)[3] = (unsigned char)((u) >> 24); \ 73 | (b)[2] = (unsigned char)((u) >> 16); \ 74 | (b)[1] = (unsigned char)((u) >> 8); \ 75 | (b)[0] = (unsigned char)( u ); \ 76 | } while(0) 77 | 78 | // b: unsigned char *, u: uint64_t 79 | #define LE_BYTES_TO_UINT64(b, u) \ 80 | ((u) = (uint64_t)((b)[7]) << 56 \ 81 | | (uint64_t)((b)[6]) << 48 \ 82 | | (uint64_t)((b)[5]) << 40 \ 83 | | (uint64_t)((b)[4]) << 32 \ 84 | | (uint64_t)((b)[3]) << 24 \ 85 | | (uint64_t)((b)[2]) << 16 \ 86 | | (uint64_t)((b)[1]) << 8 \ 87 | | (uint64_t)((b)[0]) \ 88 | ) 89 | 90 | // u: uint64_t, b: unsigned char * 91 | #define LE_UINT64_TO_BYTES(b, u) \ 92 | do { \ 93 | (b)[7] = (unsigned char)((u) >> 56); \ 94 | (b)[6] = (unsigned char)((u) >> 48); \ 95 | (b)[5] = (unsigned char)((u) >> 40); \ 96 | (b)[4] = (unsigned char)((u) >> 32); \ 97 | (b)[3] = (unsigned char)((u) >> 24); \ 98 | (b)[2] = (unsigned char)((u) >> 16); \ 99 | (b)[1] = (unsigned char)((u) >> 8); \ 100 | (b)[0] = (unsigned char)( u ); \ 101 | } while(0) 102 | 103 | #endif //SERENDIPITY_ENDIAN_H 104 | -------------------------------------------------------------------------------- /src/encrypt/rc4.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: rc4.c 3 | * @description: RC4 encryption algorithm implementation 4 | * @author: WAHAHA 5 | * @Date: 2024-03-05 14:15:45 6 | * @LastEditTime: 2024-03-05 14:46:00 7 | * @FilePath: \Serendipity\src\encrypt\rc4.c 8 | * @category: encrypt-algorithm 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | /** 15 | * @Funticon name: new_rc4 16 | * @description: new a rc4_encipher object 17 | * @Author: WAHAHA 18 | * @Date: 2024-3-10 20:40:22 19 | * @Note: None 20 | * @return {rc4_encipher *} 21 | */ 22 | rc4_encipher *new_rc4() { 23 | /* alloc the memory */ 24 | rc4_encipher *rc4 = (rc4_encipher *) malloc(sizeof(rc4_encipher)); 25 | if (rc4 == NULL) 26 | return NULL; 27 | /* set the default value */ 28 | rc4->sbox = NULL; 29 | rc4->key = NULL; 30 | rc4->key_len = 0; 31 | rc4->initialized = false; 32 | return rc4; 33 | } 34 | 35 | /** 36 | * @Funticon name: free_rc4 37 | * @description: free a rc4_encipher object 38 | * @Author: WAHAHA 39 | * @Date: 2024-3-10 21:14:23 40 | * @Note: None 41 | * @param {rc4_encipher} *rc4 42 | * @return {status} 43 | */ 44 | status free_rc4(rc4_encipher *rc4) { 45 | ASSERT(rc4 != NULL, error); 46 | if (rc4->key != NULL) 47 | free(rc4->key); 48 | if (rc4->sbox != NULL) 49 | free(rc4->sbox); 50 | free(rc4); 51 | return true; 52 | } 53 | 54 | /** 55 | * @Funticon name: rc4_init 56 | * @description: set the key of the rc4_encipher 57 | * @Author: WAHAHA 58 | * @Date: 2024-3-10 21:15:3 59 | * @Note: the key_len must be greater than 0 60 | * @Note: the sbox_len must be greater than or equal to 0 61 | * @Note: if sbox_len is 0, use the default sbox length 62 | * @param {rc4_encipher} *rc4 63 | * @param {byte} *key 64 | * @param {int} key_len 65 | * @param {int} sbox_len 66 | * @return {status} 67 | */ 68 | status rc4_init(rc4_encipher *rc4, const byte *key, int key_len, int sbox_len) { 69 | /* check the parameters */ 70 | ASSERT(rc4 != NULL && key != NULL, error); 71 | ASSERT(key_len > 0 && sbox_len >= 0, error); 72 | 73 | /* if the key is not NULL, free it */ 74 | if (rc4->key != NULL) 75 | free(rc4->key); 76 | /* alloc the memory for the new key */ 77 | rc4->key = (byte *) malloc(key_len); 78 | if (rc4->key == NULL) 79 | return error; 80 | 81 | /* set the key */ 82 | for (int i = 0; i < key_len; i++) 83 | rc4->key[i] = key[i]; 84 | rc4->key_len = key_len; 85 | rc4->initialized = true; 86 | 87 | /* alloc the memory for the sbox */ 88 | rc4->sbox_len = sbox_len == 0 ? RC4_DEFAULT_SBOX_LEN : sbox_len; 89 | if (rc4->sbox != NULL) 90 | free(rc4->sbox); 91 | rc4->sbox = (byte *) malloc(rc4->sbox_len); 92 | if (rc4->sbox == NULL) 93 | return error; 94 | 95 | /* 96 | * directly return true,the sbox will be generated in rc4_crypt(), 97 | * for the sbox will be changed every time when encrypting the data 98 | */ 99 | return true; 100 | } 101 | 102 | /** 103 | * @Funticon name: rc4_generate_sbox 104 | * @description: generate the sbox of the rc4_encipher 105 | * @Author: WAHAHA 106 | * @Date: 2024-3-10 21:26:25 107 | * @Note: None 108 | * @param {rc4_encipher} *rc4 109 | * @return {status} 110 | */ 111 | static status rc4_generate_sbox(rc4_encipher *rc4) { 112 | ASSERT(rc4 != NULL, error); 113 | int j = 0; 114 | for (int i = 0; i < rc4->sbox_len; i++) 115 | rc4->sbox[i] = i; 116 | for (int i = 0; i < rc4->sbox_len; i++) { 117 | j = (j + rc4->sbox[i] + rc4->key[i % rc4->key_len]) % rc4->sbox_len; 118 | byte temp = rc4->sbox[i]; 119 | rc4->sbox[i] = rc4->sbox[j]; 120 | rc4->sbox[j] = temp; 121 | } 122 | return true; 123 | } 124 | 125 | /** 126 | * @Funticon name: rc4_crypt 127 | * @description: crypt the data using the rc4_encipher 128 | * @Author: WAHAHA 129 | * @Date: 2024-3-10 21:28:2 130 | * @Note: the length of the out_data is equal to the data_len 131 | * @param {rc4_encipher} *rc4 132 | * @param {byte} *in_data 133 | * @param {int} data_len 134 | * @param {byte} *out_data 135 | * @return {status} 136 | */ 137 | status rc4_crypt(rc4_encipher *rc4, const byte *in_data, int data_len, byte *out_data) { 138 | ASSERT(rc4 != NULL && in_data != NULL 139 | && out_data != NULL && rc4->initialized, error); 140 | /* generate the sbox */ 141 | ASSERT(rc4_generate_sbox(rc4), error); 142 | 143 | int i = 0, j = 0; 144 | for (int k = 0; k < data_len; k++) { 145 | /* update i and j */ 146 | i = (i + 1) % rc4->sbox_len; 147 | j = (j + rc4->sbox[i]) % rc4->sbox_len; 148 | /* swap sbox[i] and sbox[j] */ 149 | byte temp = rc4->sbox[i]; 150 | rc4->sbox[i] = rc4->sbox[j]; 151 | rc4->sbox[j] = temp; 152 | /* crypt the data */ 153 | int t = (rc4->sbox[i] + rc4->sbox[j]) % rc4->sbox_len; 154 | out_data[k] = in_data[k] ^ rc4->sbox[t]; 155 | } 156 | out_data[data_len] = '\0'; 157 | return true; 158 | } 159 | -------------------------------------------------------------------------------- /include/encrypt/sm4.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: SM4.h 3 | * @description: This is a header file that contains the declaration of the SM4 encryption algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/3/15 15:48 6 | * @FilePath: \Serendipity\include\encrypt\SM4.h 7 | * @category: encrypt-algorithm 8 | */ 9 | 10 | #ifndef SERENDIPITY_SM4_H 11 | #define SERENDIPITY_SM4_H 12 | 13 | /* pre-initialization of encrypt */ 14 | #include 15 | 16 | /* SM4 system parameters and macros */ 17 | /* basic data length macro of SM4 */ 18 | #define SM4_BLOCK_SIZE 16 19 | #define SM4_WORD_SIZE 4 20 | #define SM4_KEY_SIZE 16 21 | #define SM4_ROUND 32 22 | /* encryption and decryption mode */ 23 | #define SM4_ENCRYPT 1 24 | #define SM4_DECRYPT (-1) 25 | 26 | /* system parameters for SM4 */ 27 | static const uint32_t SM4_FK[4] = {0xA3B1BAC6, 0x56AA3350, 0x677D9197, 0xB27022DC}; 28 | static const uint32_t SM4_CK[32] = { 29 | 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 30 | 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, 31 | 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, 32 | 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 33 | 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, 34 | 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, 35 | 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 36 | 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 37 | }; 38 | static const byte SM4_SBOX[256] = { 39 | 0xD6, 0x90, 0xE9, 0xFE, 0xCC, 0xE1, 0x3D, 0xB7, 0x16, 0xB6, 0x14, 0xC2, 0x28, 0xFB, 0x2C, 40 | 0x05, 41 | 0x2B, 0x67, 0x9A, 0x76, 0x2A, 0xBE, 0x04, 0xC3, 0xAA, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 42 | 0x99, 43 | 0x9C, 0x42, 0x50, 0xF4, 0x91, 0xEF, 0x98, 0x7A, 0x33, 0x54, 0x0B, 0x43, 0xED, 0xCF, 0xAC, 44 | 0x62, 45 | 0xE4, 0xB3, 0x1C, 0xA9, 0xC9, 0x08, 0xE8, 0x95, 0x80, 0xDF, 0x94, 0xFA, 0x75, 0x8F, 0x3F, 46 | 0xA6, 47 | 0x47, 0x07, 0xA7, 0xFC, 0xF3, 0x73, 0x17, 0xBA, 0x83, 0x59, 0x3C, 0x19, 0xE6, 0x85, 0x4F, 48 | 0xA8, 49 | 0x68, 0x6B, 0x81, 0xB2, 0x71, 0x64, 0xDA, 0x8B, 0xF8, 0xEB, 0x0F, 0x4B, 0x70, 0x56, 0x9D, 50 | 0x35, 51 | 0x1E, 0x24, 0x0E, 0x5E, 0x63, 0x58, 0xD1, 0xA2, 0x25, 0x22, 0x7C, 0x3B, 0x01, 0x21, 0x78, 52 | 0x87, 53 | 0xD4, 0x00, 0x46, 0x57, 0x9F, 0xD3, 0x27, 0x52, 0x4C, 0x36, 0x02, 0xE7, 0xA0, 0xC4, 0xc8, 54 | 0x9E, 55 | 0xEA, 0xBF, 0x8A, 0xD2, 0x40, 0xC7, 0x38, 0xB5, 0xA3, 0xF7, 0xF2, 0xCE, 0xF9, 0x61, 0x15, 56 | 0xA1, 57 | 0xE0, 0xAE, 0x5D, 0xA4, 0x9B, 0x34, 0x1A, 0x55, 0xAD, 0x93, 0x32, 0x30, 0xF5, 0x8C, 0xB1, 58 | 0xE3, 59 | 0x1D, 0xF6, 0xE2, 0x2E, 0x82, 0x66, 0xCA, 0x60, 0xC0, 0x29, 0x23, 0xAB, 0x0D, 0x53, 0x4E, 60 | 0x6F, 61 | 0xD5, 0xDB, 0x37, 0x45, 0xDE, 0xFD, 0x8E, 0x2F, 0x03, 0xFF, 0x6A, 0x72, 0x6D, 0x6C, 0x5B, 62 | 0x51, 63 | 0x8D, 0x1B, 0xAF, 0x92, 0xBB, 0xDD, 0xBC, 0x7F, 0x11, 0xD9, 0x5C, 0x41, 0x1F, 0x10, 0x5A, 64 | 0xd8, 65 | 0x0A, 0xC1, 0x31, 0x88, 0xA5, 0xCD, 0x7B, 0xBD, 0x2D, 0x74, 0xD0, 0x12, 0xB8, 0xE5, 0xB4, 66 | 0xB0, 67 | 0x89, 0x69, 0x97, 0x4A, 0x0C, 0x96, 0x77, 0x7E, 0x65, 0xB9, 0xF1, 0x09, 0xC5, 0x6E, 0xC6, 68 | 0x84, 69 | 0x18, 0xF0, 0x7D, 0xEC, 0x3A, 0xDC, 0x4D, 0x20, 0x79, 0xEE, 0x5F, 0x3E, 0xD7, 0xCB, 0x39, 70 | 0x48 71 | }; 72 | 73 | /* transformation function macros of SM4 */ 74 | /* tau transformation */ 75 | #define SM4_TAU(uint32_b) \ 76 | ( ((uint32_t)SM4_SBOX[SHR_NBIT((uint32_b),24) & 0xFF] << 24) \ 77 | | ((uint32_t)SM4_SBOX[SHR_NBIT((uint32_b),16) & 0xFF] << 16) \ 78 | | ((uint32_t)SM4_SBOX[SHR_NBIT((uint32_b), 8) & 0xFF] << 8) \ 79 | | ((uint32_t)SM4_SBOX[ (uint32_b) & 0xFF] ) \ 80 | ) 81 | 82 | /* L' transformation of keygen */ 83 | #define SM4_KEYGEN_L(uint32_b) \ 84 | ( (uint32_b) \ 85 | ^ CYCLE_SHL_SIZE_NBIT(uint32_b, 13, uint32_t) \ 86 | ^ CYCLE_SHL_SIZE_NBIT(uint32_b, 23, uint32_t) \ 87 | ) 88 | 89 | /* T' transformation of keygen */ 90 | #define SM4_KEYGEN_T(uint32_b) \ 91 | (SM4_KEYGEN_L(SM4_TAU(uint32_b))) 92 | 93 | /* L transformation of round function */ 94 | #define SM4_ROUND_L(uint32_b) \ 95 | ( uint32_b \ 96 | ^ CYCLE_SHL_SIZE_NBIT(uint32_b, 2, uint32_t) \ 97 | ^ CYCLE_SHL_SIZE_NBIT(uint32_b, 10, uint32_t) \ 98 | ^ CYCLE_SHL_SIZE_NBIT(uint32_b, 18, uint32_t) \ 99 | ^ CYCLE_SHL_SIZE_NBIT(uint32_b, 24, uint32_t) \ 100 | ) 101 | 102 | /* T transformation of round function */ 103 | #define SM4_ROUND_T(uint32_b) \ 104 | ( SM4_ROUND_L(SM4_TAU(uint32_b))) 105 | 106 | 107 | /* SM4 encipher */ 108 | typedef struct sm4_encipher { 109 | uint32_t *rk; // the rk of SM4 110 | byte *key; // the key of SM4 111 | status is_key_set; // the status of the SM4 112 | } sm4_encipher; 113 | 114 | /* sm4_encipher object */ 115 | sm4_encipher *new_sm4(); 116 | 117 | status free_sm4(sm4_encipher *sm4); 118 | 119 | /* SM4 functions */ 120 | /* generate the subkey of the sm4_encipher */ 121 | static status sm4_generate_subkey(sm4_encipher *sm4); 122 | 123 | /* initialize the sm4_encipher object with a 128-bit key */ 124 | status sm4_init(sm4_encipher *sm4, const byte *key); 125 | 126 | /* encrypt and decrypt the data */ 127 | status 128 | sm4_crypt(sm4_encipher *sm4, const byte *in_data, int in_data_len, byte *out_data, int mode); 129 | 130 | /* round function of SM4 */ 131 | status sm4_crypt_block_round(sm4_encipher *sm4, const uint32_t *in_data, uint32_t *out_data, 132 | int mode); 133 | 134 | /* reverse the data */ 135 | status sm4_crypt_block_reverse(uint32_t *data); 136 | 137 | #endif //SERENDIPITY_SM4_H 138 | -------------------------------------------------------------------------------- /src/misc/bf_runner/bf.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: load.c 3 | * @description: This is a source file that contains the implementation of xxx 4 | * @author: WAHAHA 5 | * @Date: 2024/8/7 下午12:45 6 | * @FilePath: bf_runner/load.c 7 | * @category: misc-bf_runner 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include "misc/bf.h" 14 | 15 | bf_ctx_t* new_ctx(unsigned char* input,unsigned char* output) { 16 | // fill with 0 17 | bf_ctx_t* ctx = (bf_ctx_t*)calloc(1, sizeof(bf_ctx_t)); 18 | ctx->array = (byte*)calloc(1, sizeof(char) * MAX_MEM_SIZE); 19 | ctx->arr_size = MAX_MEM_SIZE; 20 | ctx->input = input; 21 | ctx->output = output; 22 | 23 | return ctx; 24 | } 25 | 26 | bf_ctx_t* copy_ctx(const bf_ctx_t* old_ctx) { 27 | bf_ctx_t* new_one = (bf_ctx_t*)malloc(sizeof(bf_ctx_t)); 28 | *new_one = *old_ctx; 29 | return new_one; 30 | } 31 | 32 | void free_ctx(bf_ctx_t* ctx) { 33 | free(ctx->array); 34 | free(ctx); 35 | // NOTE: input and output fields should be freed by caller 36 | } 37 | 38 | void ctx_bind_code(bf_ctx_t* ctx, char* code, const int len) { 39 | ctx->code = code; 40 | ctx->code_len = len; 41 | // null terminate code array 42 | ctx->code[ctx->code_len] = '\0'; 43 | } 44 | 45 | int run_bf(bf_ctx_t* ctx) { 46 | const char* code = ctx->code; 47 | while (ctx->code_ptr < ctx->code_len) { 48 | const char command = code[ctx->code_ptr]; 49 | interpret_command(ctx, command); 50 | if (ctx->status == BF_STATUS_ERROR) { 51 | return -1; 52 | } 53 | ctx->code_ptr++; 54 | } 55 | return ctx->array[ctx->ptr]; 56 | } 57 | 58 | void interpret_command(bf_ctx_t* ctx, const char command) { 59 | switch (command) { 60 | case '>': 61 | vm_add_ptr(ctx); 62 | break; 63 | case '<': 64 | vm_sub_ptr(ctx); 65 | break; 66 | case '+': 67 | vm_add_val(ctx); 68 | break; 69 | case '-': 70 | vm_sub_val(ctx); 71 | break; 72 | case '.': 73 | vm_output(ctx); 74 | break; 75 | case ',': 76 | vm_input(ctx); 77 | break; 78 | case '[': 79 | vm_loop_start(ctx); 80 | break; 81 | case ']': 82 | ctx->status = BF_STATUS_ERROR; 83 | break; 84 | case '\n': // ignore newlines 85 | break; 86 | case ' ': // ignore spaces 87 | break; 88 | default: 89 | ctx->status = BF_STATUS_ERROR; 90 | } 91 | } 92 | 93 | void vm_add_ptr(bf_ctx_t* ctx) { 94 | if (ctx->ptr < ctx->arr_size - 1) { 95 | ctx->ptr++; 96 | } else { 97 | ctx->status = BF_STATUS_ERROR; 98 | } 99 | } 100 | 101 | void vm_sub_ptr(bf_ctx_t* ctx) { 102 | if (ctx->ptr > 0) { 103 | ctx->ptr--; 104 | } else { 105 | ctx->status = BF_STATUS_ERROR; 106 | } 107 | } 108 | 109 | void vm_add_val(bf_ctx_t* ctx) { 110 | if (ctx->array[ctx->ptr] < 255) { 111 | ctx->array[ctx->ptr]++; 112 | } else { 113 | // printf("[ERROR] Value overflow, cannot increment value\n"); 114 | // ctx->status = BF_STATUS_ERROR; 115 | ctx->array[ctx->ptr] = 0; // wrap around 116 | } 117 | } 118 | 119 | void vm_sub_val(bf_ctx_t* ctx) { 120 | if (ctx->array[ctx->ptr] > 0) { 121 | ctx->array[ctx->ptr]--; 122 | } else { 123 | // printf("[ERROR] Value underflow, cannot decrement value\n"); 124 | // ctx->status = BF_STATUS_ERROR; 125 | ctx->array[ctx->ptr] = 255; // wrap around 126 | } 127 | } 128 | 129 | void vm_output(bf_ctx_t* ctx) { 130 | if (ctx->output != NULL) { 131 | ctx->output[ctx->output_ptr] = ctx->array[ctx->ptr]; 132 | ctx->output_ptr++; 133 | } else { 134 | ctx->status = BF_STATUS_ERROR; 135 | // putchar(ctx->array[ctx->ptr]); 136 | } 137 | } 138 | 139 | void vm_input(bf_ctx_t* ctx) { 140 | if (ctx->input != NULL) { 141 | ctx->array[ctx->ptr] = ctx->input[ctx->input_ptr]; 142 | ctx->input_ptr++; 143 | } else { 144 | ctx->status = BF_STATUS_ERROR; 145 | // ch = getch(); // get character from stdin without buffering 146 | } 147 | } 148 | 149 | void vm_loop_start(bf_ctx_t* ctx) { 150 | int cnt; 151 | /* find the matching ']' */ 152 | size_t right_side = ctx->code_ptr; 153 | for (cnt = 1, right_side++; cnt != 0;) { 154 | if (right_side >= ctx->code_len) { 155 | ctx->status = BF_STATUS_ERROR; 156 | return; 157 | } 158 | if (ctx->code[right_side] == '[') { 159 | cnt++; 160 | } else if (ctx->code[right_side] == ']') { 161 | cnt--; 162 | } 163 | right_side++; 164 | } 165 | right_side--; // Locate the matching ']' 166 | 167 | /* check the condition */ 168 | if (ctx->array[ctx->ptr] == 0) { 169 | // skip loop 170 | ctx->code_ptr = right_side; 171 | } else { 172 | // execute loop 173 | do { 174 | /* copy the current context */ 175 | bf_ctx_t* cur_ctx = copy_ctx(ctx); 176 | cur_ctx->code_ptr = ctx->code_ptr + 1; 177 | cur_ctx->code = cur_ctx->code + cur_ctx->code_ptr; 178 | cur_ctx->code_len = right_side - cur_ctx->code_ptr; 179 | cur_ctx->code_ptr = 0; // reset the code pointer to 0 --- offset relative to the start of the loop 180 | /* run the loop */ 181 | run_bf(cur_ctx); // run the loop 182 | /* copy the result back to the original context */ 183 | ctx->ptr = cur_ctx->ptr; 184 | if (cur_ctx->status == BF_STATUS_ERROR) { 185 | ctx->status = BF_STATUS_ERROR; 186 | } 187 | /* free the copied context */ 188 | free(cur_ctx); // just free the copied context obj, but don't free the context data(ctx still owns the data) 189 | } while (ctx->array[ctx->ptr] != 0); 190 | /* move the code pointer to the end of the loop */ 191 | ctx->code_ptr = right_side; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/adt/dynamic_array.c: -------------------------------------------------------------------------------- 1 | #include "dynamic_array.h" 2 | /** 3 | * @file dynamic_array.c 4 | * @brief dynamic array implementation 5 | * @author inrootshell 6 | * @category data-structure 7 | * @date 2024-3-25 8 | */ 9 | 10 | /* 11 | *@function name:initialize_dynamic_array 12 | *@arguments:initialize dynamic array size 13 | *@return type:dynamicarray_ptr_t 14 | *@return value:success return a pointer failed return NULL 15 | */ 16 | dynamicarray_ptr_t initialize_dynamic_array(int initial_capacity_size) 17 | { 18 | if(initial_capacity_size <= 0) //if initialize size Less than or equal to zero 19 | { 20 | return NULL; //return a null pointer 21 | } 22 | 23 | dynamicarray_ptr_t dynamic_array = (dynamicarray_ptr_t)malloc(sizeof(dynamic_array_t)); //allocate memory space 24 | 25 | if(dynamic_array == NULL) //allocate fail 26 | { 27 | return NULL; //return null 28 | } 29 | 30 | dynamic_array->dynamic_array = (void**)malloc(sizeof(void*) * initial_capacity_size); //allocate array space 31 | if(dynamic_array->dynamic_array == NULL) //allocate fail 32 | { 33 | return NULL; //return null 34 | } 35 | 36 | //init array 37 | dynamic_array->array_size = 0; //array size zero 38 | dynamic_array->array_capacity = initial_capacity_size; //array capacity size = initial capacity size 39 | memset(dynamic_array->dynamic_array, 0, sizeof(void*) * initial_capacity_size); //set memory space initial 0 40 | 41 | return dynamic_array; //return dynamic array pointer 42 | } 43 | 44 | /* 45 | *@function name:insert_array_element 46 | *@arguments:dynamic array pointer, insert position and insert data 47 | *@return type:status 48 | *@return value:success return 1 failed return -1 49 | */ 50 | status insert_array_element(dynamicarray_ptr_t _Fn_In_ dynamic_array, int _Fn_In_ insert_position, void* _Fn_In_ insert_data) 51 | { 52 | if(dynamic_array == NULL || insert_position < 0 || insert_data == NULL) //pointer is null or position illegal or data pointer is null 53 | { 54 | return -1; //return error code 55 | } 56 | 57 | if(insert_position > dynamic_array->array_size) //if position The length of the array is exceeded 58 | { 59 | insert_position = dynamic_array->array_size; //tail insert 60 | } 61 | 62 | int index; 63 | 64 | if(dynamic_array->array_size == dynamic_array->array_capacity) //If the array is already full 65 | { 66 | dynamic_array->array_capacity *= 2; //Expand the array 67 | realloc(dynamic_array->dynamic_array,dynamic_array->array_capacity); //Reallocate memory size 68 | 69 | for(index = dynamic_array->array_size; index >= insert_position; index--) //Move back one place from the specified position 70 | { 71 | dynamic_array->dynamic_array[index + 1] = dynamic_array->dynamic_array[index]; //Move back element 72 | } 73 | dynamic_array->dynamic_array[insert_position] = insert_data; //insert new data 74 | dynamic_array->array_size++; //array length increment 75 | return 1; //return success code 76 | } 77 | else 78 | { 79 | for(index = dynamic_array->array_size; index >= insert_position; index--) //If there is enough space in the array 80 | { 81 | dynamic_array->dynamic_array[index + 1] = dynamic_array->dynamic_array[index]; //move back element 82 | } 83 | dynamic_array->dynamic_array[insert_position] = insert_data; //insert new data 84 | dynamic_array->array_size++; //array length increment 85 | return 1; //return success code 86 | 87 | } 88 | 89 | } 90 | 91 | /* 92 | *@function name:print_array_element 93 | *@arguments:dynamic array pointer, back call function print_func 94 | *@return type:void 95 | *@return value:void 96 | */ 97 | status print_array_element(dynamicarray_ptr_t _Fn_In_ dynamic_array, void (*print_func)(void* print_data)) 98 | { 99 | if(dynamic_array == NULL || print_func == NULL) //if pointer null 100 | { 101 | return -1; //return error code 102 | } 103 | 104 | int index; //defined array index 105 | 106 | for(index = 0 ; index < dynamic_array->array_size;index++) //foreach array 107 | { 108 | (*print_func)(dynamic_array->dynamic_array[index]); //print array element 109 | } 110 | return 1; 111 | } 112 | 113 | /* 114 | *@function name:delete_array_element 115 | *@arguments:dynamic array pointer, delete position and reseved data pointer 116 | *@return type:status 117 | *@return value:success return 1 failed return -1 118 | */ 119 | status delete_array_element(dynamicarray_ptr_t _Fn_In_ dynamic_array, int _Fn_In_ delete_position, void** _Fn_Out_ reserved) 120 | { 121 | if(dynamic_array == NULL || delete_position < 0) //poiner is null or position illegal 122 | { 123 | return -1; //return error code 124 | } 125 | 126 | if(delete_position >= dynamic_array->array_size) //position exceed array length 127 | { 128 | return -1; //return error code 129 | } 130 | 131 | int index; //defined array index 132 | 133 | if(reserved != NULL) //If the pointer to retain data is not empty 134 | { 135 | *reserved = dynamic_array->dynamic_array[delete_position]; //Dereference the pointer and save the data 136 | } 137 | 138 | for(index = delete_position; index < dynamic_array->array_size; index++) //Override starts from the incoming location 139 | { 140 | dynamic_array->dynamic_array[index] = dynamic_array->dynamic_array[index + 1];//Overwrite the data from back to front 141 | } 142 | dynamic_array->array_size--; //array size degression 143 | return 0; //return 0 144 | } 145 | 146 | /* 147 | *@function name:free_dynamic_array 148 | *@arguments:dynamic array pointer 149 | *@return type:status 150 | *@return value:success return 1 failed return -1 151 | */ 152 | status free_dynamic_array(dynamicarray_ptr_t _Fn_In_ dynamic_array) 153 | { 154 | if(dynamic_array == NULL) //if pointer null 155 | { 156 | return -1; //return error code 157 | } 158 | 159 | free(dynamic_array->dynamic_array); //free dynamic array array space 160 | free(dynamic_array); //free dynamic array struct type space 161 | 162 | return 1; //success free return success code 163 | } 164 | -------------------------------------------------------------------------------- /src/encode/morse.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: morse.c 3 | * @description: This is a source file that contains the implementation of the Morse code encoding function. 4 | * @author: WAHAHA 5 | * @Date: 2024/9/5 下午1:38 6 | * @FilePath: Serendipity/src/encode/morse.c 7 | * @category: encode 8 | */ 9 | 10 | #include 11 | #include 12 | #include "encode/morse.h" 13 | 14 | // Used to replace error morse code 15 | #define MORSE_ERROR_CHAR '?' 16 | 17 | // ASCII to Morse code 18 | const char *MORSE_TABLE_ASCII[] = { 19 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 20 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 21 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 22 | NULL, NULL, NULL, "-.-.--", ".-..-.", NULL, "...-..-", NULL, ".-...", ".----.", 23 | "-.--.", "-.--.-", NULL, ".-.-.", "--..--", "-....-", ".-.-.-", "-..-.", "-----", ".----", 24 | "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----.", "---...", "-.-.-.", 25 | NULL, "-...-", NULL, "..--..", ".--.-.", ".-", "-...", "-.-.", "-..", ".", 26 | "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", 27 | ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--", 28 | "--..", NULL, NULL, NULL, NULL, "..--.-", NULL, ".-", "-...", "-.-.", 29 | "-..", ".", "..-.", "--.", "....", "..", ".---", "-.-", ".-..", "--", 30 | "-.", "---", ".--.", "--.-", ".-.", "...", "-", "..-", "...-", ".--", 31 | "-..-", "-.--", "--..", NULL, NULL, NULL, NULL, NULL, 32 | }; 33 | 34 | // Morse Context 35 | static morse_ctx_t *ctx = NULL; 36 | 37 | static int parse_init(const char *str, const char **start, const char **end) { 38 | *start = *end = str; // Initialize the start and end pointers to the first character of the string 39 | return 0; 40 | } 41 | 42 | static int parse_next(const char **start, const char **end) { 43 | if (*start == NULL || *end == NULL) { 44 | return -1; 45 | } 46 | 47 | // Skip any leading spaces 48 | *start = *end; 49 | while (**start == ' ') (*start)++; 50 | // Move the end pointer to the next space or '\0' 51 | *end = *start; 52 | while (**end != '\0' && **end != ' ') (*end)++; 53 | // Check if reached the end of the string 54 | if (**start == '\0') 55 | return 1; // End of string 56 | return 0; 57 | } 58 | 59 | static void tree_add_code(const char *code, int ch) { 60 | size_t len = strlen(code); 61 | morse_tree_node_t *cur = ctx->root; 62 | for (size_t i = 0; i < len; i++) { 63 | if (code[i] == '.') { 64 | if (cur->left == NULL) { 65 | cur->left = (morse_tree_node_t *) malloc(sizeof(morse_tree_node_t)); 66 | cur->left->ascii = 0; 67 | cur->left->left = cur->left->right = NULL; 68 | } 69 | cur = cur->left; 70 | } else if (code[i] == '-') { 71 | if (cur->right == NULL) { 72 | cur->right = (morse_tree_node_t *) malloc(sizeof(morse_tree_node_t)); 73 | cur->right->ascii = 0; 74 | cur->right->left = cur->right->right = NULL; 75 | } 76 | cur = cur->right; 77 | } 78 | } 79 | cur->ascii = ch; 80 | } 81 | 82 | static status init_morse_ctx() { 83 | ctx = (morse_ctx_t *) malloc(sizeof(morse_ctx_t)); 84 | if (ctx == NULL) { 85 | return failed; 86 | } 87 | ctx->morse_table_ascii = MORSE_TABLE_ASCII; 88 | ctx->error_char = MORSE_ERROR_CHAR; 89 | ctx->error_flag = false; 90 | ctx->root = (morse_tree_node_t *) malloc(sizeof(morse_tree_node_t)); 91 | if (ctx->root == NULL) { 92 | return failed; 93 | } 94 | ctx->root->ascii = 0; 95 | ctx->root->left = ctx->root->right = NULL; 96 | 97 | for (int i = 0; i < 128; i++) { 98 | if (ctx->morse_table_ascii[i] != NULL) { 99 | tree_add_code(ctx->morse_table_ascii[i], i); 100 | } 101 | } 102 | 103 | return true; 104 | } 105 | 106 | static int find(const char *code, size_t len) { 107 | if (code == NULL) { 108 | return -1; 109 | } 110 | morse_tree_node_t *cur = ctx->root; 111 | for (size_t i = 0; i < len; i++) { 112 | if (code[i] == '.') { 113 | cur = cur->left; 114 | } else if (code[i] == '-') { 115 | cur = cur->right; 116 | } 117 | if (cur == NULL) { 118 | return -1; 119 | } 120 | } 121 | if (cur->ascii == 0) { 122 | ctx->error_flag = true; 123 | return ctx->error_char; 124 | } 125 | return cur->ascii; 126 | } 127 | 128 | /** 129 | * @Funticon name: morse_decode 130 | * @description: Decode Morse code to ASCII 131 | * @Author: WAHAHA 132 | * @Date: 2024-9-5 14:26:42 133 | * @Note: None 134 | * @param {const char *} str - Morse code string 135 | * @param {char *} buffer - Buffer to store decoded ASCII string 136 | * @param {size_t} buffer_size - Size of buffer, must be large enough to store decoded string 137 | * @return {status} - Status of the operation 138 | */ 139 | status morse_decode(const char *str, char *buffer, size_t buffer_size) { 140 | ASSERT(buffer_size > 0, error); 141 | ASSERT(str != NULL && buffer != NULL, error); 142 | 143 | // Init context 144 | if (ctx == NULL) { 145 | init_morse_ctx(); 146 | } 147 | 148 | // Start decoding 149 | const char *start, *end; 150 | size_t idx = 0; 151 | parse_init(str, &start, &end); 152 | while (!parse_next(&start, &end)) { 153 | if (idx >= buffer_size - 1) { 154 | return error; 155 | } 156 | buffer[idx++] = (char) find(start, end - start); 157 | } 158 | buffer[idx] = '\0'; 159 | if (ctx->error_flag == true) { 160 | return false; 161 | } 162 | return true; 163 | } 164 | 165 | 166 | // Encode ASCII to Morse code 167 | status morse_encode(const char *str, char *buffer, size_t buffer_size) { 168 | ASSERT(buffer_size > 0, error); 169 | ASSERT(str != NULL && buffer != NULL, error); 170 | if (ctx == NULL) { 171 | init_morse_ctx(); 172 | } 173 | size_t idx = 0; 174 | buffer[0] = '\0'; 175 | for (size_t i = 0; i < strlen(str); i++) { 176 | if (ctx->morse_table_ascii[str[i]] != NULL) { 177 | idx += strlen(ctx->morse_table_ascii[str[i]]); 178 | if (idx++ >= buffer_size - 1) { 179 | return error; 180 | } 181 | strcat(buffer, ctx->morse_table_ascii[str[i]]); 182 | strcat(buffer, " "); 183 | } 184 | } 185 | buffer[idx - 1] = '\0'; // Remove the last space 186 | return true; 187 | } 188 | -------------------------------------------------------------------------------- /src/adt/queue.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file queue.c 3 | * @brief queue 4 | * @author inrootshell 5 | * @category data-structure 6 | * @date 2024-4-11 7 | */ 8 | 9 | //#include "queue.h" 10 | //#include //include standard c header file 11 | //#include 12 | //#include 13 | //#include 14 | // 15 | //#ifndef SEQQUEUE_T //If There is no definition SEQQUEUE_T type 16 | // 17 | //#define SEQQUEUE_T 1 //definition SEQQUEUE_T type 18 | // 19 | //typedef int status; //define status type 20 | // 21 | //typedef struct _seqqueue_t //defien linear queue type structrue 22 | //{ 23 | // void** queue_array; //queue array 24 | // int queue_max_size; //queue max size 25 | // int queue_header; //queue header 26 | // int queue_tail; //queue tail 27 | //}seqqueue_t, *seqqueue_ptr_t; //type alias 28 | // 29 | //#endif //end definition 30 | // 31 | //seqqueue_ptr_t initialize_queue(unsigned int initialize_queue_size); 32 | // 33 | //status enter_queue(seqqueue_ptr_t queue, void* new_data); 34 | // 35 | //status out_queue(seqqueue_ptr_t queue, void** reserved_data); 36 | // 37 | //status print_queue(seqqueue_ptr_t queue, void (*print_back)(void* print_data)); 38 | // 39 | //void print_back(void* print_data); 40 | // 41 | //void* get_queue_header(seqqueue_ptr_t queue); 42 | // 43 | //void* get_queue_tail(seqqueue_ptr_t queue); 44 | // 45 | //int get_queue_current_size(seqqueue_ptr_t queue); 46 | 47 | /* 48 | *@function name:initialize_queue 49 | *@arguments:initialize queue size 50 | *@return type:seqqueue_ptr_t 51 | *@return value:success return a pointer failed return NULL 52 | */ 53 | 54 | seqqueue_ptr_t initialize_queue(unsigned int initialize_queue_size) 55 | { 56 | if(!initialize_queue_size) //If the initialization size is 0 57 | { 58 | return NULL; //return a null pointer 59 | } 60 | 61 | seqqueue_ptr_t queue = (seqqueue_ptr_t)malloc(sizeof(seqqueue_t)); //Allocate a piece of memory 62 | 63 | if(!queue) //Memory allocation failed 64 | return NULL; //return null 65 | 66 | queue->queue_array = (void**)malloc(sizeof(void*) * initialize_queue_size); //Allocate a piece of memory 67 | 68 | if(!queue->queue_array) //Memory allocation failed 69 | return NULL; //return null 70 | 71 | memset(queue->queue_array, 0, sizeof(void*) * initialize_queue_size); //The value of the initialized array memory is 0 72 | 73 | queue->queue_header = 0; //queue header index initialize is 0 74 | queue->queue_tail = queue->queue_header; //queue tail index initialize is 0 75 | queue->queue_max_size = initialize_queue_size; //The queue size is assigned to the initialization size 76 | 77 | return queue; //return queue pointer 78 | } 79 | 80 | /* 81 | *@function name:enter_queue 82 | *@arguments:Queue pointers and data pointers 83 | *@return type:status 84 | *@return value:success return 1 argments error return -1 function error return 0 85 | */ 86 | 87 | status enter_queue(seqqueue_ptr_t queue, void* new_data) 88 | { 89 | if(queue == NULL || new_data == NULL) //If the queue pointer is empty or the data pointer is empty 90 | return -1; //return error code 91 | 92 | if(queue->queue_tail == queue->queue_max_size) //If the tail of the queue is equal to the queue size 93 | return 0; //queue full return error code 94 | 95 | queue->queue_array[queue->queue_tail] = new_data; //element enter queue 96 | queue->queue_tail++; //queue tail auto increment 97 | 98 | return 1; //return success code 99 | } 100 | 101 | /* 102 | *@function name:out_queue 103 | *@arguments:Queue pointers and reserved pointers 104 | *@return type:status 105 | *@return value:success return 1 argments error return -1 function error return 0 106 | */ 107 | 108 | 109 | status out_queue(seqqueue_ptr_t queue, void** reserved_data) 110 | { 111 | if(queue == NULL) //If the queue pointer is empty 112 | return -1; //return error code 113 | 114 | if(queue->queue_tail == -1) //If the queue is null 115 | return 0; //return error queue 116 | 117 | if(reserved_data) //If the pointer is valid 118 | *reserved_data = queue->queue_array[queue->queue_header]; //Save the elements to be dequeued to this variable 119 | 120 | int queue_index; //queue index 121 | 122 | for(queue_index = 0;queue_index < queue->queue_tail; queue_index++) //Traverse the queue 123 | { 124 | queue->queue_array[queue_index] = queue->queue_array[queue_index + 1]; //Move the element 125 | } 126 | 127 | queue->queue_tail--; //queue tail auto degression 128 | 129 | return 1; //return success code 130 | } 131 | 132 | /* 133 | *@function name:print_queue 134 | *@arguments:Queue pointer and callback function pointer 135 | *@return type:status 136 | *@return value:success print return 1 fail return 0 137 | */ 138 | 139 | 140 | status print_queue(seqqueue_ptr_t queue, void (*print_back)(void* print_data)) 141 | { 142 | if(queue == NULL || print_back == NULL) //The queue pointer is empty or the callback function pointer is empty 143 | return -1; //reurn error code 144 | 145 | int queue_index; //foreach queue index 146 | 147 | for(queue_index = queue->queue_header; queue_index < queue->queue_tail; queue_index++) //foreach queue 148 | { 149 | print_back(queue->queue_array[queue_index]); //print queue elements 150 | } 151 | 152 | return 1; //return success code 153 | } 154 | 155 | /* 156 | *@function name:print_back 157 | *@arguments:print data 158 | *@return type:void 159 | *@return value:void 160 | */ 161 | 162 | void print_back(void* print_data) //callback function 163 | { 164 | printf("%d ", *(int*)print_data); 165 | } 166 | 167 | /* 168 | *@function name:get_queue_header 169 | *@arguments:queue pointer 170 | *@return type:void* 171 | *@return value:queue pointer is null return null else return queue head element 172 | */ 173 | 174 | void* get_queue_header(seqqueue_ptr_t queue) 175 | { 176 | if(!queue) //if the queue is null pointer 177 | return NULL; //return null pointer 178 | 179 | return queue->queue_array[queue->queue_header]; //return queue header element 180 | } 181 | 182 | /* 183 | *@function name:get_queue_tail 184 | *@arguments:queue pointer 185 | *@return type:void* 186 | *@return value:queue pointer is null return null else return queue tail element 187 | */ 188 | 189 | 190 | void* get_queue_tail(seqqueue_ptr_t queue) 191 | { 192 | if(!queue) //if the queue is null pointer 193 | return NULL; //return pointer null 194 | 195 | return queue->queue_array[queue->queue_tail - 1]; //return queue tail element 196 | } 197 | 198 | /* 199 | *@function name: 200 | *@arguments:queue pointer 201 | *@return type:int 202 | *@return value:queue pointer is null return 0 else return queue current size 203 | */ 204 | 205 | 206 | int get_queue_current_size(seqqueue_ptr_t queue) 207 | { 208 | if(!queue) //if the queue is null pointer 209 | return -1; //return error code 210 | 211 | return queue->queue_tail; //return queue current size 212 | } 213 | -------------------------------------------------------------------------------- /src/encrypt/sm4.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: SM4.c 3 | * @description: This is a source file that contains the implementation of RC4 encryption algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/3/15 15:49 6 | * @LastEditTime: 2024/3/15 15:49 7 | * @FilePath: Serendipity/src/encrypt/SM4.c 8 | * @category: encrypt-algorithm 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /** 18 | * @Funticon name: new_sm4 19 | * @description: new a sm4_encipher object 20 | * @Author: WAHAHA 21 | * @Date: 2024-3-15 17:23:20 22 | * @Note: None 23 | * @return {rc4_encipher *} 24 | */ 25 | sm4_encipher *new_sm4() { 26 | sm4_encipher *new_sm4 = (sm4_encipher *) malloc(sizeof(sm4_encipher)); 27 | /* check the memory */ 28 | if (new_sm4 == NULL) 29 | return NULL; 30 | new_sm4->is_key_set = false; 31 | /* the memory of "key" and "rk" will be allocated in the function of sm4_init */ 32 | new_sm4->key = NULL; 33 | new_sm4->rk = NULL; 34 | return new_sm4; 35 | } 36 | 37 | /** 38 | * @Funticon name: free_sm4 39 | * @description: free a sm4_encipher object 40 | * @Author: WAHAHA 41 | * @Date: 2024-3-15 17:47:58 42 | * @Note: None 43 | * @param {sm4_encipher} *sm4 44 | * @return {status} 45 | */ 46 | status free_sm4(sm4_encipher *sm4) { 47 | ASSERT(sm4 != NULL, error); 48 | if (sm4->key != NULL) 49 | free(sm4->key); 50 | if (sm4->rk != NULL) 51 | free(sm4->rk); 52 | free(sm4); 53 | return true; 54 | } 55 | 56 | /** 57 | * @Funticon name: sm4_generate_subkey 58 | * @description: generate the subkey of the sm4_encipher 59 | * @Author: WAHAHA 60 | * @Date: 2024-3-15 17:59:46 61 | * @Note: None 62 | * @param {sm4_encipher} *sm4 63 | * @return {status} 64 | */ 65 | static status sm4_generate_subkey(sm4_encipher *sm4) { 66 | ASSERT(sm4 != NULL, error); 67 | uint32_t *rk = sm4->rk; 68 | // uint32_t *key = (uint32_t *) sm4->key; 69 | uint32_t mk[4]; 70 | 71 | /* 72 | * copy the key 73 | * @Note: the key is stored in the big-endian format 74 | */ 75 | for (int i = 0, j = 0; i < 16; i += 4, j++) 76 | BE_BYTES_TO_UINT32(mk[j], sm4->key + i); 77 | 78 | /* xor the key with the FK */ 79 | for (int i = 0; i < 4; ++i) 80 | mk[i] ^= SM4_FK[i]; 81 | 82 | /* 83 | * generate the subkey 84 | * @Note: 4 round keys are processed per round cycle to improve efficiency. 85 | */ 86 | uint32_t i = 0; 87 | do { 88 | rk[i] = (mk[0] ^= SM4_KEYGEN_T(mk[1] ^ mk[2] ^ mk[3] ^ SM4_CK[i])); 89 | i++; 90 | rk[i] = (mk[1] ^= SM4_KEYGEN_T(mk[2] ^ mk[3] ^ mk[0] ^ SM4_CK[i])); 91 | i++; 92 | rk[i] = (mk[2] ^= SM4_KEYGEN_T(mk[3] ^ mk[0] ^ mk[1] ^ SM4_CK[i])); 93 | i++; 94 | rk[i] = (mk[3] ^= SM4_KEYGEN_T(mk[0] ^ mk[1] ^ mk[2] ^ SM4_CK[i])); 95 | i++; 96 | } while (i < SM4_ROUND); 97 | return true; 98 | } 99 | 100 | /** 101 | * @Funticon name: sm4_init 102 | * @description: initialize the sm4_encipher object with a 128-bit key 103 | * @description: 104 | * @Author: WAHAHA 105 | * @Date: 2024-3-15 17:52:5 106 | * @Note: the caller should make sure that the length of the key is 16 bytes 107 | * @param {sm4_encipher} *sm4 108 | * @return {status} 109 | */ 110 | status sm4_init(sm4_encipher *sm4, const byte *key) { 111 | /* check the parameters */ 112 | ASSERT(sm4 != NULL && key != NULL, error); 113 | /* allocate the memory for the key and rk */ 114 | sm4->key = (byte *) malloc(SM4_KEY_SIZE); 115 | sm4->rk = (uint32_t *) malloc(SM4_ROUND * sizeof(uint32_t)); 116 | if (sm4->key == NULL || sm4->rk == NULL) 117 | return failed; 118 | /* copy the key */ 119 | memcpy(sm4->key, key, SM4_KEY_SIZE); 120 | sm4->is_key_set = true; 121 | /* generate the subkey,and return the status */ 122 | return sm4_generate_subkey(sm4); 123 | } 124 | 125 | /** 126 | * @Funticon name: sm4_crypt 127 | * @description: encrypt and decrypt the data 128 | * @Author: WAHAHA 129 | * @Date: 2024-3-19 1:55:28 130 | * @Note: The caller should make sure the length of the data is a multiple of 16 131 | * @param {sm4_encipher} *sm4 132 | * @param {byte} *in_data 133 | * @param {int} data_len 134 | * @param {byte} *out_data 135 | * @param {int} mode 136 | * @return {status} 137 | */ 138 | status sm4_crypt(sm4_encipher *sm4, const byte *in_data, int in_data_len, byte *out_data,int mode) { 139 | /* check the parameters */ 140 | ASSERT(sm4 != NULL && in_data != NULL && out_data != NULL, error); 141 | ASSERT(sm4->is_key_set, error); 142 | // the length of the data should be a multiple of 16 143 | // caller should make sure the length of the data is a multiple of 16 144 | ASSERT(in_data_len % SM4_BLOCK_SIZE == 0, error); 145 | 146 | /* necessary variables */ 147 | uint32_t block_data[4]; 148 | 149 | for (int i = 0; i < in_data_len; i += 16) { 150 | /* copy the data */ 151 | for (int j = 0; j < 4; ++j) 152 | BE_BYTES_TO_UINT32(block_data[j], in_data + i + j * 4); 153 | sm4_crypt_block_round(sm4, block_data, 154 | (uint32_t *) (out_data + i), mode); 155 | sm4_crypt_block_reverse((uint32_t *) (out_data + i)); 156 | } 157 | 158 | return true; 159 | } 160 | 161 | status sm4_crypt_block_round(sm4_encipher *sm4, const uint32_t *in_data, uint32_t *out_data, 162 | int mode) { 163 | /* check the parameters */ 164 | ASSERT(sm4 != NULL && in_data != NULL && out_data != NULL, error); 165 | ASSERT(mode == SM4_ENCRYPT || mode == SM4_DECRYPT, error); 166 | /* necessary variables */ 167 | uint32_t *rk = sm4->rk; 168 | uint32_t x[SM4_BLOCK_SIZE / sizeof(uint32_t)]; 169 | int i, step = mode; 170 | /* 171 | * copy the data 172 | * @Note: the data is stored in the big-endian format 173 | */ 174 | // for (i = 0; i < 4; ++i) 175 | // BE_BYTES_TO_UINT32(x[i], in_data + i); 176 | for (i = 0; i < 4; ++i) 177 | x[i] = in_data[i]; 178 | 179 | /* 32 rounds of encryption */ 180 | i = mode == SM4_ENCRYPT ? 0 : SM4_ROUND - 1; 181 | do { 182 | x[0] ^= SM4_ROUND_T(x[1] ^ x[2] ^ x[3] ^ rk[i]); 183 | i += step; 184 | x[1] ^= SM4_ROUND_T(x[2] ^ x[3] ^ x[0] ^ rk[i]); 185 | i += step; 186 | x[2] ^= SM4_ROUND_T(x[3] ^ x[0] ^ x[1] ^ rk[i]); 187 | i += step; 188 | x[3] ^= SM4_ROUND_T(x[0] ^ x[1] ^ x[2] ^ rk[i]); 189 | i += step; 190 | } while (mode == SM4_ENCRYPT ? (i < SM4_ROUND) : (i >= 0)); 191 | /* 192 | * copy the data 193 | * @Note: the data is stored in the big-endian format 194 | */ 195 | for (i = 0; i < 4; ++i) 196 | BE_UINT32_TO_BYTES((byte *) out_data + i*4, x[i]); 197 | 198 | return true; 199 | } 200 | 201 | status sm4_crypt_block_reverse(uint32_t *data) { 202 | /* check the parameters */ 203 | ASSERT(data != NULL, error); 204 | /* reverse the data */ 205 | uint32_t tmp; 206 | tmp = data[0]; 207 | data[0] = data[3]; 208 | data[3] = tmp; 209 | tmp = data[1]; 210 | data[1] = data[2]; 211 | data[2] = tmp; 212 | return true; 213 | } -------------------------------------------------------------------------------- /src/digest/md4.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: md4.c 3 | * @description: This is a source file that contains the implementation of MD4 algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/4/11 14:52 6 | * @FilePath: Serendipity/src/encode/md4.c 7 | * @category: encode-algorithm 8 | */ 9 | 10 | #include 11 | #include "digest/md4.h" 12 | #include "encode/hex.h" 13 | #include "misc/endian.h" 14 | 15 | /* set [j,j-1,...,i] bits to 1 */ 16 | #define set_mask(i, j) (((1u << ((j) - (i) + 1)) - 1) << (i)) 17 | 18 | /** 19 | * @Funticon name: md4_padding 20 | * @description: This function is used to pad the data to a multiple of 512 bits. 21 | * @Author: WAHAHA 22 | * @Date: 2024/4/11 14:52 23 | * @Note: Every 8-bits is interpreted as a byte with the high-order bit first. 24 | * @param {const byte *} data: The data to be processed. 25 | * @param {size_t} data_bit_count: The size of the data in bits. 26 | * @param {size_t *} block_size: The block count after padding. 27 | * @return {uint32_t *}: The data after padding. 28 | */ 29 | static uint32_t *md4_padding(const byte *data, size_t data_bit_count, size_t *block_count) { 30 | /* calculate the number of bytes */ 31 | size_t data_byte_size = (data_bit_count + 7) / 8; 32 | /* calculate the number of the data after padding in blocks */ 33 | *block_count = (data_bit_count + 64 + 511) / 512; 34 | /* calculate the number of the data after padding in uint32_t */ 35 | size_t data_size = *block_count * 16; 36 | /* allocate memory for the data after padding */ 37 | uint32_t *data_padding = (uint32_t *) calloc(data_size, sizeof(uint32_t)); 38 | 39 | /* copy the original data to the data after padding with the low-order byte given first */ 40 | for (size_t i = 0; i < data_byte_size; i++) { 41 | data_padding[i >> 2] |= data[i] << (i % 4 * 8); 42 | } 43 | /* clear the extra bits of the last byte */ 44 | if (data_bit_count % 8 != 0) { 45 | data_padding[data_byte_size >> 2] &= ~set_mask( 46 | (data_byte_size % 4 - 1) * 8, 47 | (data_byte_size % 4) * 8 - (data_bit_count % 8) - 1); 48 | } 49 | 50 | /* add the 1 bit */ 51 | // 0x80 = 10000000 52 | // (data_bit_count % 8) : the number of bits in the last byte 53 | if (data_bit_count % 8 == 0) { 54 | data_padding[data_byte_size >> 2] |= 0x80 55 | << ((data_byte_size % 4) * 8); 56 | } else { 57 | data_padding[data_byte_size >> 2] |= 0x80 58 | << ((data_byte_size % 4 - 1) * 8 - data_bit_count % 8); 59 | } 60 | /* add the length */ 61 | uint64_t data_length = data_bit_count; 62 | data_padding[*block_count * 16 - 2] = data_length & 0xffffffff; 63 | data_padding[*block_count * 16 - 1] = (data_length >> 32) & 0xffffffff; 64 | 65 | return data_padding; 66 | } 67 | 68 | /** 69 | * @Funticon name: md4 70 | * @description: This function is used to calculate the MD4 hash value of the data. 71 | * @Author: WAHAHA 72 | * @Date: 2024/4/11 14:52 73 | * @Note: md4() will pad the data to a multiple of 512 bits. 74 | * @param {const byte *} data: The data to be processed. 75 | * @param {size_t} data_bit_size: The size of the data in bits. 76 | * @return {status}: The status of the function execution. 77 | */ 78 | status md4(const byte *data, size_t data_bit_size, char *digest) { 79 | /* check the input data */ 80 | ASSERT(data != NULL, error); 81 | ASSERT(digest != NULL, error); 82 | ASSERT(data_bit_size > 0, error); 83 | 84 | /* padding the data */ 85 | size_t block_count = 0; 86 | uint32_t *data_padding = md4_padding(data, data_bit_size, &block_count); 87 | 88 | /* initialize the md4 register */ 89 | // low-order byte first 90 | uint32_t A = 0x67452301; 91 | uint32_t B = 0xefcdab89; 92 | uint32_t C = 0x98badcfe; 93 | uint32_t D = 0x10325476; 94 | 95 | /* main loop */ 96 | for (size_t i = 0; i < block_count; i++) { 97 | /* copy the md4 register */ 98 | uint32_t AA = A; 99 | uint32_t BB = B; 100 | uint32_t CC = C; 101 | uint32_t DD = D; 102 | 103 | /* ROUND 1 */ 104 | FF(A, B, C, D, data_padding[i * 16 + 0], 3); 105 | FF(D, A, B, C, data_padding[i * 16 + 1], 7); 106 | FF(C, D, A, B, data_padding[i * 16 + 2], 11); 107 | FF(B, C, D, A, data_padding[i * 16 + 3], 19); 108 | 109 | FF(A, B, C, D, data_padding[i * 16 + 4], 3); 110 | FF(D, A, B, C, data_padding[i * 16 + 5], 7); 111 | FF(C, D, A, B, data_padding[i * 16 + 6], 11); 112 | FF(B, C, D, A, data_padding[i * 16 + 7], 19); 113 | 114 | FF(A, B, C, D, data_padding[i * 16 + 8], 3); 115 | FF(D, A, B, C, data_padding[i * 16 + 9], 7); 116 | FF(C, D, A, B, data_padding[i * 16 + 10], 11); 117 | FF(B, C, D, A, data_padding[i * 16 + 11], 19); 118 | 119 | FF(A, B, C, D, data_padding[i * 16 + 12], 3); 120 | FF(D, A, B, C, data_padding[i * 16 + 13], 7); 121 | FF(C, D, A, B, data_padding[i * 16 + 14], 11); 122 | FF(B, C, D, A, data_padding[i * 16 + 15], 19); 123 | /* ROUND 2 */ 124 | GG(A, B, C, D, data_padding[i * 16 + 0], 3); 125 | GG(D, A, B, C, data_padding[i * 16 + 4], 5); 126 | GG(C, D, A, B, data_padding[i * 16 + 8], 9); 127 | GG(B, C, D, A, data_padding[i * 16 + 12], 13); 128 | 129 | GG(A, B, C, D, data_padding[i * 16 + 1], 3); 130 | GG(D, A, B, C, data_padding[i * 16 + 5], 5); 131 | GG(C, D, A, B, data_padding[i * 16 + 9], 9); 132 | GG(B, C, D, A, data_padding[i * 16 + 13], 13); 133 | 134 | GG(A, B, C, D, data_padding[i * 16 + 2], 3); 135 | GG(D, A, B, C, data_padding[i * 16 + 6], 5); 136 | GG(C, D, A, B, data_padding[i * 16 + 10], 9); 137 | GG(B, C, D, A, data_padding[i * 16 + 14], 13); 138 | 139 | GG(A, B, C, D, data_padding[i * 16 + 3], 3); 140 | GG(D, A, B, C, data_padding[i * 16 + 7], 5); 141 | GG(C, D, A, B, data_padding[i * 16 + 11], 9); 142 | GG(B, C, D, A, data_padding[i * 16 + 15], 13); 143 | /* ROUND 3 */ 144 | HH(A, B, C, D, data_padding[i * 16 + 0], 3); 145 | HH(D, A, B, C, data_padding[i * 16 + 8], 9); 146 | HH(C, D, A, B, data_padding[i * 16 + 4], 11); 147 | HH(B, C, D, A, data_padding[i * 16 + 12], 15); 148 | 149 | HH(A, B, C, D, data_padding[i * 16 + 2], 3); 150 | HH(D, A, B, C, data_padding[i * 16 + 10], 9); 151 | HH(C, D, A, B, data_padding[i * 16 + 6], 11); 152 | HH(B, C, D, A, data_padding[i * 16 + 14], 15); 153 | 154 | HH(A, B, C, D, data_padding[i * 16 + 1], 3); 155 | HH(D, A, B, C, data_padding[i * 16 + 9], 9); 156 | HH(C, D, A, B, data_padding[i * 16 + 5], 11); 157 | HH(B, C, D, A, data_padding[i * 16 + 13], 15); 158 | 159 | HH(A, B, C, D, data_padding[i * 16 + 3], 3); 160 | HH(D, A, B, C, data_padding[i * 16 + 11], 9); 161 | HH(C, D, A, B, data_padding[i * 16 + 7], 11); 162 | HH(B, C, D, A, data_padding[i * 16 + 15], 15); 163 | 164 | /* update the md4 register */ 165 | A += AA; 166 | B += BB; 167 | C += CC; 168 | D += DD; 169 | } 170 | 171 | /* free the memory */ 172 | free(data_padding); 173 | 174 | /* generate the digest */ 175 | byte temp_result[16] = {0}; 176 | LE_UINT32_TO_BYTES(&temp_result[0], A); 177 | LE_UINT32_TO_BYTES(&temp_result[4], B); 178 | LE_UINT32_TO_BYTES(&temp_result[8], C); 179 | LE_UINT32_TO_BYTES(&temp_result[12], D); 180 | 181 | size_t out_len = 0; 182 | bytes_to_hex(temp_result, 16, digest, &out_len); 183 | 184 | digest[32] = '\0'; 185 | 186 | return true; 187 | } -------------------------------------------------------------------------------- /src/adt/list.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: list.c 3 | * @description: List implementation 4 | * @author: WAHAHA 5 | * @Date: 2024-02-28 11:06:35 6 | * @LastEditTime: 2024-03-04 12:44:43 7 | * @FilePath: \Serendipity\src\adt\list.c 8 | * @category: data-structure 9 | */ 10 | 11 | #include 12 | #include 13 | 14 | 15 | /** 16 | typedef struct list_node_s { 17 | void *data; 18 | struct list_node_s *next; 19 | } list_node_t; 20 | 21 | typedef struct list_s { 22 | list_node_t *head; 23 | list_node_t *tail; 24 | size_t size; 25 | int (*compare)(const void *, const void *); 26 | void (*destroy)(void *); 27 | } list_t; 28 | */ 29 | 30 | 31 | /* list operations */ 32 | /** 33 | * @Funticon name: list_create 34 | * @description: create a new list 35 | * @Author: WAHAHA 36 | * @Date: 2024-03-04 12:31:04 37 | * @Note: the 2 param are allowed to be NULL 38 | * @param {void} * 39 | * @param {void} * 40 | * @return {list_t *} 41 | */ 42 | list_t *list_create(int (*compare)(const void *, const void *), 43 | void (*destructor)(void *)) 44 | { 45 | list_t *new_list = (list_t *)malloc(sizeof(list_t)); 46 | if (new_list == NULL) 47 | return NULL; 48 | new_list->head = NULL; 49 | new_list->tail = NULL; 50 | new_list->size = 0; 51 | /* @warning: the two function pointer should be checked in other functions */ 52 | /* @todo: the compare function is not used in the current implementation */ 53 | new_list->compare = compare; 54 | new_list->destructor = destructor; 55 | return new_list; 56 | } 57 | 58 | /** 59 | * @Funticon name: list_destroy 60 | * @description: destroy the list 61 | * @Author: WAHAHA 62 | * @Date: 2024-03-04 12:33:52 63 | * @Note: None 64 | * @param {list_t} *list 65 | * @return {status} 66 | */ 67 | status list_destroy(list_t *list) 68 | { 69 | ASSERT(list != NULL, error); 70 | list_node_t *temp = list->head; 71 | list_node_t *next = NULL; 72 | /** 73 | * Dispute! Whether list_destroy() should fail if destructor equals to NULL 74 | * current implementation: just free every data of the nodes 75 | */ 76 | if (list->destructor == NULL) { 77 | while (temp != NULL) { 78 | next = temp->next; 79 | free(temp->data); 80 | free(temp); 81 | temp = next; 82 | } 83 | } else { 84 | while (temp != NULL) { 85 | next = temp->next; 86 | list->destructor(temp->data); 87 | free(temp); 88 | temp = next; 89 | } 90 | } 91 | free(list); 92 | return true; 93 | } 94 | 95 | /** 96 | * @Funticon name: list_insert 97 | * @description: insert data to the list 98 | * @Author: WAHAHA 99 | * @Date: 2024-03-04 12:35:29 100 | * @Note: None 101 | * @param {list_t} *list 102 | * @param {size_t} index 103 | * @param {void} *data 104 | * @return {status} 105 | */ 106 | status list_insert(list_t *list, size_t index, void *data) 107 | { 108 | /* if the list is NULL, return error */ 109 | ASSERT(list != NULL, error); 110 | list_node_t *new_node = (list_node_t *)malloc(sizeof(list_node_t)); 111 | /* check if malloc failed */ 112 | // if (new_node == NULL) 113 | // return failed; 114 | ASSERT(new_node != NULL, failed); 115 | 116 | new_node->data = data; 117 | new_node->next = NULL; 118 | 119 | /* check if index out of range */ 120 | ASSERT(index <= list->size, error); 121 | 122 | /* insert to the head */ 123 | if (index == 0) { 124 | new_node->next = list->head; 125 | list->head = new_node; 126 | if (list->size == 0) 127 | list->tail = new_node; 128 | } 129 | /* insert to the tail */ 130 | else if (index == list->size) { 131 | list->tail->next = new_node; 132 | list->tail = new_node; 133 | // no need to check if list->size == 0 134 | } 135 | /* insert to the middle */ 136 | else { 137 | list_node_t *prev = list->head; 138 | for (size_t i = 0; i < index - 1; i++) 139 | prev = prev->next; 140 | new_node->next = prev->next; 141 | prev->next = new_node; 142 | } 143 | list->size++; 144 | return true; 145 | } 146 | 147 | /** 148 | * @Funticon name: list_remove 149 | * @description: remove data from the list 150 | * @Author: WAHAHA 151 | * @Date: 2024-03-04 12:36:29 152 | * @Note: the removed data pointer will be stored 153 | * @param {list_t} *list 154 | * @param {size_t} index 155 | * @param {void *} *data 156 | * @return {status} 157 | */ 158 | status list_remove(list_t *list, size_t index, void **data) 159 | { 160 | /* if the list is NULL or empty, return error */ 161 | // if (list == NULL || list->size == 0) 162 | // return error; 163 | ASSERT(list != NULL && list->size != 0, error); 164 | 165 | /* check if index out of range */ 166 | ASSERT(index < list->size, error); 167 | 168 | list_node_t *temp = list->head; 169 | list_node_t *prev = NULL; 170 | 171 | /* remove the head */ 172 | if (index == 0) { 173 | list->head = temp->next; 174 | *data = temp->data; 175 | free(temp); 176 | if (list->size == 1) 177 | list->tail = NULL; 178 | } 179 | /* remove the tail */ 180 | else if (index == list->size - 1) { 181 | for (size_t i = 0; i < index - 1; i++) 182 | temp = temp->next; 183 | *data = temp->next->data; 184 | free(temp->next); 185 | temp->next = NULL; 186 | list->tail = temp; 187 | } 188 | /* remove the middle */ 189 | else { 190 | for (size_t i = 0; i < index; i++) { 191 | prev = temp; 192 | temp = temp->next; 193 | } 194 | prev->next = temp->next; 195 | *data = temp->data; 196 | free(temp); 197 | } 198 | list->size--; 199 | return true; 200 | } 201 | 202 | 203 | /** 204 | * @Funticon name: list_push_front 205 | * @description: push data to the front of the list 206 | * @Author: WAHAHA 207 | * @Date: 2024-03-04 12:38:10 208 | * @Note: call list_insert(list, 0, data) 209 | * @param {list_t} *list 210 | * @param {void} *data 211 | * @return {status} 212 | */ 213 | status list_push_front(list_t *list, void *data) 214 | { 215 | return list_insert(list, 0, data); 216 | } 217 | 218 | /** 219 | * @Funticon name: list_push_back 220 | * @description: push data to the back of the list 221 | * @Author: WAHAHA 222 | * @Date: 2024-03-04 12:39:37 223 | * @Note: call list_insert(list, list->size, data) 224 | * @param {list_t} *list 225 | * @param {void} *data 226 | * @return {status} 227 | */ 228 | status list_push_back(list_t *list, void *data) 229 | { 230 | return list_insert(list, list->size, data); 231 | } 232 | 233 | /* @note: these functions has rewritten as macros in list.h */ 234 | 235 | 236 | /* get the status of list */ 237 | 238 | /** 239 | size_t list_size(list_t *list) { 240 | if (list == NULL) { 241 | fprintf(stderr, "[%s]:%s:%d is failed! error code: %d\r\n", 242 | __FILE__, __FUNCTION__, __LINE__, error); 243 | return 0; 244 | } 245 | return list->size; 246 | } 247 | */ 248 | 249 | /** 250 | status list_empty(list_t *list) { 251 | ASSERT(list != NULL, error); 252 | return list->size == 0 ? true : false; 253 | } 254 | */ 255 | 256 | /* get the data of list */ 257 | 258 | /** 259 | void *list_front(list_t *list) { 260 | if (list == NULL || list->size == 0) 261 | return NULL; 262 | return list->head->data; 263 | } 264 | */ 265 | 266 | /** 267 | void *list_back(list_t *list) { 268 | if (list == NULL || list->size == 0) 269 | return NULL; 270 | return list->tail->data; 271 | } 272 | */ 273 | 274 | /** 275 | * @Funticon name: list_get 276 | * @description: get the data of the list 277 | * @Author: WAHAHA 278 | * @Date: 2024-03-04 12:40:08 279 | * @Note: return NULL if the list is NULL or empty 280 | * @param {list_t} *list 281 | * @param {size_t} index 282 | * @return {void *} 283 | */ 284 | void *list_get(list_t *list, size_t index) 285 | { 286 | if (list == NULL || list->size == 0 || index >= list->size) 287 | return NULL; 288 | list_node_t *temp = list->head; 289 | for (size_t i = 0; i < index; i++) 290 | temp = temp->next; 291 | return temp->data; 292 | } -------------------------------------------------------------------------------- /src/digest/md5.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: md5.c 3 | * @description: This is a source file that contains the implementation of MD5 algorithm. 4 | * @author: WAHAHA 5 | * @Date: 2024/4/7 10:30 6 | * @FilePath: Serendipity/src/digest/md5.c 7 | * @category: digest-algorithm 8 | */ 9 | 10 | #include 11 | #include "digest/md5.h" 12 | #include "encode/hex.h" 13 | #include "misc/endian.h" 14 | 15 | #define set_mask(i, j) (((1u << ((j) - (i) + 1)) - 1) << (i)) 16 | 17 | /** 18 | * @Funticon name: md5_padding 19 | * @description: This function is used to pad the data to a multiple of 512 bits. 20 | * @Author: WAHAHA 21 | * @Date: 2024-4-7 10:32:27 22 | * @Note: Every 8-bits is interpreted as a byte with the high-order bit first. 23 | * @param {const byte *} data: The data to be processed. 24 | * @param {size_t} data_bit_count: The size of the data in bits. 25 | * @param {size_t *} block_size: The block count after padding. 26 | * @return {uint32_t *}: The data after padding. 27 | */ 28 | static uint32_t *md5_padding(const byte *data, size_t data_bit_count, size_t *block_count) { 29 | /* calculate the number of bytes */ 30 | size_t data_byte_size = (data_bit_count + 7) / 8; 31 | /* calculate the number of the data after padding in blocks */ 32 | *block_count = (data_bit_count + 64 + 511) / 512; 33 | /* calculate the number of the data after padding in uint32_t */ 34 | size_t data_size = *block_count * 16; 35 | /* allocate memory for the data after padding */ 36 | uint32_t *data_padding = (uint32_t *) calloc(data_size, sizeof(uint32_t)); 37 | 38 | /* copy the original data to the data after padding with the low-order byte given first */ 39 | for (size_t i = 0; i < data_byte_size; i++) { 40 | data_padding[i >> 2] |= data[i] << (i % 4 * 8); 41 | } 42 | /* clear the extra bits of the last byte */ 43 | if (data_bit_count % 8 != 0) { 44 | data_padding[data_byte_size >> 2] &= ~set_mask( 45 | (data_byte_size % 4 - 1) * 8, 46 | (data_byte_size % 4) * 8 - (data_bit_count % 8) - 1); 47 | } 48 | 49 | /* add the 1 bit */ 50 | // 0x80 = 10000000 51 | // (data_bit_count % 8) : the number of bits in the last byte 52 | if (data_bit_count % 8 == 0) { 53 | data_padding[data_byte_size >> 2] |= 0x80 54 | << ((data_byte_size % 4) * 8); 55 | } else { 56 | data_padding[data_byte_size >> 2] |= 0x80 57 | << ((data_byte_size % 4 - 1) * 8 - data_bit_count % 8); 58 | } 59 | /* add the length */ 60 | uint64_t data_length = data_bit_count; 61 | data_padding[*block_count * 16 - 2] = data_length & 0xffffffff; 62 | data_padding[*block_count * 16 - 1] = (data_length >> 32) & 0xffffffff; 63 | 64 | return data_padding; 65 | } 66 | 67 | /** 68 | * @Funticon name: md5 69 | * @description: This function is used to calculate the MD5 hash value of the data. 70 | * @Author: WAHAHA 71 | * @Date: 2024-4-7 10:40:14 72 | * @Note: md5() will pad the data to a multiple of 512 bits. 73 | * @param {const byte *} data: The data to be processed. 74 | * @param {size_t} data_bit_size: The size of the data in bits. 75 | * @return {status}: The status of the function execution. 76 | */ 77 | status md5(const byte *data, size_t data_bit_size, char *digest) { 78 | /* check the input data */ 79 | ASSERT(data != NULL, error); 80 | ASSERT(digest != NULL, error); 81 | ASSERT(data_bit_size > 0, error); 82 | 83 | /* padding the data */ 84 | size_t block_count = 0; 85 | uint32_t *data_padding = md5_padding(data, data_bit_size, &block_count); 86 | 87 | /* initialize the md5 register */ 88 | // low-order byte first 89 | uint32_t A = 0x67452301; 90 | uint32_t B = 0xefcdab89; 91 | uint32_t C = 0x98badcfe; 92 | uint32_t D = 0x10325476; 93 | 94 | /* main loop */ 95 | for (size_t i = 0; i < block_count; i++) { 96 | /* copy the md5 register */ 97 | uint32_t AA = A; 98 | uint32_t BB = B; 99 | uint32_t CC = C; 100 | uint32_t DD = D; 101 | 102 | /* ROUND 1 */ 103 | FF(A, B, C, D, data_padding[i * 16 + 0], 7, 0XD76AA478); 104 | FF(D, A, B, C, data_padding[i * 16 + 1], 12, 0XE8C7B756); 105 | FF(C, D, A, B, data_padding[i * 16 + 2], 17, 0X242070DB); 106 | FF(B, C, D, A, data_padding[i * 16 + 3], 22, 0XC1BDCEEE); 107 | 108 | FF(A, B, C, D, data_padding[i * 16 + 4], 7, 0XF57C0FAF); 109 | FF(D, A, B, C, data_padding[i * 16 + 5], 12, 0X4787C62A); 110 | FF(C, D, A, B, data_padding[i * 16 + 6], 17, 0XA8304613); 111 | FF(B, C, D, A, data_padding[i * 16 + 7], 22, 0XFD469501); 112 | 113 | FF(A, B, C, D, data_padding[i * 16 + 8], 7, 0X698098D8); 114 | FF(D, A, B, C, data_padding[i * 16 + 9], 12, 0X8B44F7AF); 115 | FF(C, D, A, B, data_padding[i * 16 + 10], 17, 0XFFFF5BB1); 116 | FF(B, C, D, A, data_padding[i * 16 + 11], 22, 0X895CD7BE); 117 | 118 | FF(A, B, C, D, data_padding[i * 16 + 12], 7, 0X6B901122); 119 | FF(D, A, B, C, data_padding[i * 16 + 13], 12, 0XFD987193); 120 | FF(C, D, A, B, data_padding[i * 16 + 14], 17, 0XA679438E); 121 | FF(B, C, D, A, data_padding[i * 16 + 15], 22, 0X49B40821); 122 | /* ROUND 2 */ 123 | GG(A, B, C, D, data_padding[i * 16 + 1], 5, 0XF61E2562); 124 | GG(D, A, B, C, data_padding[i * 16 + 6], 9, 0XC040B340); 125 | GG(C, D, A, B, data_padding[i * 16 + 11], 14, 0X265E5A51); 126 | GG(B, C, D, A, data_padding[i * 16 + 0], 20, 0XE9B6C7AA); 127 | 128 | GG(A, B, C, D, data_padding[i * 16 + 5], 5, 0XD62F105D); 129 | GG(D, A, B, C, data_padding[i * 16 + 10], 9, 0X2441453); 130 | GG(C, D, A, B, data_padding[i * 16 + 15], 14, 0XD8A1E681); 131 | GG(B, C, D, A, data_padding[i * 16 + 4], 20, 0XE7D3FBC8); 132 | 133 | GG(A, B, C, D, data_padding[i * 16 + 9], 5, 0X21E1CDE6); 134 | GG(D, A, B, C, data_padding[i * 16 + 14], 9, 0XC33707D6); 135 | GG(C, D, A, B, data_padding[i * 16 + 3], 14, 0XF4D50D87); 136 | GG(B, C, D, A, data_padding[i * 16 + 8], 20, 0X455A14ED); 137 | 138 | GG(A, B, C, D, data_padding[i * 16 + 13], 5, 0XA9E3E905); 139 | GG(D, A, B, C, data_padding[i * 16 + 2], 9, 0XFCEFA3F8); 140 | GG(C, D, A, B, data_padding[i * 16 + 7], 14, 0X676F02D9); 141 | GG(B, C, D, A, data_padding[i * 16 + 12], 20, 0X8D2A4C8A); 142 | /* ROUND 3 */ 143 | HH(A, B, C, D, data_padding[i * 16 + 5], 4, 0XFFFA3942); 144 | HH(D, A, B, C, data_padding[i * 16 + 8], 11, 0X8771F681); 145 | HH(C, D, A, B, data_padding[i * 16 + 11], 16, 0X6D9D6122); 146 | HH(B, C, D, A, data_padding[i * 16 + 14], 23, 0XFDE5380C); 147 | 148 | HH(A, B, C, D, data_padding[i * 16 + 1], 4, 0XA4BEEA44); 149 | HH(D, A, B, C, data_padding[i * 16 + 4], 11, 0X4BDECFA9); 150 | HH(C, D, A, B, data_padding[i * 16 + 7], 16, 0XF6BB4B60); 151 | HH(B, C, D, A, data_padding[i * 16 + 10], 23, 0XBEBFBC70); 152 | 153 | HH(A, B, C, D, data_padding[i * 16 + 13], 4, 0X289B7EC6); 154 | HH(D, A, B, C, data_padding[i * 16 + 0], 11, 0XEAA127FA); 155 | HH(C, D, A, B, data_padding[i * 16 + 3], 16, 0XD4EF3085); 156 | HH(B, C, D, A, data_padding[i * 16 + 6], 23, 0X4881D05); 157 | 158 | HH(A, B, C, D, data_padding[i * 16 + 9], 4, 0XD9D4D039); 159 | HH(D, A, B, C, data_padding[i * 16 + 12], 11, 0XE6DB99E5); 160 | HH(C, D, A, B, data_padding[i * 16 + 15], 16, 0X1FA27CF8); 161 | HH(B, C, D, A, data_padding[i * 16 + 2], 23, 0XC4AC5665); 162 | /* ROUND 4 */ 163 | II(A, B, C, D, data_padding[i * 16 + 0], 6, 0XF4292244); 164 | II(D, A, B, C, data_padding[i * 16 + 7], 10, 0X432AFF97); 165 | II(C, D, A, B, data_padding[i * 16 + 14], 15, 0XAB9423A7); 166 | II(B, C, D, A, data_padding[i * 16 + 5], 21, 0XFC93A039); 167 | 168 | II(A, B, C, D, data_padding[i * 16 + 12], 6, 0X655B59C3); 169 | II(D, A, B, C, data_padding[i * 16 + 3], 10, 0X8F0CCC92); 170 | II(C, D, A, B, data_padding[i * 16 + 10], 15, 0XFFEFF47D); 171 | II(B, C, D, A, data_padding[i * 16 + 1], 21, 0X85845DD1); 172 | 173 | II(A, B, C, D, data_padding[i * 16 + 8], 6, 0X6FA87E4F); 174 | II(D, A, B, C, data_padding[i * 16 + 15], 10, 0XFE2CE6E0); 175 | II(C, D, A, B, data_padding[i * 16 + 6], 15, 0XA3014314); 176 | II(B, C, D, A, data_padding[i * 16 + 13], 21, 0X4E0811A1); 177 | 178 | II(A, B, C, D, data_padding[i * 16 + 4], 6, 0XF7537E82); 179 | II(D, A, B, C, data_padding[i * 16 + 11], 10, 0XBD3AF235); 180 | II(C, D, A, B, data_padding[i * 16 + 2], 15, 0X2AD7D2BB); 181 | II(B, C, D, A, data_padding[i * 16 + 9], 21, 0XEB86D391); 182 | 183 | /* update the md5 register */ 184 | A += AA; 185 | B += BB; 186 | C += CC; 187 | D += DD; 188 | } 189 | 190 | /* free the memory */ 191 | free(data_padding); 192 | 193 | /* generate the digest */ 194 | byte temp_result[16] = {0}; 195 | LE_UINT32_TO_BYTES(&temp_result[0], A); 196 | LE_UINT32_TO_BYTES(&temp_result[4], B); 197 | LE_UINT32_TO_BYTES(&temp_result[8], C); 198 | LE_UINT32_TO_BYTES(&temp_result[12], D); 199 | 200 | size_t out_len = 0; 201 | bytes_to_hex(temp_result, 16, digest, &out_len); 202 | 203 | digest[32] = '\0'; 204 | 205 | return true; 206 | } -------------------------------------------------------------------------------- /src/encode/base64.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: base64.c 3 | * @description: base64 implementation 4 | * @author: WAHAHA 5 | * @Date: 2024-02-28 11:06:35 6 | * @LastEditTime: 2024-03-06 00:48:03 7 | * @FilePath: \Serendipity\src\encode\base64.c 8 | * @category: encode-algorithm 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | typedef struct base64_encoder { 17 | const byte *b64_table; 18 | status(*reset)(void); 19 | status(*encode)(const byte *input, byte *output, const byte *b64_table); 20 | status(*decode)(const byte *input, byte *output, const byte *b64_table); 21 | } base64_encoder; 22 | */ 23 | 24 | /* base64 encoder constructor and destructor */ 25 | /** 26 | * @Funticon name: new_base64 27 | * @description: create a new base64 encoder 28 | * @Author: WAHAHA 29 | * @Date: 2024-03-04 12:15:45 30 | * @Note: allow the b64_table to be NULL, if NULL, use the default table 31 | * @param {byte} *b64_table 32 | * @return {base64_encoder *} 33 | */ 34 | base64_encoder *new_base64(const byte *b64_table) { 35 | base64_encoder *encoder = (base64_encoder *) malloc(sizeof(base64_encoder)); 36 | if (encoder == NULL) 37 | return NULL; 38 | /* alloc the b64_table and reverse_table */ 39 | encoder->b64_table = (byte *) malloc(64 * sizeof(byte)); 40 | encoder->reverse_table = (byte *) malloc(256 * sizeof(byte)); 41 | // the parameter for free() is allowed to be NULL 42 | if (encoder->b64_table == NULL || encoder->reverse_table == NULL) { 43 | free(encoder->b64_table); 44 | free(encoder->reverse_table); 45 | free(encoder); 46 | return NULL; 47 | } 48 | 49 | /* set the b64_table */ 50 | if (b64_table == NULL) 51 | memcpy(encoder->b64_table, base64_default_table, 64); 52 | else 53 | memcpy(encoder->b64_table, b64_table, 64); 54 | 55 | /* set the reverse_table */ 56 | generate_reverse_table(encoder->b64_table, encoder->reverse_table); 57 | 58 | return encoder; 59 | } 60 | 61 | /** 62 | * @Funticon name: free_base64 63 | * @description: free the base64 encoder 64 | * @Author: WAHAHA 65 | * @Date: 2024-03-04 12:16:25 66 | * @Note: None 67 | * @param {base64_encoder} *encoder 68 | * @return {status} 69 | */ 70 | status free_base64(base64_encoder *encoder) { 71 | ASSERT(encoder != NULL, error); 72 | free(encoder->b64_table); 73 | free(encoder->reverse_table); 74 | free(encoder); 75 | return true; 76 | } 77 | 78 | 79 | /* base64 operations */ 80 | /** 81 | * @Funticon name: generate_reverse_table 82 | * @description: generate the reverse table of the base64 table 83 | * @Author: WAHAHA 84 | * @Date: 2024-03-04 12:17:25 85 | * @Note: None 86 | * @param {byte} *b64_table 87 | * @param {byte} *reverse_table 88 | * @return {status} 89 | */ 90 | static status generate_reverse_table(const byte *b64_table, byte *reverse_table) { 91 | /** 92 | * Fill with 0xff, so if 0xff is accessed later, 93 | * it means that this character is not in the base64 table, 94 | * used for error detection 95 | */ 96 | memset(reverse_table, 0xff, 256 * sizeof(byte)); 97 | for (int i = 0; i < 64; i++) { 98 | reverse_table[b64_table[i]] = i; 99 | } 100 | reverse_table['='] = 0; // padding character 101 | return true; 102 | } 103 | 104 | /** 105 | * @Funticon name: base64_change_table 106 | * @description: change the base64 table of the encoder 107 | * @Author: WAHAHA 108 | * @Date: 2024-03-04 12:18:23 109 | * @Note: also change the reverse table 110 | * @param {base64_encoder} *encoder 111 | * @param {byte} *b64_table 112 | * @return {status} 113 | */ 114 | status base64_change_table(base64_encoder *encoder, const byte *b64_table) { 115 | ASSERT(encoder != NULL, error); 116 | ASSERT(b64_table != NULL, error); 117 | memcpy(encoder->b64_table, b64_table, 64); 118 | generate_reverse_table(b64_table, encoder->reverse_table); 119 | return true; 120 | } 121 | 122 | /** 123 | * @Funticon name: base64_reset 124 | * @description: reset the base64 encoder 125 | * @Author: WAHAHA 126 | * @Date: 2024-03-04 12:19:07 127 | * @Note: None 128 | * @param {base64_encoder} *encoder 129 | * @return {status} 130 | */ 131 | status base64_reset(base64_encoder *encoder) { 132 | ASSERT(encoder != NULL, error); 133 | encoder->output_len = 0; 134 | memcpy(encoder->b64_table, base64_default_table, 64); 135 | generate_reverse_table(base64_default_table, encoder->reverse_table); 136 | return true; 137 | } 138 | 139 | /** 140 | * @Funticon name: base64_encode 141 | * @description: encode the input to base64 142 | * @Author: WAHAHA 143 | * @Date: 2024-03-04 12:19:32 144 | * @Note: length of output will be stored in encoder->output_len 145 | * @param {base64_encoder} *encoder 146 | * @param {byte} *input 147 | * @param {int} in_len 148 | * @param {byte} *output 149 | * @return {status} 150 | */ 151 | status base64_encode(base64_encoder *encoder, const byte *input, int in_len, 152 | byte *output) { 153 | /* check the parameters */ 154 | ASSERT(input != NULL, error); 155 | ASSERT(in_len > 0, error); 156 | ASSERT(output != NULL, error); 157 | // ASSERT(out_len != NULL, error); 158 | 159 | /* calculate the length of output */ 160 | if (in_len % 3 != 0) 161 | encoder->output_len = (in_len / 3 + 1) * 4; 162 | else 163 | encoder->output_len = in_len / 3 * 4; 164 | 165 | 166 | output[encoder->output_len] = '\0'; 167 | 168 | const byte *table = encoder->b64_table; 169 | int i, j; 170 | /* encode the input */ 171 | for (i = 0, j = 0; i + 3 <= in_len; i += 3, j += 4) { 172 | /* common case */ 173 | output[j] = table[input[i] >> 2]; 174 | output[j + 1] = table[(input[i] & 0x03) << 4 | (input[i + 1] >> 4)]; 175 | output[j + 2] = table[(input[i + 1] & 0x0f) << 2 | (input[i + 2] >> 6)]; 176 | output[j + 3] = table[input[i + 2] & 0x3f]; 177 | } 178 | /* fix the padding */ 179 | if (i < in_len) { 180 | /* 2 bytes left */ 181 | if (in_len % 3 == 2) { 182 | output[j++] = table[input[i] >> 2]; 183 | output[j++] = table[(input[i] & 0x03) << 4 | (input[i + 1] >> 4)]; 184 | output[j++] = table[(input[i + 1] & 0x0f) << 2]; 185 | output[encoder->output_len - 1] = '='; 186 | } 187 | /* 1 byte left */ 188 | else if (in_len == 1) { 189 | output[j++] = table[input[i] >> 2]; 190 | output[j++] = table[(input[i] & 0x03) << 4]; 191 | output[encoder->output_len - 1] = '='; 192 | output[encoder->output_len - 2] = '='; 193 | } 194 | } 195 | 196 | return true; 197 | } 198 | 199 | /** 200 | * @Funticon name: base64_decode 201 | * @description: decode the input from base64 202 | * @Author: WAHAHA 203 | * @Date: 2024-03-04 12:22:21 204 | * @Note: length of output will be stored in encoder->output_len 205 | * @param {base64_encoder} *encoder 206 | * @param {byte} *input 207 | * @param {int} in_len 208 | * @param {byte} *output 209 | * @return {status} 210 | */ 211 | status base64_decode(base64_encoder *encoder, const byte *input, int in_len, 212 | byte *output) { 213 | /* check the parameters */ 214 | ASSERT(input != NULL, error); 215 | ASSERT(in_len > 0, error); 216 | ASSERT(output != NULL, error); 217 | 218 | /* check that if the input is valid */ 219 | if (in_len & 0x03) { // in_len % 4 != 0 220 | printf("base64_decode error: the length of input is not a multiple of 4\r\n"); 221 | output[0] = '\0'; 222 | return false; 223 | } 224 | status valid = true; 225 | for (int i = 0; i < in_len; i++) { 226 | if (encoder->reverse_table[input[i]] == 0xff) { 227 | valid = false; 228 | break; 229 | } 230 | if (input[i] == '=' && i < in_len - 2) { 231 | valid = false; 232 | break; 233 | } 234 | } 235 | if (!valid) { 236 | printf("base64_decode error: the input is not a valid base64 string\r\n"); 237 | output[0] = '\0'; 238 | return false; 239 | } 240 | 241 | 242 | /* calculate the length of output */ 243 | int pad_len = 0; 244 | if (input[in_len - 1] == '=') { 245 | pad_len++; 246 | if (input[in_len - 2] == '=') { 247 | pad_len++; 248 | } 249 | } 250 | encoder->output_len = in_len / 4 * 3 - pad_len; 251 | 252 | output[encoder->output_len] = '\0'; 253 | 254 | const byte *re_table = encoder->reverse_table; 255 | int i, j; 256 | 257 | /* decode the input */ 258 | // 000000 00|1111 1111|00 000000 259 | // 000000|00 1111|1111 00|000000 260 | // a b c d 261 | for (i = 0, j = 0; i + 4 <= in_len; i += 4, j += 3) { 262 | output[j] = (re_table[input[i]] << 2) | (re_table[input[i + 1]] >> 4); 263 | output[j + 1] = (re_table[input[i + 1]] << 4) | (re_table[input[i + 2]] >> 2); 264 | output[j + 2] = (re_table[input[i + 2]] << 6) | re_table[input[i + 3]]; 265 | } 266 | /* fix the padding */ 267 | /* 1 '=' , 2 byte left */ 268 | if (pad_len == 1) { 269 | output[j++] = (re_table[input[i]] << 2) | (re_table[input[i + 1]] >> 4); 270 | output[j++] = (re_table[input[i + 1]] << 4) | (re_table[input[i + 2]] >> 2); 271 | } 272 | /* 2 '=' , 1 byte left */ 273 | else if (pad_len == 2) { 274 | output[j++] = (re_table[input[i]] << 2) | (re_table[input[i + 1]] >> 4); 275 | } 276 | output[j] = '\0'; 277 | 278 | return true; 279 | } 280 | -------------------------------------------------------------------------------- /src/encrypt/tea.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: tea.c 3 | * @description: TEA encryption algorithm implementation 4 | * @author: WAHAHA 5 | * @Date: 2024-02-29 17:33:30 6 | * @LastEditTime: 2024-03-04 14:40:13 7 | * @FilePath: \Serendipity\src\encrypt\tea.c 8 | * @category: encrypt-algorithm 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define DELTA 0x9e3779b9 16 | #define ROUND 32 17 | #define XXTEA_MX (((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) \ 18 | ^ ((sum ^ y) + (tea->key[(p & 3) ^ e] ^ z))) 19 | 20 | /* TEA encipher */ 21 | /** 22 | * @Funticon name: new_tea 23 | * @description: new a tea_encipher object 24 | * @Author: WAHAHA 25 | * @Date: 2024-03-04 12:00:44 26 | * @Note: the returned object pointer should be considered to have been properly initialized 27 | * @param {uint32_t} delta 28 | * @param {uint32_t} key 29 | * @param {int} rounds 30 | * @return {tea_encipher *} 31 | */ 32 | tea_encipher *new_tea(uint32_t delta, const uint32_t key[4], int rounds) { 33 | /* check the key and rounds */ 34 | if (rounds < 0 || key == NULL) { 35 | printf("new_tea error: Invalid key or rounds\n"); 36 | return NULL; 37 | } 38 | /* create a tea_encipher */ 39 | tea_encipher *tea = (tea_encipher *) malloc(sizeof(tea_encipher)); 40 | if (tea == NULL) 41 | return NULL; 42 | tea->delta = (delta == 0) ? DELTA : delta; 43 | for (int i = 0; i < 4; i++) { 44 | tea->key[i] = key[i]; 45 | } 46 | tea->rounds = (rounds <= 0) ? ROUND : rounds; 47 | return tea; 48 | } 49 | 50 | /** 51 | * @Funticon name: free_tea 52 | * @description: free the tea_encipher object 53 | * @Author: WAHAHA 54 | * @Date: 2024-03-04 12:03:44 55 | * @Note: None 56 | * @param {tea_encipher} *tea 57 | * @return {status} 58 | */ 59 | status free_tea(tea_encipher *tea) { 60 | ASSERT(tea != NULL, error); 61 | free(tea); 62 | return true; 63 | } 64 | 65 | /* TEA encryption interface and subroutines */ 66 | /** 67 | * @Funticon name: tea_block_encrypt 68 | * @description: encrypt a block of plain text(2 uint32_t) using TEA algorithm 69 | * @Author: WAHAHA 70 | * @Date: 2024-03-04 12:04:18 71 | * @Note: None 72 | * @param {tea_encipher} *tea 73 | * @param {uint32_t} *plain 74 | * @param {uint32_t} *cipher 75 | * @return {status} 76 | */ 77 | static status tea_block_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher) { 78 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 79 | uint32_t v0 = plain[0], v1 = plain[1], sum = 0; 80 | for (int i = 0; i < tea->rounds; i++) { 81 | sum += tea->delta; 82 | v0 += ((v1 << 4) + tea->key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + tea->key[1]); 83 | v1 += ((v0 << 4) + tea->key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + tea->key[3]); 84 | } 85 | cipher[0] = v0; 86 | cipher[1] = v1; 87 | return true; 88 | } 89 | 90 | /** 91 | * @Funticon name: tea_block_decrypt 92 | * @description: decrypt a block of cipher text(2 uint32_t) using TEA algorithm 93 | * @Author: WAHAHA 94 | * @Date: 2024-03-04 12:05:23 95 | * @Note: None 96 | * @param {tea_encipher} *tea 97 | * @param {uint32_t} *cipher 98 | * @param {uint32_t} *plain 99 | * @return {status} 100 | */ 101 | static status tea_block_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain) { 102 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 103 | uint32_t v0 = cipher[0], v1 = cipher[1], sum = tea->delta * tea->rounds; 104 | for (int i = 0; i < tea->rounds; i++) { 105 | v1 -= ((v0 << 4) + tea->key[2]) ^ (v0 + sum) ^ ((v0 >> 5) + tea->key[3]); 106 | v0 -= ((v1 << 4) + tea->key[0]) ^ (v1 + sum) ^ ((v1 >> 5) + tea->key[1]); 107 | sum -= tea->delta; 108 | } 109 | plain[0] = v0; 110 | plain[1] = v1; 111 | return true; 112 | } 113 | 114 | /** 115 | * @Funticon name: tea_encrypt 116 | * @description: interface of TEA encryption, encrypt the plain text using TEA algorithm 117 | * @Author: WAHAHA 118 | * @Date: 2024-03-04 12:06:48 119 | * @Note: the plain will be checked if it is valid 120 | * @param {tea_encipher} *tea 121 | * @param {uint32_t} *plain 122 | * @param {uint32_t} *cipher 123 | * @return {status} 124 | */ 125 | status tea_encrypt(tea_encipher *tea,const uint32_t *plain, uint32_t *cipher) { 126 | /* check the input */ 127 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 128 | /* check if the plain text is valid */ 129 | ASSERT((tea->n & 1) == 0, false); 130 | /* start to encrypt every block */ 131 | status ret = true; 132 | for (int i = 0; i < tea->n; i += 2) { 133 | ret = tea_block_encrypt(tea, plain + i, cipher + i); 134 | } 135 | return ret; 136 | } 137 | 138 | /** 139 | * @Funticon name: tea_decrypt 140 | * @description: interface of TEA decryption, decrypt the cipher text using TEA algorithm 141 | * @Author: WAHAHA 142 | * @Date: 2024-03-04 12:09:02 143 | * @Note: the cipher will be checked if it is valid 144 | * @param {tea_encipher} *tea 145 | * @param {uint32_t} *cipher 146 | * @param {uint32_t} *plain 147 | * @return {status} 148 | */ 149 | status tea_decrypt(tea_encipher *tea,const uint32_t *cipher, uint32_t *plain) { 150 | /* check the input */ 151 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 152 | /* check if the cipher text is valid */ 153 | ASSERT((tea->n & 1) == 0, false); 154 | /* start to decrypt every block */ 155 | status ret = true; 156 | for (int i = 0; i < tea->n; i += 2) { 157 | ret = tea_block_decrypt(tea, cipher + i, plain + i); 158 | } 159 | return ret; 160 | } 161 | 162 | 163 | /* XTEA encryption interface and subroutines */ 164 | /** 165 | * @Funticon name: xtea_block_encrypt 166 | * @description: encrypt a block of plain text(2 uint32_t) using XTEA algorithm 167 | * @Author: WAHAHA 168 | * @Date: 2024-03-04 12:10:24 169 | * @Note: None 170 | * @param {tea_encipher} *tea 171 | * @param {uint32_t} *plain 172 | * @param {uint32_t} *cipher 173 | * @return {status} 174 | */ 175 | static status xtea_block_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher) { 176 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 177 | uint32_t v0 = plain[0], v1 = plain[1], sum = 0; 178 | for (int i = 0; i < tea->rounds; i++) { 179 | v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + tea->key[sum & 3]); 180 | sum += tea->delta; 181 | v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + tea->key[(sum >> 11) & 3]); 182 | } 183 | cipher[0] = v0; 184 | cipher[1] = v1; 185 | return true; 186 | } 187 | 188 | /** 189 | * @Funticon name: xtea_block_decrypt 190 | * @description: decrypt a block of cipher text(2 uint32_t) using XTEA algorithm 191 | * @Author: WAHAHA 192 | * @Date: 2024-03-04 12:10:53 193 | * @Note: None 194 | * @param {tea_encipher} *tea 195 | * @param {uint32_t} *cipher 196 | * @param {uint32_t} *plain 197 | * @return {status} 198 | */ 199 | static status xtea_block_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain) { 200 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 201 | uint32_t v0 = cipher[0], v1 = cipher[1], sum = tea->delta * tea->rounds; 202 | for (int i = 0; i < tea->rounds; i++) { 203 | v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + tea->key[(sum >> 11) & 3]); 204 | sum -= tea->delta; 205 | v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + tea->key[sum & 3]); 206 | } 207 | plain[0] = v0; 208 | plain[1] = v1; 209 | return true; 210 | } 211 | 212 | /** 213 | * @Funticon name: xtea_encrypt 214 | * @description: interface of XTEA encryption, encrypt the plain text using XTEA algorithm 215 | * @Author: WAHAHA 216 | * @Date: 2024-03-04 12:11:23 217 | * @Note: the plain will be checked if it is valid 218 | * @param {tea_encipher} *tea 219 | * @param {uint32_t} *plain 220 | * @param {uint32_t} *cipher 221 | * @return {status} 222 | */ 223 | status xtea_encrypt(tea_encipher *tea,const uint32_t *plain, uint32_t *cipher) { 224 | /* check the input */ 225 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 226 | /* check if the plain text is valid */ 227 | ASSERT((tea->n & 1) == 0, false); 228 | /* start to encrypt every block */ 229 | status ret = true; 230 | for (int i = 0; i < tea->n; i += 2) { 231 | ret = xtea_block_encrypt(tea, plain + i, cipher + i); 232 | } 233 | return ret; 234 | } 235 | 236 | /** 237 | * @Funticon name: xtea_decrypt 238 | * @description: interface of XTEA decryption, decrypt the cipher text using XTEA algorithm 239 | * @Author: WAHAHA 240 | * @Date: 2024-03-04 12:11:54 241 | * @Note: the cipher will be checked if it is valid 242 | * @param {tea_encipher} *tea 243 | * @param {uint32_t} *cipher 244 | * @param {uint32_t} *plain 245 | * @return {status} 246 | */ 247 | status xtea_decrypt(tea_encipher *tea,const uint32_t *cipher, uint32_t *plain) { 248 | /* check the input */ 249 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 250 | /* check if the cipher text is valid */ 251 | ASSERT((tea->n & 1) == 0, false); 252 | /* start to decrypt every block */ 253 | status ret = true; 254 | for (int i = 0; i < tea->n; i += 2) { 255 | ret = xtea_block_decrypt(tea, cipher + i, plain + i); 256 | } 257 | return ret; 258 | } 259 | 260 | /** 261 | * @Funticon name: xxtea_encrypt 262 | * @description: interface of XXTEA encryption, encrypt the plain text using XXTEA algorithm 263 | * @Author: WAHAHA 264 | * @Date: 2024-03-04 12:12:31 265 | * @Note: None 266 | * @param {tea_encipher} *tea 267 | * @param {uint32_t} *plain 268 | * @param {uint32_t} *cipher 269 | * @return {status} 270 | */ 271 | status xxtea_encrypt(tea_encipher *tea, const uint32_t *plain, uint32_t *cipher) { 272 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 273 | ASSERT(tea->n > 1, error); 274 | uint32_t e, sum = 0, y, z = plain[tea->n - 1]; 275 | int rounds = 6 + 52 / (tea->n), p; 276 | 277 | /* copy the plain text */ 278 | for (int i = 0; i < tea->n; i++) 279 | cipher[i] = plain[i]; 280 | 281 | /* start to encrypt */ 282 | for (int i = 0; i < rounds; ++i) { 283 | sum += tea->delta; 284 | e = (sum >> 2) & 3; 285 | for (p = 0; p < tea->n - 1; p++) { 286 | y = cipher[p + 1]; 287 | cipher[p] += XXTEA_MX; 288 | z = cipher[p]; 289 | } 290 | y = cipher[0]; 291 | cipher[tea->n - 1] += XXTEA_MX; 292 | z = cipher[tea->n - 1]; 293 | } 294 | 295 | return true; 296 | } 297 | 298 | /** 299 | * @Funticon name: xxtea_decrypt 300 | * @description: interface of XXTEA decryption, decrypt the cipher text using XXTEA algorithm 301 | * @Author: WAHAHA 302 | * @Date: 2024-03-04 12:13:09 303 | * @Note: None 304 | * @param {tea_encipher} *tea 305 | * @param {uint32_t} *cipher 306 | * @param {uint32_t} *plain 307 | * @return {status} 308 | */ 309 | status xxtea_decrypt(tea_encipher *tea, const uint32_t *cipher, uint32_t *plain) { 310 | ASSERT(tea != NULL && plain != NULL && cipher != NULL, error); 311 | ASSERT(tea->n > 1, error); 312 | uint32_t e, sum, y = cipher[0], z; 313 | int rounds = 6 + 52 / (tea->n), p; 314 | sum = rounds * tea->delta; 315 | 316 | /* copy the cipher text */ 317 | for (int i = 0; i < tea->n; i++) 318 | plain[i] = cipher[i]; 319 | 320 | /* start to decrypt */ 321 | for (int i = 0; i < tea->n; ++i) { 322 | e = (sum >> 2) & 3; 323 | for (p = tea->n - 1; p > 0; p--) { 324 | z = plain[p - 1]; 325 | plain[p] -= XXTEA_MX; 326 | y = plain[p]; 327 | } 328 | z = plain[tea->n - 1]; 329 | plain[0] -= XXTEA_MX; 330 | y = plain[0]; 331 | sum -= tea->delta; 332 | } 333 | 334 | return true; 335 | } -------------------------------------------------------------------------------- /docs/代码规范1.0.md: -------------------------------------------------------------------------------- 1 | # 1 前言 2 | 3 | 本文档的主要目的是为了统一库的统一编程的风格而进行编写,本文档借鉴了linux内核编写的一些规范加上一些实践过程的思考编写而成。《程序员之道》这本书曾说明,统一一个规范的文档是进行团队协作的前提。所以本文档给各个关于库编写相关的程序提供一个编程的风格说明参考。 4 | 5 | 编程文档参考文献 6 | 7 | 1. Linux源码下的《CodingStyle》文档。 8 | 9 | 2. 《代码整洁之道》。 10 | 11 | 3. 《GNU编码规范》。 12 | 13 | 4. 《华为技术有限公司c语言编程规范》。 14 | 15 | > 代码风格是因人而异的,而且我不愿意把自己的观点强加给任何人,但这就像我去做任何事情都必须遵循的原则那样,我也希望在绝大多数事上保持这种的态度。 16 | > 17 | > --- CodingStyle 18 | 19 | # 2 规范说明 20 | 21 | 规范问题,小到一个小项目,大到一个大公司的整体管理都是相当重要,正所谓**不以规矩,不成方圆**,一个优秀的代码规范可以的提高代码的可读性并且在一定的程度上可以减少不必要的编程低级错误。并且给程序的开发者和后续维护者一种赏心悦目的感觉,当然这并不是主要目的。代码规范和风格目的要突出简洁明了、可维护、可测试、可靠、可移植、高效 这几个特点。 22 | 23 | ## 2.1 简洁 24 | 25 | 代码最重要目的就是给开发人员看,因此简单,明了,清晰,无歧义,易于阅读为第一要义。在一定的情况下,代码的可阅读性要高于代码的性能,除非你需要高性能的需求。简单、明了、清晰的代码也利于后期维护,尤其是当你写的代码交给他人去维护的时候,请不要祸害别人。代码越长越难看懂,这个大家应该都深有体会,一个 1000 多行的函数和一个最多 100 行的函数哪个好看?所以尽量将把函数写的精简。而且代码越长越容易出错,没有用的代码,变量等一定要及时的清理掉!功能类似或者重复的代码应尽可能提炼成一个函数。 26 | 27 | ## 2.2 尽量与原有代码风格保持一致 28 | 29 | 一个公司内部的代码风格一般都是统一的,但是如果你跳槽到其他公司去,或者有时候因为业务原因需要维护别的公司的代码,此时代码风格出现冲突的话尽可能使用现在维护的代码风格。 30 | 31 | # 3 排版格式和注释 32 | 33 | 排版是为了在编写代码的时候按照“一定的规矩”来编写,主要目的是为了是代码清晰、易于阅读。注释顾名思义就为注释自己的代码,以方便他人阅读,尤其是尤其维护人员。优美的排版和言简意赅的注释可以提高阅读者的阅读效率,所以在编写代码之前一定要确定好自己打算采用的排版方式和注释方式。 34 | 35 | ## 3.1 代码缩进 36 | 37 | 代码缩进要使用制表符,也就是 TAB 键,不要使用空格键缩进!一般情况下一个 TAB 为4 个字符,但是 Linux 建议 TAB 键为 8 个字符,因为 8 个字符缩进比较多,因为有利于长时间阅读代码,可以很清晰的分辨出多级嵌套, 但是 8 个字符太多,代码向右移动的太远了,这样的话如果屏幕横向分辨率小的话每行编写的代码就会少,尤其是当一个代码块有多级缩进的时候, Linux 建议你应该修改你的代码。这里我设置的 TAB 键为 4 个字符,因为在我阅读 Linux内核源码的时候发现大部分都是 4 个字符。在switch 语句中,“swich”和“case”标签应该对齐处于同一列,不需要缩进 case 标签,如下所示: 38 | 39 | ```c 40 | switch (suffix) { 41 | case 'G': 42 | case 'g': 43 | mem <<= 30; 44 | break; 45 | case 'M': 46 | case 'm': 47 | mem <<= 20; 48 | break; 49 | case 'K': 50 | case 'k': 51 | mem <<= 10; 52 | /* fall through */ 53 | default: 54 | break; 55 | } 56 | ``` 57 | 58 | ## 3.2 代码行相关规范 59 | 60 | 1. 每一行的代码长度限制在 80 列。如果大于 80 列的话就要分成多行编写(其实当前高分辨屏幕已经很常见了,基本都是 1080P 起,甚至 4K,所以可以设置更大值),并且在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要适当进行缩进,一般进行一级缩进即可,如下所示: 61 | 62 | ```c 63 | perm_count_msg.head.len = NO7_TO_STAT_PERM_COUNT_LEN 64 | + STAT_SIZE_PER_FRAM * sizeof( _UL ); 65 | act_task_table[frame_id * STAT_TASK_CHECK_NUMBER + index].occupied 66 | = stat_poi[index].occupied; 67 | if ((taskno < max_act_task_number) 68 | && (n7stat_stat_item_valid (stat_item))) { 69 | ... // program code 70 | } 71 | ``` 72 | 73 | 2. 不要把多个语句放到一行里面,一行只写一条语句,如下所示: 74 | 75 | ```c 76 | 不规范的写法: 77 | a = x+y; b = x-y; 78 | 应该为: 79 | a=x+y; 80 | b=x-y; 81 | ``` 82 | 83 | 3. 不要在一行里面防止多个赋值语句。 84 | 4. if、for、do、while、case、swich、default 等语句单独占用一行。 85 | 86 | ## 3.3 括号与空格 87 | 88 | 1. 括号 89 | 90 | 代码中用到大括号“{”和“}”的地方,应该把起始大括号“{”放到行尾,把结束大括号“}”放到行首,如下所示: 91 | 92 | ```c 93 | if (x is true) { 94 | we do y 95 | } 96 | ``` 97 | 98 | 上面大括号“{”和“}”的用法适用于所有的非函数程序块,如 if、switch、for、do、while等,比如: 99 | 100 | ```c 101 | switch (action) { 102 | case KOBJ_ADD: 103 | return "add"; 104 | case KOBJ_REMOVE: 105 | return "remove"; 106 | case KOBJ_CHANGE: 107 | return "change"; 108 | default: 109 | return NULL; 110 | } 111 | ``` 112 | 113 | 这里要注意!!!函数的起始大括号要放置到下一行的开头!!如下所示: 114 | 115 | ```c 116 | int function(int x) 117 | { 118 | body of function 119 | } 120 | ``` 121 | 122 | 结束的大括号“}”要独自占用一行,除非后面跟着同一个语句的其它剩余部分,比如 do 语句中的“while”或者 if 语句中的“else”,如下代码所示: 123 | 124 | ```c 125 | do { 126 | body of do_loop 127 | } while (condition); 128 | ``` 129 | 130 | ```c 131 | if (x == y) { 132 | .. 133 | } else if (x > y) { 134 | ... 135 | } else { 136 | .... 137 | } 138 | ``` 139 | 140 | 当只有一个单独的语句的时候就可以不必要加大括号了,比如: 141 | 142 | ```c 143 | if (condition) 144 | action(); 145 | ``` 146 | 147 | ```c 148 | if (condition) 149 | do_this(); 150 | else 151 | do_that(); 152 | ``` 153 | 154 | 在上面的 if else 条件语句中,所有的分支都只有一行语句,所以可以都不加大括号。但是如果在条件语句中任何一个分支有大于一行语句的时候都必须加上大括号,如下所示代码: 155 | 156 | ```c 157 | if (condition) { 158 | do_this(); 159 | do_that(); 160 | } else { 161 | otherwise(); 162 | } 163 | ``` 164 | 165 | 2. 空格规范 166 | 167 | 1. 在一些关键字后面要添加空格,如: 168 | 169 | ```c 170 | if、swich、case、for、do、while 171 | ``` 172 | 173 | 但是不要在 sizeof、typedof、alignof 或者\_\_attribute\_\_这些关键字后面添加空格,因为这些大多数后面都会跟着小括号,因此看起来像个函数,如: 174 | 175 | ```c 176 | s = sizeof(struct file); 177 | ``` 178 | 179 | 2. 如果要定义指针类型,或者函数返回指针类型时,“*”应该放到靠近变量名或者函数名的一侧,而不是类型名,如: 180 | 181 | ```c 182 | char *linux_banner; 183 | unsigned long long memparse(char *ptr, char **retptr); 184 | char *match_strdup(substring_t *s); 185 | ``` 186 | 187 | 3. 二元或者三元操作符两侧都要加一个空格,例如下面所示操作符: 188 | 189 | ```c 190 | = + - < > * / % | & ^ <= >= == != ? : 191 | ``` 192 | 193 | 4. 一元操作符后不要加空格,如: 194 | 195 | ```c 196 | & * + - ~ ! sizeof typeof alignof __attribute__ defined 197 | ``` 198 | 199 | 5. 后缀自加或者自减的一元操作符前后都不加空格,如: 200 | 201 | ```c 202 | ++ -- 203 | ``` 204 | 205 | 6. “.”和“->”这两个结构体成员操作符前后不加空格。 206 | 207 | 7. 逗号、分号只在后面添加空格,如: 208 | 209 | ```c 210 | int a, b, c; 211 | ``` 212 | 213 | 8. 注释符“/”和“/”与注释内容之间要添加一个空格。 214 | 215 | ## 3.4 注释 216 | 217 | ### 3.4.1 注释风格 218 | 219 | 注释可以让别人一看你的代码就明白其中的含义和用法, 但是不要过度注释, 不要在注释里解释代码是任何运行的,一般你的注释应该告诉别人代码做了什么,而不是怎么做的,即结果,而非过程!注释要放到函数的头部,尽量不要在函数体里面放置注释,注释的风格应该选择: 220 | 221 | ```c 222 | /* ...... */ 223 | ``` 224 | 225 | 而非: 226 | 227 | ```c 228 | // ...... 229 | ``` 230 | 231 | 对于多行注释,应该选择如下风格: 232 | 233 | ```c 234 | /* 235 | * This is the preferred style for multi-line 236 | * comments in the Linux kernel source code. 237 | * Please use it consistently. 238 | * Description: A column of asterisks on the left side, 239 | * with beginning and ending almost-blank lines. 240 | */ 241 | ``` 242 | 243 | 每一行的开始处都应该放置符号“\*”, 并且所有的行的“\*”要对齐在一列上. 244 | 245 | ### 3.4.2 文件信息注释 246 | 247 | 在文件开始的地方应该对本文件做一个总体的、概括性的注释,比如:版权声明、版本号、作者、文件简介、修改日志等,如下所示的注释: 248 | 249 | ```c 250 | /** 251 | * @file: xxx 252 | * @description: This is a source file that contains the implementation of xxx 253 | * @author: xxx 254 | * @Date: xxxx/xx/xx xx:xx 255 | * @LastEditTime: xxxx/xx/xx xx:xx 256 | * @FilePath: <从项目文件夹名开始的相对路径>/xxx 257 | * @category: 该文件所属的分类 258 | */ 259 | ``` 260 | 261 | ### 3.4.3 函数的注释 262 | 263 | 函数需要注释其作用,参数的含义以及返回值的含义,注释可以放在函数声明的地方,也可以放在函数头,如下: 264 | 265 | ```c 266 | /** 267 | * @Funticon name: xxxx 268 | * @description: Description of the function 269 | * @Author: xxx 270 | * @Date: xxxx/xx/xx xx:xx 271 | * @Note: Some points to note 272 | * @param {参数类型} 参数名 273 | * @return {返回值类型} 274 | */ 275 | ``` 276 | 277 | ## 3.5 标识符命名 278 | 279 | ### 3.5.1 命名规则 280 | 281 | C 语言中的命名有多种风格,有 unix 风格的、有 windows 风格的、还有匈牙利命名法的等等。因为我们是编写 Linux 代码的,所以要使用 unix 风格,而 Linux 属于类 unix 系统。 unix 命名风格是单词用小写,然后每个单词用下划线“_”连接在一起,比如:read_adc1_value(),因此在函数和变量的命名上就要使用此种方法,这也是 Linux 内核里面所使用的命名方法。注意事项: 282 | 283 | 1. 命名一定要清晰!清晰是首位,要使用完整的单词或者大家都知道的缩写,让别人一读就懂,避免不必要的误会,比如: 284 | 285 | ```c 286 | int book_number; 287 | int number_of_beautiful_gril; 288 | ``` 289 | 290 | 2. 除了常用的缩写以外,不要使用单词缩写,更不要用汉语拼音!!! 291 | 292 | 3. 具有互斥意义的变量或者动作相反的函数应该是用互斥词组命名,如: 293 | 294 | ```c 295 | add/remove begin/end create/destroy insert/delete add/delete 296 | first/last get/release increment/decrement put/get 297 | lock/unlock open/close min/max old/new 298 | start/stop next/previous source/target show/hide 299 | send/receive source/destination copy/paste up/down 300 | ``` 301 | 302 | 4. 如果是移植的其它的代码,比如驱动,命名风格应该和原风格一致。 303 | 304 | 5. 不要使用单字节命名变量,但是允许使用 i,j,k 这样的作为局部循环变量。 305 | 306 | ### 3.5.2 文件命名 307 | 308 | 文件统一采用小写命名. 309 | 310 | ### 3.5.3 变量命名 311 | 312 | 变量名一定要有意义,并且意义准确,单词都采用小写,用下划线“_”连接。比如表示图书的数量的变量,就可以使用如下命名: 313 | 314 | ```c 315 | int number_of_book; 316 | ``` 317 | 318 | 不要采用匈牙利命名法,尽量避免使用全局变量。 319 | 320 | ### 3.5.4 函数命名 321 | 322 | 和变量命名一样. 323 | 324 | ### 3.5.5 宏命名 325 | 326 | 对于数值等常量宏定义的命名,建议使用大写,单词之间使用下划线“_”连接在一起,比如: 327 | 328 | ```c 329 | #define PI_ROUNDED 3.14 330 | ``` 331 | 332 | ## 3.6 函数规范 333 | 334 | 函数要简短而且漂亮、并且只能完成一件事,函数的本地变量数量最好不超过 5-10 个,否则函数就有问题,需要重新构思函数,将其分为更小的函数,函数要注意的事项如下: 335 | 336 | 1. 一个函数只能完成一个功能 337 | 338 | 如果一个函数实现多个功能的话将会给开发、使用和维护带来很大的困难。因此,在跟函数无关或者关联很弱的代码不要放到函数里面,否则的话会导致函数职责不明确,难以理解和修改. 339 | 340 | 2. 重复代码提炼成函数 341 | 342 | 重复的代码给人的直观感受就是啰嗦,明明说一遍别人就能记住的事情,非要说好几遍!因此一定要消除重复代码,将其提炼成函数。 343 | 344 | 3. 不同函数用空行隔开 345 | 346 | 不同的函数使用空行隔开,如果函数需要导出的话,它的 `EXPORT*` 宏应该紧贴在他的结束大括号下,比如: 347 | 348 | ```c 349 | int system_is_up(void) 350 | { 351 | return system_state == SYSTEM_RUNNING; 352 | } 353 | EXPORT_SYMBOL(system_is_up); 354 | ``` 355 | 356 | 4. 函数集中退出方法 357 | 358 | 我们在学习 C 语言的时候都会听到或者看到这种说法:少用、最好不要用 goto 语句,但是linux 源码中确大量的使用到了 goto 语句, linux 源码使用goto 语句来实现函数退出。当一个函数从多个位置推出,并且需要做一些清理的常见操作的时候, goto 语句就很方便,如果不需要清理操作的话就直接使用 return 即可,如下所示: 359 | 360 | ```c 361 | int fun(int a) 362 | { 363 | int result = 0; 364 | char *buffer; 365 | buffer = kmalloc(SIZE, GFP_KERNEL); 366 | if (!buffer) 367 | return -ENOMEM; 368 | if (condition1) { 369 | while (loop1) { 370 | ... 371 | } 372 | result = 1; 373 | goto out_buffer; 374 | ... 375 | } 376 | out_buffer: 377 | kfree(buffer); 378 | return result; 379 | } 380 | ``` 381 | 382 | 5. 函数嵌套过深,最好不要超过4层 383 | 384 | 函数嵌套深度指的是函数中的代码控制块(例如:if、for、while、switch 等)之间互相包含的深度,嵌套会增加阅读代码时候的脑力,嵌套太深非常不利于阅读! 385 | 386 | 6. 对函数的参数做合法性检查 387 | 388 | 函数要对其参数做合法性的检查,比如参数如果有指针类型数据的话如果不做检查,当传入野指针的话就会出错。比如参数的范围不做检查的话可能会传递进来一个超出范围的参数值,导致函数计算溢出等。因此函数必须对参数做合法性检查,比如 STM32 的官方库函数就会对函数的参数做合法性的检查. 389 | 390 | 7. 对函数的错误返回要做全面的处理 391 | 392 | 一个函数一般都会提供一些指示错误发生的方法,一般都用返回值来表示,因此我们必须对这些错误标识做处理。 393 | 394 | 8. 源文件范围内定义和声明的函数,除非外部可见,否则都应该用 static 函数. 395 | 396 | 如果一个函数只在同一个文件的其它地方调用,那么就应该用 static,static 确保这个函数只在声明它的文件是可见的,这样可以避免和其它库中相同标识符的函数或变量发生混淆。 397 | 398 | ## 3.7 变量 399 | 400 | 1. 一个变量只能有一个功能,不能把一个变量当作多用途 401 | 402 | 一个变量只能有一个特定功能,不能把一个变量作为多用途使用,即一个变量取值不同的时候其代表的含义也不同,如: 403 | 404 | ```c 405 | int time; 406 | time = 200; //表示时间 407 | time = getvalue(); //ret 用作返回值 408 | ``` 409 | 410 | 上述代码中变量 time 用作时间,但是也用作了函数 getvalue 的返回值。应该改为如下: 411 | 412 | ```c 413 | int time,ret; 414 | time = 200; 415 | ret = getvalue(); 416 | ``` 417 | 418 | 2. 不用或者少用全局变量 419 | 420 | 单个文件内可以使用 static 修饰的全局变量,这可以为文件的私有变量, 全局变量应该是模块的私有数据,不能作用对外的接口,使用 static 类型的定义,可以防止外部文件对本文件的全局变量的非正常访问。直接访问其它模块的私有数据,会增强模块之间的耦合关系。 421 | 422 | 3. 防止局部变量和全局变量重名 423 | 424 | 局部变量和全局变量重名会容易使人误解! 425 | 426 | 4. 严禁使用未经初始化的变量作为右值 427 | 428 | 如果使用变量作为右值的话,在使用前一定要初始化变量,禁止使用未经初始化的变量作为右值,而且在首次使用前初始化变量的地方离使用的地方越近越好!未初始化变量是 C 和C++最常见的错误源,因此在变量首次使用前一定要确保正确初始化,如: 429 | 430 | ```c 431 | /* 不可取的初始化:无意义*/ 432 | int num = 2; 433 | if(a) 434 | num = 3; 435 | else 436 | num=4 437 | /* 不可取的初始化:初始化和声明分离 */ 438 | int num; 439 | if(a) 440 | num = 3; 441 | else 442 | num=4 443 | /* 较好的初始化:使用默认有意义的初始化 */ 444 | int num = 3; 445 | if(a) 446 | num = 4; 447 | /* 较好的初始化: ?:减少数据流和控制流的混合 */ 448 | int num=a?4:3; 449 | ``` 450 | 451 | 5. 明确全局变量的初始化顺序 452 | 453 | 系统启动阶段,使用全局变量前,要考虑到全局变量该在什么地方初始化!使用全局变量和初始化全局变量之间的时序关系一定要分析清楚! 454 | 455 | 6. 尽量减少不必要的数据类型转换 456 | 457 | 进行数据类型转换的时候,其数据的意义、转换后的取值等都有可能发生变化,因此尽量减少不必要的数据类型转换。 458 | 459 | 460 | ## 3.8 宏和常量 461 | 462 | 1. 宏命名 463 | 464 | 用于定义常量的宏的名字及枚举里的标签需要大写,如: 465 | 466 | ```c 467 | #define CONSTANT 0x12345 468 | ``` 469 | 470 | 在定义几个变量的常量时,最好使用枚举. 471 | 472 | 2. 函数宏的命名 473 | 474 | 宏的名字一般用大写,但是形如函数的宏,其名字可以用小写,如果能写成内联函数的就不要写成像函数的宏。如下所示: 475 | 476 | ```c 477 | #define macrofun(a, b, c) \ 478 | do { \ 479 | if (a == 5) \ 480 | do_this(b, c); \ 481 | } while(0) 482 | ``` 483 | 484 | 使用宏的注意事项: 485 | 486 | - 避免影响控制流程的宏,如下: 487 | 488 | ```c 489 | #define FOO(x) \ 490 | do { \ 491 | if (blah(x) < 0) \ 492 | return -EBUGGERED; \ 493 | } while(0) 494 | ``` 495 | 496 | 上述代码中就很不好,它看起来像个函数,但是却能导致“调用”它的函数退出. 497 | 498 | - 作为左值的带参数的宏: FOO(x) = y,如果有人把 FOO 变成一个内联函数的话,这种用法就会出错了 499 | 500 | - 忘记优先级:使用表达式定义常量的宏必须将表达式置于一对小括号之内,如: 501 | 502 | ```c 503 | #define CONSTANT 0x4000 504 | #define CONSTEXP (CONSTANT | 3) 505 | ``` 506 | 507 | 3. 将宏所定义的多条表达式放在大括号中 508 | 509 | 如果有多条语句的话,最好的写法就是写成 do while(0)的方式,如下所示示例: 510 | 511 | ```c 512 | #define FOO(x) \ 513 | printf("arg is %d\n", x) \ 514 | do_something_useful(x); 515 | ``` 516 | 517 | 为了说明这个问题,下面以 for 语句为例: 518 | 519 | ```c 520 | for (blah = 1; blah < 10; blah++) 521 | FOO(blah) 522 | ``` 523 | 524 | 为了修改上面的 for 循环的错误,可以通过大括号来解决,如下: 525 | 526 | ```c 527 | #define FOO(x) { \ 528 | printf("arg is %s\n", x); \ 529 | do_something_useful(x); \ 530 | } 531 | ``` 532 | 533 | 4. 常量建议使用 const 定义来代替宏 534 | -------------------------------------------------------------------------------- /test/digest/SHA2/main.c: -------------------------------------------------------------------------------- 1 | #include "digest/sha2.h" 2 | 3 | #include 4 | #include 5 | 6 | void print_hex(const byte *data,const int len) { 7 | for (int i = 0; i < len; ++i) { 8 | printf("%02x", data[i]); 9 | } 10 | } 11 | 12 | void SHA256_test() { 13 | byte *data0 = "abc"; 14 | byte *data1 = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 15 | byte *data2 = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 16 | 17 | byte expected0[] = { 18 | 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 19 | 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad 20 | }; 21 | byte expected1[] = { 22 | 0xcd, 0xc4, 0x5c, 0x86, 0x98, 0xff, 0x7a, 0xa5, 0x1c, 0x9a, 0x80, 0x43, 0x8c, 0x0e, 0x4c, 0xe2, 0x45, 0x26, 23 | 0x5c, 0x96, 0x68, 0x49, 0x55, 0xf8, 0x6f, 0x5e, 0x90, 0x48, 0x5e, 0x8e, 0xb7, 0xbc 24 | }; 25 | byte expected2[] = { 26 | 0x5d, 0x5c, 0xa6, 0x81, 0xc1, 0x50, 0x92, 0x9e, 0xac, 0x87, 0x4d, 0xca, 0xca, 0x9c, 0x87, 0x87, 0x50, 0xac, 27 | 0x7f, 0xd0, 0x60, 0x69, 0xf9, 0x4c, 0xeb, 0x61, 0xbf, 0x6c, 0xc5, 0x2a, 0xee, 0x0e 28 | }; 29 | 30 | byte hash[SHA256_DIGEST_SIZE]; 31 | sha2_ctx ctx; 32 | 33 | printf("=======================SHA256 test=======================\n"); 34 | 35 | sha2_init(&ctx, SHA256); 36 | sha2_update(&ctx, data0, strlen((char *) data0)); 37 | sha2_final(&ctx, hash); 38 | printf("Test 0: \"%s\" -> ", (char*)data0); 39 | print_hex(hash, SHA256_DIGEST_SIZE); 40 | if (memcmp(hash, expected0, SHA256_DIGEST_SIZE) != 0) { 41 | printf("\nFAILED\n\n"); 42 | } else { 43 | printf("\nPASSWD\n\n"); 44 | } 45 | 46 | sha2_init(&ctx, SHA256); 47 | sha2_update(&ctx, data1, strlen((char *) data1)); 48 | sha2_final(&ctx, hash); 49 | printf("Test 1: \"%s\" -> ", (char*)data1); 50 | print_hex(hash, SHA256_DIGEST_SIZE); 51 | if (memcmp(hash, expected1, SHA256_DIGEST_SIZE) != 0) { 52 | printf("\nFAILED\n\n"); 53 | } else { 54 | printf("\nPASSWD\n\n"); 55 | } 56 | 57 | sha2_init(&ctx, SHA256); 58 | sha2_update(&ctx, data2, strlen((char *) data2)); 59 | sha2_final(&ctx, hash); 60 | printf("Test 2: \"%s\" -> ", (char*)data2); 61 | print_hex(hash, SHA256_DIGEST_SIZE); 62 | if (memcmp(hash, expected2, SHA256_DIGEST_SIZE) != 0) { 63 | printf("\nFAILED\n\n"); 64 | } else { 65 | printf("\nPASSWD\n\n"); 66 | } 67 | } 68 | 69 | void SHA224_test() { 70 | byte data0[] = "abc"; 71 | byte data1[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 72 | byte data2[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 73 | 74 | byte expected0[] = { 75 | 0x23, 0x09, 0x7d, 0x22, 0x34, 0x05, 0xd8, 0x22, 0x86, 0x42, 0xa4, 0x77, 0xbd, 0xa2, 0x55, 0xb3, 0x2a, 0xad, 76 | 0xbc, 0xe4, 0xbd, 0xa0, 0xb3, 0xf7, 0xe3, 0x6c, 0x9d, 0xa7 77 | }; 78 | byte expected1[] = { 79 | 0x30, 0x69, 0x61, 0x63, 0xec, 0x6a, 0x37, 0xbf, 0x03, 0xbc, 0xf9, 0x00, 0x1c, 0x50, 0x66, 0x46, 0x9c, 0x2c, 80 | 0x1f, 0x72, 0xfb, 0x60, 0x5f, 0x4c, 0x0f, 0x7f, 0xea, 0xbd 81 | }; 82 | byte expected2[] = { 83 | 0xec, 0x7a, 0x3f, 0x94, 0xac, 0xe7, 0x64, 0xd2, 0xe7, 0x45, 0xcb, 0xd4, 0xdc, 0x74, 0x58, 0x4d, 0x71, 0xb7, 84 | 0x34, 0xa1, 0xf6, 0x6f, 0x1d, 0xc6, 0xe2, 0x23, 0x91, 0x84 85 | }; 86 | 87 | byte hash[SHA224_DIGEST_SIZE]; 88 | sha2_ctx ctx; 89 | 90 | printf("=======================SHA224 test=======================\n"); 91 | 92 | sha2_init(&ctx, SHA224); 93 | sha2_update(&ctx, data0, strlen((char *) data0)); 94 | sha2_final(&ctx, hash); 95 | printf("Test 0: \"%s\" -> ", (char*)data0); 96 | print_hex(hash, SHA224_DIGEST_SIZE); 97 | if (memcmp(hash, expected0, SHA224_DIGEST_SIZE) != 0) { 98 | printf("\nFAILED\n\n"); 99 | } else { 100 | printf("\nPASSWD\n\n"); 101 | } 102 | 103 | sha2_init(&ctx, SHA224); 104 | sha2_update(&ctx, data1, strlen((char *) data1)); 105 | sha2_final(&ctx, hash); 106 | printf("Test 1: \"%s\" -> ", (char*)data1); 107 | print_hex(hash, SHA224_DIGEST_SIZE); 108 | if (memcmp(hash, expected1, SHA224_DIGEST_SIZE) != 0) { 109 | printf("\nFAILED\n\n"); 110 | } else { 111 | printf("\nPASSWD\n\n"); 112 | } 113 | 114 | sha2_init(&ctx, SHA224); 115 | sha2_update(&ctx, data2, strlen((char *) data2)); 116 | sha2_final(&ctx, hash); 117 | printf("Test 2: \"%s\" -> ", (char*)data2); 118 | print_hex(hash, SHA224_DIGEST_SIZE); 119 | if (memcmp(hash, expected2, SHA224_DIGEST_SIZE) != 0) { 120 | printf("\nFAILED\n\n"); 121 | } else { 122 | printf("\nPASSWD\n\n"); 123 | } 124 | } 125 | 126 | void SHA512_test() { 127 | byte data0[] = "abc"; 128 | byte data1[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 129 | byte data2[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 130 | 131 | byte expected0[] = { 132 | 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba, 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31, 0x12, 0xe6, 133 | 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2, 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a, 0x21, 0x92, 0x99, 0x2a, 134 | 0x27, 0x4f, 0xc1, 0xa8, 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd, 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 135 | 0xe8, 0x0e, 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f 136 | }; 137 | byte expected1[] = { 138 | 0xcb, 0x77, 0xd5, 0xb7, 0x68, 0x1b, 0x8b, 0x50, 0x04, 0x3c, 0x1d, 0xa2, 0xe3, 0xc9, 0xc0, 0xda, 0x2b, 0xb7, 139 | 0x59, 0xeb, 0x27, 0xff, 0xec, 0x39, 0xd7, 0x15, 0x2b, 0xad, 0x36, 0xe6, 0xc5, 0x44, 0x18, 0x6d, 0xf8, 0xd8, 140 | 0x6c, 0xa9, 0x9d, 0xfb, 0x1c, 0x37, 0xba, 0xe0, 0xc8, 0x3d, 0x34, 0xdd, 0xd5, 0x48, 0xdc, 0x40, 0x6c, 0xaa, 141 | 0xad, 0x61, 0xe6, 0xfe, 0x7c, 0x3f, 0xea, 0x8d, 0x3a, 0x5f 142 | }; 143 | byte expected2[] = { 144 | 0x4a, 0xc3, 0x4a, 0x4b, 0xb8, 0xd2, 0x58, 0x16, 0x20, 0x99, 0x3f, 0x27, 0x6d, 0x9c, 0x2e, 0xbe, 0x70, 0x0b, 145 | 0xb2, 0x9e, 0xd9, 0x41, 0x56, 0x67, 0xc9, 0x5d, 0x04, 0xdb, 0x70, 0x81, 0xdb, 0x4d, 0xe4, 0xcc, 0x4b, 0x4d, 146 | 0x5a, 0xd8, 0x85, 0x31, 0x7a, 0x2b, 0xda, 0x37, 0xf4, 0x0b, 0xb7, 0x11, 0x66, 0x37, 0xaf, 0x8f, 0xcc, 0xb7, 147 | 0x0c, 0x74, 0xb8, 0x06, 0x85, 0x27, 0x27, 0xe0, 0xae, 0x12 148 | }; 149 | 150 | byte hash[SHA512_DIGEST_SIZE]; 151 | sha2_ctx ctx; 152 | 153 | printf("=======================SHA512 test=======================\n"); 154 | 155 | sha2_init(&ctx, SHA512); 156 | sha2_update(&ctx, data0, strlen((char *) data0)); 157 | sha2_final(&ctx, hash); 158 | printf("Test 0: \"%s\" -> ", (char*)data0); 159 | print_hex(hash, SHA512_DIGEST_SIZE); 160 | if (memcmp(hash, expected0, SHA512_DIGEST_SIZE) != 0) { 161 | printf("\nFAILED\n\n"); 162 | } else { 163 | printf("\nPASSWD\n\n"); 164 | } 165 | 166 | sha2_init(&ctx, SHA512); 167 | sha2_update(&ctx, data1, strlen((char *) data1)); 168 | sha2_final(&ctx, hash); 169 | printf("Test 1: \"%s\" -> ", (char*)data1); 170 | print_hex(hash, SHA512_DIGEST_SIZE); 171 | if (memcmp(hash, expected1, SHA512_DIGEST_SIZE) != 0) { 172 | printf("\nFAILED\n\n"); 173 | } else { 174 | printf("\nPASSWD\n\n"); 175 | } 176 | 177 | sha2_init(&ctx, SHA512); 178 | sha2_update(&ctx, data2, strlen((char *) data2)); 179 | sha2_final(&ctx, hash); 180 | printf("Test 2: \"%s\" -> ", (char*)data2); 181 | print_hex(hash, SHA512_DIGEST_SIZE); 182 | if (memcmp(hash, expected2, SHA512_DIGEST_SIZE) != 0) { 183 | printf("\nFAILED\n\n"); 184 | } else { 185 | printf("\nPASSWD\n\n"); 186 | } 187 | } 188 | 189 | void SHA384_test() { 190 | byte data0[] = "abc"; 191 | byte data1[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 192 | byte data2[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 193 | 194 | byte expected0[] = { 195 | 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b, 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07, 0x27, 0x2c, 196 | 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63, 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed, 0x80, 0x86, 0x07, 0x2b, 197 | 0xa1, 0xe7, 0xcc, 0x23, 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 198 | }; 199 | byte expected1[] = { 200 | 0x60, 0xbf, 0x71, 0x71, 0xb7, 0xca, 0x37, 0x3f, 0xc2, 0x44, 0x26, 0x43, 0x52, 0x06, 0x84, 0xf5, 0x24, 0xaf, 201 | 0x34, 0x3d, 0x2c, 0x65, 0x64, 0x94, 0xef, 0xdc, 0x45, 0x5d, 0x25, 0x9d, 0xae, 0xe2, 0x5f, 0x57, 0xf2, 0x91, 202 | 0x9e, 0x1b, 0xb8, 0x46, 0x52, 0xd8, 0xad, 0xa3, 0xbb, 0x53, 0xff, 0xf7 203 | }; 204 | byte expected2[] = { 205 | 0x2c, 0x84, 0x91, 0xc1, 0x40, 0xec, 0x16, 0xe4, 0x13, 0x49, 0x4d, 0xf4, 0xf8, 0xcf, 0x67, 0xc7, 0x99, 0xe9, 206 | 0x86, 0x06, 0x15, 0xa3, 0x9b, 0x6f, 0xf5, 0x25, 0x0f, 0x3d, 0x8b, 0xbb, 0xf7, 0x58, 0x76, 0xae, 0xde, 0xfc, 207 | 0x07, 0x1c, 0x08, 0x4c, 0x2a, 0x29, 0xc3, 0xbd, 0x7a, 0x9a, 0x65, 0x3e 208 | }; 209 | 210 | byte hash[SHA384_DIGEST_SIZE]; 211 | sha2_ctx ctx; 212 | 213 | printf("=======================SHA384 test=======================\n"); 214 | 215 | sha2_init(&ctx, SHA384); 216 | sha2_update(&ctx, data0, strlen((char *) data0)); 217 | sha2_final(&ctx, hash); 218 | printf("Test 0: \"%s\" -> ", (char*)data0); 219 | print_hex(hash, SHA384_DIGEST_SIZE); 220 | if (memcmp(hash, expected0, SHA384_DIGEST_SIZE) != 0) { 221 | printf("\nFAILED\n\n"); 222 | } else { 223 | printf("\nPASSWD\n\n"); 224 | } 225 | 226 | sha2_init(&ctx, SHA384); 227 | sha2_update(&ctx, data1, strlen((char *) data1)); 228 | sha2_final(&ctx, hash); 229 | printf("Test 1: \"%s\" -> ", (char*)data1); 230 | print_hex(hash, SHA384_DIGEST_SIZE); 231 | if (memcmp(hash, expected1, SHA384_DIGEST_SIZE) != 0) { 232 | printf("\nFAILED\n\n"); 233 | } else { 234 | printf("\nPASSWD\n\n"); 235 | } 236 | 237 | sha2_init(&ctx, SHA384); 238 | sha2_update(&ctx, data2, strlen((char *) data2)); 239 | sha2_final(&ctx, hash); 240 | printf("Test 2: \"%s\" -> ", (char*)data2); 241 | print_hex(hash, SHA384_DIGEST_SIZE); 242 | if (memcmp(hash, expected2, SHA384_DIGEST_SIZE) != 0) { 243 | printf("\nFAILED\n\n"); 244 | } else { 245 | printf("\nPASSWD\n\n"); 246 | } 247 | } 248 | 249 | void SHA512_224_test() { 250 | byte data0[] = "abc"; 251 | byte data1[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 252 | byte data2[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 253 | 254 | byte expected0[] = { 255 | 0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54, 0xda, 0xae, 0x75, 0x30, 0x46, 0x08, 0x42, 0xe2, 0x0e, 0x37, 256 | 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4, 0x3e, 0x89, 0x24, 0xaa 257 | }; 258 | byte expected1[] = { 259 | 0x54, 0x16, 0x5d, 0xb1, 0x2c, 0xd5, 0x19, 0x0d, 0x5a, 0xa6, 0x96, 0x0d, 0x64, 0xcd, 0x73, 0x88, 0x22, 0x6d, 260 | 0x90, 0xd1, 0xc9, 0x12, 0x62, 0x1e, 0x96, 0xde, 0x9a, 0xda 261 | }; 262 | byte expected2[] = { 263 | 0x47, 0x48, 0xf7, 0x7e, 0xbb, 0x25, 0x9c, 0xb1, 0xae, 0x65, 0xe0, 0xc1, 0x81, 0xdc, 0x6e, 0xad, 0x23, 0x6d, 264 | 0xa4, 0x98, 0x74, 0xff, 0xa6, 0xf1, 0x66, 0x4d, 0xd7, 0xf7 265 | }; 266 | 267 | byte hash[SHA512_224_DIGEST_SIZE]; 268 | sha2_ctx ctx; 269 | 270 | printf("=======================SHA512/224 test=======================\n"); 271 | 272 | sha2_init(&ctx, SHA512_224); 273 | sha2_update(&ctx, data0, strlen((char *) data0)); 274 | sha2_final(&ctx, hash); 275 | printf("Test 0: \"%s\" -> ", (char*)data0); 276 | print_hex(hash, SHA512_224_DIGEST_SIZE); 277 | if (memcmp(hash, expected0, SHA512_224_DIGEST_SIZE) != 0) { 278 | printf("\nFAILED\n\n"); 279 | } else { 280 | printf("\nPASSWD\n\n"); 281 | } 282 | 283 | sha2_init(&ctx, SHA512_224); 284 | sha2_update(&ctx, data1, strlen((char *) data1)); 285 | sha2_final(&ctx, hash); 286 | printf("Test 1: \"%s\" -> ", (char*)data1); 287 | print_hex(hash, SHA512_224_DIGEST_SIZE); 288 | if (memcmp(hash, expected1, SHA512_224_DIGEST_SIZE) != 0) { 289 | printf("\nFAILED\n\n"); 290 | } else { 291 | printf("\nPASSWD\n\n"); 292 | } 293 | 294 | sha2_init(&ctx, SHA512_224); 295 | sha2_update(&ctx, data2, strlen((char *) data2)); 296 | sha2_final(&ctx, hash); 297 | printf("Test 2: \"%s\" -> ", (char*)data2); 298 | print_hex(hash, SHA512_224_DIGEST_SIZE); 299 | if (memcmp(hash, expected2, SHA512_224_DIGEST_SIZE) != 0) { 300 | printf("\nFAILED\n\n"); 301 | } else { 302 | printf("\nPASSWD\n\n"); 303 | } 304 | } 305 | 306 | void SHA512_256_test() { 307 | byte data0[] = "abc"; 308 | byte data1[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 309 | byte data2[] = "abcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaefabcdbcdecdbaef"; 310 | 311 | byte expected0[] = { 312 | 0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9, 0x9b, 0x2e, 0x29, 0xb7, 0x6b, 0x4c, 0x7d, 0xab, 0xe4, 0xc2, 313 | 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46, 0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23 314 | }; 315 | byte expected1[] = { 316 | 0xee, 0x31, 0x18, 0x57, 0x10, 0xb3, 0xe5, 0xe8, 0xd6, 0x06, 0xc9, 0x5b, 0xbb, 0x33, 0x88, 0x8f, 0x55, 0x82, 317 | 0xf1, 0x87, 0xbe, 0xfc, 0x0e, 0x36, 0xa8, 0xb0, 0x21, 0x7b, 0x99, 0x6f, 0x0d, 0xa2 318 | }; 319 | byte expected2[] = { 320 | 0x3a, 0xe2, 0xd4, 0x35, 0xd4, 0xbb, 0xa5, 0xa3, 0x11, 0x07, 0x5a, 0x14, 0x06, 0x43, 0xcd, 0x63, 0x3d, 0xfb, 321 | 0x15, 0x21, 0xdf, 0x3d, 0x84, 0xb0, 0x78, 0x90, 0x2a, 0x05, 0x19, 0x71, 0x78, 0xa8 322 | }; 323 | 324 | byte hash[SHA512_256_DIGEST_SIZE]; 325 | sha2_ctx ctx; 326 | 327 | printf("=======================SHA512/256 test=======================\n"); 328 | 329 | sha2_init(&ctx, SHA512_256); 330 | sha2_update(&ctx, data0, strlen((char *) data0)); 331 | sha2_final(&ctx, hash); 332 | printf("Test 0: \"%s\" -> ", (char*)data0); 333 | print_hex(hash, SHA512_256_DIGEST_SIZE); 334 | if (memcmp(hash, expected0, SHA512_256_DIGEST_SIZE) != 0) { 335 | printf("\nFAILED\n\n"); 336 | } else { 337 | printf("\nPASSWD\n\n"); 338 | } 339 | 340 | sha2_init(&ctx, SHA512_256); 341 | sha2_update(&ctx, data1, strlen((char *) data1)); 342 | sha2_final(&ctx, hash); 343 | printf("Test 1: \"%s\" -> ", (char*)data1); 344 | print_hex(hash, SHA512_256_DIGEST_SIZE); 345 | if (memcmp(hash, expected1, SHA512_256_DIGEST_SIZE) != 0) { 346 | printf("\nFAILED\n\n"); 347 | } else { 348 | printf("\nPASSWD\n\n"); 349 | } 350 | 351 | sha2_init(&ctx, SHA512_256); 352 | sha2_update(&ctx, data2, strlen((char *) data2)); 353 | sha2_final(&ctx, hash); 354 | printf("Test 2: \"%s\" -> ", (char*)data2); 355 | print_hex(hash, SHA512_256_DIGEST_SIZE); 356 | if (memcmp(hash, expected2, SHA512_256_DIGEST_SIZE) != 0) { 357 | printf("\nFAILED\n\n"); 358 | } else { 359 | printf("\nPASSWD\n\n"); 360 | } 361 | } 362 | 363 | int main() { 364 | SHA256_test(); 365 | SHA224_test(); 366 | SHA512_test(); 367 | SHA384_test(); 368 | SHA512_224_test(); 369 | SHA512_256_test(); 370 | return 0; 371 | } -------------------------------------------------------------------------------- /src/digest/sha2.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file: sha2.c 3 | * @description: This is a source file that contains the implementation of xxx 4 | * @author: WAHAHA 5 | * @Date: 2024/4/16 14:50 6 | * @FilePath: Serendipity/src/digest/sha2.c 7 | * @category: digest-algorithm 8 | */ 9 | 10 | #include 11 | #include 12 | #include "misc/bitwise_utils.h" 13 | #include "misc/endian.h" 14 | 15 | /* sha224 and sha256 logic functions */ 16 | #define SHA256_CH(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) 17 | #define SHA256_MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 18 | #define SHA256_BSIG0(x) \ 19 | (CYCLE_SHR_SIZE_NBIT(x,2 ,uint32_t) ^ CYCLE_SHR_SIZE_NBIT(x,13,uint32_t) ^ CYCLE_SHR_SIZE_NBIT(x,22,uint32_t)) 20 | #define SHA256_BSIG1(x) \ 21 | (CYCLE_SHR_SIZE_NBIT(x,6 ,uint32_t) ^ CYCLE_SHR_SIZE_NBIT(x,11,uint32_t) ^ CYCLE_SHR_SIZE_NBIT(x,25,uint32_t)) 22 | #define SHA256_SSIG0(x) \ 23 | (CYCLE_SHR_SIZE_NBIT(x,7 ,uint32_t) ^ CYCLE_SHR_SIZE_NBIT(x,18,uint32_t) ^ SHR_NBIT(x,3 )) 24 | #define SHA256_SSIG1(x) \ 25 | (CYCLE_SHR_SIZE_NBIT(x,17,uint32_t) ^ CYCLE_SHR_SIZE_NBIT(x,19,uint32_t) ^ SHR_NBIT(x,10)) 26 | 27 | /* sha384, sha512, sha512/224, sha512/256 logic functions */ 28 | #define SHA512_CH(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) 29 | #define SHA512_MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 30 | #define SHA512_BSIG0(x) \ 31 | (CYCLE_SHR_SIZE_NBIT(x,28,uint64_t) ^ CYCLE_SHR_SIZE_NBIT(x,34,uint64_t) ^ CYCLE_SHR_SIZE_NBIT(x,39,uint64_t)) 32 | #define SHA512_BSIG1(x) \ 33 | (CYCLE_SHR_SIZE_NBIT(x,14,uint64_t) ^ CYCLE_SHR_SIZE_NBIT(x,18,uint64_t) ^ CYCLE_SHR_SIZE_NBIT(x,41,uint64_t)) 34 | #define SHA512_SSIG0(x) \ 35 | (CYCLE_SHR_SIZE_NBIT(x,1 ,uint64_t) ^ CYCLE_SHR_SIZE_NBIT(x,8 ,uint64_t) ^ SHR_NBIT(x,7 )) 36 | #define SHA512_SSIG1(x) \ 37 | (CYCLE_SHR_SIZE_NBIT(x,19,uint64_t) ^ CYCLE_SHR_SIZE_NBIT(x,61,uint64_t) ^ SHR_NBIT(x,6 )) 38 | 39 | /* 128-bit word operations */ 40 | static uint128_t uint128_add_uint64(uint128_t a, uint64_t b) { 41 | uint64_t low = (a.low + b) & 0xffffffffffffffff; 42 | if (low < a.low) { 43 | a.high++; 44 | } 45 | a.low = low; 46 | return a; 47 | } 48 | 49 | /* sha224 and sha256 constants */ 50 | static const uint32_t SHA256_K[64] = { 51 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 52 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 53 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 54 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 55 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 56 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 57 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 58 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 59 | }; 60 | 61 | /* sha384 and sha512 constants */ 62 | static const uint64_t SHA512_K[80] = { 63 | 0x428A2F98D728AE22, 0x7137449123EF65CD, 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC, 64 | 0x3956C25BF348B538, 0x59F111F1B605D019, 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118, 65 | 0xD807AA98A3030242, 0x12835B0145706FBE, 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2, 66 | 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1, 0x9BDC06A725C71235, 0xC19BF174CF692694, 67 | 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3, 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65, 68 | 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483, 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5, 69 | 0x983E5152EE66DFAB, 0xA831C66D2DB43210, 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4, 70 | 0xC6E00BF33DA88FC2, 0xD5A79147930AA725, 0x06CA6351E003826F, 0x142929670A0E6E70, 71 | 0x27B70A8546D22FFC, 0x2E1B21385C26C926, 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF, 72 | 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8, 0x81C2C92E47EDAEE6, 0x92722C851482353B, 73 | 0xA2BFE8A14CF10364, 0xA81A664BBC423001, 0xC24B8B70D0F89791, 0xC76C51A30654BE30, 74 | 0xD192E819D6EF5218, 0xD69906245565A910, 0xF40E35855771202A, 0x106AA07032BBD1B8, 75 | 0x19A4C116B8D2D0C8, 0x1E376C085141AB53, 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8, 76 | 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB, 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3, 77 | 0x748F82EE5DEFB2FC, 0x78A5636F43172F60, 0x84C87814A1F0AB72, 0x8CC702081A6439EC, 78 | 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9, 0xBEF9A3F7B2C67915, 0xC67178F2E372532B, 79 | 0xCA273ECEEA26619C, 0xD186B8C721C0C207, 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178, 80 | 0x06F067AA72176FBA, 0x0A637DC5A2C898A6, 0x113F9804BEF90DAE, 0x1B710B35131C471B, 81 | 0x28DB77F523047D84, 0x32CAAB7B40C72493, 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C, 82 | 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A, 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817 83 | }; 84 | 85 | /* sha2 functions */ 86 | /** 87 | * @Funticon name: sha2_init 88 | * @description: This function is used to initialize the sha2 context. 89 | * @Author: WAHAHA 90 | * @Date: 2024-5-17 9:4:31 91 | * @Note: None 92 | * @param {sha2_ctx *} ctx: The sha2 context. 93 | * @param {SHA2_MODE} mode: The sha2 mode. 94 | * @return {status}: The status of the sha2 initialization. 95 | */ 96 | status sha2_init(sha2_ctx *ctx, SHA2_MODE mode) { 97 | ASSERT(ctx != NULL, error); 98 | ASSERT(mode >= SHA224 && mode <= SHA512_256, error); 99 | ctx->mode = mode; 100 | ctx->data_len = 0; 101 | ctx->bit_len = 0; 102 | ctx->total_len.high = 0; 103 | ctx->total_len.low = 0; 104 | 105 | switch (mode) { 106 | case SHA224: 107 | ctx->state.s32[0] = 0xc1059ed8; 108 | ctx->state.s32[1] = 0x367cd507; 109 | ctx->state.s32[2] = 0x3070dd17; 110 | ctx->state.s32[3] = 0xf70e5939; 111 | ctx->state.s32[4] = 0xffc00b31; 112 | ctx->state.s32[5] = 0x68581511; 113 | ctx->state.s32[6] = 0x64f98fa7; 114 | ctx->state.s32[7] = 0xbefa4fa4; 115 | ctx->buffer_len = 64; 116 | break; 117 | case SHA256: 118 | ctx->state.s32[0] = 0x6a09e667; 119 | ctx->state.s32[1] = 0xbb67ae85; 120 | ctx->state.s32[2] = 0x3c6ef372; 121 | ctx->state.s32[3] = 0xa54ff53a; 122 | ctx->state.s32[4] = 0x510e527f; 123 | ctx->state.s32[5] = 0x9b05688c; 124 | ctx->state.s32[6] = 0x1f83d9ab; 125 | ctx->state.s32[7] = 0x5be0cd19; 126 | ctx->buffer_len = 64; 127 | break; 128 | case SHA384: 129 | ctx->state.s64[0] = 0xcbbb9d5dc1059ed8; 130 | ctx->state.s64[1] = 0x629a292a367cd507; 131 | ctx->state.s64[2] = 0x9159015a3070dd17; 132 | ctx->state.s64[3] = 0x152fecd8f70e5939; 133 | ctx->state.s64[4] = 0x67332667ffc00b31; 134 | ctx->state.s64[5] = 0x8eb44a8768581511; 135 | ctx->state.s64[6] = 0xdb0c2e0d64f98fa7; 136 | ctx->state.s64[7] = 0x47b5481dbefa4fa4; 137 | ctx->buffer_len = 128; 138 | break; 139 | case SHA512: 140 | ctx->state.s64[0] = 0x6a09e667f3bcc908; 141 | ctx->state.s64[1] = 0xbb67ae8584caa73b; 142 | ctx->state.s64[2] = 0x3c6ef372fe94f82b; 143 | ctx->state.s64[3] = 0xa54ff53a5f1d36f1; 144 | ctx->state.s64[4] = 0x510e527fade682d1; 145 | ctx->state.s64[5] = 0x9b05688c2b3e6c1f; 146 | ctx->state.s64[6] = 0x1f83d9abfb41bd6b; 147 | ctx->state.s64[7] = 0x5be0cd19137e2179; 148 | ctx->buffer_len = 128; 149 | break; 150 | case SHA512_224: 151 | ctx->state.s64[0] = 0x8C3D37C819544DA2; 152 | ctx->state.s64[1] = 0x73E1996689DCD4D6; 153 | ctx->state.s64[2] = 0x1DFAB7AE32FF9C82; 154 | ctx->state.s64[3] = 0x679DD514582F9FCF; 155 | ctx->state.s64[4] = 0x0F6D2B697BD44DA8; 156 | ctx->state.s64[5] = 0x77E36F7304C48942; 157 | ctx->state.s64[6] = 0x3F9D85A86A1D36C8; 158 | ctx->state.s64[7] = 0x1112E6AD91D692A1; 159 | ctx->buffer_len = 128; 160 | break; 161 | case SHA512_256: 162 | ctx->state.s64[0] = 0x22312194fc2bf72c; 163 | ctx->state.s64[1] = 0x9f555fa3c84c64c2; 164 | ctx->state.s64[2] = 0x2393b86b6f53b151; 165 | ctx->state.s64[3] = 0x963877195940eabd; 166 | ctx->state.s64[4] = 0x96283ee2a88effe3; 167 | ctx->state.s64[5] = 0xbe5e1e2553863992; 168 | ctx->state.s64[6] = 0x2b0199fc2c85b8aa; 169 | ctx->state.s64[7] = 0x0eb72ddc81c52ca2; 170 | ctx->buffer_len = 128; 171 | break; 172 | } 173 | return true; 174 | } 175 | 176 | /** 177 | * @Funticon name: sha2_update 178 | * @description: This function is used to update the sha2 context with the data. 179 | * @Author: WAHAHA 180 | * @Date: 2024-5-17 9:44:8 181 | * @Note: None 182 | * @param {sha2_ctx *} ctx: The sha2 context. 183 | * @param {const byte *} data: The data to be processed. 184 | * @param {size_t} data_len: The size of the data. 185 | * @return {status}: The status of the sha2 update. 186 | */ 187 | status sha2_update(sha2_ctx *ctx, const byte *data, size_t data_len) { 188 | ASSERT(ctx != NULL, error); 189 | ASSERT(data != NULL, error); 190 | ASSERT(data_len > 0, error); 191 | 192 | size_t i; 193 | size_t space = ctx->buffer_len; // total space of the buffer, depending on the mode(64 or 128) 194 | for (i = 0; i < data_len; i++) { 195 | if (ctx->mode == SHA224 || ctx->mode == SHA256) { 196 | ctx->buffer.buf32[ctx->data_len] = data[i]; 197 | ctx->data_len++; 198 | if (ctx->data_len == space) { 199 | sha224_256_transform(ctx, ctx->buffer.buf32); 200 | ctx->bit_len += space * 8; 201 | ctx->data_len = 0; 202 | } 203 | } else { 204 | ctx->buffer.buf64[ctx->data_len] = data[i]; 205 | ctx->data_len++; 206 | if (ctx->data_len == space) { 207 | sha384_512_transform(ctx, ctx->buffer.buf64); 208 | ctx->total_len = uint128_add_uint64(ctx->total_len, (uint64_t) (space) * 8); 209 | ctx->data_len = 0; 210 | } 211 | } 212 | 213 | } 214 | return true; 215 | } 216 | 217 | /** 218 | * @Funticon name: sha2_final 219 | * @description: This function is used to finalize the sha2 context and get the digest. 220 | * @Author: WAHAHA 221 | * @Date: 2024-5-17 9:59:24 222 | * @Note: None 223 | * @param {sha2_ctx *} ctx: The sha2 context. 224 | * @param {char *} digest: The digest. 225 | * @return {status}: The status of the sha2 finalization. 226 | */ 227 | status sha2_final(sha2_ctx *ctx, byte *digest) { 228 | ASSERT(ctx != NULL, error); 229 | ASSERT(digest != NULL, error); 230 | 231 | // size_t space = ctx->buffer_len; // total space of the buffer, depending on the mode(64 or 128) 232 | size_t i = ctx->data_len; 233 | /* pad the data in the buffer */ 234 | if (ctx->mode == SHA224 || ctx->mode == SHA256) { 235 | // SHA224 and SHA256 236 | if (i < 56) { 237 | ctx->buffer.buf32[i++] = 0x80; 238 | while (i < 56) { 239 | ctx->buffer.buf32[i++] = 0x00; 240 | } 241 | } else { 242 | ctx->buffer.buf32[i++] = 0x80; 243 | while (i < 64) { 244 | ctx->buffer.buf32[i++] = 0x00; 245 | } 246 | sha224_256_transform(ctx, ctx->buffer.buf32); 247 | memset(ctx->buffer.buf32, 0, 56); 248 | } 249 | ctx->bit_len += ctx->data_len * 8; 250 | ctx->buffer.buf32[56] = (ctx->bit_len >> 56) & 0xff; 251 | ctx->buffer.buf32[57] = (ctx->bit_len >> 48) & 0xff; 252 | ctx->buffer.buf32[58] = (ctx->bit_len >> 40) & 0xff; 253 | ctx->buffer.buf32[59] = (ctx->bit_len >> 32) & 0xff; 254 | ctx->buffer.buf32[60] = (ctx->bit_len >> 24) & 0xff; 255 | ctx->buffer.buf32[61] = (ctx->bit_len >> 16) & 0xff; 256 | ctx->buffer.buf32[62] = (ctx->bit_len >> 8) & 0xff; 257 | ctx->buffer.buf32[63] = ctx->bit_len & 0xff; 258 | sha224_256_transform(ctx, ctx->buffer.buf32); 259 | } else { 260 | // SHA384 and SHA512 and SHA512_224 and SHA512_256 261 | if (i < 112) { 262 | ctx->buffer.buf64[i++] = 0x80; 263 | while (i < 112) { 264 | ctx->buffer.buf64[i++] = 0x00; 265 | } 266 | } else { 267 | ctx->buffer.buf64[i++] = 0x80; 268 | while (i < 128) { 269 | ctx->buffer.buf64[i++] = 0x00; 270 | } 271 | sha384_512_transform(ctx, ctx->buffer.buf64); 272 | memset(ctx->buffer.buf64, 0, 112); 273 | } 274 | ctx->total_len = uint128_add_uint64(ctx->total_len, (uint64_t) (ctx->data_len) * 8); 275 | ctx->buffer.buf64[112] = (ctx->total_len.high >> 56) & 0xff; 276 | ctx->buffer.buf64[113] = (ctx->total_len.high >> 48) & 0xff; 277 | ctx->buffer.buf64[114] = (ctx->total_len.high >> 40) & 0xff; 278 | ctx->buffer.buf64[115] = (ctx->total_len.high >> 32) & 0xff; 279 | ctx->buffer.buf64[116] = (ctx->total_len.high >> 24) & 0xff; 280 | ctx->buffer.buf64[117] = (ctx->total_len.high >> 16) & 0xff; 281 | ctx->buffer.buf64[118] = (ctx->total_len.high >> 8) & 0xff; 282 | ctx->buffer.buf64[119] = ctx->total_len.high & 0xff; 283 | ctx->buffer.buf64[120] = (ctx->total_len.low >> 56) & 0xff; 284 | ctx->buffer.buf64[121] = (ctx->total_len.low >> 48) & 0xff; 285 | ctx->buffer.buf64[122] = (ctx->total_len.low >> 40) & 0xff; 286 | ctx->buffer.buf64[123] = (ctx->total_len.low >> 32) & 0xff; 287 | ctx->buffer.buf64[124] = (ctx->total_len.low >> 24) & 0xff; 288 | ctx->buffer.buf64[125] = (ctx->total_len.low >> 16) & 0xff; 289 | ctx->buffer.buf64[126] = (ctx->total_len.low >> 8) & 0xff; 290 | ctx->buffer.buf64[127] = ctx->total_len.low & 0xff; 291 | sha384_512_transform(ctx, ctx->buffer.buf64); 292 | } 293 | 294 | // copy the digest 295 | // @Note: Since the SHA use big-endian, 296 | // transform the hash value from big-endian to little-endian 297 | switch (ctx->mode) { 298 | case SHA224: 299 | for (i = 0; i < 7; ++i) 300 | BE_UINT32_TO_BYTES((byte *) digest + i * 4, ctx->state.s32[i]); 301 | break; 302 | case SHA256: 303 | for (i = 0; i < 8; ++i) 304 | BE_UINT32_TO_BYTES((byte *) digest + i * 4, ctx->state.s32[i]); 305 | break; 306 | case SHA384: 307 | for (i = 0; i < 6; ++i) 308 | BE_UINT64_TO_BYTES((byte *) digest + i * 8, ctx->state.s64[i]); 309 | break; 310 | case SHA512: 311 | for (i = 0; i < 8; ++i) 312 | BE_UINT64_TO_BYTES((byte *) digest + i * 8, ctx->state.s64[i]); 313 | break; 314 | case SHA512_224: 315 | for (i = 0; i < 3; ++i) 316 | BE_UINT64_TO_BYTES((byte *) digest + i * 8, ctx->state.s64[i]); 317 | uint32_t temp = ctx->state.s64[3] >> 32; 318 | BE_UINT32_TO_BYTES((byte *) digest + 24, temp); 319 | break; 320 | case SHA512_256: 321 | for (i = 0; i < 4; ++i) 322 | BE_UINT64_TO_BYTES((byte *) digest + i * 8, ctx->state.s64[i]); 323 | break; 324 | } 325 | return true; 326 | } 327 | 328 | /* sha2 transform functions */ 329 | /** 330 | * @Funticon name: sha224_256_transform 331 | * @description: Do one SHA-224/256 transformation, processing a 32-byte chunk. 332 | * @Author: WAHAHA 333 | * @Date: 2024-5-23 21:2:4 334 | * @Note: None 335 | * @param {sha2_ctx *} ctx: the SHA-224/256 context 336 | * @param {const byte *} data: the data to be transformed 337 | * @return {void} 338 | */ 339 | static void sha224_256_transform(sha2_ctx *ctx, const byte *data) { 340 | uint32_t a, b, c, d, e, f, g, h, m[64]; 341 | uint32_t t1, t2; 342 | 343 | /* Initialize the first 16 words in the array m */ 344 | for (int i = 0, j = 0; i < 16; ++i, j += 4) { 345 | m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); 346 | } 347 | for (int i = 16; i < 64; ++i) { 348 | m[i] = SHA256_SSIG1(m[i - 2]) + m[i - 7] + SHA256_SSIG0(m[i - 15]) + m[i - 16]; 349 | } 350 | 351 | /* Initialize the working variables */ 352 | a = ctx->state.s32[0]; 353 | b = ctx->state.s32[1]; 354 | c = ctx->state.s32[2]; 355 | d = ctx->state.s32[3]; 356 | e = ctx->state.s32[4]; 357 | f = ctx->state.s32[5]; 358 | g = ctx->state.s32[6]; 359 | h = ctx->state.s32[7]; 360 | 361 | /* The main loop */ 362 | for (int i = 0; i < 64; ++i) { 363 | t1 = h + SHA256_BSIG1(e) + SHA256_CH(e, f, g) + SHA256_K[i] + m[i]; 364 | t2 = SHA256_BSIG0(a) + SHA256_MAJ(a, b, c); 365 | h = g; 366 | g = f; 367 | f = e; 368 | e = d + t1; 369 | d = c; 370 | c = b; 371 | b = a; 372 | a = t1 + t2; 373 | } 374 | 375 | /* Add the working variables back into the state */ 376 | ctx->state.s32[0] += a; 377 | ctx->state.s32[1] += b; 378 | ctx->state.s32[2] += c; 379 | ctx->state.s32[3] += d; 380 | ctx->state.s32[4] += e; 381 | ctx->state.s32[5] += f; 382 | ctx->state.s32[6] += g; 383 | ctx->state.s32[7] += h; 384 | } 385 | 386 | /** 387 | * @Funticon name: sha384_512_transform 388 | * @description: Do one SHA-384/512 transformation, processing a 64-byte chunk. 389 | * @Author: WAHAHA 390 | * @Date: 2024-5-27 19:53:41 391 | * @Note: None 392 | * @param {sha2_ctx *} ctx: the SHA-384/512 context 393 | * @param {const byte *} data: the data to be transformed 394 | * @return {void} 395 | */ 396 | static void sha384_512_transform(sha2_ctx *ctx, const byte *data) { 397 | uint64_t a, b, c, d, e, f, g, h, m[80]; 398 | uint64_t t1, t2; 399 | 400 | /* Initialize the first 16 words in the array m */ 401 | for (int i = 0, j = 0; i < 16; ++i, j += 8) { 402 | m[i] = ((uint64_t) data[j] << 56) | ((uint64_t) data[j + 1] << 48) 403 | | ((uint64_t) data[j + 2] << 40) | ((uint64_t) data[j + 3] << 32) 404 | | ((uint64_t) data[j + 4] << 24) | ((uint64_t) data[j + 5] << 16) 405 | | ((uint64_t) data[j + 6] << 8) | ((uint64_t) data[j + 7]); 406 | } 407 | for (int i = 16; i < 80; ++i) { 408 | m[i] = SHA512_SSIG1(m[i - 2]) + m[i - 7] + SHA512_SSIG0(m[i - 15]) + m[i - 16]; 409 | } 410 | 411 | /* Initialize the working variables */ 412 | a = ctx->state.s64[0]; 413 | b = ctx->state.s64[1]; 414 | c = ctx->state.s64[2]; 415 | d = ctx->state.s64[3]; 416 | e = ctx->state.s64[4]; 417 | f = ctx->state.s64[5]; 418 | g = ctx->state.s64[6]; 419 | h = ctx->state.s64[7]; 420 | 421 | /* The main loop */ 422 | for (int i = 0; i < 80; ++i) { 423 | t1 = h + SHA512_BSIG1(e) + SHA512_CH(e, f, g) + SHA512_K[i] + m[i]; 424 | t2 = SHA512_BSIG0(a) + SHA512_MAJ(a, b, c); 425 | h = g; 426 | g = f; 427 | f = e; 428 | e = d + t1; 429 | d = c; 430 | c = b; 431 | b = a; 432 | a = t1 + t2; 433 | } 434 | 435 | /* Add the working variables back into the state */ 436 | ctx->state.s64[0] += a; 437 | ctx->state.s64[1] += b; 438 | ctx->state.s64[2] += c; 439 | ctx->state.s64[3] += d; 440 | ctx->state.s64[4] += e; 441 | ctx->state.s64[5] += f; 442 | ctx->state.s64[6] += g; 443 | ctx->state.s64[7] += h; 444 | } 445 | --------------------------------------------------------------------------------