未捕获(承诺)DOMException:key.algorithm 与操作不匹配

Uncaught (in promise) DOMException: key.algorithm does not match that of operation

<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
  <script>
    let intermediateKey;
    let publicKey;
    let privateKey;
    let wrappedKey;
    let iv;

    async function rsaKeyPair() {
      let keyPair = await crypto.subtle.generateKey({
          name: "RSA-OAEP",
          modulusLength: 4096,
          publicExponent: new Uint8Array([1, 0, 1]),
          hash: "SHA-256",
        },
        true, ["wrapKey", "unwrapKey"]
      );
      publicKey = keyPair.publicKey;
      privateKey = keyPair.privateKey;
    }

    async function encrypt(secret) {
      // generating random intermediate key to encrypt and decrypt the secret
      intermediateKey = await crypto.subtle.generateKey({
          name: "AES-GCM",
          length: 256
        },
        true, ["encrypt", "decrypt"]
      );
      // encrypt secret
      // ...
      // wrap intermediate key (export + encrypt) intermediateKey using publicKey.
      iv = crypto.getRandomValues(new Uint8Array(12));
      wrappedKey = await crypto.subtle.wrapKey(
        "jwk",
        intermediateKey,
        publicKey, {
          name: "AES-GCM",
          iv: iv
        }
      );
    }

    async function decrypt(cipher) {
      // unwrap (decrypt + import) aes key using private key.
      intermediateKey = await crypto.subtle.unwrapKey(
        "jwk",
        wrappedKey,
        privateKey, {
          name: "AES-GCM",
          iv: iv
        }, {
          name: "AES-GCM"
        },
        false, ["encrypt", "decrypt"]
      );
      // decrypt the cipher
      // ...
    }

    async function solve() {
      // generate rsa-keypairs
      await rsaKeyPair();
      // encrypt secret
      const cipher = await encrypt("secret");
      // decrypt cipher
      await decrypt(cipher);
    }
    solve();
  </script>
</body>

</html>

正在生成 RSA-OAEP 密钥对(根据 http://www.w3.org/TR/WebCryptoAPI/#algorithm-overview.

当用户创建机密时,该机密会使用 AES-GCM-256 和随机生成的中间密钥进行加密。最后,这个中间密钥被用户的 public 密钥包裹起来。

终于解开中间密钥并解密。

解包中间密钥时产生错误。

两者,wrapKey() and unwrapKey() calls lack the proper specification of the wrapAlgo and unwrapAlgo parameters, respectively, which are used to specify the algorithm to encrypt the key. In this example, RSA with OAEP is applied, so a RsaOaepParams 对象必须用于两个参数。

如果在两个函数中都正确指定了参数,则AES密钥将被正确加密和解​​密:

let intermediateKey;
let publicKey;
let privateKey;
let wrappedKey;
let iv;

async function rsaKeyPair() {
    
    let keyPair = await crypto.subtle.generateKey(
        {
            name: 'RSA-OAEP',
            modulusLength: 4096,
            publicExponent: new Uint8Array([1, 0, 1]),
            hash: 'SHA-256',
        },
        true, 
        ['wrapKey', 'unwrapKey']
    );
    publicKey = keyPair.publicKey;
    privateKey = keyPair.privateKey;
}

async function encrypt() {

    // Generate AES key 
    intermediateKey = await crypto.subtle.generateKey(
        {
            name: 'AES-GCM',
            length: 256
        },
        true, 
        ['encrypt', 'decrypt']
    );
    
    // Encrypt secret
    // ...
    
    // Wrap AES key
    /*
    iv = crypto.getRandomValues(new Uint8Array(12));
    wrappedKey = await crypto.subtle.wrapKey(
        'jwk',
        intermediateKey,
        publicKey, 
        {
            name: "AES-GCM",
            iv: iv
        }
    );
    */
    wrappedKey = await crypto.subtle.wrapKey(
        'raw',
        intermediateKey,
        publicKey, 
        {                           // wrapAlgo, here an RsaOaepParams object, s. https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams
            name: 'RSA-OAEP'
        }
    );    
    console.log('Wrapped AES key: ', new Uint8Array(wrappedKey));
}

async function decrypt() {

    // Unwrap AES key
    /*
    intermediateKey = await crypto.subtle.unwrapKey(
        'jwk',
        wrappedKey,
        privateKey, 
        {
            name: "AES-GCM",
            iv: iv
        }, 
        {
            name: "AES-GCM"
        },
        false, 
        ["encrypt", "decrypt"]
    );
    */
    intermediateKey = await crypto.subtle.unwrapKey(
        'raw',
        wrappedKey,
        privateKey, 
        {                           // unwrapAlgo, here an RsaOaepParams object, s. https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams
            name: 'RSA-OAEP'
        }, 
        {
            name: 'AES-GCM'
        },
        false, ['encrypt', 'decrypt']
    );
    console.log('Unwrapped AES key: ', intermediateKey);
  
    // Decrypt ciphertext
    // ...
}

async function solve() {
    await rsaKeyPair();
    await encrypt();
    await decrypt();
}

solve();