SubtleCrypto: deriveKey() ã¡ã½ãã
Baseline
åºãå©ç¨å¯è½
*
ãã®æ©è½ã¯åºãå®è£ ããã¦ãããå¤ãã®ãã¼ã¸ã§ã³ã®ç«¯æ«ããã©ã¦ã¶ã¼ã§åä½ãã¾ãã2020å¹´1æä»¥éããã¹ã¦ã®ãã©ã¦ã¶ã¼ã§å©ç¨å¯è½ã§ãã
* ãã®æ©è½ã®ä¸é¨ã¯ã対å¿ã¬ãã«ãç°ãªãå ´åãããã¾ãã
å®å ¨ãªã³ã³ããã¹ãç¨: ãã®æ©è½ã¯ä¸é¨ã¾ãã¯ãã¹ã¦ã®å¯¾å¿ãã¦ãããã©ã¦ã¶ã¼ã«ããã¦ãå®å ¨ãªã³ã³ããã¹ã (HTTPS) ã§ã®ã¿å©ç¨ã§ãã¾ãã
ã¡ã¢: ãã®æ©è½ã¯ã¦ã§ãã¯ã¼ã«ã¼å ã§å©ç¨å¯è½ã§ãã
deriveKey() 㯠SubtleCrypto ã¤ã³ã¿ã¼ãã§ã¤ã¹ã®ã¡ã½ããã§ããã¹ã¿ã¼éµããç§å¯éµãå°åºããããã«ä½¿ç¨ãããã¨ãã§ãã¾ãã
弿°ã¨ãã¦ãåæéµç´ æã使ç¨ããå°åºã¢ã«ã´ãªãºã ãå°åºããéµã«å¿
è¦ãªããããã£ãåãã¾ãã
ããã¯æ°ããéµã表ã CryptoKey ãªãã¸ã§ã¯ãã§å±¥è¡ããã Promise ãè¿ãã¾ãã
ãªãã対å¿ãã¦ããéµå°åºã¢ã«ã´ãªãºã ã¯ãããããã¾ã£ããç°ãªãç¹æ§ãæã£ã¦ãããé©ãã¦ããç¶æ³ãã¾ã£ããç°ãªãã¾ãã ãã®è©³ç´°ã¯ã対å¿ãã¦ããã¢ã«ã´ãªãºã ãåç §ãã¦ãã ããã
æ§æ
deriveKey(algorithm, baseKey, derivedKeyAlgorithm, extractable, keyUsages)
弿°
algorithm-
使ç¨ãã¦ããå°åºã¢ã«ã´ãªãºã ãå®ç¾©ãããªãã¸ã§ã¯ãã
- ECDH ã使ç¨ããã«ã¯ã
EcdhKeyDeriveParamsãªãã¸ã§ã¯ããæ¸¡ããæååECDHãnameããããã£ã«æå®ãã¦ãã ããã - HKDF ã使ç¨ããã«ã¯ã
HkdfParamsãªãã¸ã§ã¯ããæ¸¡ãã¦ãã ããã - PBKDF2 ã使ç¨ããã«ã¯ã
Pbkdf2Paramsãªãã¸ã§ã¯ããæ¸¡ãã¦ãã ããã - X25519 ã使ç¨ããã«ã¯ã
EcdhKeyDeriveParamsãªãã¸ã§ã¯ããæ¸¡ããæååX25519ãnameããããã£ã«æå®ãã¦ãã ããã
- ECDH ã使ç¨ããã«ã¯ã
baseKey-
å°åºã¢ã«ã´ãªãºã ã¸ã®å ¥åã表ã
CryptoKeyã§ããalgorithmã ECDH ã¾ã㯠X25519 ã§ããå ´åããã㯠ECDH ã¾ã㯠X25519 ã®ç§å¯éµã¨ãªãã¾ãã ãã以å¤ã®å ´åãããã¯å°åºé¢æ°ã®åæãã¼ç´ æã«ãªãã¾ããä¾ãã°ã PBKDF2 ã®å ´åãSubtleCrypto.importKey()ã使ç¨ãã¦CryptoKeyã¨ãã¦ã¤ã³ãã¼ããããã¹ã¯ã¼ãã«ãªãã¾ãã derivedKeyAlgorithm-
å°åºéµã使ç¨ããã¢ã«ã´ãªãºã ãå®ç¾©ãããªãã¸ã§ã¯ãã§ãã
- HMAC ã®å ´åã
HmacKeyGenParamsãªãã¸ã§ã¯ããæ¸¡ãã¦ãã ããã - AES-CTRãAES-CBCãAES-GCMãAES-KW ã®ããããã®å ´åã
AesKeyGenParamsãªãã¸ã§ã¯ããæ¸¡ãã¦ãã ããã - HKDF ã®å ´åã
HkdfParamsãªãã¸ã§ã¯ããæ¸¡ãã¦ãã ããã - PBKDF2 ã®å ´åã
Pbkdf2Paramsãªãã¸ã§ã¯ããæ¸¡ãã¦ãã ããã
- HMAC ã®å ´åã
extractable-
è«çå¤ã§ã
SubtleCrypto.exportKey()ã¾ãã¯SubtleCrypto.wrapKey()ã使ç¨ãã¦éµãã¨ã¯ã¹ãã¼ããããã¨ãå¯è½ãã©ããã示ãã¾ãã keyUsages-
å°åºéµã§ä½ãã§ãããã示ã
Arrayã§ãã éµã®ä½¿ç¨ã¯derivedKeyAlgorithmã§è¨å®ããã«ã¯ã¢ã«ã´ãªãºã ã§è¨±å¯ããã¦ããªããã°ãªããªããã¨ã«æ³¨æãã¦ãã ããã é åã®ä½¿ç¨å¯è½ãªå¤ã¯ä»¥ä¸ã®éãã§ããencrypt: ãã®éµã¯ã¡ãã»ã¼ã¸ã®æå·åã§ä½¿ç¨ãããå¯è½æ§ãããã¾ããdecrypt: ãã®éµã¯ã¡ãã»ã¼ã¸ã®å¾©å·ã§ä½¿ç¨ãããå¯è½æ§ãããã¾ããsign: ãã®éµã¯ã¡ãã»ã¼ã¸ã®ç½²åã§ä½¿ç¨ãããå¯è½æ§ãããã¾ããverify: ãã®éµã¯ç½²åã®æ¤è¨¼ã§ä½¿ç¨ãããå¯è½æ§ãããã¾ããderiveKey: ãã®éµã¯æ°ããéµã®å°åºã§ä½¿ç¨ãããå¯è½æ§ãããã¾ããderiveBits: ãã®éµã¯ãããã®å°åºã§ä½¿ç¨ãããå¯è½æ§ãããã¾ããwrapKey: ãã®éµã¯éµãã©ããããã®ã«ä½¿ç¨ãããå¯è½æ§ãããã¾ããunwrapKey: ãã®éµã¯éµã®ã©ãããè§£é¤ããã®ã«ä½¿ç¨ãããå¯è½æ§ãããã¾ãã
è¿å¤
CryptoKey ã§å±¥è¡ããããããã¹ (Promise) ã§ãã
ä¾å¤
以ä¸ã®ä¾å¤ãçºçããå ´åããããã¹ã¯æå¦ããã¾ãã
InvalidAccessErrorDOMException-
ãã¹ã¿ã¼éµããªã¯ã¨ã¹ããããå°åºã¢ã«ã´ãªãºã ã®éµã§ãªãå ´åãã¾ãã¯ãã®éµã®
keyUsageså¤ã«deriveKeyãæ ¼ç´ããã¦ããªãå ´åã«çºçãã¾ãã NotSupportedDOMException-
䏿ãªã¢ã«ã´ãªãºã ãå°åºã«é©ããªãã¢ã«ã´ãªãºã ã使ç¨ãããã¨ããå ´åã ãããã¯å°åºéµã«ãªã¯ã¨ã¹ããããã¢ã«ã´ãªãºã ãéµé·ãå®ç¾©ãã¦ããªãå ´åã«çºçãã¾ãã
SyntaxErrorDOMException-
keyUsagesã空ã§ãã©ããããã¦ããªãéµã®ç¨®é¡ãsecretã¾ãã¯privateã§ããå ´åã«çºçãã¾ãã
対å¿ãã¦ããã¢ã«ã´ãªãºã
deriveKey() ã対å¿ãã¦ããã¢ã«ã´ãªãºã ã¯ãããããã¾ã£ããç°ãªãç¹æ§ãæã£ã¦ãããé©ãã¦ããç¶æ³ãã¾ã£ããç°ãªãã¾ãã
éµå°åºã¢ã«ã´ãªãºã
>HKDF
HKDF ã¯éµå°åºé¢æ°ã§ãã HKDF ã¯ã ECDH éµåæå¦çã®åºåãªã©ãé«ã¨ã³ãããã¼ã®å ¥åãã éµç´ æãå°åºããããã«è¨è¨ããã¦ãã¾ãã
ãã¹ã¯ã¼ãã®ãããªç¸å¯¾çã«ã¨ã³ãããã¼ã®ä½ãå ¥åããéµãå°åºããããã«ã¯è¨è¨ããã¦ãã¾ããã PBKDF2 ã使ç¨ãã¦ãã ããã
HKDF 㯠RFC 5869 ã§å®ç¾©ããã¦ãã¾ãã
PBKDF2
PBKDF2 ã¯éµå°åºé¢æ°ã§ãããã¾ãã ããã¯ããã¹ã¯ã¼ãã®ãããªç¸å¯¾çã«ã¨ã³ãããã¼ã®ä½ãå ¥åããéµç´ æãå°åºããããã«è¨è¨ããã¦ãã¾ãã PBKDF2 ã¯ãå ¥åããããã¹ã¯ã¼ãã« HMAC ã®ãããªæ©è½ã¨ã½ã«ããé©ç¨ãããã®å¦çãä½åº¦ãç¹°ãè¿ããã¨ã§éµç´ æãå°åºãã¾ãã ãã®å¦çãç¹°ãè¿ãåæ°ãå¤ããã°å¤ãã»ã©ãéµã®å°åºã«ã¯ã³ã³ãã¥ã¼ã¿ã¼ãå¿ è¦ã¨ããè¨ç®éãå¢ãã¾ããããã«ãããæ»æè ããã«ã¼ããã©ã¼ã¹ï¼ç·å½ããï¼ã使ç¨ãã¦ è¾æ¸æ»æã§éµãçºè¦ãããã¨ãé£ãããªãã¾ãã
PBKDF2 㯠RFC 2898 ã§å®ç¾©ããã¦ãã¾ãã
éµåæã¢ã«ã´ãªãºã
>ECDH
ECDH (Elliptic Curve Diffie-Hellman) ã¯éµåæã¢ã«ã´ãªãºã ã§ãã ECDH ã®å ¬ééµã¨ç§å¯éµã®ãã¢ãããããä¿æããäºäººãå ±æããç§å¯ãããªãã¡ãäºäººãå ±æããä»ã®äººã¨ã¯å ±æãããªãç§å¯ãçæãããã¨ãã§ãã¾ãã ãã®å ±æç§å¯ãå ±ééµã¨ãã¦ä½¿ç¨ãã¦éä¿¡ãå®å ¨ã«ããããï¼ä¾ãã° HKDF ã¢ã«ã´ãªãºã ã使ç¨ãã¦ï¼ãã®ãããªéµãå°åºããããã®å ¥åã¨ãã¦ä½¿ç¨ããããããã¨ãã§ãã¾ãã
ECDH 㯠RFC 6090 ã§å®ç¾©ããã¦ãã¾ãã
X25519
X25519 ã¯ãECDH ã¨åæ§ã®éµåæã¢ã«ã´ãªãºã ã§ããã RFC 8032 ã§å®ç¾©ããã¦ãã Edwards-Curve ãã¸ã¿ã«ç½²åã¢ã«ã´ãªãºã ï¼EdDSAï¼ ãã¡ããªã¼ã® Curve25519 æ¥åæ²ç·ã«åºã¥ãã¦æ§ç¯ããã¦ãã¾ãã
Curve25519 ã¢ã«ã´ãªãºã ã¯æå·ã§åºã使ç¨ããã¦ãããæãå¹ççã§é«éãªã¢ã«ã´ãªãºã ã®ã²ã¨ã¤ã¨ããã¦ãã¾ãã ECDH ã§ä½¿ç¨ããã¦ãã NIST ï¼ç±³å½å½ç«æ¨æºæè¡ç ç©¶æï¼ ã®æ²ç·éµäº¤æã¢ã«ã´ãªãºã ã¨æ¯è¼ããã¨ã Curve25519 ã¯å®è£ ãç°¡åã§ãéæ¿åºæ©é¢ãéçºããã¢ã«ã´ãªãºã ã§ããããããã®è¨è¨ä¸ã®æ±ºå®äºé ãéæã§å ¬éããã¦ãã¾ãã
X25519 㯠RFC 7748 ã§å®ç¾©ããã¦ãã¾ãã
ä¾
ã¡ã¢: GitHub ã®åä½ä¾ã試ãã¦ã¿ããã¨ãã§ãã¾ãã
ECDH: å ±æç§å¯éµã®å°åº
ãã®ä¾ã§ã¯ Alice 㨠Bob ããããã ECDH éµãã¢ãçæããå
¬ééµã交æãã¾ãã
ãã㦠deriveKey() ã使ã£ã¦å
±æ AES éµãçæããããã使ç¨ãã¦ã¡ãã»ã¼ã¸ãæå·åãã¾ãã
å®å
¨ãªã³ã¼ã㯠GitHub ã§ã覧ãã ããã
/*
Derive an AES key, given:
- our ECDH private key
- their ECDH public key
*/
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() {
// Generate 2 ECDH key pairs: one for Alice and one for Bob
// In more normal usage, they would generate their key pairs
// separately and exchange public keys securely
let aliceKeyPair = await window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-384",
},
false,
["deriveKey"],
);
let bobKeyPair = await window.crypto.subtle.generateKey(
{
name: "ECDH",
namedCurve: "P-384",
},
false,
["deriveKey"],
);
// Alice then generates a secret key using her private key and Bob's public key.
let aliceSecretKey = await deriveSecretKey(
aliceKeyPair.privateKey,
bobKeyPair.publicKey,
);
// Bob generates the same secret key using his private key and Alice's public key.
let bobSecretKey = await deriveSecretKey(
bobKeyPair.privateKey,
aliceKeyPair.publicKey,
);
// Alice can then use her copy of the secret key to encrypt a message to Bob.
let encryptButton = document.querySelector(".ecdh .encrypt-button");
encryptButton.addEventListener("click", () => {
encrypt(aliceSecretKey);
});
// Bob can use his copy to decrypt the message.
let decryptButton = document.querySelector(".ecdh .decrypt-button");
decryptButton.addEventListener("click", () => {
decrypt(bobSecretKey);
});
}
X25519: å ±æç§å¯éµã®å°åº
ãã®ä¾ã§ã¯ã Alice 㨠Bob ã¯ãããã X25519 éµãã¢ãçæããå
¬ééµã交æãã¾ãã
次ã«ããããã deriveKey() ã使ç¨ãã¦ãèªåèªèº«ã§çæããç§å¯éµã¨ç¸æã®å
¬ééµããå
±æã® AES éµãå°åºãã¾ãã
ãã®å
±æéµã使ç¨ãã¦ã交æããã¡ãã»ã¼ã¸ãæå·åããã³å¾©å·åãããã¨ãã§ãã¾ãã
HTML
æåã«ãAlice ãéä¿¡ãããã¬ã¼ã³ããã¹ãã¡ãã»ã¼ã¸ãå
¥åããããã«ä½¿ç¨ãã HTML ã® <input> ã¨ãæå·åããã»ã¹ãéå§ããããã«ã¯ãªãã¯ãããã¿ã³ãå®ç¾©ãã¾ãã
<label for="message">Plaintext message from Alice (Enter):</label>
<input
type="text"
id="message"
name="message"
size="50"
value="The lion roars near dawn" />
<input id="encrypt-button" type="button" value="Encrypt" />
ããã«ç¶ãã¦ãã¢ãªã¹ãç§å¯éµã®ã³ãã¼ã§å¹³æãæå·åããå¾ã«æå·æã表示ããããã® 2 ã¤ã®è¦ç´ ãããã³ãããç§å¯éµã®ã³ãã¼ã§æå·æã復å·åããå¾ã«ããã¹ãã表示ããããã® 2 ã¤ã®è¦ç´ ãç¶ãã¾ãã
<div id="results">
<label for="encrypted">Encrypted (Alice)</label>
<input
type="text"
id="encrypted"
name="encrypted"
size="30"
value=""
readonly />
<label for="results">Decrypted (Bob)</label>
<input
type="text"
id="decrypted"
name="decrypted"
size="50"
value=""
readonly />
</div>
JavaScript
以ä¸ã®ã³ã¼ãã¯ãderiveKey()' ã®ä½¿ç¨æ¹æ³ã示ãã¦ãã¾ãã
ãªã¢ã¼ãå´ã® X25519 å
¬ééµããã¼ã«ã«å´ã® X25519 ç§å¯éµã渡ãã¦ãå°åºãããéµã AES-GCM éµã¨ãããã¨ãæå®ãã¾ãã
ã¾ããå°åºãããéµã¯æ½åºä¸å¯è½ã§ãããæå·åããã³å¾©å·åã«é©ãããã®ã«è¨å®ãã¾ãã
ãã®é¢æ°ã¯ãã³ã¼ãã®ããã«ä¸ã§ã Bob 㨠Alice ç¨ã®å ±æéµã使ããããã«ä½¿ç¨ãã¾ãã
/*
Derive an AES-GCM key, given:
- our X25519 private key
- their X25519 public key
*/
function deriveSecretKey(privateKey, publicKey) {
return window.crypto.subtle.deriveKey(
{
name: "X25519",
public: publicKey,
},
privateKey,
{
name: "AES-GCM",
length: 256,
},
false,
["encrypt", "decrypt"],
);
}
次ã«ãAlice ãå¹³æã¡ãã»ã¼ã¸ã UTF-8 ã¨ã³ã³ã¼ããã¦ããæå·åããããã«ä½¿ç¨ãã颿°ãããã³ Bob ãã¡ãã»ã¼ã¸ã復å·ãã¦ãããã³ã¼ãããããã«ä½¿ç¨ãã颿°ãå®ç¾©ãã¾ãã ãããã®é¢æ°ã¯ããããããå ±æ AESéµãåæåãã¯ãã«ãããã³æå·åã¾ãã¯å¾©å·ããããã¹ãã弿°ã¨ãã¦åãã¾ãã
æå·åã¨å¾©å·ã«ã¯åãåæåãã¯ãã«ã使ç¨ããå¿ è¦ãããã¾ãããããã¯ç§å¯ã§ããå¿ è¦ã¯ããã¾ããããã®ãããéå¸¸ã¯æå·åãããã¡ãã»ã¼ã¸ã®æ¨ªã«ä¸¦ã¹ã¦éä¿¡ããã¾ãã ãã ãããã®ä¾ã§ã¯å®éã«ã¯ã¡ãã»ã¼ã¸ãéä¿¡ããªããããç´æ¥å©ç¨ã§ããããã«ãã¦ãã¾ãã
async function encryptMessage(key, initializationVector, message) {
try {
const encoder = new TextEncoder();
encodedMessage = encoder.encode(message);
// iv will be needed for decryption
return await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv: initializationVector },
key,
encodedMessage,
);
} catch (e) {
console.log(e);
return `Encoding error`;
}
}
async function decryptMessage(key, initializationVector, ciphertext) {
try {
const decryptedText = await window.crypto.subtle.decrypt(
// The iv value must be the same as that used for encryption
{ name: "AES-GCM", iv: initializationVector },
key,
ciphertext,
);
const utf8Decoder = new TextDecoder();
return utf8Decoder.decode(decryptedText);
} catch (e) {
console.log(e);
return "Decryption error";
}
}
èªã¿è¾¼ã¿æã«ã agreeSharedSecretKey() 颿°ãå¼ã³åºããã Alice 㨠Bob ã®ãã¢ã¨å
±æéµãçæãã¾ãã
ã¾ããæåã® <input> ã§å®ç¾©ãããããã¹ãã®æå·åã¨å¾©å·ãèµ·åãã "Encrypt" ãã¿ã³ã®ã¯ãªãã¯ãã³ãã©ã¼ã追å ãã¾ãã
ãã¹ã¦ã®ã³ã¼ã㯠try...catch ãã³ãã©ã¼å
ã«ããã X25519 ã¢ã«ã´ãªãºã ã«å¯¾å¿ãã¦ããªãããã«éµã®çæã«å¤±æããå ´åã確å®ã«ãã°ã«è¨é²ã§ããããã«ãã¦ãã¾ãã
async function agreeSharedSecretKey() {
try {
// Generate 2 X25519 key pairs: one for Alice and one for Bob
// In more normal usage, they would generate their key pairs
// separately and exchange public keys securely
const aliceKeyPair = await window.crypto.subtle.generateKey(
{
name: "X25519",
},
false,
["deriveKey"],
);
log(
`Created Alice's key pair: (algorithm: ${JSON.stringify(
aliceKeyPair.privateKey.algorithm,
)}, usages: ${aliceKeyPair.privateKey.usages})`,
);
const bobKeyPair = await window.crypto.subtle.generateKey(
{
name: "X25519",
},
false,
["deriveKey"],
);
log(
`Created Bob's key pair: (algorithm: ${JSON.stringify(
bobKeyPair.privateKey.algorithm,
)}, usages: ${bobKeyPair.privateKey.usages})`,
);
// Alice then generates a secret key using her private key and Bob's public key.
const aliceSecretKey = await deriveSecretKey(
aliceKeyPair.privateKey,
bobKeyPair.publicKey,
);
log(
`aliceSecretKey: ${aliceSecretKey.type} (algorithm: ${JSON.stringify(
aliceSecretKey.algorithm,
)}, usages: ${aliceSecretKey.usages}), `,
);
// Bob generates the same secret key using his private key and Alice's public key.
const bobSecretKey = await deriveSecretKey(
bobKeyPair.privateKey,
aliceKeyPair.publicKey,
);
log(
`bobSecretKey: ${bobSecretKey.type} (algorithm: ${JSON.stringify(
bobSecretKey.algorithm,
)}, usages: ${bobSecretKey.usages}), \n`,
);
// Get access for the encrypt button and the three inputs
const encryptButton = document.querySelector("#encrypt-button");
const messageInput = document.querySelector("#message");
const encryptedInput = document.querySelector("#encrypted");
const decryptedInput = document.querySelector("#decrypted");
encryptButton.addEventListener("click", async () => {
log(`Plaintext: ${messageInput.value}`);
// Define the initialization vector used when encrypting and decrypting.
// This must be regenerated for every message!
const initializationVector = window.crypto.getRandomValues(
new Uint8Array(8),
);
// Alice can use her copy of the shared key to encrypt the message.
const encryptedMessage = await encryptMessage(
aliceSecretKey,
initializationVector,
messageInput.value,
);
// We then display part of the encrypted buffer and log the encrypted message
let buffer = new Uint8Array(encryptedMessage, 0, 5);
encryptedInput.value = `${buffer}...[${encryptedMessage.byteLength} bytes total]`;
log(
`encryptedMessage: ${buffer}...[${encryptedMessage.byteLength} bytes total]`,
);
// Bob uses his shared secret key to decrypt the message.
const decryptedCiphertext = await decryptMessage(
bobSecretKey,
initializationVector,
encryptedMessage,
);
decryptedInput.value = decryptedCiphertext;
log(`decryptedCiphertext: ${decryptedCiphertext}\n`);
});
} catch (e) {
log(e);
}
}
// Finally we call the method to set the example running.
agreeSharedSecretKey();
çµæ
æå·å ãã¿ã³ãæ¼ãã¨ãä¸çªä¸ã® <input> è¦ç´ ã®ããã¹ããæå·åãããæå·åãããæå·æã¨å¾©å·ãããå¹³æã次㮠2 ã¤ã®è¦ç´ ã«è¡¨ç¤ºããã¾ãã
ä¸é¨ã®ãã°é åã«ã¯ãã³ã¼ãã«ãã£ã¦çæãããéµã«é¢ããæ
å ±ãæä¾ããã¾ãã
PBKDF2: ãã¹ã¯ã¼ããã AES éµãå°åº
ãã®ä¾ã§ã¯ãã¦ã¼ã¶ã¼ã«ãã¹ã¯ã¼ããè¦æ±ããããã使ç¨ã㦠PBKDF2 ã使ã£ã¦ AES éµãå°åºãããã® AES éµã使ã£ã¦ã¡ãã»ã¼ã¸ãæå·åãã¾ãã å®å ¨ãªã³ã¼ã㯠GitHub ã§ã覧ãã ããã
/*
deriveKeyã¡ã½ããã®å
¥åã¨ãã¦ä½¿ç¨ããéµç´ æãåå¾ãã¾ãã
éµç´ æã¯ãã¦ã¼ã¶ã¼ããæä¾ããããã¹ã¯ã¼ãã§ãã
*/
function getKeyMaterial() {
const password = window.prompt("Enter your password");
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);
}
HKDF: å ±æã®ç§å¯ãã AES éµãå°åº
ãã®ä¾ã§ã¯ãå
±æã®ç§å¯ secret ã使ç¨ãã¦ãã¡ãã»ã¼ã¸ plainText ãæå·åãã¾ãããã®ç§å¯éµã¯ãECDH ãªã©ã®ã¢ã«ã´ãªãºã ã使ç¨ãã¦å°åºããã¦ããå¯è½æ§ãããã¾ãã
å
±æã®ç§å¯ãç´æ¥ä½¿ç¨ãã代ããã«ã HKDF æ©è½ã®ããã®ãã¼ç´ æã¨ãã¦ä½¿ç¨ãã AES-GCM æå·å°åºãã¾ãããã®ãã¼ã使ç¨ãã¦ãã¡ãã»ã¼ã¸ãæå·åãã¾ãã
GitHub ã§ã³ã¼ãã®å
¨æãã覧ãã ããã
/*
Given some key material and some random salt,
derive an AES-GCM key using HKDF.
*/
function getKey(keyMaterial, salt) {
return window.crypto.subtle.deriveKey(
{
name: "HKDF",
salt: salt,
info: new TextEncoder().encode("Encryption example"),
hash: "SHA-256",
},
keyMaterial,
{ name: "AES-GCM", length: 256 },
true,
["encrypt", "decrypt"],
);
}
async function encrypt(secret, plainText) {
const message = {
salt: window.crypto.getRandomValues(new Uint8Array(16)),
iv: window.crypto.getRandomValues(new Uint8Array(12)),
};
const key = await getKey(secret, message.salt);
message.ciphertext = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: message.iv,
},
key,
plainText,
);
return message;
}
仿§æ¸
| 仿§æ¸ |
|---|
| Web Cryptography Level 2 > # SubtleCrypto-method-deriveKey > |