以下代码在Firefox 76.0.1中工作。
"use strict"
let RSAKeys
(async () => {
RSAKeys = await crypto.subtle.generateKey({
name: "RSA-OAEP",
modulusLength: 3072,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256"},
true,
// Chromium bug causes it to falsely complain that the array is empty. Sometimes adding "encrypt" helps.
["wrapKey"])
})()
但在Chromium 80中,我得到:
Uncaught (in promise) DOMException: 当创建一个键时,Usages不能为空。
["wrapKey"]
显然不是一个空数组,所以这似乎是一个浏览器的错误。可能是 这个. 你能确认吗?更重要的是,你知道有什么变通方法吗?(添加 encrypt
的用法有帮助,但只是第一次,然后就出现了同样的错误)。) 它必须是一个支持封装密钥的非对称密码。根据表中的 规范的相关章节,RSA-OAEP是唯一的可能。
我可以重现这个问题 铬 版本85.0.4162.0。关键用法 ["wrapKey"]
产生了发布的错误信息。但我无法重现,添加键的使用方法 加密 (即 ["wrapKey", "encrypt"]
)解决了这个问题(甚至不是第一次)。然而,如果加上关键用法 拆解键 (即 ["wrapKey", "unwrapKey"]
)的错误不再发生。
SubtleCrypto.generateKey()
返回一个 CryptoKeyPair
对于 "RSA-OAEP"
包含RSA密钥对。如果你在 火狐 浏览器控制台,在用密钥用途生成的密钥对上 ["wrapKey", "unwrapKey"]
可以看出,公钥的密钥用途是 ["wrapKey"]
和私钥的是 ["unwrapKey"]
. 这两种方式都是合理的,因为公钥用于封装,私钥用于解包。
但是,如果你看一下 火狐 浏览器控制台,在用密钥用途生成的密钥对上 ["wrapKey"]
你可以看到,公钥的用途是不变的。["wrapKey"]
而私钥则是 虚空:
所以 铬 通过相应的错误信息(显然是指空密钥用法的私钥)来防止生成没有密钥用法的密钥。与 铬, 火狐 显然是允许的。
现在是一个 铬 BUG?其实在没有密钥用途的情况下,创建一个密钥意义不大,因为它不能被使用!
火狐浏览器的例子: 如果在Firefox浏览器中执行以下代码,确实生成了密钥对,并且因为密钥的使用而封装了一个密钥。wrapkey 的公钥,但解包失败,出现了一个 InvalidAccessError
如果关键用法 拆解键 的私钥不见了。
var test = async () => {
try {
var mode = document.querySelector('input[name="keyUsages"]:checked').value;
var keyUsages = (mode === "wrap") ? ["wrapKey"] : ["wrapKey", "unwrapKey"]
// Create RSA key pair
var RSAKeys = await crypto.subtle.generateKey(
{name: "RSA-OAEP", modulusLength: 3072, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}},
true,
keyUsages);
// Create key to wrap
var keyToWrap = await window.crypto.subtle.generateKey(
{name: "AES-GCM", length: 128},
true,
["encrypt", "decrypt"]);
// Wrap key
var wrappedKey = await window.crypto.subtle.wrapKey(
"raw",
keyToWrap,
RSAKeys.publicKey,
{name: "RSA-OAEP", hash: {name: "SHA-256"}});
// Unwrap key
var unwrappedKey = await window.crypto.subtle.unwrapKey(
"raw",
wrappedKey,
RSAKeys.privateKey,
{name: "RSA-OAEP", modulusLength: 3072, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}},
{name: "AES-GCM", length: 128},
false,
["encrypt", "decrypt"]);
document.getElementById("result").innerHTML = "Secret key for " + unwrappedKey.algorithm.name + " unwrapped.";
console.log(unwrappedKey);
} catch(e) {
document.getElementById("result").innerHTML = e.name + ": " + e.message;
}
}
.as-console-wrapper { max-height: 7.0em !important; }
<!DOCTYPE html>
<html>
<body height="200">
<input type="radio" name="keyUsages" value="wrap" checked="true"> ["wrapKey"]
<input type="radio" name="keyUsages" value="wrapUnwrap"> ["wrapKey", "unwrapKey"]
<button onclick="test()">Run</button><br/>
<p id="result"></p>
</body>
</html>
因此,我不会把它归类为一个错误(但这只是我的观点)。