SubtleCryptoï¼wrapKey() æ¹æ³
åºçº¿
广æ³å¯ç¨
èª 2020å¹´1æ èµ·ï¼æ¤ç¹æ§å·²å¨ä¸»æµæµè§å¨ä¸å¾å°æ¯æï¼å¯å¨å¤§å¤æ°è®¾å¤åæµè§å¨çæ¬ä¸æ£å¸¸ä½¿ç¨ã
å®å ¨ä¸ä¸æ: æ¤ç¹æ§ä» å¨ä¸äºæ¯æçæµè§å¨çå®å ¨ä¸ä¸æï¼HTTPSï¼ä¸å¯ç¨ã
SubtleCrypto æ¥å£ç wrapKey() æ¹æ³ç¨äºâå
è£
âï¼wrapï¼å¯é¥ãè¿ä¸å³çå®ä»¥å¤é¨å¯ç§»æ¤çæ ¼å¼å¯¼åºå¯é¥ï¼ç¶å对å
¶è¿è¡å å¯ãå
è£
å¯é¥æå©äºå¨ä¸åä¿¡ä»»çç¯å¢ä¸ä¿æ¤å®ï¼ä¾å¦å¨æªåä¿æ¤çæ°æ®åå¨ï¼æå¨æªåä¿æ¤çç½ç»ä¸è¿è¡ä¼ è¾ã
ä¸ SubtleCrypto.exportKey() 䏿 ·ï¼ä½ éè¦æå®å¯é¥çå¯¼åºæ ¼å¼ãè¦å¯¼åºå¯é¥ï¼å¿
é¡»å° CryptoKey.extractable 设置为 trueã
使¯ï¼ç±äº wrapKey() è¿ä¼å¯¹è¦å¯¼åºçå¯é¥è¿è¡å å¯ï¼å æ¤è¿éè¦ä¼ å
¥ç¨äºå å¯çå¯é¥ãè¿ææ¶è¢«ç§°ä¸ºâå
è£
å¯é¥âï¼wrapping keyï¼ã
wrapKey() çéè¿ç®æ¯ SubtleCrypto.unwrapKey()ï¼wrapKey ç±å¯¼åº + å å¯ç»æï¼è unwrapKey ç±å¯¼å
¥ + è§£å¯ç»æã
è¯æ³
wrapKey(format, key, wrappingKey, wrapAlgo)
åæ°
format-
æè¿°å¯é¥å¨å å¯ä¹åæå¯¼åºçæ°æ®æ ¼å¼çå符串ãå®å¯ä»¥æ¯ä»¥ä¸å¼ä¹ä¸ï¼
raw-
Raw æ ¼å¼ã
pkcs8-
PKCS #8 æ ¼å¼ã
spki-
SubjectPublicKeyInfo æ ¼å¼ã
jwk-
JSON Web Key æ ¼å¼ã
key-
å°è¢«å è£ çå¯é¥ã
wrappingkey-
ç¨äºå å¯å¯¼åºå¯é¥çå¯é¥ãå¯é¥çç¨éå¿ é¡»å æ¬
wrapKeyã wrapAlgo-
æå®ç¨äºå å¯å¯¼åºå¯é¥çç®æ³ç对象ï¼ä»¥å任使éçé¢å¤åæ°ï¼
- å¯¹äº RSA-OAEPï¼è¯·ä¼ å
¥
RsaOaepParams对象ã - å¯¹äº AES-CTRï¼è¯·ä¼ å
¥
AesCtrParams对象ã - å¯¹äº AES-CBCï¼è¯·ä¼ å
¥
AesCbcParams对象ã - å¯¹äº AES-GCMï¼è¯·ä¼ å
¥
AesGcmParams对象ã - å¯¹äº AES-KWï¼è¯·ä¼ å
¥å符串
"AES-KW"ï¼æ{ "name": "AES-KW" }å½¢å¼ç对象ã
- å¯¹äº RSA-OAEPï¼è¯·ä¼ å
¥
è¿åå¼
ä¸ä¸ª Promiseï¼ä¼å
ç°ä¸ä¸ªå
å«å·²å å¯ç导åºå¯é¥ç ArrayBufferã
å¼å¸¸
å½éå°ä»¥ä¸å¼å¸¸æ¶ï¼promise å°ä¼è¢«æç»ï¼
InvalidAccessErrorDOMException-
å½å è£ å¯é¥ä¸æ¯è¦æ±çå è£ ç®æ³çå¯é¥æ¶è§¦åã
NotSupportedDOMException-
å½å°è¯ä½¿ç¨æªç¥æä¸éç¨äºå å¯/å è£ çç®æ³æ¶è§¦åã
TypeError-
å½å°è¯ä½¿ç¨æ ææ ¼å¼æ¶è§¦åã
æ¯æçç®æ³
ææå¯ç¨äºå å¯çç®æ³ï¼åªè¦è®¾ç½®äºâwrapKeyâç¨éï¼ä¹é½å¯ä»¥ç¨äºå¯é¥å è£ ã对äºå¯é¥å è£ ï¼ä½ è¿å¯ä»¥ä½¿ç¨ AES-KWã
AES-KW
AES-KW æ¯ä¸ç§ä½¿ç¨ AES å¯ç æ¥å¯¹å¯é¥è¿è¡å è£ çæ¹æ³ã
ä½¿ç¨ AES-KW ç¸æ¯äºå ¶ä» AES 模å¼ï¼ä¾å¦ AES-GCMï¼çä¸ä¸ªæç¹æ¯ï¼AES-KW ä¸éè¦åå§ååéãè¦ä½¿ç¨ AES-KWï¼è¾å ¥å¿ é¡»æ¯ 64 ä½çåæ°ã
AES-KW è§å®äº RFC 3394 ä¸ã
示ä¾
夿³¨ï¼ä½ å¯ä»¥å¨ GitHub ä¸å°è¯è¿ä¸ªå¯ç¨ç示ä¾ã
Raw å è£
以ä¸ç¤ºä¾å è£ äºä¸ä¸ª AES å¯é¥ãå®ä½¿ç¨ârawâä½ä¸ºå¯¼åºæ ¼å¼ï¼å¹¶ä½¿ç¨ AES-KW åå¯ç æ´¾çå¯é¥å¯¹å ¶è¿è¡å å¯ãå¨ GitHub 䏿¥ç宿´ç代ç ã
let salt;
/*
è·åç¨äºä½ä¸º deriveKey æ¹æ³çè¾å
¥çå¯é¥ææã
å¯é¥æææ¯ç¨æ·æä¾çå¯ç ã
*/
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"],
);
}
/*
ç»å®å¯é¥ææåéæºçï¼ä½¿ç¨ PBKDF2 æ´¾çä¸ä¸ª AES-KW å¯é¥ã
*/
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"],
);
}
/*
å
è£
ç»å®çå¯é¥ã
*/
async function wrapCryptoKey(keyToWrap) {
// è·åå¯é¥å å¯å¯é¥
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");
}
/*
çæå å¯/è§£å¯å¯é¥ï¼ç¶åå
è£
å®ã
*/
window.crypto.subtle
.generateKey(
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"],
)
.then((secretKey) => wrapCryptoKey(secretKey))
.then((wrappedKey) => console.log(wrappedKey));
PKCS #8 å è£
以ä¸ç¤ºä¾å è£ äºä¸ä¸ª RSA ç§æç¾åå¯é¥ãå®ä½¿ç¨âpkcs8âä½ä¸ºå¯¼åºæ ¼å¼ï¼å¹¶ä½¿ç¨ AES-GCM åå¯ç æ´¾çå¯é¥å¯¹å ¶è¿è¡å å¯ãå¨ GitHub 䏿¥ç宿´ç代ç ã
let salt;
let iv;
/*
è·åç¨äºä½ä¸º deriveKey æ¹æ³çè¾å
¥çå¯é¥ææã
å¯é¥æææ¯ç¨æ·æä¾çå¯ç ã
*/
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"],
);
}
/*
ç»å®å¯é¥ææåéæºçï¼ä½¿ç¨ PBKDF2 æ´¾çä¸ä¸ª AES-GCM å¯é¥ã
*/
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"],
);
}
/*
å
è£
ç»å®çå¯é¥ã
*/
async function wrapCryptoKey(keyToWrap) {
// è·åå¯é¥å å¯å¯é¥
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,
});
}
/*
çæç¾å/éªè¯å¯é¥å¯¹ï¼ç¶åå
è£
å
¶ä¸çç§é¥ã
*/
window.crypto.subtle
.generateKey(
{
name: "RSA-PSS",
// èè对éè¦é¿æå®å
¨æ§çç³»ç»ä½¿ç¨ 4096 ä½å¯é¥
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 å è£
以ä¸ç¤ºä¾å è£ äºä¸ä¸ª RSA å ¬å¼å å¯å¯é¥ãå®ä½¿ç¨âspkiâä½ä¸ºå¯¼åºæ ¼å¼ï¼å¹¶ä½¿ç¨ AES-CBC ç®æ³åå¯ç æ´¾çå¯é¥å¯¹å ¶è¿è¡å å¯ãå¨ GitHub 䏿¥ç宿´ç代ç ã
let salt;
let iv;
/*
è·åç¨äºä½ä¸º deriveKey æ¹æ³çè¾å
¥çå¯é¥ææã
å¯é¥æææ¯ç¨æ·æä¾çå¯ç ã
*/
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"],
);
}
/*
ç»å®å¯é¥ææåéæºçï¼ä½¿ç¨ PBKDF2 æ´¾çä¸ä¸ª AES-CBC å¯é¥ã
*/
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"],
);
}
/*
å
è£
ç»å®çå¯é¥ã
*/
async function wrapCryptoKey(keyToWrap) {
// è·åå¯é¥å å¯å¯é¥
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,
});
}
/*
çæå å¯/è§£å¯å¯é¥å¯¹ï¼ç¶åå
è£
å®ã
*/
window.crypto.subtle
.generateKey(
{
name: "RSA-OAEP",
// èè对éè¦é¿æå®å
¨æ§çç³»ç»ä½¿ç¨ 4096 ä½å¯é¥
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 å è£
以ä¸ç¤ºä¾å è£ äºä¸ä¸ª ECDSA ç§æç¾åå¯é¥ãå®ä½¿ç¨âjwkâä½ä¸ºå¯¼åºæ ¼å¼ï¼å¹¶ä½¿ç¨ AES-GCM åå¯ç æ´¾çå¯é¥å¯¹å ¶è¿è¡å å¯ãå¨ GitHub 䏿¥ç宿´ç代ç ã
let salt;
let iv;
/*
è·åç¨äºä½ä¸º deriveKey æ¹æ³çè¾å
¥çå¯é¥ææã
å¯é¥æææ¯ç¨æ·æä¾çå¯ç ã
*/
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"],
);
}
/*
ç»å®å¯é¥ææåéæºçï¼ä½¿ç¨ PBKDF2 æ´¾çä¸ä¸ª AES-GCM å¯é¥ã
*/
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"],
);
}
/*
å
è£
ç»å®çå¯é¥ã
*/
async function wrapCryptoKey(keyToWrap) {
// è·åå¯é¥å å¯å¯é¥
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,
});
}
/*
çæç¾å/éªè¯å¯é¥å¯¹ï¼ç¶åå
è£
å
¶ä¸çç§é¥ã
*/
window.crypto.subtle
.generateKey(
{
name: "ECDSA",
namedCurve: "P-384",
},
true,
["sign", "verify"],
)
.then((keyPair) => wrapCryptoKey(keyPair.privateKey))
.then((wrappedKey) => console.log(wrappedKey));
è§è
| è§è |
|---|
| Web Cryptography Level 2 > # SubtleCrypto-method-wrapKey > |