WebCryptoApi:无法将 "encrypt" 和 "decrypt" 处于活动状态的 "jwk" 格式包装和解包 aes-gcm 密钥
WebCryptoApi: Cannot wrap&unwrap aes-gcm key into&from "jwk" format with "encrypt" and "decrypt" active
我正在生成一个用于加密数据的密钥,然后使用主密钥将其打包并将其与加密数据一起存储。当包装成 raw
格式时一切都很好,但是当包装成 jwk
时我得到错误 DOMException: Data provided to an operation does not meet requirements
.
在指定用于加密或解密的密钥时有效,但在两者都指定为密钥用途时无效。
let wrapAlgo = {
name: "AES-KW",
length: 256
};
let encAlgo = {
name:"AES-GCM",
length:256
}
let format = "jwk";
let extractable=true;
let keyUsages = ["encrypt", "decrypt"];
let kek = await crypto.subtle.generateKey(
wrapAlgo,
false,
["wrapKey", "unwrapKey"]
);
let key = await window.crypto.subtle.generateKey(
encAlgo,
extractable, // the key is extractable (i.e. can be used in exportKey)
keyUsages
);
console.log("key", key);
let wrappedKey = await crypto.subtle.wrapKey(
format,
key,
kek,
wrapAlgo
);
console.log("wrappedKey", wrappedKey);
let unwrappedKey = await crypto.subtle.unwrapKey(
format,
wrappedKey,
kek,
wrapAlgo,
encAlgo,
extractable,
keyUsages
);
console.log("key", await crypto.subtle.exportKey("jwk", unwrappedKey));
AES-KW 是 RFC3394. The algorithm is used to wrap i. e. encrypt a key. The input, i.e. the key to be encrypted, must be an integer multiple of 8 bytes, s. also here.
中描述的密钥包装算法
要加密的密钥在 SubtleCrypto.wrapKey()
in the 2nd parameter key
as CryptoKey
中传递,因此必须在实际加密之前导出。为此,在第一个参数 format
:
中指定导出密钥的格式
const result = crypto.subtle.wrapKey(format, key, wrappingKey, wrapAlgo);
在发布的示例中,要包装的密钥是 AES-256 的 32 字节密钥。在 raw
格式中,密钥因此满足 AES-KW 长度标准。然而,在 jwk
格式中,通常不满足长度标准:
如果以 jwk
格式导出的密钥被序列化,它的密钥使用长度 ["encrypt"]
或 ["decrypt"]
恰好是 8 字节(112 字节)的整数倍,而这密钥用法并非如此 ["encrypt", "decrypt"]
(122 bytes):
(async () => {
async function getLength(keyUsages) {
var key = await window.crypto.subtle.generateKey(
{name:"AES-GCM", length: 256},
true,
keyUsages
);
var expkey = await crypto.subtle.exportKey("jwk", key)
var expkeySerLen = JSON.stringify(expkey).length;
return {KeyUsages: keyUsages, length: expkeySerLen, lenMod8: expkeySerLen % 8};
}
console.log(await getLength(["encrypt"])); // works
console.log(await getLength(["decrypt"])); // works
console.log(await getLength(["encrypt", "decrypt"])); // doesn't work
})();
这很可能是执行键用法["encrypt"]
或["decrypt"]
的代码,而不执行键用法["encrypt", "decrypt"]
的代码的原因。
最重要的是,AES-KW 可靠地 raw
格式,但不适用于 jwk
格式。
但是,jwk
格式可以在 SubtleCrypto.wrapKey()
中用于其他包装算法,例如 AES-GCM:
(async () => {
let encAlgo = {
name:"AES-GCM",
length:256
};
let wrapAlgo = {
name:"AES-GCM",
length:256
};
let aesGcmParams = {
name:"AES-GCM",
iv: window.crypto.getRandomValues(new Uint8Array(12))
};
let format = "jwk";
let extractable=true;
let keyUsages = ["encrypt", "decrypt"];
let kek = await crypto.subtle.generateKey(
wrapAlgo,
false,
["wrapKey", "unwrapKey"]
);
let key = await window.crypto.subtle.generateKey(
encAlgo,
extractable, // the key is extractable (i.e. can be used in exportKey)
keyUsages
);
console.log("key (CryptoKey)", key);
console.log("key (jwk)", await crypto.subtle.exportKey("jwk", key));
let wrappedKey = await crypto.subtle.wrapKey(
format,
key,
kek,
aesGcmParams
);
console.log("wrappedKey (ArrayBuffer)", wrappedKey);
let unwrappedKey = await crypto.subtle.unwrapKey(
format,
wrappedKey,
kek,
aesGcmParams,
encAlgo,
extractable,
keyUsages
);
console.log("unwrappedKey (jwk) ", await crypto.subtle.exportKey("jwk", unwrappedKey));
})();
我正在生成一个用于加密数据的密钥,然后使用主密钥将其打包并将其与加密数据一起存储。当包装成 raw
格式时一切都很好,但是当包装成 jwk
时我得到错误 DOMException: Data provided to an operation does not meet requirements
.
在指定用于加密或解密的密钥时有效,但在两者都指定为密钥用途时无效。
let wrapAlgo = {
name: "AES-KW",
length: 256
};
let encAlgo = {
name:"AES-GCM",
length:256
}
let format = "jwk";
let extractable=true;
let keyUsages = ["encrypt", "decrypt"];
let kek = await crypto.subtle.generateKey(
wrapAlgo,
false,
["wrapKey", "unwrapKey"]
);
let key = await window.crypto.subtle.generateKey(
encAlgo,
extractable, // the key is extractable (i.e. can be used in exportKey)
keyUsages
);
console.log("key", key);
let wrappedKey = await crypto.subtle.wrapKey(
format,
key,
kek,
wrapAlgo
);
console.log("wrappedKey", wrappedKey);
let unwrappedKey = await crypto.subtle.unwrapKey(
format,
wrappedKey,
kek,
wrapAlgo,
encAlgo,
extractable,
keyUsages
);
console.log("key", await crypto.subtle.exportKey("jwk", unwrappedKey));
AES-KW 是 RFC3394. The algorithm is used to wrap i. e. encrypt a key. The input, i.e. the key to be encrypted, must be an integer multiple of 8 bytes, s. also here.
中描述的密钥包装算法要加密的密钥在 SubtleCrypto.wrapKey()
in the 2nd parameter key
as CryptoKey
中传递,因此必须在实际加密之前导出。为此,在第一个参数 format
:
const result = crypto.subtle.wrapKey(format, key, wrappingKey, wrapAlgo);
在发布的示例中,要包装的密钥是 AES-256 的 32 字节密钥。在 raw
格式中,密钥因此满足 AES-KW 长度标准。然而,在 jwk
格式中,通常不满足长度标准:
如果以 jwk
格式导出的密钥被序列化,它的密钥使用长度 ["encrypt"]
或 ["decrypt"]
恰好是 8 字节(112 字节)的整数倍,而这密钥用法并非如此 ["encrypt", "decrypt"]
(122 bytes):
(async () => {
async function getLength(keyUsages) {
var key = await window.crypto.subtle.generateKey(
{name:"AES-GCM", length: 256},
true,
keyUsages
);
var expkey = await crypto.subtle.exportKey("jwk", key)
var expkeySerLen = JSON.stringify(expkey).length;
return {KeyUsages: keyUsages, length: expkeySerLen, lenMod8: expkeySerLen % 8};
}
console.log(await getLength(["encrypt"])); // works
console.log(await getLength(["decrypt"])); // works
console.log(await getLength(["encrypt", "decrypt"])); // doesn't work
})();
这很可能是执行键用法["encrypt"]
或["decrypt"]
的代码,而不执行键用法["encrypt", "decrypt"]
的代码的原因。
最重要的是,AES-KW 可靠地 raw
格式,但不适用于 jwk
格式。
但是,jwk
格式可以在 SubtleCrypto.wrapKey()
中用于其他包装算法,例如 AES-GCM:
(async () => {
let encAlgo = {
name:"AES-GCM",
length:256
};
let wrapAlgo = {
name:"AES-GCM",
length:256
};
let aesGcmParams = {
name:"AES-GCM",
iv: window.crypto.getRandomValues(new Uint8Array(12))
};
let format = "jwk";
let extractable=true;
let keyUsages = ["encrypt", "decrypt"];
let kek = await crypto.subtle.generateKey(
wrapAlgo,
false,
["wrapKey", "unwrapKey"]
);
let key = await window.crypto.subtle.generateKey(
encAlgo,
extractable, // the key is extractable (i.e. can be used in exportKey)
keyUsages
);
console.log("key (CryptoKey)", key);
console.log("key (jwk)", await crypto.subtle.exportKey("jwk", key));
let wrappedKey = await crypto.subtle.wrapKey(
format,
key,
kek,
aesGcmParams
);
console.log("wrappedKey (ArrayBuffer)", wrappedKey);
let unwrappedKey = await crypto.subtle.unwrapKey(
format,
wrappedKey,
kek,
aesGcmParams,
encAlgo,
extractable,
keyUsages
);
console.log("unwrappedKey (jwk) ", await crypto.subtle.exportKey("jwk", unwrappedKey));
})();