国密 SM2 的非对称签名验签过程
介绍
非对称加密确保了消息传输中的保密性,但是由于使用公钥加密,而公钥是分发出去的,可能泄露,谁都可以使用公钥加密发送消息。
因此为了保证收到的消息是由对应的发送者发出的,就需要用到非对称签名和验签逻辑,发送者通过自己的私钥进行对消息进行签名,
接收方通过公钥对消息进行验证签名。非对称签名还确保了消息在传输过程中未被篡改,还有不可否认性,因为理论上只有发送者才有私钥
椭圆曲线
椭圆曲线和公钥,私钥,和 SM2 的非对称加密解密是一致的,这里再重复提一下。
椭圆曲线是由一组方程描述的点的集合:
y2 = x3 + ax + b 其中 a, b 满足 (4a3 + 27b2 ≠ 0)
SM2 定义了一个 sm2p256v1 的椭圆曲线方程
各种参数
BigInteger p = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF");
BigInteger a = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC");
BigInteger b = FromHex("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93");
BigInteger n = FromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123");
BigInteger h = BigInteger.One;
Point G coord: (22963146547237050559479531362550074578802567295341616970375194840604139615431, 85132369209828568825618990617112496413088388631904505083283536607588877201568)
公钥,私钥
- 私钥:
可以随机生成一个 BigInteger d,必须符合区间 [1, n - 1]
- 公钥:
私钥 d * G(Point) 得到的一个 Point: Q
签名过程
私钥: d
userID: SM2 提供了一个默认的 userId "1234567812345678" 字符串的 byte 数组,可以修改
签名过程主要是为了得到 BigInteger r 和 BigInteger s
摘要过程
- d * G 生成 公钥点 Q
- 对 (userID.Length) * 8 >> 8, userID.Length, userID, 方程参数 A, B, 基点G(x,y), 公钥点 Q(x,y), 算出摘要 z
- 对 z, 原文 算出摘要 eHash: byte[32]
- 将 eHash 转成 BigInteger e
生成签名
- 随机生成一个 BigInteger k
- k * G 生成一个 Point(x, y) P
- BigInteger r = e + P.x
- BigInteger s = (k - r * d) / (d + 1)
发送方将 r,s 编码随着消息发送
验签过程
验签使用公钥点 Q 进行验签 对签名发过来的 BigInteger r, BigInteger s 进行验证
摘要过程
- 对 (userID.Length) * 8 >> 8, userID.Length, userID, 方程参数 A, B, 基点G(x,y), 公钥点 Q(x,y), 算出摘要 z
- 对 z, 原文 算出摘要 eHash: byte[32]
- 将 eHash 转成 BigInteger e
- 验证等式是否成立: r = e + (s * G + (r + s) * Q).x
证明过程:
已知条件
P = k * G
r = e + P.x
s = (k - r * d) / (d + 1)
公私钥关系 d * G = Q
e + (s * G + (r + s) * Q).x = e + P.x
s * G + (r + s) * Q = P
即要证明 s * G + r * Q + s * Q = k * G
s * G + s * Q + r * Q - k * G
∵ Q = d * G
= s * G + s * d * G + r * d * G - k * G
= (1 + d) * s * G + r * d * G - k * G
∵ s = (k - r * d) / (d + 1)
= (k - r * d) * G + r * d * G - k * G
= k * G - r * d * G + r * d * G - k * G
= k * G - k * G
= 0
总结
- 计算过程中省略了对求同余的计算
- 加密保证消息传输的保密,加签保证消息是由特定发送者发出,以及消息未被篡改
- SM2 算法中,签名过程使用私钥运算生成两个大数 (r, s) 验证过程则使用公钥来确认签名是否有效, 消息是否被篡改
- 有的机构在会约定不同的 userID