├── .gitignore ├── include ├── sm3.h ├── common.h ├── sm4.h └── sm2.h ├── src ├── common.c ├── sm3.c ├── sm4.c ├── test.c └── sm2.c ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.vscode/ 3 | /build/ -------------------------------------------------------------------------------- /include/sm3.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "openssl/evp.h" 3 | 4 | #define SM3_MD_SIZE 32 5 | 6 | #ifdef __cplusplus 7 | extern "C" 8 | { 9 | #endif 10 | EXPORT int sm3_digest(unsigned char *md, unsigned int *md_len, const unsigned char *in, size_t in_len); 11 | EXPORT EVP_MD_CTX *sm3_md_ctx_new(); 12 | EXPORT void sm3_md_ctx_free(EVP_MD_CTX *ctx); 13 | EXPORT int sm3_md_update(EVP_MD_CTX *ctx, const unsigned char *in, size_t in_len); 14 | EXPORT int sm3_md_final(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *md_len); 15 | #ifdef __cplusplus 16 | } 17 | #endif -------------------------------------------------------------------------------- /include/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef _WIN32 4 | #ifdef __GNUC__ 5 | #define EXPORT __attribute__((dllexport)) 6 | #else 7 | #define EXPORT __declspec(dllexport) 8 | #endif 9 | #else 10 | #if __GNUC__ >= 4 11 | #define EXPORT __attribute__((visibility("default"))) 12 | #else 13 | #define EXPORT 14 | #endif 15 | #endif 16 | 17 | #ifdef __cplusplus 18 | extern "C" 19 | { 20 | #endif 21 | EXPORT unsigned long get_error(char *buf); 22 | EXPORT unsigned char *mem_new(unsigned char **data, size_t len); 23 | EXPORT void mem_free(unsigned char **data); 24 | #ifdef __cplusplus 25 | } 26 | #endif -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "openssl/err.h" 3 | #include 4 | 5 | typedef int CIPHER_MODE; 6 | 7 | unsigned long get_error(char *buf) 8 | { 9 | unsigned long err = ERR_get_error(); 10 | if (err == 0) 11 | { 12 | return 0; 13 | } 14 | ERR_error_string(err, buf); 15 | return err; 16 | } 17 | 18 | unsigned char *mem_new(unsigned char **data, size_t len) 19 | { 20 | if ((*data = malloc(len))) 21 | { 22 | memset(*data, 0, len); 23 | return *data; 24 | } 25 | return NULL; 26 | } 27 | 28 | void mem_free(unsigned char **data) 29 | { 30 | if (*data) 31 | { 32 | free(*data); 33 | *data = NULL; 34 | } 35 | } -------------------------------------------------------------------------------- /src/sm3.c: -------------------------------------------------------------------------------- 1 | #include "sm3.h" 2 | 3 | EVP_MD_CTX *sm3_md_ctx_new() 4 | { 5 | EVP_MD_CTX *ctx = NULL; 6 | int success = 7 | (ctx = EVP_MD_CTX_new()) && 8 | EVP_DigestInit(ctx, EVP_sm3()); 9 | if (!success) 10 | { 11 | sm3_md_ctx_free(ctx); 12 | ctx = NULL; 13 | } 14 | return ctx; 15 | } 16 | 17 | void sm3_md_ctx_free(EVP_MD_CTX *ctx) 18 | { 19 | if (ctx) 20 | { 21 | EVP_MD_CTX_free(ctx); 22 | ctx = NULL; 23 | } 24 | } 25 | 26 | int sm3_md_update(EVP_MD_CTX *ctx, const unsigned char *in, size_t in_len) 27 | { 28 | return ctx && in && 29 | EVP_DigestUpdate(ctx, in, in_len); 30 | } 31 | 32 | int sm3_md_final(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *md_len) 33 | { 34 | return ctx && md && md_len && 35 | EVP_DigestFinal(ctx, md, md_len); 36 | } 37 | 38 | int sm3_digest(unsigned char *md, unsigned int *md_len, const unsigned char *in, size_t in_len) 39 | { 40 | if (!md || !md_len || !in) 41 | return 0; 42 | EVP_MD_CTX *ctx = NULL; 43 | int success = 44 | (ctx = sm3_md_ctx_new()) && 45 | sm3_md_update(ctx, in, in_len) && 46 | sm3_md_final(ctx, md, md_len); 47 | if (ctx) 48 | { 49 | sm3_md_ctx_free(ctx); 50 | ctx = NULL; 51 | } 52 | return success; 53 | } 54 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | lib_name=gm 2 | build_dir=build 3 | lib_dir=${build_dir}/lib 4 | bin_dir=${build_dir}/bin 5 | src_dir=src 6 | src_files=common.c sm2.c sm3.c sm4.c 7 | 8 | CFLAGS=-Iinclude -I${OPENSSL}/include -fPIC -Wall 9 | test_cflags=-Iinclude -I${OPENSSL}/include -Wall 10 | 11 | ifeq "$(OS)" "Windows_NT" 12 | os=windows 13 | lib_file_name=${lib_name}.dll 14 | bin_file_ext=.exe 15 | LDFLAGS=-shared -L${OPENSSL}/bin -lcrypto 16 | test_ldflags=-L${OPENSSL}/bin -lcrypto 17 | else ifeq ($(shell uname),Linux) 18 | os=linux 19 | lib_file_name=lib${lib_name}.so 20 | CFLAGS+= -fvisibility=hidden 21 | LDFLAGS=-shared -L${OPENSSL}/lib64 -lcrypto 22 | test_ldflags=-L${OPENSSL}/lib64 -lcrypto 23 | else ifeq ($(shell uname),Darwin) 24 | os=darwin 25 | lib_file_name=lib${lib_name}.dylib 26 | CFLAGS+= -fvisibility=hidden 27 | LDFLAGS=-dynamiclib -L${OPENSSL}/lib -lcrypto 28 | test_ldflags=-L${OPENSSL}/lib -lcrypto 29 | endif 30 | 31 | .PHONY: build build_test clean 32 | 33 | build: 34 | @echo "Building shared library..." 35 | @mkdir -p ${lib_dir} 36 | gcc -o${lib_dir}/${lib_file_name} ${CFLAGS} $(addprefix ${src_dir}/,${src_files}) ${LDFLAGS} 37 | @echo "Ok" 38 | 39 | build_test: 40 | @echo "Building test..." 41 | @mkdir -p ${bin_dir} 42 | gcc -o${bin_dir}/test${bin_file_ext} ${test_cflags} $(addprefix ${src_dir}/,common.c sm2.c sm3.c sm4.c test.c) ${test_ldflags} 43 | @echo "Ok" 44 | 45 | clean: 46 | @echo "Cleaning..." 47 | @rm -rf ${build_dir} 48 | @echo "Ok" -------------------------------------------------------------------------------- /include/sm4.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "openssl/evp.h" 3 | 4 | #define SM4_MODE_ECB 1 5 | #define SM4_MODE_CBC 2 6 | #define SM4_BLOCK_SIZE 16 7 | #define sm4_enc_max_size(size) size + SM4_BLOCK_SIZE 8 | #define sm4_dec_max_size(size) size 9 | #define sm4_encrypt_ecb(out, out_len, in, in_len, key) sm4_crypt(out, out_len, in, in_len, EVP_CIPH_ECB_MODE, key, NULL, 1) 10 | #define sm4_decrypt_ecb(out, out_len, in, in_len, key) sm4_crypt(out, out_len, in, in_len, EVP_CIPH_ECB_MODE, key, NULL, 0) 11 | #define sm4_encrypt_cbc(out, out_len, in, in_len, key, iv) sm4_crypt(out, out_len, in, in_len, EVP_CIPH_CBC_MODE, key, iv, 1) 12 | #define sm4_decrypt_cbc(out, out_len, in, in_len, key, iv) sm4_crypt(out, out_len, in, in_len, EVP_CIPH_CBC_MODE, key, iv, 0) 13 | 14 | #ifdef __cplusplus 15 | extern "C" 16 | { 17 | #endif 18 | EXPORT int sm4_generate_key(unsigned char *key); 19 | EXPORT int sm4_crypt(unsigned char *out, int *out_len, const unsigned char *in, int in_len, int mode, const unsigned char *key, const unsigned char *iv, int enc); 20 | EXPORT EVP_CIPHER_CTX *sm4_cipher_ctx_new(int mode, const unsigned char *key, const unsigned char *iv, int enc); 21 | EXPORT void sm4_cipher_ctx_free(EVP_CIPHER_CTX *ctx); 22 | EXPORT int sm4_cipher_update(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, const unsigned char *in, int in_len); 23 | EXPORT int sm4_cipher_final(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len); 24 | #ifdef __cplusplus 25 | } 26 | #endif -------------------------------------------------------------------------------- /include/sm2.h: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "openssl/evp.h" 3 | 4 | #define SM2_PUB_MAX_SIZE 65 5 | #define SM2_PRI_MAX_SIZE 32 6 | #define SM2_SIG_MAX_SIZE 72 7 | 8 | // 签名上下文 9 | typedef struct sm2_sig_ctx_st 10 | { 11 | int is_pri; 12 | EVP_PKEY *pkey; 13 | EVP_PKEY_CTX *pctx; 14 | EVP_MD_CTX *mctx; 15 | } SM2_SIG_CTX; 16 | 17 | #ifdef __cplusplus 18 | extern "C" 19 | { 20 | #endif 21 | EXPORT int sm2_cipher_to_c1c3c2(unsigned char *out, int *out_len, const unsigned char *in, int in_len); 22 | EXPORT int sm2_sig_to_rs(unsigned char *out, int *out_len, const unsigned char *in, int in_len); 23 | EXPORT int sm2_key_pair_new(unsigned char *pub, size_t *pub_len, unsigned char *pri, size_t *pri_len); 24 | EXPORT int sm2_encrypt(unsigned char **out, size_t *out_len, const unsigned char *in, size_t in_len, const unsigned char *pub, size_t pub_len); 25 | EXPORT int sm2_decrypt(unsigned char *out, size_t *out_len, const unsigned char *in, size_t in_len, const unsigned char *pri, size_t pri_len); 26 | EXPORT int sm2_sign(unsigned char *sig, size_t *sig_len, const unsigned char *in, size_t in_len, const unsigned char *pri, size_t pri_len); 27 | EXPORT int sm2_verify(const unsigned char *sig, size_t sig_len, const unsigned char *in, size_t in_len, const unsigned char *pub, size_t pub_len); 28 | EXPORT SM2_SIG_CTX *sm2_sig_ctx_new(const unsigned char *key, size_t key_len, int is_pri); 29 | EXPORT void sm2_sig_ctx_free(SM2_SIG_CTX *ctx); 30 | EXPORT int sm2_sig_update(SM2_SIG_CTX *ctx, const unsigned char *in, size_t in_len); 31 | EXPORT int sm2_sig_sign(SM2_SIG_CTX *ctx, unsigned char *sig, size_t *sig_len); 32 | EXPORT int sm2_sig_verify(SM2_SIG_CTX *ctx, const unsigned char *sig, size_t sig_len); 33 | #ifdef __cplusplus 34 | } 35 | #endif -------------------------------------------------------------------------------- /src/sm4.c: -------------------------------------------------------------------------------- 1 | #include "sm4.h" 2 | #include "string.h" 3 | 4 | int sm4_generate_key(unsigned char *key) 5 | { 6 | if (!key) 7 | return 0; 8 | BIGNUM *rnd = NULL; 9 | int success = 10 | (rnd = BN_new()) && 11 | BN_rand(rnd, 128, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY) && 12 | BN_bn2bin(rnd, key); 13 | if (rnd) 14 | { 15 | BN_free(rnd); 16 | rnd = NULL; 17 | } 18 | return success; 19 | } 20 | 21 | EVP_CIPHER_CTX *sm4_cipher_ctx_new(int mode, const unsigned char *key, const unsigned char *iv, int enc) 22 | { 23 | if (!key) 24 | return NULL; 25 | const EVP_CIPHER *cipher; 26 | switch (mode) 27 | { 28 | case EVP_CIPH_ECB_MODE: 29 | cipher = EVP_sm4_ecb(); 30 | break; 31 | case EVP_CIPH_CBC_MODE: 32 | cipher = EVP_sm4_cbc(); 33 | break; 34 | default: 35 | return NULL; 36 | } 37 | EVP_CIPHER_CTX *ctx = NULL; 38 | int success = 39 | (ctx = EVP_CIPHER_CTX_new()) && 40 | EVP_CipherInit(ctx, cipher, key, iv, enc) && 41 | EVP_CIPHER_CTX_set_padding(ctx, EVP_PADDING_PKCS7); 42 | if (!success && ctx) 43 | { 44 | EVP_CIPHER_CTX_free(ctx); 45 | ctx = NULL; 46 | } 47 | return ctx; 48 | } 49 | 50 | void sm4_cipher_ctx_free(EVP_CIPHER_CTX *ctx) 51 | { 52 | if (ctx) 53 | { 54 | EVP_CIPHER_CTX_free(ctx); 55 | ctx = NULL; 56 | } 57 | } 58 | 59 | int sm4_cipher_update(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, const unsigned char *in, int in_len) 60 | { 61 | return ctx && out && out_len && in && 62 | EVP_CipherUpdate(ctx, out, out_len, in, in_len); 63 | } 64 | 65 | int sm4_cipher_final(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) 66 | { 67 | return ctx && out && out_len && 68 | EVP_CipherFinal(ctx, out, out_len); 69 | } 70 | 71 | int sm4_crypt(unsigned char *out, int *out_len, const unsigned char *in, int in_len, int mode, const unsigned char *key, const unsigned char *iv, int enc) 72 | { 73 | if (!out || !out_len || !in || !key) 74 | return 0; 75 | EVP_CIPHER_CTX *ctx = NULL; 76 | int update_len = 0; 77 | int final_len = 0; 78 | int success = 79 | (ctx = sm4_cipher_ctx_new(mode, key, iv, enc)) && 80 | sm4_cipher_update(ctx, out, &update_len, in, in_len) && 81 | sm4_cipher_final(ctx, out + update_len, &final_len) && 82 | (*out_len = update_len + final_len); 83 | if (ctx) 84 | { 85 | sm4_cipher_ctx_free(ctx); 86 | ctx = NULL; 87 | } 88 | return success; 89 | } 90 | -------------------------------------------------------------------------------- /src/test.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "openssl/crypto.h" 3 | #include "sm2.h" 4 | #include "sm3.h" 5 | #include "sm4.h" 6 | #include 7 | #include 8 | 9 | static const char data[] = "Hello World! My name is Hello, your name is World. 你好世界!我的名字是你好,你的名字是世界。床前明月光,疑似地上霜。举头望明月,低头思故乡。Hello World! My name is Hello, your name is World. 你好世界!我的名字是你好,你的名字是世界。床前明月光,疑似地上霜。举头望明月,低头思故乡。"; 10 | 11 | static void print_bin(const char *name, const unsigned char *data, int data_len) 12 | { 13 | // int out_len = (data_len + 2) / 3 * 4; 14 | // unsigned char out[out_len]; 15 | // out_len = EVP_EncodeBlock(out, data, data_len); 16 | // printf("%s: (%d Bytes) %.*s\n", name, data_len, out_len, out); 17 | printf("%s", name); 18 | printf(": (%d Bytes) ", data_len); 19 | for (int i = 0; i < data_len; i++) 20 | { 21 | printf("%02x", *data++); 22 | } 23 | printf("\n"); 24 | } 25 | 26 | static int test_sm2() 27 | { 28 | printf("========== SM2 Test ==========\n"); 29 | size_t pub_len = SM2_PUB_MAX_SIZE; 30 | unsigned char pub[pub_len]; 31 | size_t pri_len = SM2_PRI_MAX_SIZE; 32 | unsigned char pri[pri_len]; 33 | if (!sm2_key_pair_new(pub, &pub_len, pri, &pri_len)) 34 | return 0; 35 | print_bin("sm2-pub", pub, pub_len); 36 | print_bin("sm2-pri", pri, pri_len); 37 | int data_len = strlen(data); 38 | size_t enc_len = 0; 39 | unsigned char *enc = NULL; 40 | if (!sm2_encrypt(&enc, &enc_len, (unsigned char *)data, strlen(data), pub, pub_len)) 41 | { 42 | mem_free(&enc); 43 | return 0; 44 | } 45 | print_bin("sm2-enc", enc, enc_len); 46 | int enc_raw_len = enc_len; 47 | unsigned char enc_raw[enc_raw_len]; 48 | if (!sm2_cipher_to_c1c3c2(enc_raw, &enc_raw_len, enc, enc_len)) 49 | { 50 | mem_free(&enc); 51 | return 0; 52 | } 53 | print_bin("sm2-c1c3c2", enc_raw, enc_raw_len); 54 | size_t dec_len = enc_len; 55 | unsigned char dec[dec_len]; 56 | if (!sm2_decrypt(dec, &dec_len, enc, enc_len, pri, pri_len)) 57 | { 58 | mem_free(&enc); 59 | return 0; 60 | } 61 | printf("sm2-dec: %.*s\n", (int)dec_len, dec); 62 | mem_free(&enc); 63 | size_t sig_len = SM2_SIG_MAX_SIZE; 64 | unsigned char sig[sig_len]; 65 | if (!sm2_sign(sig, &sig_len, (const unsigned char *)data, data_len, pri, pri_len)) 66 | return 0; 67 | print_bin("sm2-sig", sig, sig_len); 68 | int sig_raw_len = sig_len; 69 | unsigned char sig_raw[sig_raw_len]; 70 | if (!sm2_sig_to_rs(sig_raw, &sig_raw_len, sig, sig_len)) 71 | return 0; 72 | print_bin("sm2-sig-raw", sig_raw, sig_raw_len); 73 | if (sm2_verify(sig, sig_len, (unsigned char *)data, data_len, pub, pub_len)) 74 | printf("sm2-ver: Ok\n"); 75 | else 76 | printf("sm2-ver: Failed\n"); 77 | return 1; 78 | } 79 | 80 | static int test_sm3() 81 | { 82 | printf("========== SM3 Test ==========\n"); 83 | unsigned char md[SM3_MD_SIZE]; 84 | unsigned int md_len = sizeof(md); 85 | if (!sm3_digest(md, &md_len, (unsigned char *)data, strlen(data))) 86 | return 0; 87 | print_bin("sm3-md", md, md_len); 88 | return 1; 89 | } 90 | 91 | static int test_sm4() 92 | { 93 | printf("========== SM4 Test ==========\n"); 94 | unsigned char key[SM4_BLOCK_SIZE]; 95 | if (!sm4_generate_key(key)) 96 | return 0; 97 | print_bin("sm4-key", key, sizeof(key)); 98 | unsigned char enc[sm4_enc_max_size(strlen(data))]; 99 | int enc_len = 0; 100 | if (!sm4_encrypt_ecb(enc, &enc_len, (unsigned char *)data, strlen(data), key)) 101 | return 0; 102 | print_bin("sm4-ecb-enc", enc, enc_len); 103 | unsigned char dec[sm4_dec_max_size(enc_len)]; 104 | int dec_len = 0; 105 | if (!sm4_decrypt_ecb(dec, &dec_len, enc, enc_len, key)) 106 | return 0; 107 | printf("sm4-ecb-dec: %.*s\n", dec_len, dec); 108 | unsigned char iv[SM4_BLOCK_SIZE]; 109 | if (!sm4_generate_key(iv)) 110 | return 0; 111 | print_bin("sm4-iv", iv, sizeof(iv)); 112 | if (!sm4_encrypt_cbc(enc, &enc_len, (unsigned char *)data, strlen(data), key, iv)) 113 | return 0; 114 | print_bin("sm4-cbc-enc", enc, enc_len); 115 | if (!sm4_decrypt_cbc(dec, &dec_len, enc, enc_len, key, iv)) 116 | return 0; 117 | printf("sm4-cbc-dec: %.*s\n", dec_len, dec); 118 | return 1; 119 | } 120 | 121 | int main() 122 | { 123 | print_bin("data", (unsigned char *)data, strlen(data)); 124 | if (!test_sm2()) 125 | printf("sm2 test failed\n"); 126 | if (!test_sm3()) 127 | printf("sm3 test failed\n"); 128 | if (!test_sm4()) 129 | printf("sm4 test failed\n"); 130 | return 0; 131 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 环境 2 | 3 | 程序基于openssl-3.2.1编写,编译前需要设置`OPENSSL`环境变量指向openssl安装目录。 4 | 5 | # 编译 6 | 7 | ```bash 8 | make 9 | ``` 10 | 11 | # 说明 12 | 13 | ## SM2 14 | 15 | 数据格式可以参考《GB/T 35276-2017 信息安全技术 SM2密码算法使用规范》。 16 | 17 | ```c 18 | int sm2_key_pair_new(unsigned char *pub, size_t *pub_len, unsigned char *pri, size_t *pri_len); 19 | int sm2_encrypt(unsigned char **out, size_t *out_len, const unsigned char *in, size_t in_len, const unsigned char *pub, size_t pub_len); 20 | int sm2_decrypt(unsigned char *out, size_t *out_len, const unsigned char *in, size_t in_len, const unsigned char *pri, size_t pri_len); 21 | int sm2_sign(unsigned char *sig, size_t *sig_len, const unsigned char *in, size_t in_len, const unsigned char *pri, size_t pri_len); 22 | int sm2_verify(const unsigned char *sig, size_t sig_len, const unsigned char *in, size_t in_len, const unsigned char *pub, size_t pub_len); 23 | SM2_SIG_CTX *sm2_sig_ctx_new(const unsigned char *key, size_t key_len, int is_pri); 24 | void sm2_sig_ctx_free(SM2_SIG_CTX *ctx); 25 | int sm2_sig_update(SM2_SIG_CTX *ctx, const unsigned char *in, size_t in_len); 26 | int sm2_sig_sign(SM2_SIG_CTX *ctx, unsigned char *sig, size_t *sig_len); 27 | int sm2_sig_verify(SM2_SIG_CTX *ctx, const unsigned char *sig, size_t sig_len); 28 | ``` 29 | 30 | ### sm2_key_pair_new 31 | 32 | 新建SM2密钥对。 33 | 34 | | 参数 | 类型 | 说明 | 35 | | ------- | --------------- | --------------------------- | 36 | | pub | unsigned char * | [out]用于接收公钥的缓冲区。 | 37 | | pub_len | size_t * | [out]用于接收公钥长度。 | 38 | | pri | unsigned char * | [out]用于接收私钥的缓冲区。 | 39 | | pri_len | size_t * | [out]用于接收私钥长度。 | 40 | 41 | 返回1表示成功,0表示失败。 42 | 43 | ### sm2_encrypt 44 | 45 | 加密。 46 | 47 | | 参数 | 类型 | 说明 | 48 | | ------- | --------------------- | ------------------------------------- | 49 | | out | unsigned char ** | [out]用于接收加密数据的缓冲区的指针。 | 50 | | out_len | size_t * | [out]用于接收加密数据长度。 | 51 | | in | const unsigned char * | 需要加密的数据。 | 52 | | in_len | size_t | 需要加密的数据长度。 | 53 | | pub | const unsigned char * | 公钥。 | 54 | | pub_len | size_t | 公钥长度。 | 55 | 56 | 返回1表示成功,0表示失败。 57 | 58 | ### sm2_decrypt 59 | 60 | 解密。 61 | 62 | | 参数 | 类型 | 说明 | 63 | | ------- | --------------------- | ------------------------------------------------------------ | 64 | | out | unsigned char * | [out]用于接收解密数据的缓冲区。需要的缓冲区大小不会超过需要加密的数据长度。 | 65 | | out_len | size_t * | [out]用于接收解密数据长度。 | 66 | | in | const unsigned char * | 需要解密的数据。 | 67 | | in_len | size_t | 需要解密的数据长度。 | 68 | | pri | const unsigned char * | 私钥。 | 69 | | pri_len | size_t | 私钥长度。 | 70 | 71 | 返回1表示成功,0表示失败。 72 | 73 | ### sm2_sign 74 | 75 | 签名。 76 | 77 | | 参数 | 类型 | 说明 | 78 | | ------- | --------------------- | ------------------------------------------------------- | 79 | | sig | unsigned char * | [out]用于接收签名的缓冲区。需要的缓冲区大小不会超过72。 | 80 | | sig_len | size_t * | [out]签名长度。 | 81 | | in | const unsigned char * | 需要签名的数据。 | 82 | | in_len | size_t | 需要签名的数据长度。 | 83 | | pri | const unsigned char * | 私钥。 | 84 | | pri_len | size_t | 私钥长度。 | 85 | 86 | 返回1表示成功,0表示失败。 87 | 88 | ### sm2_verify 89 | 90 | 验签。 91 | 92 | | 参数 | 类型 | 说明 | 93 | | ------- | --------------------- | -------------------- | 94 | | sig | const unsigned char * | 签名。 | 95 | | sig_len | size_t | 签名长度。 | 96 | | in | const unsigned char * | 需要验签的数据。 | 97 | | in_len | size_t | 需要验签的数据长度。 | 98 | | pub | const unsigned char * | 公钥。 | 99 | | pub_len | size_t | 公钥长度。 | 100 | 101 | 返回1表示成功,0表示失败。 102 | 103 | ## SM3 104 | 105 | ### sm3_digest 106 | 107 | 摘要。 108 | 109 | | 参数 | 类型 | 说明 | 110 | | ------ | --------------------- | --------------------------------------------------------- | 111 | | md | unsigned char * | [out]用于接收哈希值的缓冲区。需要的缓冲区大小不会超过32。 | 112 | | md_len | unsigned int * | [out]用于接收哈希值长度。 | 113 | | in | const unsigned char * | 需要计算哈希值的数据。 | 114 | | in_len | size_t | 需要计算哈希值的数据长度。 | 115 | 116 | 返回1表示成功,0表示失败。 117 | 118 | ## SM4 119 | 120 | ### sm4_generate_key 121 | 122 | 生成密钥。 123 | 124 | | 参数 | 类型 | 说明 | 125 | | ---- | --------------- | ------------------------------------------------- | 126 | | key | unsigned char * | [out]用于接收密钥的缓冲区。需要的缓冲区大小为16。 | 127 | 128 | 返回1表示成功,0表示失败。 129 | 130 | ### sm4_crypt 131 | 132 | 加/解密。 133 | 134 | | 参数 | 类型 | 说明 | 135 | | ------- | --------------------- | ------------------------------------------------------------ | 136 | | out | unsigned char * | [out]用于接收加/解密数据的缓冲区。加密数据需要的缓冲区大小不会超过待加密数据长度加16,解密数据需要的缓冲区大小不会超过待解密数据长度。 | 137 | | out_len | int * | [out]用于接收加/解密数据长度。 | 138 | | in | const unsigned char * | 待加/解密数据。 | 139 | | in_len | int | 待加/解密数据长度。 | 140 | | mode | int | 模式。1-ECB;2-CBC。 | 141 | | key | const unsigned char * | 密钥。 | 142 | | iv | const unsigned char * | 模式为CBC时需要设置初始向量。 | 143 | | enc | int | 是否为加密。0表示解密,其它表示加密。 | 144 | 145 | ### 宏 146 | 147 | ```c 148 | #define sm4_enc_max_size(size) ... 149 | #define sm4_dec_max_size(size) ... 150 | #define sm4_encrypt_ecb(out, out_len, in, in_len, key) ... 151 | #define sm4_decrypt_ecb(out, out_len, in, in_len, key) ... 152 | #define sm4_encrypt_cbc(out, out_len, in, in_len, key, iv) ... 153 | #define sm4_decrypt_cbc(out, out_len, in, in_len, key, iv) ... 154 | ``` 155 | 156 | -------------------------------------------------------------------------------- /src/sm2.c: -------------------------------------------------------------------------------- 1 | #include "sm2.h" 2 | #include "openssl/asn1.h" 3 | #include "openssl/asn1t.h" 4 | #include "openssl/ec.h" 5 | #include "openssl/param_build.h" 6 | #include 7 | 8 | typedef struct sm2_cipher_st 9 | { 10 | BIGNUM *x_coordinate; 11 | BIGNUM *y_coordinate; 12 | ASN1_OCTET_STRING *hash; 13 | ASN1_OCTET_STRING *cipher_text; 14 | } SM2_CIPHER; 15 | DECLARE_ASN1_FUNCTIONS(SM2_CIPHER) 16 | ASN1_SEQUENCE(SM2_CIPHER) = { 17 | ASN1_SIMPLE(SM2_CIPHER, x_coordinate, BIGNUM), 18 | ASN1_SIMPLE(SM2_CIPHER, y_coordinate, BIGNUM), 19 | ASN1_SIMPLE(SM2_CIPHER, hash, ASN1_OCTET_STRING), 20 | ASN1_SIMPLE(SM2_CIPHER, cipher_text, ASN1_OCTET_STRING), 21 | } ASN1_SEQUENCE_END(SM2_CIPHER) IMPLEMENT_ASN1_FUNCTIONS(SM2_CIPHER); 22 | 23 | typedef struct sm2_signature_st 24 | { 25 | BIGNUM *r; 26 | BIGNUM *s; 27 | } SM2_SIGNATURE; 28 | DECLARE_ASN1_FUNCTIONS(SM2_SIGNATURE) 29 | ASN1_SEQUENCE(SM2_SIGNATURE) = { 30 | ASN1_SIMPLE(SM2_SIGNATURE, r, BIGNUM), 31 | ASN1_SIMPLE(SM2_SIGNATURE, s, BIGNUM), 32 | } ASN1_SEQUENCE_END(SM2_SIGNATURE) IMPLEMENT_ASN1_FUNCTIONS(SM2_SIGNATURE); 33 | 34 | typedef struct sm2_enveloped_key_st 35 | { 36 | ASN1_UTF8STRING *sym_alg_id; 37 | ASN1_OCTET_STRING *sym_encrypted_key; 38 | ASN1_OCTET_STRING *sm2_public_key; 39 | ASN1_OCTET_STRING *sm2_encrypted_private_key; 40 | } SM2_ENVELOPED_KEY; 41 | 42 | static int export_pub(unsigned char **pub, size_t *pub_len, BIGNUM *pri) 43 | { 44 | if (!pub || !pub_len || !pri) 45 | return 0; 46 | EC_GROUP *group = NULL; 47 | EC_POINT *pub_key = NULL; 48 | int success = 49 | (group = EC_GROUP_new_by_curve_name(NID_sm2)) && 50 | (pub_key = EC_POINT_new(group)) && 51 | EC_POINT_mul(group, pub_key, pri, NULL, NULL, NULL) && 52 | (*pub_len = EC_POINT_point2oct(group, pub_key, POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL)) && 53 | (*pub = malloc(*pub_len)) && 54 | EC_POINT_point2oct(group, pub_key, POINT_CONVERSION_UNCOMPRESSED, *pub, *pub_len, NULL); 55 | if (!success) 56 | { 57 | free(*pub); 58 | *pub = NULL; 59 | } 60 | if (pub_key) 61 | { 62 | EC_POINT_free(pub_key); 63 | pub_key = NULL; 64 | } 65 | if (group) 66 | { 67 | EC_GROUP_free(group); 68 | group = NULL; 69 | } 70 | return success; 71 | } 72 | 73 | int sm2_cipher_to_c1c3c2(unsigned char *out, int *out_len, const unsigned char *in, int in_len) 74 | { 75 | if (!out || !out_len || !in) 76 | return 0; 77 | SM2_CIPHER *seq = NULL; 78 | int success = 79 | d2i_SM2_CIPHER(&seq, &in, in_len) && 80 | BN_bn2bin(seq->x_coordinate, out) && 81 | BN_bn2bin(seq->y_coordinate, out += BN_num_bytes(seq->x_coordinate)) && 82 | memcpy(out += BN_num_bytes(seq->y_coordinate), seq->hash->data, seq->hash->length) && 83 | memcpy(out += seq->hash->length, seq->cipher_text->data, seq->cipher_text->length) && 84 | (*out_len = BN_num_bytes(seq->x_coordinate) + BN_num_bytes(seq->y_coordinate) + seq->hash->length + seq->cipher_text->length); 85 | if (seq) 86 | { 87 | SM2_CIPHER_free(seq); 88 | seq = NULL; 89 | } 90 | return success; 91 | } 92 | 93 | int sm2_sig_to_rs(unsigned char *out, int *out_len, const unsigned char *in, int in_len) 94 | { 95 | if (!out || !out_len || !in) 96 | return 0; 97 | SM2_SIGNATURE *seq = NULL; 98 | int success = 99 | d2i_SM2_SIGNATURE(&seq, &in, in_len) && 100 | BN_bn2bin(seq->r, out) && 101 | BN_bn2bin(seq->s, out += BN_num_bytes(seq->r)) && 102 | (*out_len = BN_num_bytes(seq->r) + BN_num_bytes(seq->s)); 103 | if (seq) 104 | { 105 | SM2_SIGNATURE_free(seq); 106 | seq = NULL; 107 | } 108 | return success; 109 | } 110 | 111 | int sm2_key_pair_new(unsigned char *pub, size_t *pub_len, unsigned char *pri, size_t *pri_len) 112 | { 113 | EVP_PKEY *pkey = EVP_EC_gen(SN_sm2); 114 | if (!pkey) 115 | return 0; 116 | int success = 1; 117 | if (pub && pub_len) 118 | { 119 | success = EVP_PKEY_get_octet_string_param(pkey, "pub", pub, *pub_len, pub_len); 120 | } 121 | if (success && pri && pri_len) 122 | { 123 | BIGNUM *pri_bn = NULL; 124 | success = 125 | EVP_PKEY_get_bn_param(pkey, "priv", &pri_bn) && 126 | (*pri_len = BN_num_bytes(pri_bn)) && 127 | BN_bn2bin(pri_bn, pri); 128 | if (pri_bn) 129 | { 130 | BN_free(pri_bn); 131 | pri_bn = NULL; 132 | } 133 | } 134 | if (pkey) 135 | { 136 | EVP_PKEY_free(pkey); 137 | pkey = NULL; 138 | } 139 | return success; 140 | } 141 | 142 | static EVP_PKEY *new_key(const unsigned char *key, size_t key_len, int is_pri) 143 | { 144 | if (!key) 145 | return NULL; 146 | OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new(); 147 | if (!bld) 148 | { 149 | return NULL; 150 | } 151 | int selection = 0; 152 | OSSL_PARAM *params = NULL; 153 | BIGNUM *pri_d = NULL; 154 | size_t exp_pub_len = 0; 155 | unsigned char *exp_pub = NULL; 156 | if (is_pri) 157 | { 158 | if ((pri_d = BN_bin2bn(key, key_len, NULL)) && 159 | OSSL_PARAM_BLD_push_BN(bld, "priv", pri_d) && 160 | export_pub(&exp_pub, &exp_pub_len, pri_d) && 161 | OSSL_PARAM_BLD_push_octet_string(bld, "pub", exp_pub, exp_pub_len)) 162 | { 163 | selection = EVP_PKEY_KEYPAIR; 164 | } 165 | } 166 | else 167 | { 168 | if (OSSL_PARAM_BLD_push_octet_string(bld, "pub", key, key_len)) 169 | { 170 | selection = EVP_PKEY_PUBLIC_KEY; 171 | } 172 | } 173 | 174 | if (OSSL_PARAM_BLD_push_utf8_string(bld, "group", SN_sm2, 0)) 175 | { 176 | params = OSSL_PARAM_BLD_to_param(bld); 177 | } 178 | if (exp_pub) 179 | { 180 | free(exp_pub); 181 | exp_pub = NULL; 182 | } 183 | if (pri_d) 184 | { 185 | BN_free(pri_d); 186 | pri_d = NULL; 187 | } 188 | OSSL_PARAM_BLD_free(bld); 189 | bld = NULL; 190 | if (!params) 191 | { 192 | return NULL; 193 | } 194 | EVP_PKEY *pkey = NULL; 195 | EVP_PKEY_CTX *ctx = NULL; 196 | int success = 197 | (ctx = EVP_PKEY_CTX_new_from_name(NULL, SN_sm2, NULL)) && 198 | EVP_PKEY_fromdata_init(ctx) && 199 | EVP_PKEY_fromdata(ctx, &pkey, selection, params); 200 | if (!success) 201 | { 202 | pkey = NULL; 203 | } 204 | if (ctx) 205 | { 206 | EVP_PKEY_CTX_free(ctx); 207 | ctx = NULL; 208 | } 209 | OSSL_PARAM_free(params); 210 | params = NULL; 211 | return pkey; 212 | } 213 | 214 | int sm2_encrypt(unsigned char **out, size_t *out_len, const unsigned char *in, size_t in_len, const unsigned char *pub, size_t pub_len) 215 | { 216 | if (!out || !out_len || !in || !pub) 217 | return 0; 218 | EVP_PKEY *pkey = NULL; 219 | EVP_PKEY_CTX *ctx = NULL; 220 | int success = 221 | (pkey = new_key(pub, pub_len, 0)) && 222 | (ctx = EVP_PKEY_CTX_new(pkey, NULL)) && 223 | EVP_PKEY_encrypt_init(ctx) && 224 | EVP_PKEY_encrypt(ctx, NULL, out_len, in, in_len) && 225 | mem_new(out, *out_len) && 226 | EVP_PKEY_encrypt(ctx, *out, out_len, in, in_len); 227 | if (!success) 228 | { 229 | mem_free(out); 230 | } 231 | if (ctx) 232 | { 233 | EVP_PKEY_CTX_free(ctx); 234 | ctx = NULL; 235 | } 236 | if (pkey) 237 | { 238 | EVP_PKEY_free(pkey); 239 | pkey = NULL; 240 | } 241 | return success; 242 | } 243 | 244 | int sm2_decrypt(unsigned char *out, size_t *out_len, const unsigned char *in, size_t in_len, const unsigned char *pri, size_t pri_len) 245 | { 246 | if (!out || !out_len || !in || !pri) 247 | return 0; 248 | EVP_PKEY *pkey = NULL; 249 | EVP_PKEY_CTX *ctx = NULL; 250 | int success = 251 | (pkey = new_key(pri, pri_len, 1)) && 252 | (ctx = EVP_PKEY_CTX_new(pkey, NULL)) && 253 | EVP_PKEY_decrypt_init(ctx) && 254 | EVP_PKEY_decrypt(ctx, out, out_len, in, in_len); 255 | if (ctx) 256 | { 257 | EVP_PKEY_CTX_free(ctx); 258 | ctx = NULL; 259 | } 260 | if (pkey) 261 | { 262 | EVP_PKEY_free(pkey); 263 | pkey = NULL; 264 | } 265 | return success; 266 | } 267 | 268 | static unsigned char id[] = "1234567812345678"; 269 | 270 | SM2_SIG_CTX *sm2_sig_ctx_new(const unsigned char *key, size_t key_len, int is_pri) 271 | { 272 | if (!key) 273 | return NULL; 274 | SM2_SIG_CTX *ctx = malloc(sizeof(SM2_SIG_CTX)); 275 | if (!ctx) 276 | return NULL; 277 | ctx->is_pri = is_pri; 278 | int success = 279 | (ctx->pkey = new_key(key, key_len, is_pri)) && 280 | (ctx->pctx = EVP_PKEY_CTX_new(ctx->pkey, NULL)) && 281 | EVP_PKEY_CTX_set1_id(ctx->pctx, id, 16) && 282 | (ctx->mctx = EVP_MD_CTX_new()); 283 | if (!success) 284 | { 285 | sm2_sig_ctx_free(ctx); 286 | ctx = NULL; 287 | } 288 | EVP_MD_CTX_set_pkey_ctx(ctx->mctx, ctx->pctx); 289 | success = ctx->is_pri 290 | ? EVP_DigestSignInit(ctx->mctx, NULL, EVP_sm3(), NULL, ctx->pkey) 291 | : EVP_DigestVerifyInit(ctx->mctx, NULL, EVP_sm3(), NULL, ctx->pkey); 292 | if (!success) 293 | { 294 | sm2_sig_ctx_free(ctx); 295 | ctx = NULL; 296 | } 297 | return ctx; 298 | } 299 | 300 | void sm2_sig_ctx_free(SM2_SIG_CTX *ctx) 301 | { 302 | if (ctx) 303 | { 304 | if (ctx->mctx) 305 | { 306 | EVP_MD_CTX_free(ctx->mctx); 307 | ctx->mctx = NULL; 308 | } 309 | if (ctx->pctx) 310 | { 311 | EVP_PKEY_CTX_free(ctx->pctx); 312 | ctx->pctx = NULL; 313 | } 314 | if (ctx->pkey) 315 | { 316 | EVP_PKEY_free(ctx->pkey); 317 | ctx->pkey = NULL; 318 | } 319 | free(ctx); 320 | ctx = NULL; 321 | } 322 | } 323 | 324 | int sm2_sig_update(SM2_SIG_CTX *ctx, const unsigned char *in, size_t in_len) 325 | { 326 | return ctx && in && ctx->is_pri 327 | ? EVP_DigestSignUpdate(ctx->mctx, in, in_len) 328 | : EVP_DigestVerifyUpdate(ctx->mctx, in, in_len); 329 | } 330 | 331 | int sm2_sig_sign(SM2_SIG_CTX *ctx, unsigned char *sig, size_t *sig_len) 332 | { 333 | return ctx && sig && sig_len && ctx->is_pri && 334 | EVP_DigestSignFinal(ctx->mctx, sig, sig_len); 335 | } 336 | 337 | int sm2_sig_verify(SM2_SIG_CTX *ctx, const unsigned char *sig, size_t sig_len) 338 | { 339 | return ctx && sig && !ctx->is_pri && 340 | EVP_DigestVerifyFinal(ctx->mctx, sig, sig_len); 341 | } 342 | 343 | int sm2_sign(unsigned char *sig, size_t *sig_len, const unsigned char *in, size_t in_len, const unsigned char *pri, size_t pri_len) 344 | { 345 | if (!sig || !sig_len || !in || !pri) 346 | return 0; 347 | SM2_SIG_CTX *ctx = NULL; 348 | int success = 349 | (ctx = sm2_sig_ctx_new(pri, pri_len, 1)) && 350 | sm2_sig_update(ctx, in, in_len) && 351 | sm2_sig_sign(ctx, sig, sig_len); 352 | if (ctx) 353 | { 354 | sm2_sig_ctx_free(ctx); 355 | ctx = NULL; 356 | } 357 | return success; 358 | } 359 | 360 | int sm2_verify(const unsigned char *sig, size_t sig_len, const unsigned char *in, size_t in_len, const unsigned char *pub, size_t pub_len) 361 | { 362 | if (!sig || !in || !pub) 363 | return 0; 364 | SM2_SIG_CTX *ctx = NULL; 365 | int success = 366 | (ctx = sm2_sig_ctx_new(pub, pub_len, 0)) && 367 | sm2_sig_update(ctx, in, in_len) && 368 | sm2_sig_verify(ctx, sig, sig_len); 369 | if (ctx) 370 | { 371 | sm2_sig_ctx_free(ctx); 372 | ctx = NULL; 373 | } 374 | return success; 375 | } 376 | --------------------------------------------------------------------------------