Setup:
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..
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('');
}