/* * SM2算法是基于ECC算法的,签名同样返回2个大数,共64byte。由于原来RSA算法已很普遍支持, * 要实现RSA的签名验签都有标准库的实现,而SM2是国密算法在国际上还没有标准通用,算法Oid标识在X509标准中是没定义的。 * 在.Net或Java中可以基于使用BouncyCastle加密库实现,开源的也比较好学习扩展。SM2算法验签可以使用软验签, * 即可以不需要使用硬件设备,同样使用原始数据、签名、证书(公钥)来实现对签名方验证,保证数据完整性未被篡改。 * 验证过程同样需先摘要原文数据,公钥在证书中是以一个66byte的BitString,去掉前面标记位即64byte为共钥坐标(x,y), * 中间分割截取再以Hex方式转成BigInteger大数计算,验签代码如下: */ /// <summary> /// /// </summary> /// <param name="md">消息</param> /// <param name="userD">秘钥</param> /// <param name="userKey">公钥</param> /// <param name="sm2Ret">sm2Ret集合</param> public virtual void Sm2Sign(byte[] md, BigInteger userD, ECPoint userKey, SM2Result sm2Ret) { // e BigInteger e = new BigInteger(1, md); //字节转化大整数 // k BigInteger k = null; //初始定义大数k为空 ECPoint kp = null; //定义kp点为空 BigInteger r = null; //定义大数r为空,保存求得的r值 BigInteger s = null; //定义大数r为空,保存求得的s值 do { do { if (!sm2Test)//产生随机数k { AsymmetricCipherKeyPair keypair = ecc_key_pair_generator.GenerateKeyPair(); ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)keypair.Private; //产生私钥 ECPublicKeyParameters ecpub = (ECPublicKeyParameters)keypair.Public; //产生公钥 k = ecpriv.D; //产生真正的k kp = ecpub.Q; //kp=生成元 } else//如果产生不了则手动添加 { string kS = "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F6CB28D99385C175C94F94E9348176240B"; k = new BigInteger(kS, 16); kp = ecc_point_g.Multiply(k); } // r r = e.Add(kp.X.ToBigInteger()); //r=e+kp坐标点的X r = r.Mod(ecc_n); //对r进行模n运算,防止越界 }while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n)); //r==或者0当r==n时跳出循环 // (1 + dA)~-1 BigInteger da_1 = userD.Add(BigInteger.One); //da_1=秘钥+1; da_1 = da_1.ModInverse(ecc_n); //对da_1求逆运算 // s s = r.Multiply(userD); //s=r*秘钥 s = k.Subtract(s).Mod(ecc_n); //s=((k-s)%n); s = da_1.Multiply(s).Mod(ecc_n); //s=((da_1*s)%n) }while (s.Equals(BigInteger.Zero)); //s==0的时候跳出循环 sm2Ret.r = r; sm2Ret.s = s; }
/* * SM2算法是基于ECC算法的,签名同样返回2个大数,共64byte。由于原来RSA算法已很普遍支持, * 要实现RSA的签名验签都有标准库的实现,而SM2是国密算法在国际上还没有标准通用,算法Oid标识在X509标准中是没定义的。 * 在.Net或Java中可以基于使用BouncyCastle加密库实现,开源的也比较好学习扩展。SM2算法验签可以使用软验签, * 即可以不需要使用硬件设备,同样使用原始数据、签名、证书(公钥)来实现对签名方验证,保证数据完整性未被篡改。 * 验证过程同样需先摘要原文数据,公钥在证书中是以一个66byte的BitString,去掉前面标记位即64byte为共钥坐标(x,y), * 中间分割截取再以Hex方式转成BigInteger大数计算,验签代码如下: */ /// <summary> /// /// </summary> /// <param name="md">消息</param> /// <param name="userD">秘钥</param> /// <param name="userKey">公钥</param> /// <param name="sm2Ret">sm2Ret集合</param> public virtual void Sm2Sign(byte[] md, BigInteger userD, ECPoint userKey, SM2Result sm2Ret) { // e BigInteger e = new BigInteger(1, md); //字节转化大整数 // k BigInteger k; //初始定义大数k为空 ECPoint kp; //定义kp点为空 BigInteger r; //定义大数r为空,保存求得的r值 BigInteger s; //定义大数r为空,保存求得的s值 do { do { AsymmetricCipherKeyPair keypair = ecc_key_pair_generator.GenerateKeyPair(); ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters)keypair.Private; //产生私钥 ECPublicKeyParameters ecpub = (ECPublicKeyParameters)keypair.Public; //产生公钥 k = ecpriv.D; //产生真正的k kp = ecpub.Q; //this.ecc_point_g.Multiply(k); //新加 // r r = e.Add(kp.XCoord.ToBigInteger()); //r=e+kp坐标点的X r = r.Mod(ecc_n); //对r进行模n运算,防止越界 }while (r.Equals(BigInteger.Zero) || r.Add(k).Equals(ecc_n)); //r==或者0当r==n时跳出循环 // (1 + dA)~-1 BigInteger da_1 = userD.Add(BigInteger.One); //da_1=秘钥+1; da_1 = da_1.ModInverse(ecc_n); //对da_1求逆运算 // s s = r.Multiply(userD); //s=r*秘钥 s = k.Subtract(s).Mod(ecc_n); //s=((k-s)%n); s = da_1.Multiply(s).Mod(ecc_n); //s=((da_1*s)%n) }while (s.Equals(BigInteger.Zero)); //s==0的时候跳出循环 sm2Ret.r = r; sm2Ret.s = s; }
/// <summary> /// /// </summary> /// <param name="md">消息</param> /// <param name="userKey">公钥</param> /// <param name="r">由数字签名得到的大数r</param> /// <param name="s">由数字签名得到的大数s</param> /// <param name="sm2Ret"></param> public virtual void Sm2Verify(byte[] md, ECPoint userKey, BigInteger r, BigInteger s, SM2Result sm2Ret)//客户端验证 { sm2Ret.R = null; // e_ BigInteger e = new BigInteger(1, md); //字节转化大整数e // t BigInteger t = r.Add(s).Mod(ecc_n); //大数t=(r+s)%n; if (t.Equals(BigInteger.Zero)) //如果t==0,返回上一层 { return; } // x1y1 ECPoint x1y1 = ecc_point_g.Multiply(sm2Ret.s); //x1y1=g*s x1y1 = x1y1.Add(userKey.Multiply(t)); //x1y1=x1y1+公钥*(t),其中t=(r+s)%n // R sm2Ret.R = e.Add(x1y1.X.ToBigInteger()).Mod(ecc_n);//r=(x1y1点的X的大数形式+e)%n }