国密SM2算法的java和nodejs实现
来源:互联网 发布:淘宝招牌图片素材尺寸 编辑:程序博客网 时间:2024/05/29 14:00
转至 http://mp.weixin.qq.com/s/nboZAvg1qYiJIEun6yF2aQ
国密即国家密码局认定的国产密码算法,即商用密码。包括对称加密(SM1) ,非对称加密(SM2) , 信息摘要(SM3). 本文介绍SM2
SM2 基于 ECC实现。.国家密码局推荐ECC曲线是256位,相当于比特币的secp256k1.
SM2 数学计算过程可以参考国家密码局官网的公布文档
本文介绍SM2 签名验签的java和nodejs的实现
ECC 算法依赖两个重要的数学运算 1,大数运算,2,椭圆乘法运算。
Java 中天生有BigInteger类,椭圆乘法运算可以借助于开源的java加密库:bouncycastle ,gradle 工程添加依赖:
compile ‘org.bouncycastle:bcprov-jdk15on:1.55’
下面就贴代码吧
~~~
public class SM2
{
//测试参数
// public static final String[] ecc_param = {
// “8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3”,
// “787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498”,
// “63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A”,
// “8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7”,
// “421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D”,
// “0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2”
// };
//正式参数
public static String[] ecc_param = {
“FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF”,
“FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC”,
“28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93”,
“FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123”,
“32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7”,
“BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0”
};
public static SM2 Instance()
{
return new SM2();
}
public final BigInteger ecc_p;
public final BigInteger ecc_a;
public final BigInteger ecc_b;
public final BigInteger ecc_n;
public final BigInteger ecc_gx;
public final BigInteger ecc_gy;
public final ECCurve ecc_curve;
public final ECPoint ecc_point_g;
public final ECDomainParameters ecc_bc_spec;
public final ECKeyPairGenerator ecc_key_pair_generator;
public final ECFieldElement ecc_gx_fieldelement;
public final ECFieldElement ecc_gy_fieldelement;
public SM2()
{
this.ecc_p = new BigInteger(ecc_param[0], 16);
this.ecc_a = new BigInteger(ecc_param[1], 16);
this.ecc_b = new BigInteger(ecc_param[2], 16);
this.ecc_n = new BigInteger(ecc_param[3], 16);
this.ecc_gx = new BigInteger(ecc_param[4], 16);
this.ecc_gy = new BigInteger(ecc_param[5], 16);
this.ecc_gx_fieldelement = new Fp(this.ecc_p, this.ecc_gx); this.ecc_gy_fieldelement = new Fp(this.ecc_p, this.ecc_gy); this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b); this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldelement, this.ecc_gy_fieldelement); this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n); ECKeyGenerationParameters ecc_ecgenparam; ecc_ecgenparam = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom()); this.ecc_key_pair_generator = new ECKeyPairGenerator(); this.ecc_key_pair_generator.init(ecc_ecgenparam);
}
}
签名代码片段:
public static BigInteger[] Sm2Sign(byte[] md, AsymmetricCipherKeyPair keypair) {
SM3Digest sm3 = new SM3Digest();
ECPublicKeyParameters ecpub = (ECPublicKeyParameters) keypair.getPublic();
byte[] hashData = new byte[32];
sm3.update(md, 0, md.length);
sm3.doFinal(hashData, 0);
// e
BigInteger e = new BigInteger(1, hashData);
// k
BigInteger k = null;
ECPoint kp = null;
BigInteger r = null;
BigInteger s = null;
BigInteger userD = null;
BigInteger ecc_n = null;
do {
do {
ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) keypair.getPrivate(); k = ecpriv.getD(); kp = ecpub.getQ(); ecc_n = ecpriv.getParameters().getN(); userD = ecpriv.getD(); // r = (e+x) mod n r = e.add(kp.getX().toBigInteger()); r = r.mod(ecc_n); } while (r.equals(BigInteger.ZERO) || r.add(k).equals(ecc_n)); //s= (((1 + dA)~-1) * (k - r*da )) mod n BigInteger da_1 = userD.add(BigInteger.ONE); da_1 = da_1.modInverse(ecc_n); // s s = r.multiply(userD); s = k.subtract(s).mod(ecc_n); s = da_1.multiply(s).mod(ecc_n); } while (s.equals(BigInteger.ZERO)); return new BigInteger[]{r, s};}
签验代码片段:
public static boolean Sm2verify(byte[] md, BigInteger r, BigInteger s, AsymmetricCipherKeyPair keypair) {
SM3Digest sm3 = new SM3Digest(); ECPublicKeyParameters ecpub = (ECPublicKeyParameters) keypair.getPublic(); byte[] hashData = new byte[32]; sm3.update(md, 0, md.length); sm3.doFinal(hashData, 0); // e BigInteger e = new BigInteger(1, hashData); // k ECPoint k; ECPoint G = null; ECPoint Pa = null; BigInteger t = null; BigInteger R = null; BigInteger ecc_n = null; Pa = ecpub.getQ(); G = ecpub.getParameters().getG(); ecc_n = ecpub.getParameters().getN(); if(r.equals(BigInteger.ONE) || r.equals(ecc_n)) { return false; } if(s.equals(BigInteger.ONE) || s.equals(ecc_n)) { return false; } t = r.add(s).mod(ecc_n); if (t.equals(BigInteger.ZERO)) { return false; } //k(x,y) = s*G + t*Pa k = G.multiply(s).add(Pa.multiply(t)); //R = (e+k.x) mod n R = e.add(k.getX().toBigInteger()).mod(ecc_n); //R == r true if (R.equals(r)) return true; return false;}
~~~
nodejs的实现方式
nodejs本身没有BigInteger的,但有牛人写了个BigInteger ,https://www.npmjs.com/package/biginteger
椭圆运算:https://github.com/cryptocoinjs/ecurve
有这两基本运算,就可以按国密局文档编写我们的SM2算法了
下面直接贴代码吧
~~~
var ecurve = require(‘ecurve’);
var Point = ecurve.Point;
var BigInteger = require(‘bigi’);
var Curve = ecurve.Curve;
var assert = require(‘assert’)
var SM2=getCurveSM2();
function getCurveSM2() {
var curve = {
p: “FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF”,
a: “FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC”,
b: “28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93”,
n: “FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123”,
h: “01”,
Gx: “32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7”,
Gy: “BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0”
}
if (!curve) return nullvar p = new BigInteger(curve.p, 16)var a = new BigInteger(curve.a, 16)var b = new BigInteger(curve.b, 16)var n = new BigInteger(curve.n, 16)var h = new BigInteger(curve.h, 16)var Gx = new BigInteger(curve.Gx, 16)var Gy = new BigInteger(curve.Gy, 16)return new Curve(p, a, b, Gx, Gy, n, h)
}
function getQ(d) {
var D = BigInteger.fromBuffer(d);
var G = SM2.G
var Q = G.multiply(D);
return Q;
}
function decodeFrom(buffer) {
return Point.decodeFrom(SM2,buffer);
}
function decodeFromXY(buffer) {
var byteLength = Math.floor((SM2.p.bitLength() + 7) / 8)
assert.equal(buffer.length, byteLength * 2, ‘Invalid sequence length’)
var x = BigInteger.fromBuffer(buffer.slice(0, byteLength))
var y = BigInteger.fromBuffer(buffer.slice(byteLength))
var Q = Point.fromAffine(SM2, x, y)
return Q;
}
function sign(hash, d) {
//var x = d.toBuffer(32)
var e = BigInteger.fromBuffer(hash)
var D = BigInteger.fromBuffer(d);
var n = SM2.n
var G = SM2.G
var Q = G.multiply(D);
var r, s;
do {
do {
r = e.add(Q.affineX);
r = r.mod(n);
}
while (r.equals(BigInteger.ZERO) || r.add(D).equals(n));
//s= (((1 + dA)~-1) * (k - r*da )) mod n var da_1 = D.add(BigInteger.ONE); da_1 = da_1.modInverse(n); // s s = r.multiply(D); s = D.subtract(s).mod(n); s = da_1.multiply(s).mod(n);}while (s.equals(BigInteger.ZERO));return {r:r.toBuffer(),s:s.toBuffer()};
}
function verify (hash, signature, Q) {
var n = SM2.n
var G = SM2.G
var r = BigInteger.fromBuffer(signature.r);var s = BigInteger.fromBuffer(signature.s);// 1.4.1 Enforce r and s are both integers in the interval [1, n − 1]if (r.signum() <= 0 || r.compareTo(n) >= 0) return falseif (s.signum() <= 0 || s.compareTo(n) >= 0) return false// 1.4.2 H = Hash(M), already done by the user// 1.4.3 e = Hvar e = BigInteger.fromBuffer(hash)var t;t = r.add(s).mod(n);if (t.equals(BigInteger.ZERO)) { return false;}//k(x,y) = s*G + t*Pavar k = G.multiply(s).add(Q.multiply(t));//R = (e+k.x) mod nR = e.add(k.affineX).mod(n);//R == r trueif (R.equals(r)) return true;return false;
}
module.exports = {
Curve: SM2,
Point:Point,
decodeFrom:decodeFrom,
decodeFromXY:decodeFromXY,
getQ:getQ,
sign: sign,
verify: verify
}
~~~
以上代码只是代码片段,需要完整工程的同学可以留下邮箱索取源代码
如果你喜欢这篇文章,请动动手指点击二维码关注本公众号
微信扫一扫
关注该公众号
- 国密SM2算法的java和nodejs实现
- SM2数字签名算法java实现
- 国密SM2算法密钥派生函数KDF的实现
- 国密SM2非对称算法与实现
- 国密SM2非对称算法与实现
- 国密SM2非对称算法与实现
- 国密SM2非对称算法与实现
- 国密SM2非对称算法与实现
- 国密SM2非对称算法与实现
- java sm2实现
- SM2算法第三篇:实现SM2秘钥交换协议的算法流程
- 国密SM2算法
- 国密SM2数字签名算法
- SM2算法第十三篇:SM2密钥协商协议的C语言实现
- 国密SM1\ SM2\ SM3\ SM4\ SSF33算法和国际RSA算法的对应关系
- SM2算法第五篇:socket的基本原理与实现
- 终于把JAVA的SM2算法搞出来了!!!!!!!!!!!!!!!!!!!!!
- 使用miracl实现国密sm2算法
- base64乱码
- bzoj2957分块或线段树
- 高斯噪声与高斯滤波
- Python Numpy入门
- 光纤跳线电信级和网络级相关知识
- 国密SM2算法的java和nodejs实现
- 我喜欢培根
- 理解RESTful架构
- C#--WinForm项目核心模块 --用DataTable绑定下拉框的数据源
- maven项目中找不到Maven Dependencies解决办法
- com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'id' cannot be n
- dedecms实现在线留言功能
- 事件回放:因「鹿晗、关晓彤」公布恋情,微博瘫痪了……
- 新能源车企新财路!双积分政策引出450亿元大蛋糕【附下载】| 智东西内参