SubtleCrypto: phương thức wrapKey()
Baseline
Widely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since January 2020.
Secure context: This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.
Note: This feature is available in Web Workers.
Phương thức wrapKey() của giao diện SubtleCrypto "bọc" một khóa.
Điều này có nghĩa là nó xuất khóa ở định dạng bên ngoài, có thể di chuyển, sau đó mã hóa khóa đã xuất.
Việc bọc khóa giúp bảo vệ khóa trong các môi trường không đáng tin, chẳng hạn như trong kho lưu trữ không được bảo vệ hoặc khi truyền qua mạng không bảo mật.
Như với SubtleCrypto.exportKey(), bạn chỉ định một định dạng xuất cho khóa.
Để xuất một khóa, nó phải có CryptoKey.extractable được đặt thành true.
Nhưng vì wrapKey() cũng mã hóa khóa cần xuất, bạn cũng cần truyền khóa phải dùng để mã hóa nó.
Đôi khi đây được gọi là "khóa bọc khóa".
Ngược lại với wrapKey() là SubtleCrypto.unwrapKey(): trong khi wrapKey được cấu thành từ export + encrypt, unwrapKey được cấu thành từ import + decrypt.
Cú pháp
wrapKey(format, key, wrappingKey, wrapAlgo)
Tham số
format-
Một chuỗi mô tả định dạng dữ liệu mà khóa sẽ được xuất trước khi được mã hóa. Nó có thể là một trong các giá trị sau:
raw-
Định dạng Raw.
pkcs8-
Định dạng PKCS #8.
spki-
Định dạng SubjectPublicKeyInfo.
jwk-
Định dạng JSON Web Key.
key-
CryptoKeycần bọc. wrappingKey-
CryptoKeyđược sử dụng để mã hóa khóa đã xuất. Khóa phải có cách sử dụngwrapKey. wrapAlgo-
Một đối tượng chỉ định thuật toán sẽ sử dụng để mã hóa khóa đã xuất, và bất kỳ tham số bổ sung nào cần thiết:
- Để sử dụng RSA-OAEP,
truyền một đối tượng
RsaOaepParams. - Để sử dụng AES-CTR,
truyền một đối tượng
AesCtrParams. - Để sử dụng AES-CBC,
truyền một đối tượng
AesCbcParams. - Để sử dụng AES-GCM,
truyền một đối tượng
AesGcmParams. - Để sử dụng AES-KW,
truyền chuỗi
"AES-KW", hoặc một đối tượng có dạng{ name: "AES-KW" }.
- Để sử dụng RSA-OAEP,
truyền một đối tượng
Giá trị trả về
Một Promise được fulfill với một ArrayBuffer chứa khóa đã xuất được mã hóa.
Ngoại lệ
Promise bị reject khi gặp một trong các ngoại lệ sau:
InvalidAccessErrorDOMException-
Ném lên khi khóa bọc không phải là khóa cho thuật toán bọc được yêu cầu.
NotSupportedDOMException-
Ném lên khi cố sử dụng một thuật toán không xác định hoặc không phù hợp để mã hóa hoặc bọc.
TypeError-
Ném lên khi cố sử dụng một định dạng không hợp lệ.
Các thuật toán được hỗ trợ
Tất cả các thuật toán có thể sử dụng để mã hóa đều có thể sử dụng để bọc khóa, miễn là khóa có cách sử dụng "wrapKey". Để bọc khóa, bạn có thêm lựa chọn AES-KW.
AES-KW
AES-KW là một cách sử dụng bộ mã AES để bọc khóa.
Một ưu điểm của việc sử dụng AES-KW so với chế độ AES khác như AES-GCM là AES-KW không yêu cầu vector khởi tạo. Để sử dụng AES-KW, đầu vào phải là bội số của 64 bit.
AES-KW được chỉ định trong RFC 3394.
Ví dụ
Note: Bạn có thể thử các ví dụ hoạt động trên GitHub.
Bọc Raw
Ví dụ này bọc một khóa AES. Nó sử dụng "raw" làm định dạng xuất và AES-KW, với khóa phái sinh từ mật khẩu, để mã hóa nó. Xem mã đầy đủ trên GitHub.
let salt;
/*
Lấy một số tài liệu khóa để sử dụng làm đầu vào cho phương thức deriveKey.
Tài liệu khóa là mật khẩu do người dùng cung cấp.
*/
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"],
);
}
/*
Với một số tài liệu khóa và một số salt ngẫu nhiên
phái sinh một khóa AES-KW bằng 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"],
);
}
/*
Bọc khóa đã cho.
*/
async function wrapCryptoKey(keyToWrap) {
// lấy khóa mã hóa khóa
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");
}
/*
Tạo một khóa bí mật mã hóa/giải mã,
sau đó bọc nó.
*/
window.crypto.subtle
.generateKey(
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"],
)
.then((secretKey) => wrapCryptoKey(secretKey))
.then((wrappedKey) => console.log(wrappedKey));
Bọc PKCS #8
Ví dụ này bọc một khóa riêng tư ký RSA. Nó sử dụng "pkcs8" làm định dạng xuất và AES-GCM, với khóa phái sinh từ mật khẩu, để mã hóa nó. Xem mã đầy đủ trên GitHub.
let salt;
let iv;
/*
Lấy một số tài liệu khóa để sử dụng làm đầu vào cho phương thức deriveKey.
Tài liệu khóa là mật khẩu do người dùng cung cấp.
*/
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"],
);
}
/*
Với một số tài liệu khóa và một số salt ngẫu nhiên
phái sinh một khóa AES-GCM bằng 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"],
);
}
/*
Bọc khóa đã cho.
*/
async function wrapCryptoKey(keyToWrap) {
// lấy khóa mã hóa khóa
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,
});
}
/*
Tạo một cặp khóa ký/xác minh,
sau đó bọc khóa riêng tư.
*/
window.crypto.subtle
.generateKey(
{
name: "RSA-PSS",
// Cân nhắc sử dụng khóa 4096-bit cho các hệ thống yêu cầu bảo mật dài hạn
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
},
true,
["sign", "verify"],
)
.then((keyPair) => wrapCryptoKey(keyPair.privateKey))
.then((wrappedKey) => {
console.log(wrappedKey);
});
Bọc SubjectPublicKeyInfo
Ví dụ này bọc một khóa công khai mã hóa RSA. Nó sử dụng "spki" làm định dạng xuất và AES-CBC, với khóa phái sinh từ mật khẩu, để mã hóa nó. Xem mã đầy đủ trên GitHub.
let salt;
let iv;
/*
Lấy một số tài liệu khóa để sử dụng làm đầu vào cho phương thức deriveKey.
Tài liệu khóa là mật khẩu do người dùng cung cấp.
*/
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"],
);
}
/*
Với một số tài liệu khóa và một số salt ngẫu nhiên
phái sinh một khóa AES-CBC bằng 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"],
);
}
/*
Bọc khóa đã cho.
*/
async function wrapCryptoKey(keyToWrap) {
// lấy khóa mã hóa khóa
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,
});
}
/*
Tạo một cặp khóa mã hóa/giải mã,
sau đó bọc nó.
*/
window.crypto.subtle
.generateKey(
{
name: "RSA-OAEP",
// Cân nhắc sử dụng khóa 4096-bit cho các hệ thống yêu cầu bảo mật dài hạn
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
},
true,
["encrypt", "decrypt"],
)
.then((keyPair) => wrapCryptoKey(keyPair.publicKey))
.then((wrappedKey) => console.log(wrappedKey));
Bọc JSON Web Key
Ví dụ này bọc một khóa riêng tư ký ECDSA. Nó sử dụng "jwk" làm định dạng xuất và AES-GCM, với khóa phái sinh từ mật khẩu, để mã hóa nó. Xem mã đầy đủ trên GitHub.
let salt;
let iv;
/*
Lấy một số tài liệu khóa để sử dụng làm đầu vào cho phương thức deriveKey.
Tài liệu khóa là mật khẩu do người dùng cung cấp.
*/
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"],
);
}
/*
Với một số tài liệu khóa và một số salt ngẫu nhiên
phái sinh một khóa AES-GCM bằng 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"],
);
}
/*
Bọc khóa đã cho.
*/
async function wrapCryptoKey(keyToWrap) {
// lấy khóa mã hóa khóa
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,
});
}
/*
Tạo một cặp khóa ký/xác minh,
sau đó bọc khóa riêng tư
*/
window.crypto.subtle
.generateKey(
{
name: "ECDSA",
namedCurve: "P-384",
},
true,
["sign", "verify"],
)
.then((keyPair) => wrapCryptoKey(keyPair.privateKey))
.then((wrappedKey) => console.log(wrappedKey));
Đặc tả kỹ thuật
| Specification |
|---|
| Web Cryptography Level 2> # SubtleCrypto-method-wrapKey> |