【问题标题】:AES decryption with password using CryptoJS returns a blank value使用 CryptoJS 使用密码进行 AES 解密返回一个空白值
【发布时间】:2015-12-04 13:50:15
【问题描述】:

场景

我有以下代码:

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/aes.js"></script>
<div id="decrypted">Please wait...</div>
Insert new note:<input type="text" id="new_note"><input type="button" id="enc_button" value="Save">
<script>
    var password = "testpassword";
    var encrypted_text = localStorage.getItem("encrypted");
    var rawData = atob(encrypted_text);
    var iv = rawData.substring(0,16);
    var crypttext = rawData.substring(16);
    var plaintextArray = CryptoJS.AES.decrypt(
      { ciphertext: CryptoJS.enc.Latin1.parse(crypttext) },
      CryptoJS.enc.Hex.parse(password),
      { iv: CryptoJS.enc.Latin1.parse(iv) }
    );
    var decrypted = CryptoJS.enc.Latin1.stringify(plaintextArray);
    document.getElementById("decrypted").innerHTML = decrypted;
    document.getElementById("enc_button").onclick = function(){
    	var text = document.getElementById("new_note").value;
    	var encrypted = CryptoJS.AES.encrypt(text, password);
    	localStorage.setItem("encrypted",encrypted);
    }
</script>

我的代码应该做什么

使用 CryptoJS 使用 AES 加密字符串;解密保存在本地存储中的加密文本并在 div 中显示结果

什么不工作

虽然字符串似乎已加密,但变量 decrypt 为空。 chrome 控制台中不会触发任何错误。

我的问题

我怎样才能成功地加密和解密我的文本?

【问题讨论】:

    标签: javascript encryption cryptography cryptojs


    【解决方案1】:

    CryptoJS 有两种略有不同的加密/解密类型。

    当你使用时

    var encrypted = CryptoJS.AES.encrypt(text, password);
    

    那么您使用的基于密码的加密与纯密钥/基于 IV 的加密不同。这意味着密码和随机生成的盐通过一次 MD5 调用运行,以生成用于实际加密的密钥和 IV。这是一种与 OpenSSL 兼容的加密方式。 encrypted 对象存储用于生成密钥和 IV 的随机盐。

    当您强制将encrypted 转换为字符串(例如将其添加到localStorage)时,它会转换为包含盐的OpenSSL 兼容字符串编码。为了再次解密,你不需要自己弄乱密钥、IV 或盐,因为 CryptoJS 会自动为你做这些:

    var decrypted = CryptoJS.AES.decrypt(encrypted, password);
    

    请记住,decrypted 是一个WordArray 对象,当您强制将其转换为字符串时,默认情况下会将内容编码为十六进制。如果您不想这样,则需要自己指定编码,例如 UTF-8。

    由于密钥错误、密文错误或编码错误等原因解密失败,通常会返回一个空值。 CryptoJS 不会抛出自定义错误消息,但会尝试继续,因为您应该知道自己在做什么。

    完整代码:

    var password = "testpassword";
    
    document.getElementById("enc_button").onclick = function(){
      var text = document.getElementById("new_note").value;
      
      var encrypted = CryptoJS.AES.encrypt(text, password);
      encrypted = encrypted.toString();
      
      var decrypted = CryptoJS.AES.decrypt(encrypted, password);
      decrypted = decrypted.toString(CryptoJS.enc.Utf8)
      
      document.getElementById("decrypted").innerHTML = decrypted;
    }
    <script src="https://cdn.rawgit.com/CryptoStore/crypto-js/3.1.2/build/rollups/aes.js"></script>
    <div id="decrypted">Please wait...</div>
    Insert new note:<input type="text" id="new_note"><input type="button" id="enc_button" value="Encrypt & Decrypt">

    【讨论】:

    • 我删除了 localStorage 代码,因为它只会混淆问题。
    【解决方案2】:

    我厌倦了通过将脚本放在 try-catch 中来调试您的代码,并且看起来 document.getElementById 返回未定义。这是因为在创建元素之前调用了该方法。以下步骤使这项工作:

    头:

    var password = "testpassword";
    var encrypted_text = localStorage.getItem("encrypted");
    var rawData = atob(encrypted_text);
    var iv = rawData.substring(0,16);
    var crypttext = rawData.substring(16);
    var plaintextArray = CryptoJS.AES.decrypt(
      { ciphertext: CryptoJS.enc.Latin1.parse(crypttext) },
      CryptoJS.enc.Hex.parse(password),
      { iv: CryptoJS.enc.Latin1.parse(iv) }
    );
    var decrypted = CryptoJS.enc.Latin1.stringify(plaintextArray);
    
    function setComponents() {
        try {
            document.getElementById("decrypted").innerHTML = decrypted;
            document.getElementById("enc_button").onclick = function(){
                var text = document.getElementById("new_note").value;
                var encrypted = CryptoJS.AES.encrypt(text, password);
                localStorage.setItem("encrypted",encrypted);
                alert(encrypted);
            };
        } catch(e) {
            alert(e);
        }
    }
    

    主体:

    <body onload="setComponents()">
    <div id="decrypted">Please wait...</div>
    Insert new note:<input type="text" id="new_note"/><input type="button" id="enc_button" value="Save"/>
    </body>
    

    【讨论】:

    • 感谢您的回答,但问题是 Artjom B. 发现的问题
    【解决方案3】:

    您可以查看源代码...有示例。
    以任何方式使其从密码生成密钥、iv 和盐的最简单方法,
    是正常的方式CryptoJS.AES.encrypt("attack at early!","passphrase")
    但是您可以通过使用

    来设置参数before
    CryptoJS.algo.AES.keySize=32
    CryptoJS.algo.AES.blockSize=8
    CryptoJS.algo.AES.ivSize=16
    CryptoJS.algo.EvpKDF.cfg.iterations=100
    CryptoJS.algo.EvpKDF.cfg.keySize=32
    

    等等等等

    【讨论】:

    • CryptoJS.algo.AES.blockSize=8 是错误的,AES 的块大小总是 16 字节。此外,IV 大小与块大小相同,始终为 16 字节,无需为 AES 设置这些值中的任何一个。 EvpKDF.cfg.iterations的100次迭代可能正确也可能不正确,瞄准点是100ms的CPU时间。
    猜你喜欢
    • 1970-01-01
    • 2014-12-16
    • 2017-01-11
    • 1970-01-01
    • 2014-08-17
    • 2021-08-13
    • 1970-01-01
    • 2019-06-27
    • 1970-01-01
    相关资源
    最近更新 更多