最近项目中需要通过C语言实现SM2、SM4国密算法,这里我基于GMSSL来进行实现,本人已在这5种环境下全部实现,并已使用在生产环境中。
1、GMSSL编译
GMSSL编译在不同环境下都不一样,这里我提供Window64、Arm64、Linux64、Android、himix200海思芯片 环境编译方法,传送门如下:
如果各位都是比较懒得人,我这里也给各位提供上述五种环境已经编好的库,传送门如下:
Gmssl链接库(himix200、android、arm64、linux64、windows64)
2、SM2实现
我们基于第一步编译出来的库来实现我们的SM2算法,头文件相关代码(authref.h)如下:
#ifndef __AUTHREF_H__
#define __AUTHREF_H__
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SM2_PUB_KEY_SIZE 178 // SM2 公钥的位数
typedef struct SM2_KEY
{
uint8_t *pub_key;
uint8_t *pri_key;
} T_sm2_key;
typedef struct ENCRYPT_KEY
{
uint8_t *text;
int len;
} T_encrypt_key;
typedef struct DECRYPT_KEY
{
uint8_t *text;
int len;
} T_decrypt_key;
//得到椭圆曲线(EC_KEY)
// key – 密钥
// is_public – 是否公钥(0:否,1:是)
// return – 椭圆曲线(EC_KEY)
EC_KEY* CreateEC(unsigned char* key, int is_public);
// 生成SM2 Key
// return – SM2密钥(T_sm2_key)
T_sm2_key GenKey(void);
// SM2加密
// public_key – 公钥
// plain_text – 明文
// pResOut – 返回值
int Encrypt(const char *public_key, uint8_t plain_text[UID_LEN], int plain_len);
// SM2解密
// public_key – 私钥
// plain_text – 密文
// pResOut – 返回值
int Decrypt(const char *private_key, T_encrypt_key *enc_text, T_decrypt_key *pResOut);
#ifdef __cplusplus
}
#endif
#endif //__AUTHREF_H__
具体实现代码(authref.c)如下:
#include "authref.h"
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/sm2.h>
T_sm2_key GenKey(void) {
EC_KEY *keypair = NULL;
EC_GROUP *group1 = NULL;
keypair = EC_KEY_new();
if (!keypair) {
printf("%s", "Failed to Gen Key");
exit(1);
}
group1 = EC_GROUP_new_by_curve_name(NID_sm2p256v1);
if (group1 == NULL) {
printf("%s", "Failed to Gen Key");
exit(1);
}
int ret1 = EC_KEY_set_group(keypair, group1);
if (ret1 != 1) {
printf("%s", "Failed to Gen Key");
exit(1);
}
int ret2 = EC_KEY_generate_key(keypair);
if (ret2 != 1) {
printf("%s", "Failed to Gen Key");
exit(1);
}
int pri_len;
int pub_len;
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
PEM_write_bio_ECPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_EC_PUBKEY(pub, keypair);
pri_len = BIO_pending(pri);
pub_len = BIO_pending(pub);
char *pri_key = NULL;
char *pub_key = NULL;
pri_key = malloc(pri_len + 1);
pub_key = malloc(pub_len + 1);
BIO_read(pri, pri_key, pri_len);
BIO_read(pub, pub_key, pub_len);
pri_key[pri_len] = '\0';
pub_key[pub_len] = '\0';
T_sm2_key key = {pub_key, pri_key};
EC_KEY_free(keypair);
BIO_free_all(pub);
BIO_free_all(pri);
return key;
}
EC_KEY *CreateEC(unsigned char *key, int is_public) {
EC_KEY *ec_key = NULL;
BIO *keybio = NULL;
keybio = BIO_new_mem_buf(key, -1);
if (keybio == NULL) {
printf("%s", "[BIO_new_mem_buf]->key len=%d,Failed to Get Key", strlen((char *) key));
exit(1);
}
if (is_public) {
ec_key = PEM_read_bio_EC_PUBKEY(keybio, NULL, NULL, NULL);
} else {
ec_key = PEM_read_bio_ECPrivateKey(keybio, NULL, NULL, NULL);
}
if (ec_key == NULL) {
printf("Failed to Get Key");
exit(1);
}
return ec_key;
}
unsigned char encrypted[1024] = {};
size_t encrypted_length = 1024;
int Encrypt(const char *public_key, uint8_t plain_text[UID_LEN], int plain_len) {
int nRet = 0;
if (plain_text) {
EC_KEY *rsa = CreateEC((unsigned char *) public_key, 1);
int encrypt = SM2_encrypt(NID_sm3, plain_text, plain_len,
encrypted, &(encrypted_length), rsa);
if (encrypt == 0) {
printf("%s\n", "Failed to Encrypt");
nRet = -1;
}
}
return nRet;
}
int Decrypt(const char *private_key, T_encrypt_key *enc_text, T_decrypt_key *pResOut) {
int nRet = 0;
if (pResOut && enc_text) {
EC_KEY *key1 = CreateEC((unsigned char *) private_key, 0);
pResOut->text = (unsigned char *) malloc(enc_text->len);
memset(pResOut->text, 0, enc_text->len);
int ret = SM2_decrypt_with_recommended(enc_text->text, enc_text->len, pResOut->text,
&(pResOut->len), key1);
if (ret == 0) {
printf("%s", "Failed to Decrypt");
nRet = -1;
}
}
return nRet;
}
到此我们就实现了基于GMSSL的SM2算法。
来源:CSDN
作者:张志翔
链接:https://blog.csdn.net/qq_19734597/article/details/104060859