未捕获承诺DOMException:key.algorithm 与操作

问题描述

<!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,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
        },["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,iv: iv
        },{
          name: "aes-gcm"
        },false,"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 和随机生成的中间密钥进行加密。最后,这个中间密钥用用户的公钥包装起来。

最后解开中间密钥和解密。

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

解决方法

wrapKey()unwrapKey() 调用都分别缺少用于指定加密密钥的算法的 wrapAlgounwrapAlgo 参数的正确规范.在此示例中,应用了带有 OAEP 的 RSA,因此必须将 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,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
        },['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',{                           // 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,iv: iv
        },{
            name: "AES-GCM"
        },false,["encrypt","decrypt"]
    );
    */
    intermediateKey = await crypto.subtle.unwrapKey(
        'raw',{                           // unwrapAlgo,s. https://developer.mozilla.org/en-US/docs/Web/API/RsaOaepParams
            name: 'RSA-OAEP'
        },{
            name: 'AES-GCM'
        },'decrypt']
    );
    console.log('Unwrapped AES key: ',intermediateKey);
  
    // Decrypt ciphertext
    // ...
}

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

solve();