2

<!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 和随机生成的中间密钥进行加密。最后,这个中间密钥与用户的公钥一起包装。

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

该错误是在展开中间密钥期间生成的。

4

1 回答 1

2

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, 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();

于 2021-01-24T19:25:24.783 回答