郑州建站怎么操作南平网站seo
引言
SM2是我国自主研发的非对称加密算法(国密算法),于2010年由国密局发布,2017年成为ISO/IEC国际标准。其基于椭圆曲线密码学(ECC),具备安全性高(256位密钥强度相当于RSA-3072位)、运算速度快、密钥短(256位)等优势,广泛应用于数字签名、公钥加密、密钥交换等领域,是金融、政务、物联网等场景的核心安全技术。本文从算法原理到代码实现,系统解析SM2的核心技术。
一、SM2算法基础
1.1 算法概述
SM2属于非对称加密算法,包含三个核心功能:
- 数字签名:基于椭圆曲线离散对数难题(ECDLP),保障数据来源认证与完整性
- 公钥加密:使用接收方公钥加密数据,私钥解密
- 密钥交换:通过ECDH协议生成共享密钥,用于后续对称加密
1.2 核心数学原理
SM2的安全性依赖于椭圆曲线离散对数问题:已知椭圆曲线点P和Q=kP,求k在计算上不可行。其数学基础包括:
- 有限域运算:素域Fp上的加法、乘法、逆运算
- 椭圆曲线方程:标准方程为 ( y^2 = x^3 + ax + b \mod p ),推荐参数为256位素数域
- 点运算:点加(P+Q)、倍点(2P)和标量乘法(kP)构成核心运算
1.3 核心参数
国密推荐曲线参数如下(十六进制):
- 素数p:
FFFFFFFE FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 00000000 FFFFFFFF FFFFFFFF
- 系数a:
FFFFFFFE ... FFFFFFFC
- 基点G:(x, y)坐标,阶n为
FFFFFFFE ... 39D54123
1.4 算法组件
SM2包含四大核心算法模块:
- 密钥生成:随机数d∈[1,n-1]作为私钥,公钥P=dG
注
:根据上述密钥生成的流程,是先生成私钥d
,然后计算公钥P
,因此在SM2的密钥中,可以根据私钥计算出公钥 - 数字签名:使用私钥对消息哈希值签名,生成(r,s)
- 加密/解密:基于KDF生成会话密钥,结合椭圆曲线点运算
- 密钥协商:通过两次握手协议生成共享密钥
二、算法原理详解
2.1 数字签名流程
签名生成:
- 计算消息哈希值e=HASH(Z_A || M),Z_A为用户身份标识
- 生成随机数k∈[1,n-1],计算点(x1,y1)=kG
- r=(e + x1) mod n,若r=0则重新选k
- s=((1+d_A)^-1 * (k - r*d_A)) mod n,输出签名(r,s)
验签流程:
- 验证r,s∈[1,n-1]
- 计算t=(r+s) mod n,点(x1,y1)=sG + tP_A
- 验证r ≡ (e + x1) mod n
2.2 加密与解密流程
加密:
- 生成随机数k,计算C1=kG(椭圆曲线点)
- 计算S=h*P_B(h为余因子),若S为无穷远点则报错
- 计算(x2,y2)=kP_B,通过KDF生成密钥t
- 密文C2=M⊕t,C3=HASH(x2||M||y2)
- 输出C=C1||C3||C2
解密:
- 验证C1在曲线上,计算S=h*C1
- 计算(x2,y2)=d_B*C1,生成t=KDF(x2||y2)
- 解密M’=C2⊕t,验证C3=HASH(x2||M’||y2)
2.3 密钥交换协议
基于改进的ECDH协议,两轮交互生成共享密钥:
- 双方生成临时密钥对(r_A, R_A)和(r_B, R_B)
- 计算共享点U=r_A(r_B G + P_B) 和 U’=r_B(r_A G + P_A)
- 通过KDF处理U的坐标生成会话密钥
2.4 椭圆曲线数学优化
- 坐标系选择:Jacobian射影坐标减少模逆运算
- 标量乘法优化:采用滑动窗口法、NAF编码降低计算量
- 预计算技术:固定基点G的预计算表加速kG运算
三、算法实现技术
3.1 硬件实现
- 专用芯片:如HS32U2-U,通过SPI接口实现低功耗加密
- FPGA优化:流水线设计SM2协处理器,时钟频率达50MHz,标量乘仅0.869ms
- 抗侧信道技术:随机化NAF窗口、盲化标量防御SPA/DPA攻击
3.2 软件实现
- Bouncy Castle库:Java示例代码展示密钥生成与加密
- OpenSSL引擎:集成SM2到EVP接口,支持标准API调用
- 性能优化技巧:
- 预计算常用点坐标(如16个预计算点加速kP)
- SIMD指令加速有限域乘法(如Intel AVX2)
四、安全性分析
4.1 算法设计安全性
- 数学安全性:基于ECDLP难题,256位密钥抗量子攻击优于RSA-3072
- 抗碰撞性:SM3哈希保障签名与加密数据完整性
- 标准化认证:通过国密GM/T 0003.5-2012、ISO/IEC 14888-3
4.2 抗攻击能力
- 侧信道防护:随机化标量乘顺序、加入噪声指令
- 故障注入防御:双点校验、错误感染技术
- 弱曲线防御:强制验证公共参数防止参数替换攻击
4.3 与RSA/AES对比
特性 | SM2 | RSA-3072 | AES-256 |
---|---|---|---|
密钥长度 | 256位 | 3072位 | 256位 |
安全强度 | 抗量子 | 不抗量子 | 抗量子 |
签名速度 | 0.98ms(FPGA) | 3.2ms | N/A |
适用场景 | 非对称加密 | 传统非对称加密 | 对称加密 |
五、C++跨平台自实现(Header-Only
)
5.1 源码封装
/*****************************************************************************
* Copyright (c) 2025, arbboter. All rights reserved.
* File : filename.cpp
* Desc : 本文件实现SM2模块的核心算法
* - SM2的签名和验签
* - SM2的加密和解密
* Version : 1.0.0.1
* Date : 2025-04-11
* Author : arbboter@hotmail.com
* License : SPDX-License-Identifier: Apache-2.0 (详见 LICENSE 文件)
*
* ------------------------- Revision History --------------------------------
* <Version> <Date> <Author> <Modification Description>
* 1.0.0.1 2025-01-01 arbboter@hotmail.com 初始版本创建
*****************************************************************************/
#ifndef __SM2_H__
#define __SM2_H__
#include <stdio.h>
#include <string.h>
#include <cstdint>#ifdef _WIN32
#include <windows.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#ifndef NT_SUCCESS
#define NT_SUCCESS(status) ((NTSTATUS)(status) >= 0)
#endif
#else
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#endif#ifndef GET_UINT32_BE
#define GET_UINT32_BE(n,b,i) \{\(n) = ((unsigned int)(b)[(i) ] << 24 ) \| ((unsigned int)(b)[(i) + 1] << 16 ) \| ((unsigned int)(b)[(i) + 2] << 8 ) \| ((unsigned int)(b)[(i) + 3] );\}
#endif#ifndef PUT_UINT32_BE
#define PUT_UINT32_BE(n,b,i) \{\(b)[(i) ] = (unsigned char) ( (n) >> 24 );\(b)[(i) + 1] = (unsigned char) ( (n) >> 16 );\(b)[(i) + 2] = (unsigned char) ( (n) >> 8 );\(b)[(i) + 3] = (unsigned char) ( (n) );\}
#endif#define FF0(x,y,z) ( (x) ^ (y) ^ (z))
#define FF1(x,y,z) (((x) & (y)) | ( (x) & (z)) | ( (y) & (z)))#define GG0(x,y,z) ( (x) ^ (y) ^ (z))
#define GG1(x,y,z) (((x) & (y)) | ( (~(x)) & (z)) )#define SHL(x,n) (((x) & 0xFFFFFFFF) << n)
#define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))#define P0(x) ((x) ^ ROTL((x),9) ^ ROTL((x),17))
#define P1(x) ((x) ^ ROTL((x),15) ^ ROTL((x),23))#define GETU32(p) ((uint32_t)(p)[0] << 24 | (uint32_t)(p)[1] << 16 | (uint32_t)(p)[2] << 8 | (uint32_t)(p)[3])
#define PUTU32(p,V) ((p)[0] = (uint8_t)((V) >> 24), (p)[1] = (uint8_t)((V) >> 16), (p)[2] = (uint8_t)((V) >> 8), (p)[3] = (uint8_t)(V))#define SM2_MIN_PLAINTEXT_SIZE 1
#define SM2_MAX_PLAINTEXT_SIZE 3072
#define SM2_DEFAULT_ID "1234567812345678"
#define RAND_MAX_BUF_SIZE 256
#ifndef INT_MAX
#define INT_MAX 2147483647
#endif#define ASN1_TAG_INTEGER 2
#define ASN1_TAG_OCTET_STRING 4
#define ASN1_TAG_SEQUENCE 0x30typedef uint64_t SM2_BN[8];
typedef SM2_BN SM2_Fp;
typedef SM2_BN SM2_Fn;typedef struct
{uint8_t x[32];uint8_t y[32];
} SM2_POINT;typedef struct
{SM2_POINT public_key;uint8_t private_key[32];
} SM2_KEY;typedef struct
{uint8_t r[32];uint8_t s[32];
} SM2_SIGNATURE;// 雅可比行列式
typedef struct
{SM2_BN X;SM2_BN Y;SM2_BN Z;
} SM2_JACOBIAN_POINT;typedef struct
{SM2_POINT point;uint8_t hash[32];uint32_t ciphertext_size;uint8_t ciphertext[SM2_MAX_PLAINTEXT_SIZE];
} SM2_CIPHERTEXT;const SM2_BN SM2_P =
{0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe,
};const SM2_BN SM2_B =
{0x4d940e93, 0xddbcbd41, 0x15ab8f92, 0xf39789f5,0xcf6509a7, 0x4d5a9e4b, 0x9d9f5e34, 0x28e9fa9e,
};const SM2_JACOBIAN_POINT _SM2_G =
{{0x334c74c7, 0x715a4589, 0xf2660be1, 0x8fe30bbf,0x6a39c994, 0x5f990446, 0x1f198119, 0x32c4ae2c,},{0x2139f0a0, 0x02df32e5, 0xc62a4740, 0xd0a9877c,0x6b692153, 0x59bdcee3, 0xf4f6779c, 0xbc3736a2,},{1, 0, 0, 0, 0, 0, 0, 0,},
};
const SM2_JACOBIAN_POINT* SM2_G = &_SM2_G;const SM2_BN SM2_N =
{0x39d54123, 0x53bbf409, 0x21c6052b, 0x7203df6b,0xffffffff, 0xffffffff, 0xffffffff, 0xfffffffe,
};const SM2_BN SM2_ONE = { 1,0,0,0,0,0,0,0 };
const SM2_BN SM2_TWO = { 2,0,0,0,0,0,0,0 };typedef struct
{unsigned int total[2]; // number of bytes processedunsigned int state[8]; // intermediate digest stateunsigned char buffer[64]; // data block being processedunsigned char ipad[64]; // HMAC: inner paddingunsigned char opad[64]; // HMAC: outer padding
} sm3_context;class SM3
{
public:static void Starts(sm3_context* ctx){ctx->total[0] = 0;ctx->total[1] = 0;ctx->state[0] = 0x7380166F;ctx->state[1] = 0x4914B2B9;ctx->state[2] = 0x172442D7;ctx->state[3] = 0xDA8A0600;ctx->state[4] = 0xA96F30BC;ctx->state[5] = 0x163138AA;ctx->state[6] = 0xE38DEE4D;ctx->state[7] = 0xB0FB0E4E;}static void Update(sm3_context* ctx, unsigned char* input, size_t ilen){unsigned int fill = 0;unsigned int left = 0;if (ilen == 0) { return; }left = ctx->total[0] & 0x3F;fill = 64 - left;ctx->total[0] += (unsigned int)ilen;ctx->total[0] &= 0xFFFFFFFF;if (ctx->total[0] < ilen){ctx->total[1]++;}if (left && ilen >= fill){memcpy(ctx->buffer + left, input, fill);Process(ctx, ctx->buffer);input += fill;ilen -= fill;left = 0;}while (ilen >= 64){Process(ctx, input);input += 64;ilen -= 64;}if (ilen > 0){memcpy(ctx->buffer + left, input, ilen);}}static void Finish(sm3_context* ctx, unsigned char output[32]){unsigned char sm3_padding[64] = { 0 };unsigned int last, padn;unsigned int high, low;unsigned char msglen[8];high = (ctx->total[0] >> 29)| (ctx->total[1] << 3);low = (ctx->total[0] << 3);PUT_UINT32_BE(high, msglen, 0);PUT_UINT32_BE(low, msglen, 4);last = ctx->total[0] & 0x3F;padn = (last < 56) ? (56 - last) : (120 - last);sm3_padding[0] = '\x80';Update(ctx, sm3_padding, padn);Update(ctx, msglen, 8);PUT_UINT32_BE(ctx->state[0], output, 0);PUT_UINT32_BE(ctx->state[1], output, 4);PUT_UINT32_BE(ctx->state[2], output, 8);PUT_UINT32_BE(ctx->state[3], output, 12);PUT_UINT32_BE(ctx->state[4], output, 16);PUT_UINT32_BE(ctx->state[5], output, 20);PUT_UINT32_BE(ctx->state[6], output, 24);PUT_UINT32_BE(ctx->state[7], output, 28);}private:static void Process(sm3_context* ctx, unsigned char data[64]){unsigned int SS1, SS2, TT1, TT2, W[68], W1[64];unsigned int A, B, C, D, E, F, G, H;unsigned int T[64];unsigned int Temp1, Temp2, Temp3, Temp4, Temp5;unsigned int n;for (n = 0; n < 16; n++) { T[n] = 0x79CC4519; }for (n = 16; n < 64; n++) { T[n] = 0x7A879D8A; }GET_UINT32_BE(W[0], data, 0);GET_UINT32_BE(W[1], data, 4);GET_UINT32_BE(W[2], data, 8);GET_UINT32_BE(W[3], data, 12);GET_UINT32_BE(W[4], data, 16);GET_UINT32_BE(W[5], data, 20);GET_UINT32_BE(W[6], data, 24);GET_UINT32_BE(W[7], data, 28);GET_UINT32_BE(W[8], data, 32);GET_UINT32_BE(W[9], data, 36);GET_UINT32_BE(W[10], data, 40);GET_UINT32_BE(W[11], data, 44);GET_UINT32_BE(W[12], data, 48);GET_UINT32_BE(W[13], data, 52);GET_UINT32_BE(W[14], data, 56);GET_UINT32_BE(W[15], data, 60);for (n = 16; n < 68; n++){Temp1 = W[n - 16] ^ W[n - 9];Temp2 = ROTL(W[n - 3], 15);Temp3 = Temp1 ^ Temp2;Temp4 = P1(Temp3);Temp5 = ROTL(W[n - 13], 7) ^ W[n - 6];W[n] = Temp4 ^ Temp5;}for (n = 0; n < 64; n++){W1[n] = W[n] ^ W[n + 4];}A = ctx->state[0];B = ctx->state[1];C = ctx->state[2];D = ctx->state[3];E = ctx->state[4];F = ctx->state[5];G = ctx->state[6];H = ctx->state[7];for (n = 0; n < 16; n++){SS1 = ROTL((ROTL(A, 12) + E + ROTL(T[n], n)), 7);SS2 = SS1 ^ ROTL(A, 12);TT1 = FF0(A, B, C) + D + SS2 + W1[n];TT2 = GG0(E, F, G) + H + SS1 + W[n];D = C;C = ROTL(B, 9);B = A;A = TT1;H = G;G = ROTL(F, 19);F = E;E = P0(TT2);}for (n = 16; n < 64; n++){SS1 = ROTL((ROTL(A, 12) + E + ROTL(T[n], n)), 7);SS2 = SS1 ^ ROTL(A, 12);TT1 = FF1(A, B, C) + D + SS2 + W1[n];TT2 = GG1(E, F, G) + H + SS1 + W[n];D = C;C = ROTL(B, 9);B = A;A = TT1;H = G;G = ROTL(F, 19);F = E;E = P0(TT2);}ctx->state[0] ^= A;ctx->state[1] ^= B;ctx->state[2] ^= C;ctx->state[3] ^= D;ctx->state[4] ^= E;ctx->state[5] ^= F;ctx->state[6] ^= G;ctx->state[7] ^= H;}static void Process(unsigned char* input, size_t ilen, unsigned char output[32]){sm3_context ctx;Starts(&ctx);Update(&ctx, input, ilen);Finish(&ctx, output);memset(&ctx, 0, sizeof(sm3_context));}static void HmacStarts(sm3_context* ctx, unsigned char* key, size_t keylen){unsigned int i;unsigned char sum[32];if (keylen > 64){Process(key, keylen, sum);keylen = 32;key = sum;}memset(ctx->ipad, 0x36, 64);memset(ctx->opad, 0x5C, 64);for (i = 0; i < keylen; i++){ctx->ipad[i] = (unsigned char)(ctx->ipad[i] ^ key[i]);ctx->opad[i] = (unsigned char)(ctx->opad[i] ^ key[i]);}Starts(ctx);Update(ctx, ctx->ipad, 64);memset(sum, 0, sizeof(sum));}static void HmacUpdate(sm3_context* ctx, unsigned char* input, size_t ilen){Update(ctx, input, ilen);}static void HmacFinish(sm3_context* ctx, unsigned char output[32]){unsigned int hlen;unsigned char tmpbuf[32];hlen = 32;Finish(ctx, tmpbuf);Starts(ctx);Update(ctx, ctx->opad, 64);Update(ctx, tmpbuf, hlen);Finish(ctx, output);memset(tmpbuf, 0, sizeof(tmpbuf));}void Hmac(unsigned char* key, size_t keylen, unsigned char* input, size_t ilen, unsigned char output[32]){sm3_context ctx;HmacStarts(&ctx, key, keylen);HmacUpdate(&ctx, input, ilen);HmacFinish(&ctx, output);memset(&ctx, 0, sizeof(sm3_context));}
};class SM2
{
public:int SM2Encrypt(const unsigned char* src, size_t srcLen, unsigned char* dst, size_t* dstLen){const SM2_KEY* pk = &_key;if (encrypt(pk, src, srcLen, dst, dstLen) != 1) {return 0;}return 1;}int SM2Decrypt(const unsigned char* src, size_t srcLen, unsigned char* dst, size_t* dstLen){const SM2_KEY* sk = &_key;if (decrypt(sk, src, srcLen, dst, dstLen) != 1){return 0;}return 1;}int SM2Sign(const unsigned char* src, size_t srcLen, unsigned char* sgn, size_t* sgnLen, bool rawRS = false){const SM2_KEY* sk = &_key;sm3_context ctx;if (sign_init(&ctx, sk, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1) {return 0;}if (sign_update(&ctx, src, srcLen) != 1) {return 0;}if (sign_finish(&ctx, sk, sgn, sgnLen, rawRS) != 1) {return 0;}return 1;}int SM2Verify(const unsigned char* src, size_t srcLen, const unsigned char* sgn, size_t sgnLen, bool rawRS = false){const SM2_KEY* sk = &_key;sm3_context ctx;if (verify_init(&ctx, sk, SM2_DEFAULT_ID, strlen(SM2_DEFAULT_ID)) != 1){return 0;}if (verify_update(&ctx, src, srcLen) != 1) {return 0;}if (verify_finish(&ctx, sk, sgn, sgnLen, rawRS) != 1){return 0;}return 1;}bool InitKey(const char* pri_key, const char* pub_key){char pPubKey[256] = { 0};char pPriKey[256] = { 0 };if (pub_key && strlen(pub_key) == 130){memcpy(pPubKey, pub_key + 2, 128);}if (pub_key && strlen(pub_key) == 128){memcpy(pPubKey, pub_key, 128);}if (pri_key && strlen(pri_key) == 64){memcpy(pPriKey, pri_key, 64);}if (pPubKey[0] == '\0' && pPriKey[0] == '\0'){return false;}memset(&_key, 0, sizeof(_key));// 初始化size_t nLen = 32;bool bRet = false;if (strlen(pPubKey) == 128){Hex2Bin(pPubKey, 64, (char*)_key.public_key.x, nLen);Hex2Bin(pPubKey + 64, 64, (char*)_key.public_key.y, nLen);bRet = true;}if (strlen(pPriKey) == 64){Hex2Bin(pPriKey, 64, (char*)_key.private_key, nLen);bRet = true;}return bRet;}static bool Bin2Hex(const char* pIn, size_t nIn, char* pOut, size_t& nOut){if (pIn == nullptr || nIn == 0 || pOut == nullptr || nOut < 2 * nIn){return false;}auto ps = (const unsigned char*)pIn;auto pe = ps + nIn;const char* hex = "0123456789abcdef";auto p = (unsigned char*)pOut;for (; ps < pe; ++ps, p += 2){*p = hex[*ps >> 4];*(p + 1) = hex[*ps & 0xf];}nOut = 2 * nIn;return true;}static bool Hex2Bin(const char* pIn, size_t nIn, char* pOut, size_t& nOut){if (pIn == nullptr || nIn == 0 || (nIn&1) || pOut == nullptr || nOut < nIn/2){return false;}const unsigned char* ps = (const unsigned char*)pIn;const unsigned char* pe = ps + nIn;unsigned char* p = (unsigned char*)pOut;for (; ps + 1 < pe; ps += 2, ++p){*p = (hex2int(*ps) << 4) | (hex2int(*(ps + 1)));}nOut = nIn / 2;return true;}private:SM2_KEY _key;private:static unsigned char hex2int(unsigned char c){if (c >= 'a' && c <= 'f'){return (c - 'a' + 10);}else if (c >= 'A' && c <= 'F'){return (c - 'A' + 10);}else{return c - '0';}}void bn_to_bytes(const SM2_BN a, uint8_t out[32]){int i = 0;for (i = 7; i >= 0; i--) {uint32_t ai = (uint32_t)a[i];PUTU32(out, ai);out += sizeof(uint32_t);}}void bn_from_bytes(SM2_BN r, const uint8_t in[32]){int i = 0;for (i = 7; i >= 0; i--) {r[i] = GETU32(in);in += sizeof(uint32_t);}}void bn_set_word(SM2_BN r, uint32_t a){int i = 0;r[0] = a;for (i = 1; i < 8; i++){r[i] = 0;}}void jacobian_point_from_bytes(SM2_JACOBIAN_POINT* P, const uint8_t in[64]){bn_from_bytes(P->X, in);bn_from_bytes(P->Y, in + 32);bn_set_word(P->Z, 1);}int rand_bytes(uint8_t* buf, size_t len){if (!len) {return 0;}#ifdef _WIN32/* Windows 实现 */NTSTATUS status = BCryptGenRandom(NULL,buf,(ULONG)len,BCRYPT_USE_SYSTEM_PREFERRED_RNG);return NT_SUCCESS(status) ? 1 : -1;
#else/* 类 Unix 实现 */int fd = open("/dev/urandom", O_RDONLY);if (fd == -1) return -1;ssize_t bytes_read = 0;while (bytes_read < (ssize_t)len) {ssize_t n = read(fd, buf + bytes_read, len - bytes_read);if (n == -1) {// 被中断信号打断则重试if (errno == EINTR) continue;close(fd);return -1;}// 永远不会触发(字符设备会持续提供数据)if (n == 0) {close(fd);return -1;}bytes_read += n;}close(fd);return 1;
#endif}int bn_cmp(const SM2_BN a, const SM2_BN b){int i;for (i = 7; i >= 0; i--) {if (a[i] > b[i])return 1;if (a[i] < b[i])return -1;}return 0;}int bn_rand_range(SM2_BN r, const SM2_BN range){uint8_t buf[32];do{if (rand_bytes(buf, sizeof(buf)) != 1){return -1;}bn_from_bytes(r, buf);} while (bn_cmp(r, range) >= 0);return 1;}int bn_is_zero(const SM2_BN a){int i = 0;for (i = 0; i < 8; i++) {if (a[i] != 0){return 0;}}return 1;}int bn_is_one(const SM2_BN a){int i;if (a[0] != 1)return 0;for (i = 1; i < 8; i++) {if (a[i] != 0)return 0;}return 1;}void bn_sub(SM2_BN ret, const SM2_BN a, const SM2_BN b){int i;SM2_BN r;r[0] = ((uint64_t)1 << 32) + a[0] - b[0];for (i = 1; i < 7; i++) {r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32);r[i - 1] &= 0xffffffff;}r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1;r[i - 1] &= 0xffffffff;memcpy(ret, r, sizeof(SM2_BN));}int fn_rand(SM2_BN r){if (bn_rand_range(r, SM2_N) != 1){return -1;}return 1;}void fp_mul(SM2_Fp r, const SM2_Fp a, const SM2_Fp b){int i = 0, j = 0;uint64_t s[16] = { 0 };SM2_BN d = { 0 };uint64_t u = 0;// s = a * bfor (i = 0; i < 8; i++) {u = 0;for (j = 0; j < 8; j++) {u = s[i + j] + a[i] * b[j] + u;s[i + j] = u & 0xffffffff;u >>= 32;}s[i + 8] = u;}r[0] = s[0] + s[8] + s[9] + s[10] + s[11] + s[12] + ((s[13] + s[14] + s[15]) << 1);r[1] = s[1] + s[9] + s[10] + s[11] + s[12] + s[13] + ((s[14] + s[15]) << 1);r[2] = s[2];r[3] = s[3] + s[8] + s[11] + s[12] + s[14] + s[15] + (s[13] << 1);r[4] = s[4] + s[9] + s[12] + s[13] + s[15] + (s[14] << 1);r[5] = s[5] + s[10] + s[13] + s[14] + (s[15] << 1);r[6] = s[6] + s[11] + s[14] + s[15];r[7] = s[7] + s[8] + s[9] + s[10] + s[11] + s[15] + ((s[12] + s[13] + s[14] + s[15]) << 1);for (i = 1; i < 8; i++) {r[i] += r[i - 1] >> 32;r[i - 1] &= 0xffffffff;}d[2] = s[8] + s[9] + s[13] + s[14];d[3] = d[2] >> 32;d[2] &= 0xffffffff;bn_sub(r, r, d);while (bn_cmp(r, SM2_P) >= 0) {bn_sub(r, r, SM2_P);}}void fp_sqr(SM2_Fp r, const SM2_Fp a){fp_mul(r, a, a);}void fp_inv(SM2_Fp r, const SM2_Fp a){SM2_BN a1;SM2_BN a2;SM2_BN a3;SM2_BN a4;SM2_BN a5;int i;fp_sqr(a1, a);fp_mul(a2, a1, a);fp_sqr(a3, a2);fp_sqr(a3, a3);fp_mul(a3, a3, a2);fp_sqr(a4, a3);fp_sqr(a4, a4);fp_sqr(a4, a4);fp_sqr(a4, a4);fp_mul(a4, a4, a3);fp_sqr(a5, a4);for (i = 1; i < 8; i++) fp_sqr(a5, a5);fp_mul(a5, a5, a4);for (i = 0; i < 8; i++) fp_sqr(a5, a5);fp_mul(a5, a5, a4);for (i = 0; i < 4; i++) fp_sqr(a5, a5);fp_mul(a5, a5, a3);fp_sqr(a5, a5);fp_sqr(a5, a5);fp_mul(a5, a5, a2);fp_sqr(a5, a5);fp_mul(a5, a5, a);fp_sqr(a4, a5);fp_mul(a3, a4, a1);fp_sqr(a5, a4);for (i = 1; i < 31; i++) fp_sqr(a5, a5);fp_mul(a4, a5, a4);fp_sqr(a4, a4);fp_mul(a4, a4, a);fp_mul(a3, a4, a2);for (i = 0; i < 33; i++) fp_sqr(a5, a5);fp_mul(a2, a5, a3);fp_mul(a3, a2, a3);for (i = 0; i < 32; i++) fp_sqr(a5, a5);fp_mul(a2, a5, a3);fp_mul(a3, a2, a3);fp_mul(a4, a2, a4);for (i = 0; i < 32; i++) fp_sqr(a5, a5);fp_mul(a2, a5, a3);fp_mul(a3, a2, a3);fp_mul(a4, a2, a4);for (i = 0; i < 32; i++) fp_sqr(a5, a5);fp_mul(a2, a5, a3);fp_mul(a3, a2, a3);fp_mul(a4, a2, a4);for (i = 0; i < 32; i++) fp_sqr(a5, a5);fp_mul(a2, a5, a3);fp_mul(a3, a2, a3);fp_mul(a4, a2, a4);for (i = 0; i < 32; i++) fp_sqr(a5, a5);fp_mul(r, a4, a5);memset(a1, 0, sizeof(SM2_BN));memset(a2, 0, sizeof(SM2_BN));memset(a3, 0, sizeof(SM2_BN));memset(a4, 0, sizeof(SM2_BN));memset(a5, 0, sizeof(SM2_BN));}void bn_add(SM2_BN r, const SM2_BN a, const SM2_BN b){int i = 0;r[0] = a[0] + b[0];for (i = 1; i < 8; i++){r[i] = a[i] + b[i] + (r[i - 1] >> 32);}for (i = 0; i < 7; i++){r[i] &= 0xffffffff;}}void fp_add(SM2_Fp r, const SM2_Fp a, const SM2_Fp b){bn_add(r, a, b);if (bn_cmp(r, SM2_P) >= 0) {bn_sub(r, r, SM2_P);}}void fp_sub(SM2_Fp r, const SM2_Fp a, const SM2_Fp b){if (bn_cmp(a, b) >= 0) {bn_sub(r, a, b);}else{SM2_BN t;bn_sub(t, SM2_P, b);bn_add(r, t, a);}}void fp_dbl(SM2_Fp r, const SM2_Fp a){fp_add(r, a, a);}void fp_tri(SM2_Fp r, const SM2_Fp a){SM2_BN t = { 0 };fp_dbl(t, a);fp_add(r, t, a);}void fp_div2(SM2_Fp r, const SM2_Fp a){int i = 0;memcpy(r, a, sizeof(SM2_BN));if (r[0] & 0x01){bn_add(r, r, SM2_P);}for (i = 0; i < 7; i++) {r[i] = (r[i] >> 1) | ((r[i + 1] & 0x01) << 31);}r[i] >>= 1;}void bn_to_bits(const SM2_BN a, char bits[256]){int i, j;uint64_t w;for (i = 7; i >= 0; i--){w = a[i];for (j = 0; j < 32; j++){*bits++ = (w & 0x80000000) ? '1' : '0';w <<= 1;}}}void fn_add(SM2_Fn r, const SM2_Fn a, const SM2_Fn b){bn_add(r, a, b);if (bn_cmp(r, SM2_N) >= 0) {bn_sub(r, r, SM2_N);}}void fn_sub(SM2_Fn r, const SM2_Fn a, const SM2_Fn b){if (bn_cmp(a, b) >= 0) {bn_sub(r, a, b);}else {SM2_BN t;bn_add(t, a, SM2_N);bn_sub(r, t, b);}}/* bn288 only used in barrett reduction */static int bn288_cmp(const uint64_t a[9], const uint64_t b[9]){int i = 0;for (i = 8; i >= 0; i--) {if (a[i] > b[i]) return 1;if (a[i] < b[i]) return -1;}return 0;}static void bn288_add(uint64_t r[9], const uint64_t a[9], const uint64_t b[9]){int i = 0;r[0] = a[0] + b[0];for (i = 1; i < 9; i++) {r[i] = a[i] + b[i] + (r[i - 1] >> 32);}for (i = 0; i < 8; i++) {r[i] &= 0xffffffff;}}static void bn288_sub(uint64_t ret[9], const uint64_t a[9], const uint64_t b[9]){int i = 0;uint64_t r[9] = { 0 };r[0] = ((uint64_t)1 << 32) + a[0] - b[0];for (i = 1; i < 8; i++) {r[i] = 0xffffffff + a[i] - b[i] + (r[i - 1] >> 32);r[i - 1] &= 0xffffffff;}r[i] = a[i] - b[i] + (r[i - 1] >> 32) - 1;r[i - 1] &= 0xffffffff;for (i = 0; i < 9; i++) {ret[i] = r[i];}}void fn_mul(SM2_BN ret, const SM2_BN a, const SM2_BN b){SM2_BN r;static const uint64_t mu[9] = {0xf15149a0, 0x12ac6361, 0xfa323c01, 0x8dfc2096, 1, 1, 1, 1, 1,};uint64_t s[18] = { 0 };uint64_t zh[9] = { 0 };uint64_t zl[9] = { 0 };uint64_t q[9] = { 0 };uint64_t w = 0;int i = 0, j = 0;/* z = a * b */for (i = 0; i < 8; i++) {s[i] = 0;}for (i = 0; i < 8; i++) {w = 0;for (j = 0; j < 8; j++) {w += s[i + j] + a[i] * b[j];s[i + j] = w & 0xffffffff;w >>= 32;}s[i + 8] = w;}/* zl = z mod (2^32)^9 = z[0..8]* zh = z // (2^32)^7 = z[7..15] */for (i = 0; i < 9; i++){zl[i] = s[i];zh[i] = s[7 + i];}/* q = zh * mu // (2^32)^9 */for (i = 0; i < 9; i++) {s[i] = 0;}for (i = 0; i < 9; i++) {w = 0;for (j = 0; j < 9; j++) {w += s[i + j] + zh[i] * mu[j];s[i + j] = w & 0xffffffff;w >>= 32;}s[i + 9] = w;}for (i = 0; i < 8; i++) {q[i] = s[9 + i];}/* q = q * n mod (2^32)^9 */for (i = 0; i < 17; i++) {s[i] = 0;}for (i = 0; i < 8; i++) {w = 0;for (j = 0; j < 8; j++){w += s[i + j] + q[i] * SM2_N[j];s[i + j] = w & 0xffffffff;w >>= 32;}s[i + 8] = w;}for (i = 0; i < 9; i++) {q[i] = s[i];}/* r = zl - q (mod (2^32)^9) */if (bn288_cmp(zl, q)) {bn288_sub(zl, zl, q);}else {uint64_t c[9] = { 0,0,0,0,0,0,0,0,0x100000000 };bn288_sub(q, c, q);bn288_add(zl, q, zl);}for (i = 0; i < 8; i++) {r[i] = zl[i];}r[7] += zl[8] << 32;/* while r >= p do: r = r - n */while (bn_cmp(r, SM2_N) >= 0){bn_sub(r, r, SM2_N);}memcpy(ret, r, sizeof(SM2_BN));}void fn_sqr(SM2_BN r, const SM2_BN a){fn_mul(r, a, a);}void fn_exp(SM2_BN r, const SM2_BN a, const SM2_BN e){SM2_BN t = { 0 };uint32_t w = 0;int i = 0, j = 0;bn_set_word(t, 1);for (i = 7; i >= 0; i--) {w = (uint32_t)e[i];for (j = 0; j < 32; j++) {fn_sqr(t, t);if (w & 0x80000000) {fn_mul(t, t, a);}w <<= 1;}}memcpy(r, t, sizeof(SM2_BN));}void fn_inv(SM2_BN r, const SM2_BN a){SM2_BN e = { 0 };bn_sub(e, SM2_N, SM2_TWO);fn_exp(r, a, e);}void jacobian_point_set_xy(SM2_JACOBIAN_POINT* R, const SM2_BN x, const SM2_BN y){memcpy(R->X, x, sizeof(SM2_BN));memcpy(R->Y, y, sizeof(SM2_BN));bn_set_word(R->Z, 1);}void jacobian_point_get_xy(const SM2_JACOBIAN_POINT* P, SM2_BN x, SM2_BN y){if (bn_is_one(P->Z)) {memcpy(x, P->X, sizeof(SM2_BN));if (y) {memcpy(y, P->Y, sizeof(SM2_BN));}}else {SM2_BN z_inv;fp_inv(z_inv, P->Z);if (y) {fp_mul(y, P->Y, z_inv);}fp_sqr(z_inv, z_inv);fp_mul(x, P->X, z_inv);if (y) {fp_mul(y, y, z_inv);}}}void jacobian_point_init(SM2_JACOBIAN_POINT* R){memset(R, 0, sizeof(SM2_JACOBIAN_POINT));R->X[0] = 1;R->Y[0] = 1;}int jacobian_point_is_on_curve(const SM2_JACOBIAN_POINT* P){SM2_BN t0 = { 0 };SM2_BN t1 = { 0 };SM2_BN t2 = { 0 };if (bn_is_one(P->Z)) {fp_sqr(t0, P->Y);fp_add(t0, t0, P->X);fp_add(t0, t0, P->X);fp_add(t0, t0, P->X);fp_sqr(t1, P->X);fp_mul(t1, t1, P->X);fp_add(t1, t1, SM2_B);}else {fp_sqr(t0, P->Y);fp_sqr(t1, P->Z);fp_sqr(t2, t1);fp_mul(t1, t1, t2);fp_mul(t1, t1, SM2_B);fp_mul(t2, t2, P->X);fp_add(t0, t0, t2);fp_add(t0, t0, t2);fp_add(t0, t0, t2);fp_sqr(t2, P->X);fp_mul(t2, t2, P->X);fp_add(t1, t1, t2);}if (bn_cmp(t0, t1) != 0) {return -1;}return 1;}void jacobian_point_dbl(SM2_JACOBIAN_POINT* R, const SM2_JACOBIAN_POINT* P){const uint64_t* X1 = P->X;const uint64_t* Y1 = P->Y;const uint64_t* Z1 = P->Z;SM2_BN T1 = { 0 };SM2_BN T2 = { 0 };SM2_BN T3 = { 0 };SM2_BN X3 = { 0 };SM2_BN Y3 = { 0 };SM2_BN Z3 = { 0 };if (bn_is_zero(P->Z)) {memcpy(R, P, sizeof(SM2_JACOBIAN_POINT));return;}fp_sqr(T1, Z1);fp_sub(T2, X1, T1);fp_add(T1, X1, T1);fp_mul(T2, T2, T1);fp_tri(T2, T2);fp_dbl(Y3, Y1);fp_mul(Z3, Y3, Z1);fp_sqr(Y3, Y3);fp_mul(T3, Y3, X1);fp_sqr(Y3, Y3);fp_div2(Y3, Y3);fp_sqr(X3, T2);fp_dbl(T1, T3);fp_sub(X3, X3, T1);fp_sub(T1, T3, X3);fp_mul(T1, T1, T2);fp_sub(Y3, T1, Y3);memcpy(R->X, X3, sizeof(SM2_BN));memcpy(R->Y, Y3, sizeof(SM2_BN));memcpy(R->Z, Z3, sizeof(SM2_BN));}void jacobian_point_add(SM2_JACOBIAN_POINT* R, const SM2_JACOBIAN_POINT* P, const SM2_JACOBIAN_POINT* Q){const uint64_t* X1 = P->X;const uint64_t* Y1 = P->Y;const uint64_t* Z1 = P->Z;const uint64_t* x2 = Q->X;const uint64_t* y2 = Q->Y;SM2_BN T1 = { 0 };SM2_BN T2 = { 0 };SM2_BN T3 = { 0 };SM2_BN T4 = { 0 };SM2_BN X3 = { 0 };SM2_BN Y3 = { 0 };SM2_BN Z3 = { 0 };if (bn_is_zero(Q->Z)) {memcpy(R, P, sizeof(SM2_JACOBIAN_POINT));return;}if (bn_is_zero(P->Z)) {memcpy(R, Q, sizeof(SM2_JACOBIAN_POINT));return;}if (bn_is_one(Q->Z) == 0) {return;}fp_sqr(T1, Z1);fp_mul(T2, T1, Z1);fp_mul(T1, T1, x2);fp_mul(T2, T2, y2);fp_sub(T1, T1, X1);fp_sub(T2, T2, Y1);if (bn_is_zero(T1)) {if (bn_is_zero(T2)) {SM2_JACOBIAN_POINT _Q, * Q = &_Q;jacobian_point_set_xy(Q, x2, y2);jacobian_point_dbl(R, Q);return;}else {jacobian_point_init(R);return;}}fp_mul(Z3, Z1, T1);fp_sqr(T3, T1);fp_mul(T4, T3, T1);fp_mul(T3, T3, X1);fp_dbl(T1, T3);fp_sqr(X3, T2);fp_sub(X3, X3, T1);fp_sub(X3, X3, T4);fp_sub(T3, T3, X3);fp_mul(T3, T3, T2);fp_mul(T4, T4, Y1);fp_sub(Y3, T3, T4);memcpy(R->X, X3, sizeof(SM2_BN));memcpy(R->Y, Y3, sizeof(SM2_BN));memcpy(R->Z, Z3, sizeof(SM2_BN));}void jacobian_point_mul(SM2_JACOBIAN_POINT* R, const SM2_BN k, const SM2_JACOBIAN_POINT* P){char bits[257] = { 0 };SM2_JACOBIAN_POINT _Q, * Q = &_Q;SM2_JACOBIAN_POINT _T, * T = &_T;int i;if (!bn_is_one(P->Z)) {SM2_BN x = { 0 };SM2_BN y = { 0 };jacobian_point_get_xy(P, x, y);jacobian_point_set_xy(T, x, y);P = T;}jacobian_point_init(Q);bn_to_bits(k, bits);for (i = 0; i < 256; i++) {jacobian_point_dbl(Q, Q);if (bits[i] == '1') {jacobian_point_add(Q, Q, P);}}memcpy(R, Q, sizeof(SM2_JACOBIAN_POINT));}void jacobian_point_to_bytes(const SM2_JACOBIAN_POINT* P, uint8_t out[64]){SM2_BN x = { 0 };SM2_BN y = { 0 };jacobian_point_get_xy(P, x, y);bn_to_bytes(x, out);bn_to_bytes(y, out + 32);}void jacobian_point_mul_generator(SM2_JACOBIAN_POINT* R, const SM2_BN k){jacobian_point_mul(R, k, SM2_G);}/* R = t * P + s * G */void jacobian_point_mul_sum(SM2_JACOBIAN_POINT* R, const SM2_BN t, const SM2_JACOBIAN_POINT* P, const SM2_BN s){SM2_JACOBIAN_POINT _sG, * sG = &_sG;SM2_BN x = { 0 };SM2_BN y = { 0 };/* T = s * G */jacobian_point_mul_generator(sG, s);// R = t * Pjacobian_point_mul(R, t, P);jacobian_point_get_xy(R, x, y);jacobian_point_set_xy(R, x, y);// R = R + Tjacobian_point_add(R, sG, R);}int sm2_point_is_on_curve(const SM2_POINT* P){SM2_JACOBIAN_POINT T;jacobian_point_from_bytes(&T, (const uint8_t*)P);return jacobian_point_is_on_curve(&T);}int kdf(const uint8_t* in, size_t inlen, size_t outlen, uint8_t* out){sm3_context ctx;uint8_t counter_be[4];uint8_t dgst[32];uint32_t counter = 1;size_t len;while (outlen) {PUTU32(counter_be, counter);counter++;SM3::Starts(&ctx);SM3::Update(&ctx, (uint8_t*)in, (int)inlen);SM3::Update(&ctx, counter_be, sizeof(counter_be));SM3::Finish(&ctx, dgst);len = outlen < 32 ? outlen : 32;memcpy(out, dgst, len);out += len;outlen -= len;}memset(&ctx, 0, sizeof(sm3_context));memset(dgst, 0, sizeof(dgst));return 1;}static int all_zero(const uint8_t* buf, size_t len){size_t i = 0;for (i = 0; i < len; i++) {if (buf[i]) {return 0;}}return 1;}void gm_memxor(void* r, const void* a, const void* b, size_t len){uint8_t* pr = (uint8_t*)r;const uint8_t* pa = (const uint8_t*)a;const uint8_t* pb = (const uint8_t*)b;size_t i;for (i = 0; i < len; i++) {pr[i] = pa[i] ^ pb[i];}}int asn1_length_to_der(size_t len, uint8_t** out, size_t* outlen){if (len > INT_MAX) {return -1;}if (!outlen) {return -1;}if (len < 128) {if (out && *out) {*(*out)++ = (uint8_t)len;}(*outlen)++;}else {uint8_t buf[4] = { 0 };int nbytes = 0;if (len < 256) nbytes = 1;else if (len < 65536) nbytes = 2;else if (len < (1 << 24)) nbytes = 3;else nbytes = 4;PUTU32(buf, (uint32_t)len);if (out && *out) {*(*out)++ = 0x80 + nbytes;memcpy(*out, buf + 4 - nbytes, nbytes);(*out) += nbytes;}(*outlen) += 1 + nbytes;}return 1;}int asn1_length_from_der(size_t* len, const uint8_t** in, size_t* inlen){if (!len || !in || !(*in) || !inlen) {return -1;}if (*inlen == 0) {return -1;}if (**in < 128) {*len = *(*in)++;(*inlen)--;}else {uint8_t buf[4] = { 0 };size_t nbytes = *(*in)++ & 0x7f;(*inlen)--;if (nbytes < 1 || nbytes > 4) {return -1;}if (*inlen < nbytes) {return -1;}memcpy(buf + 4 - nbytes, *in, nbytes);*len = (size_t)GETU32(buf);*in += nbytes;*inlen -= nbytes;}// check if the left input is enough for readingif (*inlen < *len) {return -2;}return 1;}int asn1_integer_to_der_ex(int tag, const uint8_t* a, size_t alen, uint8_t** out, size_t* outlen){if (!outlen) {return -1;}if (!a) {return 0;}if (alen <= 0 || alen > INT_MAX) {return -1;}if (out && *out) {*(*out)++ = tag;}(*outlen)++;while (*a == 0 && alen > 1) {a++;alen--;}if (a[0] & 0x80) {asn1_length_to_der(alen + 1, out, outlen);if (out && *out) {*(*out)++ = 0x00;memcpy(*out, a, alen);(*out) += alen;}(*outlen) += 1 + alen;}else {asn1_length_to_der(alen, out, outlen);if (out && *out) {memcpy(*out, a, alen);(*out) += alen;}(*outlen) += alen;}return 1;}//02200000FD0A697866AA1C79237AB65F740E24D9098C0846710EF692E187AA740BEF//022000009286DCB4F8183AE098FB3817749F46FE15B9822AC20483D4BD037590BA6C//022100917A0B39FBF089EC08D291A44E8171960F80BE6346A1AC97BCDD0642C69FE801int asn1_integer_from_der_32(int tag, const uint8_t** a, size_t* alen, const uint8_t** in, size_t* inlen){size_t len = 0;if (!a || !alen || !in || !(*in) || !inlen){return -1;}// tagif (*inlen == 0 || **in != tag) {*a = NULL;*alen = 0;return 0;}(*in)++;(*inlen)--;// length (not zero)if (asn1_length_from_der(&len, in, inlen) != 1) {return -1;}if (len == 0) {return -1;}// check if ASN1_INTEGER is negativeif (**in & 0x80) {return -1;}// remove leading zeroif (**in == 0 && len == 33) {(*in)++;(*inlen)--;len--;}// return integer bytes*a = *in;*alen = len;*in += len;*inlen -= len;return 1;}int asn1_header_to_der(int tag, size_t dlen, uint8_t** out, size_t* outlen){if (!outlen) {return -1;}if (out && *out) {*(*out)++ = (uint8_t)tag;}(*outlen)++;(void)asn1_length_to_der(dlen, out, outlen);return 1;}int asn1_type_to_der(int tag, const uint8_t* d, size_t dlen, uint8_t** out, size_t* outlen){if (!outlen) {return -1;}if (!d) {if (dlen) {return -1;}return 0;}// tagif (out && *out) {*(*out)++ = (uint8_t)tag;}(*outlen)++;// length(void)asn1_length_to_der(dlen, out, outlen);// dataif (out && *out) {memcpy(*out, d, dlen);*out += dlen;}*outlen += dlen;return 1;}int asn1_type_from_der(int tag, const uint8_t** d, size_t* dlen, const uint8_t** in, size_t* inlen){if (!d || !dlen || !in || !(*in) || !inlen) {return -1;}// tagif (*inlen == 0 || **in != tag) {*d = NULL;*dlen = 0;return 0;}(*in)++;(*inlen)--;// lengthif (asn1_length_from_der(dlen, in, inlen) != 1) {return -1;}// data*d = *in;*in += *dlen;*inlen -= *dlen;return 1;}int asn1_check(int expr){if (expr) {return 1;}return -1;}int asn1_length_is_zero(size_t len){if (len) {return -1;}return 1;}int asn1_length_le(size_t len1, size_t len2){if (len1 > len2) {return -1;}return 1;}int ciphertext_to_der(const SM2_CIPHERTEXT* C, uint8_t** out, size_t* outlen){size_t len = 0;if (!C) {return 0;}if (asn1_integer_to_der_ex(ASN1_TAG_INTEGER, C->point.x, 32, NULL, &len) != 1|| asn1_integer_to_der_ex(ASN1_TAG_INTEGER, C->point.y, 32, NULL, &len) != 1|| asn1_type_to_der(ASN1_TAG_OCTET_STRING, C->hash, 32, NULL, &len) != 1|| asn1_type_to_der(ASN1_TAG_OCTET_STRING, C->ciphertext, C->ciphertext_size, NULL, &len) != 1|| asn1_header_to_der(ASN1_TAG_SEQUENCE, len, out, outlen) != 1|| asn1_integer_to_der_ex(ASN1_TAG_INTEGER, C->point.x, 32, out, outlen) != 1|| asn1_integer_to_der_ex(ASN1_TAG_INTEGER, C->point.y, 32, out, outlen) != 1|| asn1_type_to_der(ASN1_TAG_OCTET_STRING, C->hash, 32, out, outlen) != 1|| asn1_type_to_der(ASN1_TAG_OCTET_STRING, C->ciphertext, C->ciphertext_size, out, outlen) != 1) {return -1;}return 1;}int ciphertext_from_der(SM2_CIPHERTEXT* C, const uint8_t** in, size_t* inlen){int ret = 0;const uint8_t* d = nullptr;size_t dlen = 0;const uint8_t* x = nullptr;const uint8_t* y = nullptr;const uint8_t* hash = nullptr;const uint8_t* c = nullptr;size_t xlen = 0, ylen = 0, hashlen = 0, clen = 0;if ((ret = asn1_type_from_der(ASN1_TAG_SEQUENCE, &d, &dlen, in, inlen)) != 1) {return ret;}if (asn1_integer_from_der_32(ASN1_TAG_INTEGER, &x, &xlen, &d, &dlen) != 1|| asn1_length_le(xlen, 32) != 1) {return -1;}if (asn1_integer_from_der_32(ASN1_TAG_INTEGER, &y, &ylen, &d, &dlen) != 1|| asn1_length_le(ylen, 32) != 1) {return -1;}if (asn1_type_from_der(ASN1_TAG_OCTET_STRING, &hash, &hashlen, &d, &dlen) != 1|| asn1_check(hashlen == 32) != 1) {return -1;}if (asn1_type_from_der(ASN1_TAG_OCTET_STRING, &c, &clen, &d, &dlen) != 1|| asn1_length_le(clen, SM2_MAX_PLAINTEXT_SIZE) != 1) {return -1;}if (asn1_length_is_zero(dlen) != 1) {return -1;}memset(C, 0, sizeof(SM2_CIPHERTEXT));memcpy(C->point.x + 32 - xlen, x, xlen);memcpy(C->point.y + 32 - ylen, y, ylen);if (sm2_point_is_on_curve(&C->point) != 1) {return -1;}memcpy(C->hash, hash, hashlen);memcpy(C->ciphertext, c, clen);C->ciphertext_size = (uint32_t)clen;return 1;}int signature_to_der(const SM2_SIGNATURE* sig, uint8_t** out, size_t* outlen){size_t len = 0;if (!sig) {return 0;}if (asn1_integer_to_der_ex(ASN1_TAG_INTEGER, sig->r, 32, NULL, &len) != 1|| asn1_integer_to_der_ex(ASN1_TAG_INTEGER, sig->s, 32, NULL, &len) != 1|| asn1_header_to_der(ASN1_TAG_SEQUENCE, len, out, outlen) != 1|| asn1_integer_to_der_ex(ASN1_TAG_INTEGER, sig->r, 32, out, outlen) != 1|| asn1_integer_to_der_ex(ASN1_TAG_INTEGER, sig->s, 32, out, outlen) != 1) {return -1;}return 1;}int signature_from_der(SM2_SIGNATURE* sig, const uint8_t** in, size_t* inlen){int ret = 0;const uint8_t* d = nullptr;size_t dlen = 0;const uint8_t* r = nullptr;size_t rlen = 0;const uint8_t* s = nullptr;size_t slen = 0;if ((ret = asn1_type_from_der(ASN1_TAG_SEQUENCE, &d, &dlen, in, inlen)) != 1) {return ret;}if (asn1_integer_from_der_32(ASN1_TAG_INTEGER, &r, &rlen, &d, &dlen) != 1|| asn1_integer_from_der_32(ASN1_TAG_INTEGER, &s, &slen, &d, &dlen) != 1|| asn1_length_le(rlen, 32) != 1|| asn1_length_le(slen, 32) != 1|| asn1_length_is_zero(dlen) != 1) {return -1;}memset(sig, 0, sizeof(*sig));memcpy(sig->r + 32 - rlen, r, rlen);memcpy(sig->s + 32 - slen, s, slen);return 1;}int do_encrypt(const SM2_KEY* key, const uint8_t* in, size_t inlen, SM2_CIPHERTEXT* out){SM2_BN k = { 0 };SM2_JACOBIAN_POINT _P, * P = &_P;SM2_JACOBIAN_POINT _C1, * C1 = &_C1;SM2_JACOBIAN_POINT _kP, * kP = &_kP;uint8_t x2y2[64] = { 0 };sm3_context sm3_ctx;if (!(SM2_MIN_PLAINTEXT_SIZE <= inlen && inlen <= SM2_MAX_PLAINTEXT_SIZE)) {return -1;}jacobian_point_from_bytes(P, (uint8_t*)&key->public_key);// S = h * P, check S != O// for sm2 curve, h == 1 and S == P// SM2_POINT can not present point at infinity, do do nothing hereretry:// rand k in [1, n - 1]do {if (fn_rand(k) != 1) {return -1;}} while (bn_is_zero(k));// output C1 = k * G = (x1, y1)jacobian_point_mul_generator(C1, k);jacobian_point_to_bytes(C1, (uint8_t*)&out->point);// k * P = (x2, y2)jacobian_point_mul(kP, k, P);jacobian_point_to_bytes(kP, x2y2);// t = KDF(x2 || y2, inlen)kdf(x2y2, 64, inlen, out->ciphertext);// if t is all zero, retryif (all_zero(out->ciphertext, inlen)) {goto retry;}// output C2 = M xor tgm_memxor(out->ciphertext, out->ciphertext, in, inlen);out->ciphertext_size = (uint32_t)inlen;// output C3 = Hash(x2 || m || y2)SM3::Starts(&sm3_ctx);SM3::Update(&sm3_ctx, x2y2, 32);SM3::Update(&sm3_ctx, (uint8_t*)in, inlen);SM3::Update(&sm3_ctx, x2y2 + 32, 32);SM3::Finish(&sm3_ctx, out->hash);memset(k, 0, sizeof(k));memset(kP, 0, sizeof(SM2_JACOBIAN_POINT));memset(x2y2, 0, sizeof(x2y2));return 1;}int do_decrypt(const SM2_KEY* key, const SM2_CIPHERTEXT* in, uint8_t* out, size_t* outlen){int ret = -1;SM2_BN d;SM2_JACOBIAN_POINT _C1, * C1 = &_C1;uint8_t x2y2[64];sm3_context sm3_ctx;uint8_t hash[32];// check C1 is on sm2 curvejacobian_point_from_bytes(C1, (uint8_t*)&in->point);if (!jacobian_point_is_on_curve(C1)) {return -1;}// check if S = h * C1 is point at infinity// this will not happen, as SM2_POINT can not present point at infinity// d * C1 = (x2, y2)bn_from_bytes(d, key->private_key);jacobian_point_mul(C1, d, C1);// t = KDF(x2 || y2, klen) and check t is not all zerosjacobian_point_to_bytes(C1, x2y2);kdf(x2y2, 64, in->ciphertext_size, out);if (all_zero(out, in->ciphertext_size)) {goto end;}// M = C2 xor tgm_memxor(out, out, in->ciphertext, in->ciphertext_size);*outlen = in->ciphertext_size;// u = Hash(x2 || M || y2)SM3::Starts(&sm3_ctx);SM3::Update(&sm3_ctx, x2y2, 32);SM3::Update(&sm3_ctx, out, in->ciphertext_size);SM3::Update(&sm3_ctx, x2y2 + 32, 32);SM3::Finish(&sm3_ctx, hash);// check if u == C3if (memcmp(in->hash, hash, sizeof(hash)) != 0) {goto end;}ret = 1;end:memset(d, 0, sizeof(d));memset(C1, 0, sizeof(SM2_JACOBIAN_POINT));memset(x2y2, 0, sizeof(x2y2));return ret;}int encrypt(const SM2_KEY* key, const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen){SM2_CIPHERTEXT C;if (!key || !in || !out || !outlen) {return -1;}if (!inlen) {return -1;}if (do_encrypt(key, in, inlen, &C) != 1) {return -1;}*outlen = 0;if (ciphertext_to_der(&C, &out, outlen) != 1) {return -1;}return 1;}int decrypt(const SM2_KEY* key, const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen){SM2_CIPHERTEXT C;if (!key || !in || !out || !outlen) {return -1;}if (ciphertext_from_der(&C, &in, &inlen) != 1|| asn1_length_is_zero(inlen) != 1) {return -1;}if (do_decrypt(key, &C, out, outlen) != 1) {return -1;}return 1;}int sm2_do_sign(const SM2_KEY* key, const uint8_t dgst[32], SM2_SIGNATURE* sig){SM2_JACOBIAN_POINT _P, * P = &_P;SM2_BN d;SM2_BN d_inv;SM2_BN e;SM2_BN k;SM2_BN x;SM2_BN t;SM2_BN r;SM2_BN s;bn_from_bytes(d, key->private_key);// compute (d + 1)^-1 (mod n)fn_add(d_inv, d, SM2_ONE);if (bn_is_zero(d_inv)) {return -1;}fn_inv(d_inv, d_inv);// e = H(M)bn_from_bytes(e, dgst);retry:// rand k in [1, n - 1]do {if (fn_rand(k) != 1) {return -1;}} while (bn_is_zero(k));// (x, y) = kGjacobian_point_mul_generator(P, k);jacobian_point_get_xy(P, x, NULL);// r = e + x (mod n)if (bn_cmp(e, SM2_N) >= 0) {bn_sub(e, e, SM2_N);}if (bn_cmp(x, SM2_N) >= 0) {bn_sub(x, x, SM2_N);}fn_add(r, e, x);// if r == 0 or r + k == n re-generate kbn_add(t, r, k);if (bn_is_zero(r) || bn_cmp(t, SM2_N) == 0) {goto retry;}// s = ((1 + d)^-1 * (k - r * d)) mod nfn_mul(t, r, d);fn_sub(k, k, t);fn_mul(s, d_inv, k);// check s != 0if (bn_is_zero(s)) {goto retry;}bn_to_bytes(r, sig->r);bn_to_bytes(s, sig->s);memset(d, 0, sizeof(d));memset(d_inv, 0, sizeof(d_inv));memset(k, 0, sizeof(k));memset(t, 0, sizeof(t));return 1;}int do_verify(const SM2_KEY* key, const uint8_t dgst[32], const SM2_SIGNATURE* sig){SM2_JACOBIAN_POINT _P, * P = &_P;SM2_JACOBIAN_POINT _R, * R = &_R;SM2_BN r;SM2_BN s;SM2_BN e;SM2_BN x;SM2_BN t;// parse public keyjacobian_point_from_bytes(P, (const uint8_t*)&key->public_key);// parse signature valuesbn_from_bytes(r, sig->r);bn_from_bytes(s, sig->s);// check r, s in [1, n-1]if (bn_is_zero(r) == 1|| bn_cmp(r, SM2_N) >= 0|| bn_is_zero(s) == 1|| bn_cmp(s, SM2_N) >= 0) {return -1;}// e = H(M)bn_from_bytes(e, dgst);// t = r + s (mod n), check t != 0fn_add(t, r, s);if (bn_is_zero(t)) {return -1;}// Q = s * G + t * Pjacobian_point_mul_sum(R, t, P, s);jacobian_point_get_xy(R, x, NULL);// r' = e + x (mod n)if (bn_cmp(e, SM2_N) >= 0) {bn_sub(e, e, SM2_N);}if (bn_cmp(x, SM2_N) >= 0) {bn_sub(x, x, SM2_N);}fn_add(e, e, x);// check if r == r'if (bn_cmp(e, r) != 0) {return -1;}return 1;}int sign(const SM2_KEY* key, const uint8_t dgst[32], uint8_t* sigbuf, size_t* siglen, bool rawRS){SM2_SIGNATURE sig;if (!key || !dgst || !sigbuf || !siglen) {return -1;}if (sm2_do_sign(key, dgst, &sig) != 1) {return -1;}if (rawRS){*siglen = sizeof(SM2_SIGNATURE);memcpy(sigbuf, &sig, *siglen);return 1;}*siglen = 0;if (signature_to_der(&sig, &sigbuf, siglen) != 1) {return -1;}return 1;}int verify(const SM2_KEY* key, const uint8_t dgst[32], const uint8_t* sigbuf, size_t siglen, bool rawRS){SM2_SIGNATURE sig;if (!key || !dgst || !sigbuf || !siglen){return -1;}if (rawRS){if (siglen != sizeof(SM2_SIGNATURE)) {return -1;}memcpy(&sig, sigbuf, siglen);}else{if (signature_from_der(&sig, &sigbuf, &siglen) != 1|| asn1_length_is_zero(siglen) != 1) {return -1;}}if (do_verify(key, dgst, &sig) != 1) {return -1;}return 1;}int compute_z(uint8_t z[32], const SM2_POINT* pub, const char* id, size_t idlen){sm3_context ctx;uint8_t zin[18 + 32 * 6] = {0x00, 0x80,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFC,0x28,0xE9,0xFA,0x9E,0x9D,0x9F,0x5E,0x34,0x4D,0x5A,0x9E,0x4B,0xCF,0x65,0x09,0xA7,0xF3,0x97,0x89,0xF5,0x15,0xAB,0x8F,0x92,0xDD,0xBC,0xBD,0x41,0x4D,0x94,0x0E,0x93,0x32,0xC4,0xAE,0x2C,0x1F,0x19,0x81,0x19,0x5F,0x99,0x04,0x46,0x6A,0x39,0xC9,0x94,0x8F,0xE3,0x0B,0xBF,0xF2,0x66,0x0B,0xE1,0x71,0x5A,0x45,0x89,0x33,0x4C,0x74,0xC7,0xBC,0x37,0x36,0xA2,0xF4,0xF6,0x77,0x9C,0x59,0xBD,0xCE,0xE3,0x6B,0x69,0x21,0x53,0xD0,0xA9,0x87,0x7C,0xC6,0x2A,0x47,0x40,0x02,0xDF,0x32,0xE5,0x21,0x39,0xF0,0xA0,};if (!z || !pub || !id) {return -1;}memcpy(&zin[18 + 32 * 4], pub->x, 32);memcpy(&zin[18 + 32 * 5], pub->y, 32);SM3::Starts(&ctx);if (strcmp(id, SM2_DEFAULT_ID) == 0) {SM3::Update(&ctx, zin, sizeof(zin));}else {uint8_t idbits[2];idbits[0] = (uint8_t)(idlen >> 5);idbits[1] = (uint8_t)(idlen << 3);SM3::Update(&ctx, idbits, 2);SM3::Update(&ctx, (uint8_t*)id, idlen);SM3::Update(&ctx, zin + 18, 32 * 6);}SM3::Finish(&ctx, z);return 1;}int sign_init(sm3_context* ctx, const SM2_KEY* key, const char* id, size_t idlen){if (!ctx || !key) {return -1;}SM3::Starts(ctx);if (id) {uint8_t z[32];if (idlen <= 0 || idlen > SM2_MAX_PLAINTEXT_SIZE) {return -1;}compute_z(z, &key->public_key, id, idlen);SM3::Update(ctx, z, sizeof(z));}return 1;}int sign_update(sm3_context* ctx, const uint8_t* data, size_t datalen){if (!ctx) {return -1;}if (data && datalen > 0) {SM3::Update(ctx, (uint8_t*)data, datalen);}return 1;}int sign_finish(sm3_context* ctx, const SM2_KEY* key, uint8_t* sig, size_t* siglen, bool rawRS){uint8_t dgst[32];if (!ctx || !key || !sig || !siglen) {return -1;}SM3::Finish(ctx, dgst);if (sign(key, dgst, sig, siglen, rawRS) != 1) {return -1;}return 1;}int verify_init(sm3_context* ctx, const SM2_KEY* key, const char* id, size_t idlen){if (!ctx || !key) {return -1;}SM3::Starts(ctx);if (id) {uint8_t z[32];if (idlen <= 0 || idlen > SM2_MAX_PLAINTEXT_SIZE) {return -1;}compute_z(z, &key->public_key, id, idlen);SM3::Update(ctx, z, sizeof(z));}return 1;}int verify_update(sm3_context* ctx, const uint8_t* data, size_t datalen){if (!ctx) {return -1;}if (data && datalen > 0) {SM3::Update(ctx, (uint8_t*)data, datalen);}return 1;}int verify_finish(sm3_context* ctx, const SM2_KEY* key, const uint8_t* sig, size_t siglen, bool rawRS){uint8_t dgst[32];if (!ctx || !sig) {return -1;}SM3::Finish(ctx, dgst);if (verify(key, dgst, sig, siglen, rawRS) != 1) {return -1;}return 1;}int GetPubKeyOfCerStr(const char* cer, size_t cerLen, char* pubKey){if (!cer || !cerLen || cer[0] != '0') {return 0;}unsigned char subjectPublicKeyHead[25] = { 0 };subjectPublicKeyHead[0] = '\x30';//表示一个Sequence(Subject Public Key Info)subjectPublicKeyHead[1] = '\x59';//后续字节数subjectPublicKeyHead[2] = '\x30';//表示一个Sequence(Public Key Algorithm)subjectPublicKeyHead[3] = '\x13';//后续字节数subjectPublicKeyHead[4] = '\x06';//表示一个ObjectID:1.2.840.10045.2.1 Elliptic curve public key cryptographysubjectPublicKeyHead[5] = '\x07';//后续字节数subjectPublicKeyHead[6] = '\x2A';subjectPublicKeyHead[7] = '\x86';subjectPublicKeyHead[8] = '\x48';subjectPublicKeyHead[9] = '\xCE';subjectPublicKeyHead[10] = '\x3D';subjectPublicKeyHead[11] = '\x02';subjectPublicKeyHead[12] = '\x01';subjectPublicKeyHead[13] = '\x06';//表示一个ObjectID:1.2.156.10197.1.301 "SM2" elliptic curve cryptographysubjectPublicKeyHead[14] = '\x08';//后续字节数subjectPublicKeyHead[15] = '\x2A';subjectPublicKeyHead[16] = '\x81';subjectPublicKeyHead[17] = '\x1C';subjectPublicKeyHead[18] = '\xCF';subjectPublicKeyHead[19] = '\x55';subjectPublicKeyHead[20] = '\x01';subjectPublicKeyHead[21] = '\x82';subjectPublicKeyHead[22] = '\x2D';subjectPublicKeyHead[23] = '\x03';//表示一个BitString类型(Public-Key)subjectPublicKeyHead[24] = '\x42';//后续字节数size_t hdrLen = sizeof(subjectPublicKeyHead);unsigned char ch;for (size_t i = 0; i < cerLen - hdrLen; i++) {if (memcmp(cer + i, subjectPublicKeyHead, hdrLen) == 0) {for (size_t j = 2; j < 0x42; j++) {ch = (cer[i + hdrLen + j] & 0xf0) >> 4;pubKey[(j - 2) * 2] = (ch > 9) ? ch + 'A' - 10 : ch + '0';ch = cer[i + hdrLen + j] & 0x0f;pubKey[(j - 2) * 2 + 1] = (ch > 9) ? ch + 'A' - 10 : ch + '0';}return 1;}}return 0;}
};#endif // !__SM2_H__
5.2 单元测试
void TestSM2()
{const char* priKey = "ee9751a685f4f1ca1ef355b15b937475f90757c6ea930f04a3242901a13b94a2";const char* pubKey = "04de16070290a70b3457fef7651c5e3be8902b5d589f3d0b80efc5f4e38a78d0e7d09b9d82acc2f31eb6314f831f0766cf644c1d5856794b9106b5f964b7b6fb5d";const char* pMsg = "Hello, World,I love 中国.";SM2 sm2;// 初始化密钥if (!sm2.InitKey(priKey, pubKey)){std::cout << "初始化SM2密钥失败" << std::endl;return;}std::cout << "测试数据:" << strlen(pMsg) << "," << pMsg << std::endl;// 签名char hex[512] = { 0 };char sign[128] = { 0 };size_t len = sizeof(sign);if (!sm2.SM2Sign((unsigned char*)pMsg, strlen(pMsg), (unsigned char*)sign, &len) || len == 0){std::cout << "生成签名失败" << std::endl;return;}size_t out_len = sizeof(hex);memset(hex, 0, sizeof(hex));SM2::Bin2Hex(sign, len, hex, out_len);std::cout << "生成签名成功" << std::endl;if (!sm2.SM2Verify((unsigned char*)pMsg, strlen(pMsg), (unsigned char*)sign, len)){std::cout << "签名校验失败" << std::endl;return;}std::cout << "签名校验成功:" << out_len << "," << hex << std::endl;// 加密char ciphertext[512] = { 0 };len = sizeof(ciphertext);if (!sm2.SM2Encrypt((unsigned char*)pMsg, strlen(pMsg), (unsigned char*)ciphertext, &len)){std::cout << "加密失败" << std::endl;return;}out_len = sizeof(hex);memset(hex, 0, sizeof(hex));SM2::Bin2Hex(ciphertext, len, hex, out_len);std::cout << "加密成功:" << out_len << "," << hex << std::endl;char text[512] = { 0 };size_t text_len = sizeof(text);if (!sm2.SM2Decrypt((unsigned char*)ciphertext, len, (unsigned char*)text, &text_len)){std::cout << "解密失败" << std::endl;return;}std::cout << "解密成功:" << text_len << "," << text << std::endl;
}
5.3 输出结果
测试数据:26,Hello, World,I love 中国.
生成签名成功
签名校验成功:144,3046022100945d19ee176dae52533cf0a8af25030204020131d5ac232a0ed1bdb806b2d76d022100b3cdf47895c5e3c390442f7436b0f902b2eb5c8723a70ff8479fcec0b8adae63
加密成功:270,308184022100c1a0e063e981a544f974a9aacd1dd5e193f31378ec52d79e1d4522cd8f0200a0022100de6137f68384f86735c7af776525ab42b1177574305ddeec3f2547161da3ca6a042044e04f1bd288027c43eb99c6a6b1c2071a440f27f07194e0308dfa7530841c26041a926716f58ad2d5bd0c451df6ce1bdef976c608ed03aaf2f7f21f
解密成功:26,Hello, World,I love 中国.
六、结语
SM2作为我国密码技术的核心成果,已在政务、金融、物联网等领域大规模应用。其设计融合了ECC的高效性与抗量子特性,结合国密标准生态(如SM3/SM4),构建了自主可控的安全体系。未来随着抗量子算法的演进,SM2将在后量子密码时代持续发挥关键作用。