gm-sm
Version:
sm2
212 lines (209 loc) • 7.13 kB
JavaScript
const {SM3Digest} = require('./sm3');
const {KJUR} = require('./KJUR');
const {CryptoJS} = require('./core');
const {ECPointFp} = require('./ec');
const {BigInteger} = require('./jsbn');
const SM2CipherMode = {
C1C2C3: '0',
C1C3C2: '1'
};
function SM2Cipher(cipherMode) {
this.ct = 1;
this.p2 = null;
this.sm3keybase = null;
this.sm3c3 = null;
this.key = new Array(32);
this.keyOff = 0;
if (typeof (cipherMode) != 'undefined') {
this.cipherMode = cipherMode
} else {
this.cipherMode = SM2CipherMode.C1C3C2
}
}
SM2Cipher.prototype = {
Reset: function () {
this.sm3keybase = new SM3Digest();
this.sm3c3 = new SM3Digest();
var xWords = this.byteConvert32Bytes(this.p2.getX().toBigInteger());
var yWords = this.byteConvert32Bytes(this.p2.getY().toBigInteger());
this.sm3keybase.BlockUpdate(xWords, 0, xWords.length);
this.sm3c3.BlockUpdate(xWords, 0, xWords.length);
this.sm3keybase.BlockUpdate(yWords, 0, yWords.length);
this.ct = 1;
this.NextKey()
},
NextKey: function () {
var sm3keycur = new SM3Digest(this.sm3keybase);
sm3keycur.Update((this.ct >> 24 & 0x00ff));
sm3keycur.Update((this.ct >> 16 & 0x00ff));
sm3keycur.Update((this.ct >> 8 & 0x00ff));
sm3keycur.Update((this.ct & 0x00ff));
sm3keycur.DoFinal(this.key, 0);
this.keyOff = 0;
this.ct++
},
InitEncipher: function (userKey) {
var k = null;
var c1 = null;
var ec = new KJUR.crypto.ECDSA({
"curve": "sm2"
});
var keypair = ec.generateKeyPairHex();
k = new BigInteger(keypair.ecprvhex, 16);
var pubkeyHex = keypair.ecpubhex;
c1 = ECPointFp.decodeFromHex(ec.ecparams['curve'], pubkeyHex);
this.p2 = userKey.multiply(k);
this.Reset();
return c1
},
EncryptBlock: function (data) {
this.sm3c3.BlockUpdate(data, 0, data.length);
for (var i = 0; i < data.length; i++) {
if (this.keyOff == this.key.length) {
this.NextKey()
}
data[i] ^= this.key[this.keyOff++]
}
},
InitDecipher: function (userD, c1) {
this.p2 = c1.multiply(userD);
this.Reset()
},
DecryptBlock: function (data) {
for (var i = 0; i < data.length; i++) {
if (this.keyOff == this.key.length) {
this.NextKey()
}
data[i] ^= this.key[this.keyOff++]
}
this.sm3c3.BlockUpdate(data, 0, data.length)
},
Dofinal: function (c3) {
var yWords = this.byteConvert32Bytes(this.p2.getY().toBigInteger());
this.sm3c3.BlockUpdate(yWords, 0, yWords.length);
this.sm3c3.DoFinal(c3, 0);
this.Reset()
},
Encrypt: function (pubKey, plaintext) {
var data = new Array(plaintext.length);
Array.Copy(plaintext, 0, data, 0, plaintext.length);
var c1 = this.InitEncipher(pubKey);
this.EncryptBlock(data);
var c3 = new Array(32);
this.Dofinal(c3);
var hexString = this.bin2hex(c1.getEncoded(false))
+ this.bin2hex(data) + this.bin2hex(c3);
if (this.cipherMode == SM2CipherMode.C1C3C2) {
hexString = this.bin2hex(c1.getEncoded(false))
+ this.bin2hex(c3) + this.bin2hex(data)
}
return hexString
},
GetWords: function (hexStr) {
var words = [];
var hexStrLength = hexStr.length;
for (var i = 0; i < hexStrLength; i += 2) {
words[words.length] = parseInt(hexStr.substr(i, 2), 16)
}
return words
},
byteConvert32Bytes: function (n) {
var tmpd = [];
if (n == null) {
return tmpd;
}
if (n.toByteArray().length == 33) {
tmpd = new Array(32);
Array.Copy(n.toByteArray(), 1, tmpd, 0, 32);
}
else if (n.toByteArray().length == 32) {
tmpd = n.toByteArray();
}
else {
tmpd = new Array(32);
for (var i = 0; i < 32 - n.toByteArray().length; i++) {
tmpd[i] = 0;
}
Array.Copy(n.toByteArray(), 0, tmpd, 32 - n.toByteArray().length, n.toByteArray().length);
}
for (var i = 0; i < 32; i++) {
tmpd[i] &= 0xFF;
}
return tmpd
},
bin2hex: function (arr) {
var base = "0123456789abcdef";
var result = "";
for (var i = 0; i < arr.length; i++) {
var c = arr[i] & 0xff;
result += base.charAt(c >>> 4);
result += base.charAt(c & 0xf);
}
return result;
},
str2Bytes: function (str) {
var pos = 0;
var len = str.length;
if (len % 2 != 0) {
return null;
}
var hexA = new Array();
for (; pos < len; pos += 2) {
var b1 = parseInt(str.charAt(pos), 16);
var b2 = parseInt(str.charAt(pos + 1), 16);
var v = ((b1 << 4) | b2);
hexA.push(v);
}
return hexA;
},
GetHex: function (arr) {
var words = [];
var j = 0;
for (var i = 0; i < arr.length * 2; i += 2) {
words[i >>> 3] |= parseInt(arr[j]) << (24 - (i % 8) * 4);
j++
}
var wordArray = new CryptoJS.lib.WordArray.init(words, arr.length);
return wordArray
},
Decrypt: function (privateKey, ciphertext) {
var hexString = ciphertext;
var c1X = hexString.substr(0, 130);
var encrypData = hexString.substr(c1X.length,
hexString.length - c1X.length - 64);
var c3 = hexString.substr(hexString.length - 64);
if (this.cipherMode == SM2CipherMode.C1C3C2) {
c3 = hexString.substr(c1X.length, 64);
encrypData = hexString.substr(c1X.length + 64)
}
var data = this.str2Bytes(encrypData);
var c1 = this.CreatePoint(c1X);
this.InitDecipher(privateKey, c1);
this.DecryptBlock(data);
var c3_ = new Array(32);
this.Dofinal(c3_);
var isDecrypt = this.bin2hex(c3_).toString() == c3;
if (isDecrypt) {
var wordArray = CryptoJS.enc.Hex.parse(this.bin2hex(data));
var decryptData = CryptoJS.enc.Utf8.stringify(wordArray);
return decryptData
} else {
return ''
}
},
CreatePoint: function (pubkeyHex) {
var ec = new KJUR.crypto.ECDSA({
"curve": "sm2"
});
var ecc_curve = ec.ecparams['curve'];
var point = ECPointFp.decodeFromHex(ec.ecparams['curve'], pubkeyHex);
return point
}
};
// window.SM2CipherMode = {
// C1C2C3: '0',
// C1C3C2: '1'
// };
module.exports = {
SM2Cipher
};