2

Setup:

  • I generate a key-encryption-key (kek, AES-GCM, 256)
  • I generate a RSA-OAEP keypair
  • I wrap the generated private key with the kek using AES-GCM-256 and a random iv, exported as pkcs8
  • I try to unwrap the key, this fails at the "import" stage

The error message shown in the console is "DOMException: Data provided to an operation does not meet requirements", I have managed to create a MWE as follows:

(async() => {
  let exportFormat = "pkcs8";


  const keyWrappingAlgorithm = {
      name: "AES-GCM",
      length: 256,
  }
  let keyPairAlgorithm = {
      name: "RSA-OAEP",
      modulusLength: 4096,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256",
  };


  let kek = await window.crypto.subtle.generateKey(
      keyWrappingAlgorithm, 
      true, 
      ["decrypt", "wrapKey", "unwrapKey"]
  );

  let keyPair = await crypto.subtle.generateKey(
      keyPairAlgorithm, 
      true, 
      ["encrypt", "decrypt"]
  )



  const iv = crypto.getRandomValues(new Uint8Array(96/8));



  let wrappedPrivateKey = await crypto.subtle.wrapKey(
      exportFormat,
      keyPair.privateKey,
      kek,
      {
          ...keyWrappingAlgorithm,
          iv: iv,
      }
  )

  let decryptedData = await crypto.subtle.decrypt(
      {
          ...keyWrappingAlgorithm,
          iv: iv,
      },
      kek,
      wrappedPrivateKey,
  )
  console.log("done 1", decryptedData)
  await crypto.subtle.importKey(
      exportFormat,
      decryptedData,
      keyPairAlgorithm,
      true,
      ["encrypt", "decrypt"]
  ).then(() => {
      console.log("Success 1! This was not expected.")
  }).catch((error) => console.log("error 1", error))

  let unwrappedKey = await crypto.subtle.unwrapKey(
      exportFormat,
      wrappedPrivateKey,
      kek,
      {
          ...keyWrappingAlgorithm,
          iv: iv,
      },
      keyPairAlgorithm,
      true,
      ["encrypt", "decrypt"]
  ).then(() => {
      console.log("Success 2! This was not expected.")
  }).catch((error) => console.log("error 2", error))
})()

What is going on here? How can I correct this behavior and unwrap the wrapped key?

I've been sitting at this for at least 2 hours by now to extract the MWE, but the error message doesn't give much information. I tried changing the export format, but that didn't really help. The keys all are exportable, so this shouldn't be an issue either. I also think that I added all the required key usages..

Kaiido
  • 123,334
  • 13
  • 219
  • 285
shilomig
  • 57
  • 4

1 Answers1

1

For RSA-OAEP a private key can only be used for decryption (encryption is done with the public key), i.e. for keyUsages ["decrypt"] has to be used and not ["encrypt", "decrypt"]. The error message ...Cannot create a key using the specified key usages... points this out.
If you apply ["decrypt"] as keyUsages in importKey() and unwrapKey() the importing and unwrapping works:

(async() => {
  let exportFormat = "pkcs8";
  const keyWrappingAlgorithm = {
      name: "AES-GCM",
      length: 256,
  }
  let keyPairAlgorithm = {
      name: "RSA-OAEP",
      modulusLength: 4096,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256",
  };

  let kek = await window.crypto.subtle.generateKey(
      keyWrappingAlgorithm, 
      true, 
      ["decrypt", "wrapKey", "unwrapKey"]
  );
  let keyPair = await crypto.subtle.generateKey(
      keyPairAlgorithm, 
      true, 
      ["encrypt", "decrypt"]
  )

  const iv = crypto.getRandomValues(new Uint8Array(96/8));

  let wrappedPrivateKey = await crypto.subtle.wrapKey(
      exportFormat,
      keyPair.privateKey,
      kek,
      {
          ...keyWrappingAlgorithm,
          iv: iv,
      }
  )

  let decryptedData = await crypto.subtle.decrypt(
      {
          ...keyWrappingAlgorithm,
          iv: iv,
      },
      kek,
      wrappedPrivateKey,
  )
  
  let decryptedKey = await crypto.subtle.importKey(
      exportFormat,
      decryptedData,
      keyPairAlgorithm,
      true,
      ["decrypt"]
  )
  console.log(decryptedKey);
  console.log(ab2hex(await crypto.subtle.exportKey('pkcs8', decryptedKey)));

  let unwrappedKey = await crypto.subtle.unwrapKey(
      exportFormat,
      wrappedPrivateKey,
      kek,
      {
          ...keyWrappingAlgorithm,
          iv: iv,
      },
      keyPairAlgorithm,
      true,
      ["decrypt"]
  )
  console.log(unwrappedKey);
  console.log(ab2hex(await crypto.subtle.exportKey('pkcs8', unwrappedKey)));
})()

function ab2hex(ab) { 
  return Array.prototype.map.call(new Uint8Array(ab), x => ('00' + x.toString(16)).slice(-2)).join('');
}
Topaco
  • 40,594
  • 4
  • 35
  • 62