2026-07-27 11:28:33 +08:00

318 lines
10 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 功能:加解密工具类第三方系统及对外接口专用版
* 说明使用国密SM4算法
* JavaScript版本实现
*/
const sm4 = require('sm-crypto').sm4;
const crypto = require('crypto');
// 密文前缀常量
const CIPHERTEXT_PREFIX_THIRD_AES128 = "|$|";
const CIPHERTEXT_PREFIX_THIRD_AES128_REGEX = /\|\$\|/;
const CIPHERTEXT_PREFIX_THIRD_SM4ECB = "|$4|";
const CIPHERTEXT_PREFIX_THIRD_SM4ECB_REGEX = /\|\$4\|/;
/**
* 判断字符串是否为空
* @param {string} str - 待判断的字符串
* @returns {boolean} 是否为空
*/
function isBlank(str) {
return !str || str.length === 0;
}
/**
* 将字节数组转换为Base64字符串
* @param {Buffer} binaryData - 字节数组
* @returns {string} Base64字符串
*/
function base64StringFromByteArray(binaryData) {
try {
const base64String = binaryData.toString('base64');
return base64String
} catch (e) {
console.error('Exception - base64StringFromByteArray() | binaryData :', binaryData);
return null;
}
}
/**
* 将Base64字符串转换为字节数组
* @param {string} base64String - Base64字符串
* @returns {Buffer} 字节数组
*/
function byteArrayFromBase64String(base64String) {
try {
return Buffer.from(base64String, 'base64');
} catch (e) {
console.error('Exception - byteArrayFromBase64String() | base64String :', base64String);
return null;
}
}
/**
* SM4 ECB模式加密带PKCS5Padding
* @param {Buffer} content - 待加密内容
* @param {Buffer} key - SM4密钥16字节
* @returns {Buffer} 加密后的字节数组
*/
function encryptECBPadding(content, key) {
try {
// sm-crypto 的 sm4.encrypt 使用 ECB 模式,自动处理 PKCS5Padding
// 密钥需要转换为十六进制字符串内容需要转换为UTF-8字符串
const keyHex = key.toString('hex');
const contentStr = content.toString('utf8');
// sm4.encrypt(data, key, mode, outputEncoding)
// mode: 1=ECB, 2=CBC; outputEncoding: 'base64' 或 'hex',默认为 'base64'
// 第一个参数应该是UTF-8字符串而不是hex字符串
const encryptedHex = sm4.encrypt(contentStr, keyHex, 1, 'hex');
return Buffer.from(encryptedHex, 'hex');
} catch (e) {
console.error('Exception-encryptECBPadding()', e.message);
return null;
}
}
/**
* SM4 ECB模式解密带PKCS5Padding
* @param {Buffer} cipherText - 待解密内容
* @param {Buffer} key - SM4密钥16字节
* @returns {Buffer} 解密后的字节数组
*/
function decryptECBPadding(cipherText, key) {
try {
// sm-crypto 的 sm4.decrypt 使用 ECB 模式,自动处理 PKCS5Padding
const keyHex = key.toString('hex');
const cipherTextHex = cipherText.toString('hex');
// sm4.decrypt(data, key, mode, outputEncoding)
// mode: 1=ECB, 2=CBC; outputEncoding: 'base64' 或 'hex',默认为 'base64'
// 第一个参数应该是hex字符串密文的hex表示
const decryptedHex = sm4.decrypt(cipherTextHex, keyHex, 1, 'hex');
return Buffer.from(decryptedHex, 'hex');
} catch (e) {
console.error('Exception-decryptECBPadding()', e.message);
return null;
}
}
/**
* SM4 ECB模式加密Base64输入输出
* @param {string} content - 待加密内容
* @param {string} key - Base64编码的SM4密钥
* @returns {string} Base64编码的加密结果
*/
function encryptECBPaddingBase64(content, key) {
if (isBlank(content) || isBlank(key)) {
console.error('【警告】encryptECBPaddingBase64():[IN]content or [IN]key is null!|content=' + content);
return content;
}
try {
const contentBuffer = Buffer.from(content, 'utf8');
const keyBuffer = byteArrayFromBase64String(key);
if (!keyBuffer) {
return null;
}
const encryptedBuffer = encryptECBPadding(contentBuffer, keyBuffer);
if (!encryptedBuffer) {
return null;
}
return base64StringFromByteArray(encryptedBuffer);
} catch (e) {
console.error('Exception-encryptECBPaddingBase64()', e.message);
return null;
}
}
/**
* SM4 ECB模式解密Base64输入输出
* @param {string} cipherText - Base64编码的密文
* @param {string} key - Base64编码的SM4密钥
* @returns {string} 解密后的明文
*/
function decryptECBPaddingBase64(cipherText, key) {
if (isBlank(cipherText) || isBlank(key)) {
console.error('【警告】decryptECBPaddingBase64():[IN]cipherText or [IN]key is null!|cipherText=' + cipherText);
return cipherText;
}
try {
const cipherTextBuffer = byteArrayFromBase64String(cipherText);
const keyBuffer = byteArrayFromBase64String(key);
if (!cipherTextBuffer || !keyBuffer) {
return null;
}
const decryptedBuffer = decryptECBPadding(cipherTextBuffer, keyBuffer);
if (!decryptedBuffer) {
return null;
}
return decryptedBuffer.toString('utf8');
} catch (e) {
console.error('Exception-decryptECBPaddingBase64()', e.message);
return null;
}
}
/**
* AES128加密
* @param {string} content - 待加密内容
* @param {Buffer} byteAESKey - AES密钥16字节
* @returns {Buffer} 加密后的字节数组
*/
function encryptAES(content, byteAESKey) {
try {
const cipher = crypto.createCipheriv('aes-128-ecb', byteAESKey, null);
cipher.setAutoPadding(true);
let encrypted = cipher.update(content, 'utf8');
encrypted = Buffer.concat([encrypted, cipher.final()]);
return encrypted;
} catch (e) {
console.error('Exception - encryptAES()', e.message);
return null;
}
}
/**
* AES128解密
* @param {Buffer} content - 待解密内容
* @param {Buffer} byteAESKey - AES密钥16字节
* @returns {Buffer} 解密后的字节数组
*/
function decryptAES(content, byteAESKey) {
try {
const decipher = crypto.createDecipheriv('aes-128-ecb', byteAESKey, null);
decipher.setAutoPadding(true);
let decrypted = decipher.update(content);
decrypted = Buffer.concat([decrypted, decipher.final()]);
return decrypted;
} catch (e) {
console.error('Exception - decryptAES()', e.message);
return null;
}
}
/**
* AES128加密Base64输入输出
* @param {string} content - 待加密内容
* @param {string} base64AESKey - Base64编码的AES密钥
* @returns {string} Base64编码的加密结果
*/
function encryptBase64(content, base64AESKey) {
try {
const keyBuffer = byteArrayFromBase64String(base64AESKey);
if (!keyBuffer) {
return null;
}
const encryptedBuffer = encryptAES(content, keyBuffer);
if (!encryptedBuffer) {
return null;
}
return base64StringFromByteArray(encryptedBuffer);
} catch (e) {
console.error('Exception - encryptBase64()', e.message);
return null;
}
}
/**
* AES128解密Base64输入输出
* @param {string} base64Content - Base64编码的密文
* @param {Buffer} byteAESKey - AES密钥16字节
* @returns {Buffer} 解密后的字节数组
*/
function decryptBase64FromBuffer(base64Content, byteAESKey) {
try {
const contentBuffer = byteArrayFromBase64String(base64Content);
if (!contentBuffer) {
return null;
}
return decryptAES(contentBuffer, byteAESKey);
} catch (e) {
console.error('Exception - decryptBase64FromBuffer()', e.message);
return null;
}
}
/**
* AES128解密Base64输入输出返回字符串
* @param {string} base64Content - Base64编码的密文
* @param {string} base64AESKey - Base64编码的AES密钥
* @returns {string} 解密后的明文
*/
function decryptBase64(base64Content, base64AESKey) {
try {
const keyBuffer = byteArrayFromBase64String(base64AESKey);
if (!keyBuffer) {
return null;
}
const decryptedBuffer = decryptBase64FromBuffer(base64Content, keyBuffer);
if (!decryptedBuffer) {
return null;
}
return decryptedBuffer.toString('utf8');
} catch (e) {
console.error('Exception - decryptBase64()', e.message);
return null;
}
}
/**
* 功能国密商用SM4加密
* 说明:用于加密其它敏感类数据,带密钥参数
* @param {string} plaintext - 明文
* @param {string} key - Base64编码的SM4密钥
* @returns {string} 加密后的密文(带前缀 |$4|
*/
function sm4Encrypt(plaintext, key) {
if (isBlank(plaintext) || isBlank(key)
|| plaintext.startsWith(CIPHERTEXT_PREFIX_THIRD_AES128)
|| plaintext.startsWith(CIPHERTEXT_PREFIX_THIRD_SM4ECB)
) {
return plaintext;
} else {
const tmp = encryptECBPaddingBase64(plaintext, key);
if (tmp == null) {
console.error('ERROR-sm4Encrypt():plaintext=' + plaintext + ',encryptRes=' + tmp);
}
return tmp != null ? (CIPHERTEXT_PREFIX_THIRD_SM4ECB + tmp) : null;
}
}
/**
* 功能国密商用SM4解密
* 说明用于解密其它敏感类数据带密钥参数兼容AES128算法
* @param {string} ciphertext - 密文
* @param {string} key - Base64编码的SM4密钥
* @returns {string} 解密后的明文
*/
function sm4Decrypt(ciphertext, key) {
if (isBlank(ciphertext) || isBlank(key)) {
return ciphertext;
}
if (ciphertext.startsWith(CIPHERTEXT_PREFIX_THIRD_SM4ECB)) {
const tmp = decryptECBPaddingBase64(ciphertext.replace(CIPHERTEXT_PREFIX_THIRD_SM4ECB_REGEX, ''), key);
if (tmp == null) {
console.error('ERROR-sm4Decrypt():ciphertext=' + ciphertext + ',decryptRes=' + tmp);
}
return tmp;
} else if (ciphertext.startsWith(CIPHERTEXT_PREFIX_THIRD_AES128)) {
const tmp = decryptBase64(ciphertext.replace(CIPHERTEXT_PREFIX_THIRD_AES128_REGEX, ''), key);
if (tmp == null) {
console.error('ERROR-sm4Decrypt():ciphertext=' + ciphertext + ',decryptRes=' + tmp);
}
return tmp;
} else {
return ciphertext;
}
}
// 导出函数
module.exports = {
sm4Encrypt,
sm4Decrypt,
encryptECBPaddingBase64,
decryptECBPaddingBase64,
encryptBase64,
decryptBase64
};