SubtleCrypto.deriveKey()
åºçº¿
广æ³å¯ç¨
*
èª 2020å¹´1æ èµ·ï¼æ¤ç¹æ§å·²å¨ä¸»æµæµè§å¨ä¸å¾å°æ¯æï¼å¯å¨å¤§å¤æ°è®¾å¤åæµè§å¨çæ¬ä¸æ£å¸¸ä½¿ç¨ã
* æ¤ç¹æ§çæäºé¨åçæ¯æç¨åº¦å¯è½ææä¸åã
å®å ¨ä¸ä¸æ: æ¤ç¹æ§ä» å¨ä¸äºæ¯æçæµè§å¨çå®å ¨ä¸ä¸æï¼HTTPSï¼ä¸å¯ç¨ã
SubtleCrypto æ¥å£ç deriveKey() æ¹æ³ç¨äºä»ä¸»å¯é¥æ´¾çå¯é¥ã
å®ä»¥åºæ¬å¯é¥ã使ç¨çæ´¾çç®æ³åæ´¾çå¯é¥æéç屿§ä¸ºåæ°ãè¿åä¸ä¸ª Promiseï¼ä¼å
ç°ä¸ä¸ªè¡¨ç¤ºæ°å¯é¥ç CryptoKey 对象ã
å¼å¾æ³¨æçæ¯ï¼ä½ å¯ä»¥ä½¿ç¨çä¸ç§å¯é¥æ´¾çç®æ³ææªç¶ä¸åçç¹æ§ï¼èéç¨äºæªç¶ä¸åçæ åµãåè§æ¯æçç®æ³ä»¥è·å详ç»ä¿¡æ¯ã
è¯æ³
deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages)
åæ°
algorithm-
ä¸ä¸ªå¯¹è±¡ï¼ç¨äºæå®ä½¿ç¨çæ´¾çç®æ³ã
- ä½¿ç¨ ECDHï¼åä¼ å
¥
EcdhKeyDeriveParams对象ã - ä½¿ç¨ HKDFï¼åä¼ å
¥
HkdfParams对象ã - ä½¿ç¨ PBKDF2ï¼åä¼ å
¥
Pbkdf2Params对象ã
- ä½¿ç¨ ECDHï¼åä¼ å
¥
baseKey-
ä¸ä¸ª
CryptoKeyï¼è¡¨ç¤ºæ´¾çç®æ³çè¾å ¥ãå¦æç®æ³ï¼algorithmï¼ä¸º ECDHï¼å该对象为 ECDH çç§é¥ãå¦åï¼å®ä¸ºæ´¾ç彿°çåå§å¯é¥ææï¼key materialï¼ï¼ä¾å¦ï¼å¯¹äº PBKDF2ï¼å®å¯è½æ¯ä¸ä¸ªå¯ç ï¼ä½¿ç¨SubtleCrypto.importKey()å¯¼å ¥ä¸ºä¸ä¸ªCryptoKey对象ï¼ã derivedKeyAlgorithm-
ä¸ä¸ªç¨äºæ´¾çå¯é¥ç®æ³ç对象ã
- å¯¹äº HMACï¼ä¼ å
¥
HmacKeyGenParams对象ã - å¯¹äº AES-CTRãAES-CBCãAES-GCM æ AES-KWï¼ä¼ å
¥
AesKeyGenParams对象ã
- å¯¹äº HMACï¼ä¼ å
¥
extractable-
ä¸ä¸ªå¸å°å¼ï¼è¡¨ç¤ºæ¯å¦å¯ä»¥ä½¿ç¨
SubtleCrypto.exportKey()æSubtleCrypto.wrapKey()æ¥å¯¼åºå¯é¥ã keyUsages-
ä¸ä¸ªæ°ç»ï¼è¡¨ç¤ºæ´¾çåºæ¥çå¯é¥çç¨éãæ³¨æï¼å¯é¥çç¨æ³å¿ é¡»æ¯
derivedKeyAlgorithm设置çç®æ³æå 许çãæ°ç»å ç´ å¯è½ç弿ï¼encryptï¼å¯é¥å¯ç¨äºå 坿¶æ¯ãdecryptï¼å¯é¥å¯ç¨äºè§£å¯æ¶æ¯ãsignï¼å¯é¥å¯ç¨äºå¯¹æ¶æ¯è¿è¡ç¾åãverifyï¼å¯é¥å¯ç¨äºéªè¯ç¾åãderiveKeyï¼å¯é¥å¯ç¨äºæ´¾çæ°çå¯é¥ãderiveBitsï¼å¯é¥å¯ç¨äºæ´¾çæ¯ç¹åºåãwrapKeyï¼å¯é¥å¯ç¨äºå è£ ä¸ä¸ªå¯é¥ãunwrapKeyï¼å¯é¥å¯ç¨äºè§£å¼ä¸ä¸ªå¯é¥çå è£ ã
è¿åå¼
å¼å¸¸
å½åçä¸ä¸å ç§å¼å¸¸æ¶ï¼promise ä¼è¢«æç»ï¼
InvalidAccessErrorDOMException-
è¥ä¸»å¯é¥ä¸è¦æ±çæ´¾çç®æ³æä½¿ç¨çå¯é¥ç±»åä¸å¹é ï¼æå¯é¥ç
keyUsagesçå¼ä¸ä¸å å«deriveKeyï¼åä¼æåºæ¤å¼å¸¸ã NotSupportedDOMException-
è¥å°è¯ä½¿ç¨æªç¥æä¸éç¨äºæ´¾ççç®æ³ï¼æç¨äºæ´¾çå¯é¥çç®æ³ï¼algorithmï¼æ²¡æå®ä¹å¯é¥é¿åº¦ï¼key lengthï¼ï¼åä¼æåºæ¤å¼å¸¸ã
SyntaxErrorDOMException-
è¥
keyUsagesæ¯ç©ºçï¼èè§£å è£ å¯é¥çç±»åæ¯secretæprivateï¼åæåºæ¤å¼å¸¸ã
æ¯æçç®æ³
deriveKey() æ¯æçä¸ç§ç®æ³åæç¹ç¹èéç¨äºä¸åçåºåã
ECDH
ECDHï¼æ¤åæ²çº¿è¿ªè²âèµ«å°æ¼å¯é¥äº¤æ¢ï¼Elliptic Curve Diffie-Hellmanï¼æ¯ä¸ç§å¯é¥ååç®æ³ãå®ä½¿æ¯ä¸ªäººé½è½æ¥æç¨äºçæå ±äº«å¯é¥ç ECDH å ¬é¥/ç§é¥å¯¹ï¼å³ï¼å¯é¥ä» å¨ä¸¤äººä¹é´å ±äº«ï¼èä¸å æ¬å ¶ä»äººï¼ãç¶åä»ä»¬å¯ä»¥ä½¿ç¨è¿ä¸ªå ±äº«å¯é¥ä½ä¸ºå¯¹ç§°å¯é¥æ¥ä¿æ¤ä»ä»¬çéä¿¡ï¼æå¯ä»¥ä½¿ç¨å¯é¥æ¥ä½ä¸ºæ´¾çåç±»å¯é¥ï¼ä¾å¦ï¼ä½¿ç¨ HKDF ç®æ³ï¼çè¾å ¥ã
ECDH çè§èå®äº RFC 6090ã
HKDF
HKDF æ¯ä¸ç§å¯é¥æ´¾ç彿°ãå®è¢«ç¨äºä»ä¸äºçµå¼ç¸å¯¹è¾é«çè¾å ¥ï¼å¦ ECDH å¯é¥ååæä½çè¾åºï¼æ´¾çå¯é¥ææã
å®å¹¶éç¨äºä»çµå¼ç¸å¯¹è¾ä½çè¾å ¥ï¼ä¾å¦å¯ç ï¼æ´¾çå¯é¥ãå¯¹äºæ¤ç§ç¨éï¼è¯·ä½¿ç¨ PBKDF2ã
HKDF çè§èå®äº RFC 5869ã
PBKDF2
PBKDF2 乿¯ä¸ç§å¯é¥æ´¾ç彿°ãå®è¢«ç¨äºä»ä¸äºçµå¼ç¸å¯¹è¾ä½çè¾å ¥ï¼ä¾å¦å¯ç ï¼æ´¾çå¯é¥ææãå®éè¿å°ä¾å¦ HMAC ç彿°ä»¥åå çï¼saltï¼æä½çä¸èµ·åºç¨å°è¾å ¥å¯ç ä¸ï¼å¹¶å¤æ¬¡é夿¤è¿ç¨æ¥æ´¾çå¯é¥ææãè¿ä¸ªè¿ç¨éå¤ç次æ°è¶å¤ï¼å¯é¥æ¨å¯¼è®¡ç®çææ¬å°±è¶é«ï¼è¿ä½¿å¾æ»å»è é¾ä»¥ä½¿ç¨åå ¸æ»å»è¿ç±»æ´åç ´è§£çæ¹æ³æ¥æ¾åºå¯é¥ã
PBKDF2 çè§èå®äº RFC 2898ã
示ä¾
夿³¨ï¼ä½ å¯ä»¥å¨ GitHub ä¸å°è¯å¯ç¨ç示ä¾ã
ECDH
卿¤ç¤ºä¾ä¸ï¼Alice å Bob åå«çæäºä¸ä¸ª ECDH å¯é¥å¯¹ï¼ç¶åç¸äºäº¤æ¢å
¬é¥ãå¹¶ä½¿ç¨ deriveKey() æ¥æ´¾çä¸ä¸ªå¯ç¨äºå 坿¶æ¯çå
±äº« AES å¯é¥ãå¨ GitHub 䏿¥ç宿´ä»£ç ã
/*
æ´¾ç AES å¯é¥ï¼éè¦æä¾ï¼
- èªå·±ç ECDH ç§é¥
- 对æ¹ç ECDH å
¬é¥
*/
function deriveSecretKey(privateKey, publicKey) {
return window.crypto.subtle.deriveKey(
{
name: "ECDH",
public: publicKey,
},
privateKey,
{
name: "AES-GCM",
length: 256,
},
false,
["encrypt", "decrypt"],
);
}
async function agreeSharedSecretKey() {
// çæä¸¤ä¸ª ECDH å¯é¥å¯¹ï¼ä¸ä¸ªæ¯ Alice çï¼ä¸ä¸ªæ¯ Bob ç
// 卿£å¸¸çä½¿ç¨æ
åµä¸ï¼ä»ä»¬ä¼åç¬çæå¯é¥å¯¹ï¼å¹¶å®å
¨å°äº¤æ¢å
¬é¥ã
let alicesKeyPair = await window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-384",
},
false,
["deriveKey"],
);
let bobsKeyPair = await window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-384",
},
false,
["deriveKey"],
);
// ç¶å Alice 使ç¨å¥¹çç§é¥å Bob çå
¬é¥çæå¯é¥ï¼secret keyï¼ã
let alicesSecretKey = await deriveSecretKey(
alicesKeyPair.privateKey,
bobsKeyPair.publicKey,
);
// Bob 使ç¨ä»çç§é¥å Alice çå
¬é¥æ¥çæç¸åçå¯é¥ã
let bobsSecretKey = await deriveSecretKey(
bobsKeyPair.privateKey,
alicesKeyPair.publicKey,
);
// Alice å¯ä»¥ä½¿ç¨å¥¹çå¯é¥æ·è´æ¥å å¯åéç» Bob çæ¶æ¯ã
let encryptButton = document.querySelector(".ecdh .encrypt-button");
encryptButton.addEventListener("click", () => {
encrypt(alicesSecretKey);
});
// Bob å¯ä»¥ä½¿ç¨ä»çæ·è´æ¥è§£å¯æ¶æ¯ã
let decryptButton = document.querySelector(".ecdh .decrypt-button");
decryptButton.addEventListener("click", () => {
decrypt(bobsSecretKey);
});
}
PBKDF2
卿¤ç¤ºä¾ä¸ï¼æä»¬è¦æ±ç¨æ·æä¾å¯ç ï¼ç¶åä½¿ç¨ PBKDF2 æ´¾ç AES å¯é¥ï¼å¹¶ä½¿ç¨ AES å¯é¥æ¥å 坿¶æ¯ã å¨ GitHub 䏿¥ç宿´ä»£ç ã
/*
è·åç¨äºä½ä¸º deriveKey æ¹æ³çè¾å
¥çå¯é¥ææã
å¯é¥æææ¯ç¨æ·æä¾çå¯ç ã
*/
function getKeyMaterial() {
const password = window.prompt("请è¾å
¥ä½ çå¯ç ");
const enc = new TextEncoder();
return window.crypto.subtle.importKey(
"raw",
enc.encode(password),
"PBKDF2",
false,
["deriveBits", "deriveKey"],
);
}
async function encrypt(plaintext, salt, iv) {
const keyMaterial = await getKeyMaterial();
const key = await window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt,
iterations: 100000,
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"],
);
return window.crypto.subtle.encrypt({ name: "AES-GCM", iv }, key, plaintext);
}
è§è
| è§è |
|---|
| Web Cryptography Level 2 > # SubtleCrypto-method-deriveKey > |