crypto加密-实战篇之对称加密
服务端生成密钥
需要主要的是 对称加密只会产出一个密钥文件,也就是加密和解密都用这个密钥,不分公钥和私钥!
// 对称加密
const genKeyPair = () => {
// 生成的对称密钥,以 Buffer 格式表示。
const aesKey = crypto.randomBytes(32); // 32字节 = 256位
// 将密钥转换为十六进制字符串,便于查看和存储。
const aesKeyHex = aesKey.toString('hex');
fs.outputFileSync("aes-keys/aesKey.hex", aesKeyHex);
}
客户端加密数据
获取密钥
// 从hex字符串生成AES密钥
const genAESKeyFromHex = async (hexKeyText) => {
// 将hex字符串转换为ArrayBuffer
const keyBuffer = new Uint8Array(
hexKeyText.match(/.{1,2}/g).map((byte) => parseInt(byte, 16))
);
// 导入AES密钥
return await crypto.subtle.importKey(
"raw",
keyBuffer,
{
name: "AES-GCM",
},
false,
["encrypt", "decrypt"]
);
};
// 封装一个通用方法,加载文件
const loadFile = (filePath) => {
const response = fetch(filePath).then((res) => res.text());
return response;
};
const hexKeyStr = await loadFile("./aes-keys/aesKey.hex");
const aesKey = await genAESKeyFromHex(hexKeyStr);
加密数据
// 使用AES密钥加密
const encrypt = async (data, aesKey) => {
// 将内容字符串转换为ArrayBuffer
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
// 生成随机IV(初始化向量)
const iv = crypto.getRandomValues(new Uint8Array(12)); // AES-GCM推荐12字节IV
// 加密
const encrypted = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
aesKey,
dataBuffer
);
// 将IV和加密数据合并,然后转换为Base64
const encryptedArray = new Uint8Array(encrypted);
const combined = new Uint8Array(iv.length + encryptedArray.length);
combined.set(iv);
combined.set(encryptedArray, iv.length);
const base64String = btoa(String.fromCharCode(...combined));
return base64String;
};
看看效果
<input type="text" />
<button>加密数据</button>
<div class="encrypted-data">
<p>加密后的数据:</p>
<p class="encrypted-data-content" style="word-break: break-all"></p>
</div>
<script>
// ...省略上诉代码
const input = document.querySelector("input");
const button = document.querySelector("button");
const encryptedDataContent = document.querySelector(
".encrypted-data-content"
);
button.addEventListener("click", async () => {
// 从文件加载hex密钥(假设密钥文件包含hex字符串)
const hexKeyStr = await loadFile("./key-pair/aes-key.hex");
const hexKey = hexKeyStr.trim(); // 移除可能的换行符
const aesKey = await genAESKeyFromHex(hexKey);
const content = input.value;
const encryptedData = await encrypt(content, aesKey);
encryptedDataContent.innerText = encryptedData;
});
</script>

服务端解密
// 使用AES密钥解密(对称加密)
export const decrypt = (encryptedData: string) => {
// 读取hex格式的AES密钥
const aesKeyHex = fs.readFileSync("aes-keys/aesKey.hex", "utf8").trim();
const aesKey = Buffer.from(aesKeyHex, 'hex');
// 将Base64编码的加密数据转换为Buffer
const encryptedBuffer = Buffer.from(encryptedData, 'base64');
// AES-GCM格式:IV(12字节) + 密文 + 认证标签(16字节)
const iv = encryptedBuffer.subarray(0, 12);
const authTag = encryptedBuffer.subarray(-16); // authTag由crypto.subtle.encrypt方法生成,并且包含在加密后的数据中。
const cipherText = encryptedBuffer.subarray(12, -16);
// 创建解密器
const decipher = crypto.createDecipheriv('aes-256-gcm', aesKey, iv);
decipher.setAuthTag(authTag);
// 解密数据
let decrypted = decipher.update(cipherText, undefined, 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
};
const content = "AzULO8EToCvznlMt0qndPsoMZc2DOqQi/DBwU7odng==";
console.log(decrypt(content));


浙公网安备 33010602011771号