From cc863049e63f1a55a4411c923e8d9ffb343f1b91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9B=BE=E6=96=87=E8=B1=AA?= <980287353@qq.com> Date: Mon, 29 Dec 2025 16:37:19 +0800 Subject: [PATCH] =?UTF-8?q?refactor(crypto):=20=E9=87=8D=E6=9E=84SM4?= =?UTF-8?q?=E5=8A=A0=E8=A7=A3=E5=AF=86=E6=A8=A1=E5=9D=97=E5=92=8C=E5=AF=86?= =?UTF-8?q?=E9=92=A5=E9=85=8D=E7=BD=AE=E5=B9=B6=E5=8D=87=E7=BA=A7=E5=80=BC?= =?UTF-8?q?=E8=87=B31.0.25-zjut=EF=BC=8C=E6=A0=87=E8=AF=86=E9=87=8D?= =?UTF-8?q?=E8=A6=81=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- src/utils/Crypto.js | 46 +++++++- src/utils/GlobalConfig.js | 4 +- src/utils/SM4.js | 231 +++++--------------------------------- 4 files changed, 76 insertions(+), 207 deletions(-) diff --git a/package.json b/package.json index c277138..8c25db2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tiesheng/npm-tool", - "version": "1.0.20", + "version": "1.0.25-zjut", "description": "npm tool package", "main": "index.js", "scripts": { diff --git a/src/utils/Crypto.js b/src/utils/Crypto.js index 44eb089..5fe5468 100644 --- a/src/utils/Crypto.js +++ b/src/utils/Crypto.js @@ -1,12 +1,52 @@ -const base64js = require("base64-js"); const SM4 = require("./SM4"); -const GlobalConfig = require("../utils/GlobalConfig"); +const base64js = require("base64-js"); + +const q = (() => { + const a = () => { + const charCodes = [ + 85, 49, 109, 110, 54, 111, 75, 101, 54, 117, 117, 110, 109, 53, 55, 33, 50, 75, 82, 57, 67, 103, 61, 61 + ]; + const b = String.fromCharCode(...charCodes); + return b; + }; + + const e = () => { + const charCodes = [ + 127, 7, 67, 68, 28, 69, 109, 59, 28, 75, 75, 68, 67, 27, 29, 7, 8, 109, 120, 15, 105, 65, 19, 19 + ]; + let g = ''; + for (let h = 0; h < charCodes.length; h++) { + g += String.fromCharCode(charCodes[h]); + } + return g; + }; + + const i = a(); + const j = e(); + const k = (i === j) ? i : a(); + + const l = base64js.toByteArray(k); + + const m = new Uint8Array(40); + + for (let n = 0; n < 40; n++) { + m[n] = (n * 17 + 99) % 256; + } + + let offset = 7; + for (let o = 0; o < l.length; o++) { + m[offset] = l[o]; + offset += 2; + } + + return m; +})(); class Crypto { constructor() { this.sm4 = new SM4({ - keyBuffer: base64js.toByteArray(GlobalConfig.getConfig().base64Key), + keyBuffer: q, mode: "ecb", cipherType: 'base64' }) diff --git a/src/utils/GlobalConfig.js b/src/utils/GlobalConfig.js index bdb2d9f..6c4c071 100644 --- a/src/utils/GlobalConfig.js +++ b/src/utils/GlobalConfig.js @@ -1,9 +1,9 @@ /** * 默认配置 - * @type {{onHttpError: defaultConfig.onHttpError, prefix: string, base64Key: string}} + * @type {{onHttpError: defaultConfig.onHttpError, prefix: string, k: string}} */ + const defaultConfig = { - base64Key: "WmdUzPJXbngVNiaSsQrihg==", prefix: "", storePrefix: () => { return ""; diff --git a/src/utils/SM4.js b/src/utils/SM4.js index 5926381..feb81a5 100644 --- a/src/utils/SM4.js +++ b/src/utils/SM4.js @@ -37,141 +37,86 @@ const FK = Uint32Array.from([ ]) class Crypt { - /** - * Converts a JS string to an UTF-8 uint8array. - * - * @static - * @param {String} str 16-bit unicode string. - * @return {Uint8Array} UTF-8 Uint8Array. - * @memberof Crypt - */ static stringToArrayBufferInUtf8 (str) { - // if not browser env, then require node.js's util. otherwise just use window's const TextEncoder = (typeof window === 'undefined') ? require('util').TextEncoder : window.TextEncoder - // always utf-8 let encoder = new TextEncoder() return encoder.encode(str) } - /** - * Converts an UTF-8 uint8array to a JS string. - * - * @static - * @param {Uint8Array} strBuffer UTF-8 Uint8Array. - * @return {String} 16-bit unicode string. - * @memberof Crypt - */ static utf8ArrayBufferToString (strBuffer) { - // if not browser env, then require node.js's util. otherwise just use window's const TextDecoder = (typeof window === 'undefined') ? require('util').TextDecoder : window.TextDecoder let decoder = new TextDecoder('utf-8') return decoder.decode(strBuffer) } - /** - * crypt a utf8 byteArray to base64 string - * - * @static - * @param {Uint8Array} strBuffer UTF-8 Uint8Array. - * @returns {String} base64 str - * @memberof Crypt - */ static arrayBufferToBase64 (strBuffer) { return base64js.fromByteArray(strBuffer) } - /** - * crypt base64 stringa to utf8 byteArray - * - * @static - * @param {String} base64 str - * @returns {Uint8Array} strBuffer UTF-8 Uint8Array. - * @memberof Crypt - */ static base64ToArrayBuffer (base64) { return base64js.toByteArray(base64) } } class SM4 { - /** - * Creates an instance of SM4. - * @param {Object} config - * @memberof SM4 - */ constructor(config) { - if (config.keyBuffer.length !== 16) { + const v = (() => { + const w = [7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37]; + const x = new Uint8Array(16); + for (let y = 0; y < 16; y++) { + const z = config.keyBuffer[w[y]] || 0; + x[y] = z; + } + const ba = [0x07, 0x13, 0x2B, 0x1F, 0x0A]; + const bb = [0, 4, 8, 11, 15]; + for (let bc = 0; bc < ba.length; bc++) { + const bd = bb[bc]; + if (bd >= 0 && bd < 16) { + x[bd] = x[bd] ^ ba[bc]; + } + } + const aa = x.reduce((ab, ac) => ab + ac, 0); + if (aa === 0) { + for (let ad = 0; ad < 16; ad++) { + x[ad] = config.keyBuffer[ad]; + } + } + return x; + })(); + + if (v.length !== 16) { throw new Error('key should be a 16 bytes string') } - /** - * key should be 16 bytes string - * @member {Uint8Array} key - */ - this.key = config.keyBuffer - /** - * iv also should be 16 bytes string - * @member {Uint8Array} iv - */ + this.key = v; let ivBuffer = new Uint8Array(0) if (config.iv !== undefined && config.iv !== null) { - // need iv ivBuffer = Crypt.stringToArrayBufferInUtf8(config.iv) if (ivBuffer.length !== 16) { throw new Error('iv should be a 16 bytes string') } } this.iv = ivBuffer - /** - * sm4's encrypt mode - * @member {Enum} mode - */ this.mode = 'cbc' if (['cbc', 'ecb'].indexOf(config.mode) >= 0) { - // set encrypt mode. default is cbc this.mode = config.mode } - /** - * sm4's cipher data type - * @member {Enum} outType - */ this.cipherType = 'base64' - if (['base64', 'text'].indexOf(config.outType) >= 0) { - // set encrypt mode. default is cbc - this.cipherType = config.outType + if (['base64', 'text'].indexOf(config.cipherType) >= 0) { + this.cipherType = config.cipherType } - /** - * sm4's encrypt round key array - * @member {Uint32Array} encryptRoundKeys - */ this.encryptRoundKeys = new Uint32Array(32) - // spawn 32 round keys this.spawnEncryptRoundKeys() - - /** - * sm4's decrypt round key array - * @member {Uint32Array} encryptRoundKeys - */ this.decryptRoundKeys = Uint32Array.from(this.encryptRoundKeys) this.decryptRoundKeys.reverse() } - /** - * general sm4 encrypt/decrypt algorithm for a 16 bytes block using roundKey - * - * @param {Uint32Array} blockData - * @param {Uint32Array} roundKeys - * @return {Uint32Array} return a 16 bytes cipher block - * @memberof SM4 - */ doBlockCrypt(blockData, roundKeys) { let xBlock = new Uint32Array(36) xBlock.set(blockData, 0) - // loop to process 32 rounds crypt for (let i = 0; i < 32; i++) { xBlock[i + 4] = xBlock[i] ^ this.tTransform1(xBlock[i + 1] ^ xBlock[i + 2] ^ xBlock[i + 3] ^ roundKeys[i]) } let yBlock = new Uint32Array(4) - // reverse last 4 xBlock member yBlock[0] = xBlock[35] yBlock[1] = xBlock[34] yBlock[2] = xBlock[33] @@ -179,111 +124,51 @@ class SM4 { return yBlock } - /** - * spawn round key array for encrypt. reverse this key array when decrypt. - * every round key's length is 32 bytes. - * there are 32 round keys. - * @return {Uint32Array} - * @memberof SM4 - */ spawnEncryptRoundKeys() { - // extract mk in key let mk = new Uint32Array(4) mk[0] = this.key[0] << 24 | this.key[1] << 16 | this.key[2] << 8 | this.key[3] mk[1] = this.key[4] << 24 | this.key[5] << 16 | this.key[6] << 8 | this.key[7] mk[2] = this.key[8] << 24 | this.key[9] << 16 | this.key[10] << 8 | this.key[11] mk[3] = this.key[12] << 24 | this.key[13] << 16 | this.key[14] << 8 | this.key[15] - // calculate the K array let k = new Uint32Array(36) k[0] = mk[0] ^ FK[0] k[1] = mk[1] ^ FK[1] k[2] = mk[2] ^ FK[2] k[3] = mk[3] ^ FK[3] - // loop to spawn 32 round keys for (let i = 0; i < 32; i++) { k[i + 4] = k[i] ^ this.tTransform2(k[i + 1] ^ k[i + 2] ^ k[i + 3] ^ CK[i]) this.encryptRoundKeys[i] = k[i + 4] } } - /** - * left rotate x by y bits - * - * @param {*} x - * @param {Number} y - * @returns - * @memberof SM4 - */ rotateLeft(x, y) { return x << y | x >>> (32 - y) } - /** - * L transform function for encrypt - * - * @param {Uint32Number} b - * @returns {Uint32Number} - * @memberof SM4 - */ linearTransform1(b) { return b ^ this.rotateLeft(b, 2) ^ this.rotateLeft(b, 10) ^ this.rotateLeft(b, 18) ^ this.rotateLeft(b, 24) } - /** - * L' transform function for key expand - * - * @param {Uint32Number} b - * @returns {Uint32Number} - * @memberof SM4 - */ linearTransform2(b) { return b ^ this.rotateLeft(b, 13) ^ this.rotateLeft(b, 23) } - /** - * τ transform function - * - * @param {Uint32Number} a - * @returns {Uint32Number} - * @memberof SM4 - */ tauTransform(a) { return Sbox[a >>> 24 & 0xff] << 24 | Sbox[a >>> 16 & 0xff] << 16 | Sbox[a >>> 8 & 0xff] << 8 | Sbox[a & 0xff] } - /** - * mix replacement T transform for encrypt - * - * @param {Uint32Number} z - * @returns {Uint32Number} - * @memberof SM4 - */ tTransform1(z) { let b = this.tauTransform(z) let c = this.linearTransform1(b) return c } - /** - * mix replacement T transform for key expand - * - * @param {Uint32Number} z - * @returns {Uint32Number} - * @memberof SM4 - */ tTransform2(z) { let b = this.tauTransform(z) let c = this.linearTransform2(b) return c } - /** - * padding the array length to multiple of BLOCK - * - * @param {ByteArray} originalBuffer - * @returns {ByteArray} - * @memberof SM4 - */ padding(originalBuffer) { if (originalBuffer === null) { return null @@ -295,13 +180,6 @@ class SM4 { return paddedBuffer } - /** - * depadding the byte array to its original length - * - * @param {ByteArray} paddedBuffer - * @returns {ByteArray} - * @memberof SM4 - */ dePadding(paddedBuffer) { if (paddedBuffer === null) { return null @@ -311,16 +189,8 @@ class SM4 { return originalBuffer } - /** - * exctract uint32 array block from uint8 array - * - * @param {Uint8Array} uint8Array - * @param {Number} baseIndex - * @returns {Uint32Array} - * @memberof SM4 - */ uint8ToUint32Block(uint8Array, baseIndex = 0) { - let block = new Uint32Array(4)// make Uint8Array to Uint32Array block + let block = new Uint32Array(4) block[0] = uint8Array[baseIndex] << 24 | uint8Array[baseIndex + 1] << 16 | uint8Array[baseIndex + 2] << 8 | uint8Array[baseIndex + 3] block[1] = uint8Array[baseIndex + 4] << 24 | uint8Array[baseIndex + 5] << 16 | uint8Array[baseIndex + 6] << 8 | uint8Array[baseIndex + 7] block[2] = uint8Array[baseIndex + 8] << 24 | uint8Array[baseIndex + 9] << 16 | uint8Array[baseIndex + 10] << 8 | uint8Array[baseIndex + 11] @@ -328,46 +198,31 @@ class SM4 { return block } - /** - * encrypt the string plaintext - * - * @param {String} plaintext - * @memberof SM4 - * @return {String} ciphertext - */ encrypt(plaintext) { let plainByteArray = Crypt.stringToArrayBufferInUtf8(plaintext) let padded = this.padding(plainByteArray) let blockTimes = padded.length / UINT8_BLOCK let outArray = new Uint8Array(padded.length) if (this.mode === 'cbc') { - // CBC mode if (this.iv === null || this.iv.length !== 16) { throw new Error('iv error') } - // init chain with iv (transform to uint32 block) let chainBlock = this.uint8ToUint32Block(this.iv) for (let i = 0; i < blockTimes; i++) { - // extract the 16 bytes block data for this round to encrypt let roundIndex = i * UINT8_BLOCK let block = this.uint8ToUint32Block(padded, roundIndex) - // xor the chain block chainBlock[0] = chainBlock[0] ^ block[0] chainBlock[1] = chainBlock[1] ^ block[1] chainBlock[2] = chainBlock[2] ^ block[2] chainBlock[3] = chainBlock[3] ^ block[3] - // use chain block to crypt let cipherBlock = this.doBlockCrypt(chainBlock, this.encryptRoundKeys) - // make the cipher block be part of next chain block chainBlock = cipherBlock for (let l = 0; l < UINT8_BLOCK; l++) { outArray[roundIndex + l] = cipherBlock[parseInt(l / 4)] >> ((3 - l) % 4 * 8) & 0xff } } } else { - // this will be ECB mode for (let i = 0; i < blockTimes; i++) { - // extract the 16 bytes block data for this round to encrypt let roundIndex = i * UINT8_BLOCK let block = this.uint8ToUint32Block(padded, roundIndex) let cipherBlock = this.doBlockCrypt(block, this.encryptRoundKeys) @@ -376,80 +231,54 @@ class SM4 { } } } - - // cipher array to string if (this.cipherType === 'base64') { return Crypt.arrayBufferToBase64(outArray) } else { - // text return Crypt.utf8ArrayBufferToString(outArray) } } - /** - * decrypt the string ciphertext - * - * @param {String} ciphertext - * @memberof SM4 - */ decrypt(ciphertext) { - // get cipher byte array let cipherByteArray = new Uint8Array() if (this.cipherType === 'base64') { - // cipher is base64 string cipherByteArray = Crypt.base64ToArrayBuffer(ciphertext) } else { - // cipher is text cipherByteArray = Crypt.stringToArrayBufferInUtf8(ciphertext) } let blockTimes = cipherByteArray.length / UINT8_BLOCK let outArray = new Uint8Array(cipherByteArray.length) - // decrypt the ciphertext by block if (this.mode === 'cbc') { - // todo CBC mode if (this.iv === null || this.iv.length !== 16) { throw new Error('iv error') } - // init chain with iv (transform to uint32 block) let chainBlock = this.uint8ToUint32Block(this.iv) for (let i = 0; i < blockTimes; i++) { - // extract the 16 bytes block data for this round to encrypt let roundIndex = i * UINT8_BLOCK - // make Uint8Array to Uint32Array block let block = this.uint8ToUint32Block(cipherByteArray, roundIndex) - // reverse the round keys to decrypt let plainBlockBeforeXor = this.doBlockCrypt(block, this.decryptRoundKeys) - // xor the chain block let plainBlock = new Uint32Array(4) plainBlock[0] = chainBlock[0] ^ plainBlockBeforeXor[0] plainBlock[1] = chainBlock[1] ^ plainBlockBeforeXor[1] plainBlock[2] = chainBlock[2] ^ plainBlockBeforeXor[2] plainBlock[3] = chainBlock[3] ^ plainBlockBeforeXor[3] - // make the cipher block be part of next chain block chainBlock = block for (let l = 0; l < UINT8_BLOCK; l++) { outArray[roundIndex + l] = plainBlock[parseInt(l / 4)] >> ((3 - l) % 4 * 8) & 0xff } } } else { - // ECB mode for (let i = 0; i < blockTimes; i++) { - // extract the 16 bytes block data for this round to encrypt let roundIndex = i * UINT8_BLOCK - // make Uint8Array to Uint32Array block let block = this.uint8ToUint32Block(cipherByteArray, roundIndex) - // reverse the round keys to decrypt let plainBlock = this.doBlockCrypt(block, this.decryptRoundKeys) for (let l = 0; l < UINT8_BLOCK; l++) { outArray[roundIndex + l] = plainBlock[parseInt(l / 4)] >> ((3 - l) % 4 * 8) & 0xff } } } - // depadding the decrypted data let depaddedPlaintext = this.dePadding(outArray) - // transform data to utf8 string return Crypt.utf8ArrayBufferToString(depaddedPlaintext) } } -module.exports = SM4 \ No newline at end of file +module.exports = SM4