目录
前言
1.概述:
2.术语解读:(简单的这里不做解释,具体请看文末文档)
3.基础参数:
4.密钥对生成
4.1 公私钥原理
4.2 公私钥的生成
4.2.1 私钥:
4.2.2 签证书:
4.2.3 用私钥对证书进行自签名
4.2.4 证书格式转换
4.2.5 查看证书内容
5.签名算法
5.1 预处理1
5.2 预处理2
5.3数字签名的生成算法及流程
5.4数字签名的验证算法及流程
经历过国密的坑,这里来对国密进行总结。本篇主要讲的SM2国密算法。
先来个SM2和RSA比较
SM2是国家密码管理局于2010年12月17日发布的“椭圆曲线公钥密码算法”。这里附上国家密码管理局发布这篇算法的公告地址:http://www.sca.gov.cn/sca/xwdt/2010-12/17/content_1002386.shtml。本篇博客基本是对这篇算法的粗浅解读,具体密码算法精髓,则需要你们自行领悟了。
SM2和椭圆曲线算法是什么关系?
一提起曲线,大家就会想到方程,椭圆曲线算法是通过方程确定的,SM2算法采用的椭圆曲线方程为:
y2 = x3 + ax + b 。在SM2算法标准中,通过指定a、b系数,确定了唯一的标准曲线。同时,为了将曲线映射为加密算法,SM2标准中还确定了其它参数,供算法程序使用。
椭圆曲线算法是什么原理?
本文不探讨椭圆曲线的数学理论,仅通过图示展示算法原理。请参见下图:
上图为方程:y2 = x3–x的曲线。
1、P点为基点;
2、通过P点做切线,交与点 2P点,在2P’点做竖线,交与2P点,2P点即为P点的2倍点;
3、进一步,P点和2P点之间做直线,交与3P’点,在3P’点做竖线,交与3P点,3P点即为P点的3倍点;
4、同理,可以计算出P点的4、5、6、… 倍点;
5、如果给定图上Q点是P的一个倍点,请问Q是P的几倍点呢?
6、直观上理解,正向计算一个倍点是容易的,反向计算一个点是P的几倍点则困难的多。
在椭圆曲线算法中,将倍数d做为私钥,将Q做为公钥。当然,椭圆曲线算法还有更严格的计算过程,相对图示要复杂的多。
数字签名算法由一个签名者对数据产生数字签名,并由一个验证者验证签名的可靠性。每个签名者都有一个公钥和一个私钥,其中私钥用于产生签名,验证者用签名者的公钥验证签名。在签名的生成过程之前,要用密码杂凑算法对 ZA和待签消息 M
M进行压缩;在验证过程之前,要用密码杂凑算法对 ZA 和待签消息 M进行同样的压缩。
杂凑函数 hash function:将一个比特串映射为一个固定长度比特串的函数。该函数满足如下性质:
a) 对于任意给定的输出,要找到其对应的输入,在计算上是不可行的;
b) 对于任意给定的输入,要找到输出相同的另一个输入,在计算上是不可行的。注:计算可行性依赖于具体的安全需求和环境。
椭圆曲线系统参数包括有限域Fq的规模q(当q=时,还包括元素表示法的标识和约化多项式); 定义椭圆曲线E(Fq)的方程的两个元素a、b∈Fq;E(Fq)上的基点G=(x,yG) (G̸=O),其中xG和yG是Fq中 的两个元素;G的阶n及其它可选项(如n的余因子h等)。
在前后端SM2加解密签名应用中,请预先商定一组称为椭圆曲线域参数的系统参数。椭圆曲线域参数生成需要大量的计算,耗时较长,一旦生成之后可以长期、广泛地使用,因此通常由可信的机构经过反复生成不同的椭圆曲线域参数并挑选出安全性和性能俱佳的公布为标准(推荐参数)。我们在用java bc库,或者GMSSL,亦或OpenSSL 加密库SM2签名的时候,请确认你们的椭圆曲线域参数一致,否则联调不通。(一般库默认256比特的素数域椭圆曲线域参数)
这里用GMSSL命令生成SM2证书。
gmssl ecparam -genkey -name sm2p256v1 -text -out user.key
gmssl req -new -key user.key -out user.req。 签证书会提示以下信息:
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value。
证书包含唯一标示,从安全角度考虑建议用公司名或者个人唯一标示,不要用默认。
gmssl x509 -req -days 3650 -sm3 -in user.req -signkey user.key -out user.crt。有效期建议一年。
crt转cer :gmssl x509 -inform pem -in user.crt -outform der -out user.cer
cer转p12:openssl pkcs12 -export -clcerts -in user.cer -inkey prikey.pem -out shfft.p12
crt转p12:将client.crt和client.key转换为pkcs12:
openssl pkcs12 -export -in client.crt -inkey client.key -out client.p12
查看EC私钥文件
cat attestation_key.pem
查看crt :gmssl x509 -in user.crt -text -noout
查看cer: gmssl x509 -in user.cer -inform der -text -noout
openssl 生成SM2的公私钥的方法,可参考链接:https://blog.csdn.net/dong_beijing/article/details/81365060。(具体是否可行还未验证)
我们在用java bc库,或者GMSSL,亦或OpenSSL 加密库SM2签名的时候,库通常会给我们设置默认值ID为1234567812345678,或者[email protected]。我们在前后端进行联调的时候,请确认ID必须一致,否则联调肯定不通。可以前后端统一设置为一样。没有设置的话,库会采用默认值,这时候请注意库不同可能默认值不同。个人建议安全性的话不要用默认值,统一设置。
预处理2是指使用Z值和待签名消息,通过SM3运算得到杂凑值H的过程。杂凑值H用于SM2数字签名。
输入: Z:字节串,预处理2的输入
M:字节串,待签名消息
输出: H:字节串,杂凑值
计算公式:H=SM3(Z∣∣M)
SM2签名是指使用预处理2的结果和签名者的私钥,通过签名计算得到签名结果的过程。
输入:d SM2PrivateKey,签名者私钥
H 字节串,预处理2的结果
输出:sign SM2Signature,签名值
先来看张流程图
sign SM2Signature,签名值。最终输出的签名值,不同的库可能输出不同。比如java BC库最终输出的是base64的字符串;OpenSSl,GMSSL输出的是16进制;还有C实现的算法库输出的R和S字符串,不同库之间使用要注意转换。其中R,S的如何转换成base64一个签名值字符串,可以使用OpenSSL里的Api来转换如下代码。而java bc库里是R,S用ASN1编码后得到base64的签名结果。我逆推并没成功,具体bc库怎么ASN1编码还有待查看源码
BIGNUM *a = NULL;
BIGNUM *b = NULL;
const char *signR = [strR cStringUsingEncoding:NSUTF8StringEncoding];
const char *signS = [strS cStringUsingEncoding:NSUTF8StringEncoding];
BN_hex2bn(&a,signR);
BN_hex2bn(&b,signS);
ECDSA_SIG *sm2sigTemp = ECDSA_SIG_new();
int setSIG = ECDSA_SIG_set0(sm2sigTemp, a, b);
if (!setSIG) {
return nil;
}
unsigned char *pp = NULL;
int toChar = i2d_ECDSA_SIG(sm2sigTemp, &pp);
if (!toChar) {
return nil;
}
unsigned char sm2signature[toChar];
memcpy(sm2signature, pp, toChar);
NSString *signResult =[FFT_Base64 base64StringFromData:[NSData dataWithBytes:sm2signature length:toChar]];
SM2签名验证是指使用预处理2的结果、签名值和签名者的公钥,通过验签计算确定签名是否通过验证的过程。
输入:H 字节串,预处理2的结果
sign SM2Signature,签名值
Q PublicKey,签名者的公钥
输出:为真表示验证通过,为假表示验证不通过
https://www.cnblogs.com/wsonepiece/p/3977021.html
目前java bc库和基于OpenSSL 的C 算法库能够很好的实现SM2加解密算法和签名。而java bc 和GMSSL也能够实现,并得到验证,但是没有项目应用。但是最新的OpenSSL库也支持SM2了,但是和java bc库对接时,出现bc库签名的内容,OpenSSL库可以验证通过,OpenSSL库签名的内容,java bc库却不能够验证通过,这是个坑,具体内容为什么,因为缺乏比较懂 java bc库的人员配合,导致一致没有找到原因搁浅。
最后感谢博主zcc0721,主要参考他的文章,写得非常好。
参考链接:https://blog.csdn.net/u013137970/article/details/84573200#1__2
https://www.cnblogs.com/wsonepiece/p/3977021.html
国家密码管理局关于发布《SM2椭圆曲线公钥密码算法》公告:http://www.sca.gov.cn/sca/xwdt/2010-12/17/content_1002386.shtml
个人Github文档地址:https://github.com/yazhouZhang/SM2-SM3-SM4-SM9