You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动