js加密和解密
window.crypto.subtle(也称为 crypto.subtle)提供了加密和解密字符串的能力,但请注意,它是一个低级别的 API,需要你自己处理密钥管理、编码转换等工作。下面是一个简单的例子,展示如何使用 AES-GCM 模式来加密和解密字符串。
这里实现这样的效果
function encrypt(key='string', data='string');
function decrypt(key='string', data='string');
为了实现这样的 encrypt
和 decrypt
函数,这涉及到几个步骤:生成密钥、将字符串转换为 ArrayBuffer、加密或解密数据、并将结果转换回字符串。
以下是完整的实现:
生成密钥
由于我们希望 encrypt
和 decrypt
函数能够接受字符串形式的密钥,我们需要首先将字符串形式的密钥转换为合适的密钥对象。这里我们假设密钥字符串是经过某种方式生成的,并且已经被正确地转换为密钥对象。
async function generateKeyFromPassword(password) {
// 密钥生成算法,这里使用 PBKDF2 从密码派生密钥
const salt = window.crypto.getRandomValues(new Uint8Array(16));
const keyMaterial = await window.crypto.subtle.importKey(
"raw",
salt,
{ name: "PBKDF2", hash: { name: "SHA-256" }, salt, iterations: 100000 },
false,
["deriveBits"]
);
const key = await window.crypto.subtle.deriveBits(
{
name: "PBKDF2",
salt,
iterations: 100000,
hash: { name: "SHA-256" }
},
keyMaterial,
256, // 密钥长度
true
);
return await window.crypto.subtle.importKey(
"raw",
new Uint8Array(key),
{ name: "AES-GCM" },
true,
["encrypt", "decrypt"]
);
}
加密字符串
async function encrypt(key, data) {
const encoder = new TextEncoder(); // 用于编码字符串到 ArrayBuffer
const encodedData = encoder.encode(data);
const iv = window.crypto.getRandomValues(new Uint8Array(12)); // 生成初始向量
const encryptedData = await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv }, // 配置选项
key,
encodedData
);
// 将密文和 IV 结合在一起
const combinedData = new Uint8Array(iv.length + encryptedData.byteLength);
combinedData.set(iv);
combinedData.set(new Uint8Array(encryptedData), iv.length);
return btoa(String.fromCharCode(...combinedData)); // 将 ArrayBuffer 转换为 Base64 编码的字符串
}
解密字符串
async function decrypt(key, data) {
const decodedData = atob(data); // 将 Base64 编码的字符串转换回 ArrayBuffer
const combinedData = new Uint8Array(decodedData.length);
for (let i = 0; i < decodedData.length; i++) {
combinedData[i] = decodedData.charCodeAt(i);
}
const iv = combinedData.slice(0, 12);
const encryptedData = combinedData.slice(12);
const decryptedData = await window.crypto.subtle.decrypt(
{ name: "AES-GCM", iv }, // 配置选项
key,
encryptedData
);
const decoder = new TextDecoder(); // 用于解码 ArrayBuffer 到字符串
return decoder.decode(decryptedData);
}
使用这些函数
(async () => {
try {
const password = "my-secret-password"; // 示例密码
const key = await generateKeyFromPassword(password);
const originalText = "Hello, world!";
const encryptedText = await encrypt(key, originalText);
console.log("Encrypted:", encryptedText);
const decryptedText = await decrypt(key, encryptedText);
console.log("Decrypted:", decryptedText);
} catch (error) {
console.error("Error:", error);
}
})();
注意事项
- 这个示例使用了
PBKDF2
从密码派生密钥,并使用AES-GCM
模式进行加密。这是一个较为安全的做法,但请注意,密码派生过程可能会比较耗时。 - 为了方便起见,这里的
encrypt
和decrypt
函数直接使用 Base64 编码来表示加密后的数据。这种方法适合在网络上传输,但请注意 Base64 编码会增加数据的大小。 - 在实际应用中,密钥管理是非常重要的,应确保密钥的安全性,并考虑使用更复杂的方法来保护密码,例如使用更安全的密码派生函数(如
argon2
)。
