2020年如何仅用人类可读密码实现字符串加解密?
2020年推荐的人类可读密码加密/解密方案
针对你想用普通人类可读密码实现「仅靠密码就能加解密字符串」的需求,2020年最推荐的是基于浏览器原生**Web Crypto API(SubtleCrypto)**的方案——虽然它本身需要密钥、IV这类额外数据,但我们可以通过密码衍生+数据打包的方式,让用户只需要记住密码就能完成加解密,完美适配你的需求。
为什么选这个方案?
- 原生浏览器支持,无需引入第三方库,安全性更可靠(底层实现避免了JS层常见的漏洞);
- 采用2020年业界公认的安全标准:AES-GCM(带认证的加密算法,同时保证保密性和数据完整性)+ PBKDF2(密码衍生密钥,抵御暴力破解);
- 完全满足你「仅靠密码解密」的要求:把加密所需的盐、IV和密文打包成一个字符串,解密时拆分即可。
完整示例代码
下面是符合你需求的实现,调用方式和你给出的示例完全一致:
async function encrypt(data, password) { // 生成随机盐和IV(加密的必要参数,会和密文一起存储) const salt = window.crypto.getRandomValues(new Uint8Array(16)); const iv = window.crypto.getRandomValues(new Uint8Array(12)); // AES-GCM推荐用12字节IV // 从人类可读密码衍生出AES加密密钥 const keyMaterial = await window.crypto.subtle.importKey( "raw", new TextEncoder().encode(password), { name: "PBKDF2" }, false, ["deriveKey"] ); const encryptionKey = await window.crypto.subtle.deriveKey( { name: "PBKDF2", salt: salt, iterations: 100000, // 2020年合理的迭代次数,平衡安全与性能 hash: "SHA-256" }, keyMaterial, { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"] ); // 加密原始数据 const encryptedBuffer = await window.crypto.subtle.encrypt( { name: "AES-GCM", iv: iv }, encryptionKey, new TextEncoder().encode(data) ); // 把盐、IV、密文转成Base64并拼接成字符串,方便存储/传输 const saltB64 = btoa(String.fromCharCode(...salt)); const ivB64 = btoa(String.fromCharCode(...iv)); const encryptedB64 = btoa(String.fromCharCode(...new Uint8Array(encryptedBuffer))); return `${saltB64}:${ivB64}:${encryptedB64}`; } async function decrypt(encryptedStr, password) { // 拆分出存储的盐、IV和密文 const [saltB64, ivB64, encryptedB64] = encryptedStr.split(":"); const salt = new Uint8Array(atob(saltB64).split("").map(c => c.charCodeAt(0))); const iv = new Uint8Array(atob(ivB64).split("").map(c => c.charCodeAt(0))); const encryptedBuffer = new Uint8Array(atob(encryptedB64).split("").map(c => c.charCodeAt(0))); // 用相同的密码衍生出解密密钥 const keyMaterial = await window.crypto.subtle.importKey( "raw", new TextEncoder().encode(password), { name: "PBKDF2" }, false, ["deriveKey"] ); const decryptionKey = await window.crypto.subtle.deriveKey( { name: "PBKDF2", salt: salt, iterations: 100000, hash: "SHA-256" }, keyMaterial, { name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"] ); // 解密并还原原始字符串 const decryptedBuffer = await window.crypto.subtle.decrypt( { name: "AES-GCM", iv: iv }, decryptionKey, encryptedBuffer ); return new TextDecoder().decode(decryptedBuffer); } // 调用示例 (async () => { const data = "Hello World"; const key = "SuperSecret"; const encrypted = await encrypt(data, key); console.log(encrypted); // 输出类似:abc123:def456:ghijkl(Base64拼接的乱码) const decrypted = await decrypt(encrypted, key); console.log(decrypted); // 输出:Hello World })();
关键细节说明
- AES-GCM算法:2020年已经是主流的安全加密算法,不仅能加密数据,还能验证数据是否被篡改,比旧的CBC模式更安全;
- PBKDF2迭代次数:100000次在2020年是兼顾安全性和性能的选择,次数越高,暴力破解密码的成本越高;
- 数据打包:把盐、IV和密文合并成一个字符串,这样你只需要保存这个加密字符串和密码,解密时就能还原所有必要信息,完全不需要额外存储其他数据。
如果实在不想用原生API,2020年也可以考虑crypto-js这类第三方库,但原生Web Crypto的安全性更有保障,优先推荐。
内容的提问来源于stack exchange,提问作者nagy.zsolt.hun




