二简单介绍了一下理论,三来简单说下sm2签名的实现,
首先因为openssl太复杂没搞懂,就去看gmssl的代码,gmssl的密钥结构体很简单,长这个样子:
typedef struct {
SM2_POINT public_key;
uint8_t private_key[32];
} SM2_KEY;
typedef struct {
uint8_t x[32];
uint8_t y[32];
} SM2_POINT;
很明显公钥是一个点由xy两个坐标组成,私钥是一个长串。
sm2签名过程可以大体上分成三步,生成公私钥——(交换密钥)——使用私钥进行签名——使用公钥验签。
在gmssl中直接使用sm2_key_generate(&sm2_key)函数,生成密钥并将密钥置入结构体中,或者直接使用命令生成密钥也可以。
获取到密钥之后就对原报文进行签名,具体流程是:
原报文通过sm3算法(没错,sm2签名用了sm3算法)生成杂凑数据(也就是e值,e值好像是个通用的叫法?)(也叫做摘要),再将杂凑数据传递到签名函数中,通过私钥进行签名得到签名串。
为什么突然出现sm3呢?这里还需要解释sm3是什么东西,sm3是一种密码散列函数标准,他的特点是,将原数据不可逆的生成一串256位长度数据。这样签名起来就变得很简单。
具体实现如下:
int sm2_sign_pre(SM2_KEY *sm2_key,
unsigned char *msg,
unsigned char *dgst,
unsigned char *sig,
size_t *siglen ) {
int ret = 0;
sm3_digest(msg, strlen((char*)msg), dgst);
/* sm2_key_generate(&sm2_key); 生成私钥key和公钥*/
if ((ret = sm2_sign(sm2_key, dgst, sig, siglen)) != 1) {
fprintf(stderr, "signature failed\n");
}
else {
printf("signature success\n");
}
return ret;
}
而验签是当报文收到之后,对报文再次进行摘要(sm3生成杂凑数据),而签名串则拿去用公钥去解密,解密结果如果报文没有被篡改,那么将是相同的,验签通过,如果原报文经过篡改,那么sm3生成杂凑数据会变化,以至于对比结果不相同,验签无法通过
代码如下:
int sm2_verify_pre( SM2_KEY *pub_key,
unsigned char* msg,
unsigned char *dgst,
unsigned char *sig,
size_t siglen
) {
int ret;
sm3_digest(msg, strlen((char*)msg), dgst);
if ((ret = sm2_verify(pub_key, dgst, sig, siglen)) != 1) {
return ret;
}
else {
return 0;
}
}
版权归原作者 glodrar 所有, 如有侵权,请联系我们删除。