crypto-js不支持 AES_GCM 加密 ,听说可以用 crypto 支持?当时是自己写的....
crypto API 要求页面在安全上下文(Secure Context)中运行。localhost 和 127.0.0.1 被视为安全上下文,但通过普通 IP 地址(如 192.168.x.x)访问时,浏览器可能认为不安全。
解决方法:
如果必须使用 IP 地址,可以尝试将 IP 地址添加到浏览器的安全上下文中(不推荐,仅限开发环境)。
在生产环境中,强烈建议使用 HTTPS 来确保安全上下文。
async function deriveKeyFromMaterial(keyMaterial, lengthBits) {
// 使用 SHA-256 哈希算法来生成足够长度的密钥材料
// const hashedKey = await crypto.subtle.digest(
// "SHA-256",
// new TextEncoder().encode(keyMaterial)
// );
// console.log(hashedKey, "hashedKey");
let hashedKey = stringToBytes(keyMaterial);
hashedKey = adjustKeyLength(hashedKey, 16);
// 导入哈希后的密钥材料作为AES密钥
return await crypto.subtle.importKey(
"raw",
// lengthBits === 256 ? hashedKey : hashedKey.slice(0, lengthBits / 8),
hashedKey,
{ name: "AES-GCM" },
false,
["encrypt", "decrypt"]
);
}
function stringToBytes(str) {
const encoder = new TextEncoder(); // 默认使用 UTF-8 编码
return encoder.encode(str);
}
function adjustKeyLength(keyBytes, requiredLength) {
if (keyBytes.length === requiredLength) {
return keyBytes;
}
const adjustedKey = new Uint8Array(requiredLength);
if (keyBytes.length < requiredLength) {
// 填充
adjustedKey.set(keyBytes);
for (let i = keyBytes.length; i < requiredLength; i++) {
adjustedKey[i] = 0; // 用 0 填充
}
} else {
// 截断
for (let i = 0; i < requiredLength; i++) {
adjustedKey[i] = keyBytes[i];
}
}
return adjustedKey;
}
async function encryptText(text, keyMaterial, keyLengthBits) {
const key = await deriveKeyFromMaterial(keyMaterial, keyLengthBits);
// 生成IV
const iv = crypto.getRandomValues(new Uint8Array(12)); // GCM模式推荐使用12字节IV
// 加密数据
const encoder = new TextEncoder();
const encryptedData = await crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv,
},
key,
encoder.encode(text)
);
// 将IV和加密后的数据拼接起来
const combined = new Uint8Array(iv.length + encryptedData.byteLength);
combined.set(iv, 0);
combined.set(new Uint8Array(encryptedData), iv.length);
// 将结果编码为Base64字符串
return btoa(String.fromCharCode.apply(null, combined));
}
async function decryptText(encryptedBase64, keyMaterial, keyLengthBits) {
// 将Base64字符串转换为Uint8Array
const binaryString = atob(encryptedBase64);
const combined = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
combined[i] = binaryString.charCodeAt(i);
}
// 提取IV
const iv = combined.slice(0, 12);
// 提取加密数据
const encryptedBytes = combined.slice(12);
// 导入密钥材料(需要确保这个密钥与Java端使用的是一样的)
const key = await deriveKeyFromMaterial(keyMaterial, keyLengthBits);
try {
// 解密数据
const decryptedData = await crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: iv,
},
key,
encryptedBytes
);
// 将解密后的数据转换为字符串
const decoder = new TextDecoder();
return decoder.decode(decryptedData);
} catch (error) {
console.error("Decryption failed:", error);
throw error;
}
}
const keyMaterial = "_aes_secret_key_"; // 确保这与Java端的密钥一致
const textToEncrypt = "admsdsdin";
encryptText(textToEncrypt, keyMaterial).then((encrypted) => {
console.log("Encrypted:", encrypted);
decryptText(encrypted, keyMaterial).then((decrypted) => {
console.log("Decrypted:", decrypted);
});
});
浙公网安备 33010602011771号