一、传输加密
这里用 对称加密模式 ASE实现。
React 前端
const CryptoJS = require("crypto-js");
// 示例1:ECB模式(无需IV)
const encryptECB = (plainText, key) => {
return CryptoJS.AES.encrypt(plainText, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString();
};
const decryptECB = (cipherText, key) => {
const bytes = CryptoJS.AES.decrypt(cipherText, key, {
mode: CryptoJS.mode.ECB
});
return bytes.toString(CryptoJS.enc.Utf8);
};
// 示例2:CBC模式(需要IV)
const encryptCBC = (plainText, key, iv) => {
return CryptoJS.AES.encrypt(plainText, key, {
iv: CryptoJS.enc.Utf8.parse(iv),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
};
const decryptCBC = (cipherText, key, iv) => {
const bytes = CryptoJS.AES.decrypt(cipherText, key, {
iv: CryptoJS.enc.Utf8.parse(iv)
});
return bytes.toString(CryptoJS.enc.Utf8);
};
// 测试用例
const key = "my-secret-key-123"; // 16/24/32字节
const iv = "1234567890123456"; // 16字节
const text = "Hello AES!";
// ECB模式
const ecbEncrypted = encryptECB(text, key);
console.log("ECB加密结果:", ecbEncrypted);
console.log("ECB解密结果:", decryptECB(ecbEncrypted, key));
// CBC模式
const cbcEncrypted = encryptCBC(text, key, iv);
console.log("CBC加密结果:", cbcEncrypted);
console.log("CBC解密结果:", decryptCBC(cbcEncrypted, key, iv));
Express 中间件
解密中间件封装
创建 AES_decrypt.js
中间件文件,处理请求体的加密数据:
const { AES_decrypt } = require('../utils/AES');
const decryptMiddleware = (req, res, next) => {
if (req.body?.content && req.body?.iv) {
try {
const decrypted = AES_decrypt(req.body.content, req.body.iv);
req.decryptedData = JSON.parse(decrypted); // 存储解密结果到请求对象
next();
} catch (err) {
res.status(400).json({ error: "解密失败" });
}
} else {
next(); // 非加密请求跳过
}
};
module.exports = decryptMiddleware;
引用自实际中间件解密实现
在 utils/AES.js
中定义解密函数,需与前端 CryptoJS 的 CBC 模式配置一致:
const crypto = require('crypto');
const secretKey = '1234567890123456'; // 16字节密钥
function AES_decrypt(encryptedText, ivHex) {
const decipher = crypto.createDecipheriv(
'aes-128-cbc',
Buffer.from(secretKey),
Buffer.from(ivHex, 'hex')
);
let decrypted = decipher.update(encryptedText, 'base64', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
module.exports = { AES_decrypt };
下面是ECB(无vi模式)
const crypto = require('crypto');
const secretKey = process.env.AES_KEY || 'default16byteskey!'; // 16字节密钥
module.exports = (req, res, next) => {
if (req.body?.encryptedData) {
try {
const decipher = crypto.createDecipheriv(
'aes-128-ecb',
Buffer.from(secretKey),
null // ECB模式无需IV
);
let decrypted = decipher.update(req.body.encryptedData, 'base64', 'utf8');
decrypted += decipher.final('utf8');
req.decryptedBody = JSON.parse(decrypted);
next();
} catch (err) {
res.status(400).json({ error: "ECB解密失败", details: err.message });
}
} else {
next(); // 非加密请求跳过
}
};
二、不可逆加密
这里用bcryptjs实现
import bcrypt from 'bcryptjs';
/**
* 加密(不可逆转加密)
* @param rawData
*/
export const getHashedData = (rawData: string): string => {
const salt = bcrypt.genSaltSync(10); // 成本因子推荐10-12
const hashedData = bcrypt.hashSync(rawData, salt);
return hashedData;
}
/**
* 匹配不可逆转加密方式生成的数据
* @param rawData
* @param hashedData
* @returns
*/
export const matchHashDataAndRawData = (rawData: string, hashedData: string): boolean => {
return bcrypt.compareSync(rawData, hashedData);
}
调用
加密
const hashedPassword = getHashedData(password);
比对数据
matchHashDataAndRawData(newPassword, password);