SubtleCrypto: wrapKey() 方法
注意:此功能在 Web Workers 中可用。
SubtleCrypto 介面的 wrapKey() 方法用於“包裝”一個金鑰。這意味著它會以外部、可移植的格式匯出金鑰,然後加密匯出的金鑰。包裝金鑰有助於在不受信任的環境中保護它,例如在未受保護的資料儲存中或在不受保護的網路上傳輸時。
與 SubtleCrypto.exportKey() 一樣,您需要為金鑰指定一個 匯出格式。要匯出金鑰,其 CryptoKey.extractable 必須設定為 true。
但由於 wrapKey() 還會加密要匯出的金鑰,因此您還需要傳入必須用於加密它的金鑰。這有時被稱為“包裝金鑰”。
wrapKey() 的逆操作是 SubtleCrypto.unwrapKey():wrapKey 由匯出 + 加密組成,而 unwrapKey 由匯入 + 解密組成。
語法
wrapKey(format, key, wrappingKey, wrapAlgo)
引數
格式(format)-
一個描述金鑰將要匯出的資料格式的字串,之後會被加密。它可以是以下之一:
key-
要包裝的
CryptoKey。 wrappingkey-
用於加密匯出金鑰的
CryptoKey。該金鑰必須具有wrapKey用途。 wrapAlgo-
一個物件,指定用於加密匯出金鑰的 演算法以及任何必需的額外引數。
- 要使用 RSA-OAEP,請傳遞一個
RsaOaepParams物件。 - 要使用 AES-CTR,請傳遞一個
AesCtrParams物件。 - 要使用 AES-CBC,請傳遞一個
AesCbcParams物件。 - 要使用 AES-GCM,請傳遞一個
AesGcmParams物件。 - 要使用 AES-KW,請傳遞字串
"AES-KW",或者一個形式為{ name: "AES-KW" }的物件。
- 要使用 RSA-OAEP,請傳遞一個
返回值
一個 Promise,該 Promise 會 fulfilled 為一個包含加密後的匯出金鑰的 ArrayBuffer。
異常
當遇到以下任一異常時,Promise 將被拒絕:
InvalidAccessErrorDOMException-
當包裝金鑰不是請求的包裝演算法的金鑰時丟擲。
NotSupportedDOMException-
嘗試使用未知或不適合加密或包裝的演算法時丟擲。
TypeError-
當嘗試使用無效格式時丟擲。
支援的演算法
所有 可用於加密的演算法 也可用於金鑰包裝,前提是金鑰具有“wrapKey”用途。對於金鑰包裝,您還可以選擇 AES-KW。
AES-KW
AES-KW 是一種使用 AES 密碼進行金鑰包裝的方法。
與 AES-GCM 等其他 AES 模式相比,使用 AES-KW 的一個優點是 AES-KW 不需要初始化向量。要使用 AES-KW,輸入必須是 64 位的倍數。
AES-KW 在 RFC 3394 中有規定。
示例
注意: 您可以在 GitHub 上 嘗試這些工作示例。
Raw wrap
此示例包裝一個 AES 金鑰。它使用“raw”作為匯出格式,並使用 AES-KW(帶有一個密碼派生金鑰)來加密它。在 GitHub 上檢視完整程式碼。
let salt;
/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
const password = window.prompt("Enter your password");
const enc = new TextEncoder();
return window.crypto.subtle.importKey(
"raw",
enc.encode(password),
{ name: "PBKDF2" },
false,
["deriveBits", "deriveKey"],
);
}
/*
Given some key material and some random salt
derive an AES-KW key using PBKDF2.
*/
function getKey(keyMaterial, salt) {
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 100000,
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-KW", length: 256 },
true,
["wrapKey", "unwrapKey"],
);
}
/*
Wrap the given key.
*/
async function wrapCryptoKey(keyToWrap) {
// get the key encryption key
const keyMaterial = await getKeyMaterial();
salt = window.crypto.getRandomValues(new Uint8Array(16));
const wrappingKey = await getKey(keyMaterial, salt);
return window.crypto.subtle.wrapKey("raw", keyToWrap, wrappingKey, "AES-KW");
}
/*
Generate an encrypt/decrypt secret key,
then wrap it.
*/
window.crypto.subtle
.generateKey(
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"],
)
.then((secretKey) => wrapCryptoKey(secretKey))
.then((wrappedKey) => console.log(wrappedKey));
PKCS #8 wrap
此示例包裝一個 RSA 私有簽名金鑰。它使用“pkcs8”作為匯出格式,並使用 AES-GCM(帶有一個密碼派生金鑰)來加密它。在 GitHub 上檢視完整程式碼。
let salt;
let iv;
/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
const password = window.prompt("Enter your password");
const enc = new TextEncoder();
return window.crypto.subtle.importKey(
"raw",
enc.encode(password),
{ name: "PBKDF2" },
false,
["deriveBits", "deriveKey"],
);
}
/*
Given some key material and some random salt
derive an AES-GCM key using PBKDF2.
*/
function getKey(keyMaterial, salt) {
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 100000,
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
true,
["wrapKey", "unwrapKey"],
);
}
/*
Wrap the given key.
*/
async function wrapCryptoKey(keyToWrap) {
// get the key encryption key
const keyMaterial = await getKeyMaterial();
salt = window.crypto.getRandomValues(new Uint8Array(16));
const wrappingKey = await getKey(keyMaterial, salt);
iv = window.crypto.getRandomValues(new Uint8Array(12));
return window.crypto.subtle.wrapKey("pkcs8", keyToWrap, wrappingKey, {
name: "AES-GCM",
iv,
});
}
/*
Generate a sign/verify key pair,
then wrap the private key.
*/
window.crypto.subtle
.generateKey(
{
name: "RSA-PSS",
// Consider using a 4096-bit key for systems that require long-term security
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
},
true,
["sign", "verify"],
)
.then((keyPair) => wrapCryptoKey(keyPair.privateKey))
.then((wrappedKey) => {
console.log(wrappedKey);
});
SubjectPublicKeyInfo wrap
此示例包裝一個 RSA 公有加密金鑰。它使用“spki”作為匯出格式,並使用 AES-CBC(帶有一個密碼派生金鑰)來加密它。在 GitHub 上檢視完整程式碼。
let salt;
let iv;
/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
const password = window.prompt("Enter your password");
const enc = new TextEncoder();
return window.crypto.subtle.importKey(
"raw",
enc.encode(password),
{ name: "PBKDF2" },
false,
["deriveBits", "deriveKey"],
);
}
/*
Given some key material and some random salt
derive an AES-CBC key using PBKDF2.
*/
function getKey(keyMaterial, salt) {
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 100000,
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-CBC", length: 256 },
true,
["wrapKey", "unwrapKey"],
);
}
/*
Wrap the given key.
*/
async function wrapCryptoKey(keyToWrap) {
// get the key encryption key
const keyMaterial = await getKeyMaterial();
salt = window.crypto.getRandomValues(new Uint8Array(16));
const wrappingKey = await getKey(keyMaterial, salt);
iv = window.crypto.getRandomValues(new Uint8Array(16));
return window.crypto.subtle.wrapKey("spki", keyToWrap, wrappingKey, {
name: "AES-CBC",
iv,
});
}
/*
Generate an encrypt/decrypt key pair,
then wrap it.
*/
window.crypto.subtle
.generateKey(
{
name: "RSA-OAEP",
// Consider using a 4096-bit key for systems that require long-term security
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
},
true,
["encrypt", "decrypt"],
)
.then((keyPair) => wrapCryptoKey(keyPair.publicKey))
.then((wrappedKey) => console.log(wrappedKey));
JSON Web Key wrap
此示例包裝一個 ECDSA 私有簽名金鑰。它使用“jwk”作為匯出格式,並使用 AES-GCM(帶有一個密碼派生金鑰)來加密它。在 GitHub 上檢視完整程式碼。
let salt;
let iv;
/*
Get some key material to use as input to the deriveKey method.
The key material is a password supplied by the user.
*/
function getKeyMaterial() {
const password = window.prompt("Enter your password");
const enc = new TextEncoder();
return window.crypto.subtle.importKey(
"raw",
enc.encode(password),
{ name: "PBKDF2" },
false,
["deriveBits", "deriveKey"],
);
}
/*
Given some key material and some random salt
derive an AES-GCM key using PBKDF2.
*/
function getKey(keyMaterial, salt) {
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 100000,
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
true,
["wrapKey", "unwrapKey"],
);
}
/*
Wrap the given key.
*/
async function wrapCryptoKey(keyToWrap) {
// get the key encryption key
const keyMaterial = await getKeyMaterial();
salt = window.crypto.getRandomValues(new Uint8Array(16));
const wrappingKey = await getKey(keyMaterial, salt);
iv = window.crypto.getRandomValues(new Uint8Array(12));
return window.crypto.subtle.wrapKey("jwk", keyToWrap, wrappingKey, {
name: "AES-GCM",
iv,
});
}
/*
Generate a sign/verify key pair,
then wrap the private key
*/
window.crypto.subtle
.generateKey(
{
name: "ECDSA",
namedCurve: "P-384",
},
true,
["sign", "verify"],
)
.then((keyPair) => wrapCryptoKey(keyPair.privateKey))
.then((wrappedKey) => console.log(wrappedKey));
規範
| 規範 |
|---|
| Web 加密級別 2 # SubtleCrypto-method-wrapKey |
瀏覽器相容性
載入中…