使用AES密钥包装RSA私钥,然后解包

时间:2017-12-30 22:24:55

标签: javascript encryption cryptography webcryptoapi

我一直在尝试用密码保护使用Web Cryptography API生成的RSA私钥。为此,

  1. 我首先生成一个RSA密钥对
  2. 然后我从密码
  3. 派生出AES对称密钥
  4. 然后,我使用步骤2中的AES密钥从步骤1中包装RSA私钥。
  5. 当我完成后,我尝试通过立即将所有这些传递给unwrap方法来验证这是否有效,我试图将其解包
  6. 以下是代码:

    <html>
    <script>
    function wrap(password) {
      var iterations = 1000000;
    
      // Utility function
      var stringToByteArray = function(s){
        if ("TextEncoder" in window) {
          encoder = new window.TextEncoder;
          return encoder.encode(s);
        }
        var result = new Uint8Array(s.length);
        for (var i=0; i<s.length; i++){
            result[i] = s.charCodeAt(i);
        }
        return result;
      }
    
      var saltBytes = stringToByteArray("NaCl");
      var passphraseBytes = stringToByteArray(password);
    
      return crypto.subtle.generateKey({
        name: "RSA-OAEP",
        modulusLength: 2048,
        publicExponent: new Uint8Array([1, 0, 1]),
        hash: {name: "SHA-256"}
      }, true, ["encrypt", "decrypt"]).then(function(keyPair) {
        return crypto.subtle.importKey(
          "raw", passphraseBytes, {name: "PBKDF2"}, false, ["deriveKey"]
        ).then(function(baseKey) {
          return window.crypto.subtle.deriveKey(
            {name: "PBKDF2", salt: saltBytes, iterations: iterations, hash: "SHA-1"},
            baseKey,
            {name: "AES-CBC", length: 256},
            false,
            ["encrypt", "decrypt", "wrapKey", "unwrapKey"]
          ).then(function(wrapperKey) {
            var iv = crypto.getRandomValues(new Uint8Array(16));
            return crypto.subtle.wrapKey(
              "pkcs8",
              keyPair.privateKey,
              wrapperKey,
              {name: "AES-CBC", iv: iv }
            ).then(function(wrappedKey) {
              return {
                iv: iv,
                wrapper: wrapperKey,
                wrapped: wrappedKey
              }
            })
          });
        }).catch(function(err) {
          console.log(err);
        });
      })
    }
    
    
    function unwrap(account) {
      console.log(account);
      crypto.subtle.unwrapKey(
        "pkcs8",
        account.wrapped,
        account.wrapper,
        {
          name: "AES-CBC",
          iv: account.iv
        },
        {
          name: "RSA-OAEP",
          modulusLength: 2048,
          publicExponent: new Uint8Array([1, 0, 1]),
          hash: {name: "SHA-256"}
        },
        true,
        ['decrypt', 'encrypt']
      ).then(function(privateKey) {
        console.log("unwrapped = ", privateKey);
      }).catch(function(e) {
        console.log(e)
      })
    }
    
    // Finally I call "wrap" and then "unwrap"
    wrap("password").then(unwrap)
    
    </script>
    </html>
    

    但代码不起作用。包装代码不会抛出任何错误,似乎生成密钥(虽然我不知道这些是否有效)。但是当我尝试运行unwrapKey方法时,我收到以下错误:

    DOMException: Cannot create a key using the specified key usages.
    

    过去24小时我一直在拔头发,因为我无法让它发挥作用。谁能发现问题?这是一个完全独立的代码段,因此您可以通过复制和粘贴到HTML文件并在浏览器中打开来试用它。

1 个答案:

答案 0 :(得分:0)

您要做的事情是,使用对称密钥包装公钥/私钥,并不是打包/解包的工作方式。

  
      
  • wrapKey,允许密钥包含对称密钥以供使用   (转移,存储)在不安全的环境中。
  •   
  • unwrapKey,允许   解开使用(传输,存储)的对称键的关键   不安全的环境。
  •   

您可以打包/解包对称密钥,但是您无法打包/解包公钥/私钥对(或密钥),因为wrap / unwrap可能希望包装的密钥是对称密钥而不是非对称密钥。

  

SubtleCrypto.wrapKey()方法返回一个包装的Promise   在不安全的环境中使用(传输,存储)的对称密钥。   返回的包装缓冲区采用参数中给出的格式,和   包含由给定包装键包装的密钥   算法

     

SubtleCrypto.unwrapKey()方法返回CryptoKey的Promise   对应于参数中给出的包装键。