260 lines
7.8 KiB
C++
260 lines
7.8 KiB
C++
#include "crypto.h"
|
||
#include <math.h>
|
||
|
||
Crypto::Crypto()
|
||
{
|
||
|
||
}
|
||
|
||
Crypto* Crypto::getInstance()
|
||
{
|
||
static Crypto crypto_instance;
|
||
return &crypto_instance;
|
||
}
|
||
|
||
int Crypto::hex2bytearray(char s[], unsigned char bits[], u32 len)
|
||
{
|
||
u32 i, n = 0;
|
||
for (i = 0; i < len; i += 2) {
|
||
if (s[i] >= 'a' && s[i] <= 'f') bits[n] = s[i] - 'a' + 10;
|
||
else if (s[i] >= 'A' && s[i] <= 'F') bits[n] = s[i] - 'A' + 10;
|
||
else bits[n] = s[i] - '0';
|
||
if (s[i + 1] >= 'a' && s[i + 1] <= 'f') bits[n] = (bits[n] << 4) | (s[i + 1] - 'a' + 10);
|
||
else if (s[i + 1] >= 'A' && s[i + 1] <= 'F') bits[n] = (bits[n] << 4) | (s[i + 1] - 'A' + 10);
|
||
else bits[n] = (bits[n] << 4) | (s[i + 1] - '0');
|
||
++n;
|
||
}
|
||
bits[n] = 0;
|
||
return n;
|
||
}
|
||
|
||
int Crypto::hex2bytearray(char s[], unsigned char *bits)
|
||
{
|
||
int i=0, n = 0;
|
||
if (s[i] >= 'a' && s[i] <= 'f') *bits = s[i] - 'a' + 10;
|
||
else if (s[i] >= 'A' && s[i] <= 'F') *bits = s[i] - 'A' + 10;
|
||
else *bits = s[i] - '0';
|
||
if (s[i + 1] >= 'a' && s[i + 1] <= 'f') *bits = (*bits << 4) | (s[i + 1] - 'a' + 10);
|
||
else if (s[i + 1] >= 'A' && s[i + 1] <= 'F') *bits = (*bits << 4) | (s[i + 1] - 'A' + 10);
|
||
else *bits = (*bits << 4) | (s[i + 1] - '0');
|
||
++n;
|
||
return n;
|
||
}
|
||
|
||
void Crypto::bytearray2hex(u8 in_s[], char out_b[], u32 len)
|
||
{
|
||
u32 i;
|
||
for (i = 0; i < len; i++) {
|
||
snprintf(out_b + i * 2, 2, "%02X", in_s[i]);
|
||
}
|
||
out_b[len * 2] = 0;
|
||
}
|
||
|
||
void Crypto::bytearray2hex(ecc_point in_s, char out_b[])
|
||
{
|
||
int i;
|
||
for (i = 0; i < 4; i++) {
|
||
for (int j = 0; j < 8; j++) {
|
||
snprintf(out_b + i * 8 * 2 + j * 2, 2, "%02X", (u8)(in_s.x[i] >> (j * 8)));
|
||
}
|
||
}
|
||
for (i = 0; i < 4; i++) {
|
||
for (int j = 0; j < 8; j++) {
|
||
snprintf(out_b + i * 8 * 2 + j * 2 + 64, 2, "%02X", (u8)(in_s.y[i] >> (j * 8)));
|
||
}
|
||
}
|
||
out_b[128] = 0;
|
||
}
|
||
|
||
void Crypto::pubhex2point(char *in_b, ecc_point *out_s)
|
||
{
|
||
u64 temp = 0;
|
||
for (int i = 0; i < 4; i++) {
|
||
out_s->x[i] = 0;
|
||
for (int j = 0; j < 8; j++) {
|
||
sscanf(in_b + i * 8 * 2 + j * 2, "%2llX", &temp);
|
||
out_s->x[i] += temp << (j * 8);
|
||
}
|
||
}
|
||
for (int i = 0; i < 4; i++) {
|
||
out_s->y[i] = 0;
|
||
for (int j = 0; j < 8; j++) {
|
||
sscanf(in_b + i * 8 * 2 + j * 2 + 64, "%2llX", &temp);
|
||
out_s->y[i] += temp << (j * 8);
|
||
}
|
||
}
|
||
}
|
||
|
||
void Crypto::sm2_key_gen(SM2_key *sm2_keypair,bool buffed)
|
||
{
|
||
SM2_key temp_keypair;
|
||
ecc_point temp_pub_p;
|
||
u8 temp_pub[129]={0},temp_pri[65]={0};
|
||
sm2_make_keypair(temp_pri,&temp_pub_p);
|
||
bytearray2hex(temp_pub_p, (char *)temp_pub);
|
||
hex2bytearray((char *)temp_pub,temp_keypair.pub_key,128);
|
||
strncpy((char *)temp_keypair.pri_key,(char *)temp_pri, 32);
|
||
strncpy((char *)sm2_keypair->pri_key,(char *)temp_keypair.pri_key, 32);
|
||
strncpy((char *)sm2_keypair->pub_key,(char *)temp_keypair.pub_key, 64);
|
||
if (buffed)
|
||
{
|
||
u8 pri_buf[65];
|
||
bytearray2hex(sm2_keypair->pri_key, (char *)pri_buf);
|
||
strncpy((char *)sm2_keypair->pri_key,(char *)pri_buf, 64);
|
||
strncpy((char *)sm2_keypair->pub_key,(char *)temp_pub, 128);
|
||
}
|
||
}
|
||
|
||
void Crypto::SM2_encrypt(u8 *pub, u8 *M, u32 Mlen, u8 *C, u32 *Clen, s32 mode)
|
||
{
|
||
ecc_point pub_point;
|
||
memcpy(pub_point.x, pub, 32);
|
||
memcpy(pub_point.y, pub+32, 32);
|
||
sm2_encrypt(&pub_point, (u8 *)M, Mlen, (u8 *)C, Clen);
|
||
if (!mode) {
|
||
u8 *temp_C = (u8 *)malloc(sizeof(u8) * (*Clen));
|
||
memset(temp_C, 0, sizeof(u8) * (*Clen));
|
||
sm2_C1C2C3ConvertToC1C3C2(temp_C, (u8 *)C, *Clen, mode);
|
||
memset(C, 0, sizeof(u8) * (*Clen));
|
||
memcpy(C, temp_C, sizeof(u8) * (*Clen));
|
||
free(temp_C);
|
||
}
|
||
}
|
||
|
||
// Default Input C1|C3|C2
|
||
void Crypto::SM2_decrypt(u8 *pri, u8 *C, u32 Clen, u8 *M, u32 *Mlen, s32 mode)
|
||
{
|
||
u8 *temp_C = (u8 *)malloc(sizeof(u8) * Clen);
|
||
if (!mode) {
|
||
sm2_C1C2C3ConvertToC1C3C2(temp_C, C, Clen, !mode);
|
||
}
|
||
sm2_decrypt(pri, temp_C, Clen, (u8 *)M, Mlen);
|
||
free(temp_C);
|
||
}
|
||
|
||
// Output r | s
|
||
void Crypto::SM2_sign(u8 *pri, u8 *data, u32 datalen, u8 *out)
|
||
{
|
||
struct sm3_ctx h;
|
||
u8 hash[33] = { 0 };
|
||
u8 r[33] = { 0 }, s[33] = { 0 };
|
||
sm3_finup(&h, data, datalen, hash);
|
||
sm2_sign(r, s, pri, hash);
|
||
memcpy(out, r, 32);
|
||
memcpy(out+32, s, 32);
|
||
}
|
||
|
||
bool Crypto::SM2_verify(u8 *pub, u8 *data,u32 data_len, u8 *sig)
|
||
{
|
||
struct sm3_ctx h;
|
||
u8 hash[33] = { 0 };
|
||
u8 r[33] = { 0 }, s[33] = { 0 };
|
||
ecc_point pub_point;
|
||
memcpy(pub_point.x, pub, 32);
|
||
memcpy(pub_point.y, pub+32, 32);
|
||
sm3_finup(&h, data, data_len, hash);
|
||
memcpy(r, sig, 32);
|
||
memcpy(s, sig+32, 32);
|
||
return (sm2_verify(&pub_point, hash, r, s) == 0 ? true : false);
|
||
}
|
||
|
||
void Crypto::SM3_HMAC(u8 *key, int keylen, u8 *input, int ilen, u8 *output)
|
||
{
|
||
sm3_hmac(key, keylen, input, ilen, output);
|
||
}
|
||
|
||
bool Crypto::SM4_encrypt(u8 *key_origin, u32 key_len, u8 *in_origin, u32 in_len, u8 *out, u32 *out_len)
|
||
{
|
||
struct sm4_ctx a;
|
||
u32 max_len;
|
||
u8 key[17] = { 0 }, *in = (u8 *)malloc(sizeof(u8) * (in_len + 16 * 2 + 1)); // 为保证C兼容性,不使用智能指针 两个16分别是为首末尾填充留足留足空间,1是冗余量
|
||
u8 iv[17] = {
|
||
0x21, 0xBC, 0xC1, 0xEA, 0x0D, 0xB8, 0x54, 0x6D, 0xCE, 0xE4, 0xDB, 0x3C, 0xFA, 0xC1, 0x3C, 0xEF }, fix_len; // 此处为省时才用固定IV,实际上此处IV必须是随机的才可真正保证SM4 CBC模式下加解密的强度
|
||
for (int i = 0; i < 16; i++)
|
||
{
|
||
iv[i] = Crypto::getInstance()->get_rand(); // 使用随机数IV,如果想节省时间可以注释
|
||
}
|
||
if (key_len > 16) {
|
||
free(in);
|
||
return false;
|
||
}
|
||
fix_len = 16 - key_len;
|
||
memcpy(key, key_origin, key_len);
|
||
for (int i = 0; i < 16; i++)
|
||
{
|
||
in[i] = Crypto::getInstance()->get_rand(); // 首填充
|
||
}
|
||
memcpy(in + 16, in_origin, in_len);
|
||
if (key_len < 16) {
|
||
for (int i = key_len; i < 16; i++) {
|
||
key[i] = fix_len;
|
||
}
|
||
}
|
||
if (in_len % 16 != 0) {
|
||
max_len = ceil(in_len / 16.0)* 16 + 16;
|
||
fix_len = max_len - 16 - in_len;
|
||
for (u32 i = in_len + 16; i < max_len; i++) {
|
||
in[i] = fix_len;
|
||
}
|
||
in_len = max_len;
|
||
} else {
|
||
for (u32 i = in_len + 16; i < in_len + 16 * 2; i++) {
|
||
in[i] = 16;
|
||
}
|
||
in_len += 16 * 2;
|
||
}
|
||
*out_len = in_len;
|
||
sm4_cbc_encrypt(&a, key, iv, in, in_len, out);
|
||
free(in);
|
||
return true;
|
||
}
|
||
|
||
bool Crypto::SM4_decrypt(u8 *key_origin, u32 key_len, u8 *in, u32 in_len, u8 *out, u32 *out_len)
|
||
{
|
||
struct sm4_ctx b;
|
||
u32 fix_len;
|
||
u8 key[17] = { 0 };
|
||
u8 iv[17] = {
|
||
0x21, 0xBC, 0xC1, 0xEA, 0x0D, 0xB8, 0x54, 0x6D, 0xCE, 0xE4, 0xDB, 0x3C, 0xFA, 0xC1, 0x3C, 0xEF }; // 此处为省时才用固定IV,实际上此处IV必须是随机的才可真正保证SM4 CBC模式下加解密的强度
|
||
u8* out_buf = (u8* )malloc(in_len * sizeof(u8)); // 为保证C兼容性,不使用智能指针
|
||
for (int i = 0; i < 16; i++)
|
||
{
|
||
iv[i] = Crypto::getInstance()->get_rand(); // 使用随机数IV,如果想节省时间可以注释
|
||
}
|
||
if (key_len > 16) {
|
||
free(out_buf);
|
||
return false;
|
||
}
|
||
fix_len = 16 - key_len;
|
||
memcpy(key, key_origin, key_len);
|
||
if (in_len % 16 != 0) {
|
||
free(out_buf);
|
||
return false;
|
||
}
|
||
if (key_len < 16) {
|
||
for (int i = key_len; i < 16; i++) {
|
||
key[i] = fix_len;
|
||
}
|
||
}
|
||
sm4_cbc_decrypt(&b, key, iv, in, in_len, out_buf);
|
||
fix_len = out_buf[in_len - 1];
|
||
if (fix_len>in_len)
|
||
{
|
||
free(out_buf);
|
||
return false;
|
||
}
|
||
*out_len = in_len - fix_len - 16;
|
||
memcpy(out, out_buf + 16, *out_len);
|
||
free(out_buf);
|
||
return true;
|
||
}
|
||
|
||
uint8_t Crypto::get_rand()
|
||
{
|
||
uint8_t num = 0;
|
||
static time_t seed = 0;
|
||
srand(time(nullptr) + seed);
|
||
seed = rand();
|
||
return rand() % 256;
|
||
}
|