[英]window.crypto returns 352 bit key instead of 256?
我正在嘗試使用window.crypto
加密一些文本:
await crypto.subtle.encrypt(algorithm, key, dataArrayBuffer).catch(error => console.error(error));
但是我得到這個錯誤AES key data must be 128 or 256 bits
。 我正在使用 PBKDF2 從密碼創建一個 256 位密鑰,並指定密鑰長度為256
:
window.crypto.subtle.deriveKey(
{
"name": "PBKDF2",
"salt": salt,
"iterations": iterations,
"hash": hash
},
baseKey,
{"name": "AES-GCM", "length": 256}, //<------------
true,
["encrypt", "decrypt"]
);
但是我最終得到了這個密鑰edi5Fou4yCdSdx3DX3Org+L2XFAsVdomVgpVqUGjJ1g=
在我exportKey
並將其從ArrayBuffer
轉換為長度為44
字節和352
位的string
之后......
這可以解釋錯誤,但是如何從window.crypto
的PBKDF2
創建一個實際的256
位密鑰?
JSFiddle: https://jsfiddle.net/6Lyaoudc/1/
顯示的長度是指 Base64 編碼密鑰。 根據顯示的值,32 字節密鑰的 Base64 編碼長度為 44 字節(352 位),因此是正確的,請參見此處的示例。
錯誤在於,在第二個importKey
中(請參閱從 import 為 AES-GCM 創建 CryptoKey 的注釋),傳遞的是 Base64 編碼的密鑰(即keyString
)而不是二進制密鑰(即ArrayBuffer
keyBytes
)。 如果keyBytes
被傳遞,加密工作:
function deriveAKey(password, salt, iterations, hash) { // First, create a PBKDF2 "key" containing the password window.crypto.subtle.importKey( "raw", stringToArrayBuffer(password), {"name": "PBKDF2"}, false, ["deriveKey"]). then(function(baseKey){ // Derive a key from the password return window.crypto.subtle.deriveKey( { "name": "PBKDF2", "salt": salt, "iterations": iterations, "hash": hash }, baseKey, {"name": "AES-GCM", "length": 256}, // Key we want.Can be any AES algorithm ("AES-CTR", "AES-CBC", "AES-CMAC", "AES-GCM", "AES-CFB", "AES-KW", "ECDH", "DH", or "HMAC") true, // Extractable ["encrypt", "decrypt"] // For new key ); }).then(function(aesKey) { // Export it so we can display it return window.crypto.subtle.exportKey("raw", aesKey); }).then(async function(keyBytes) { // Display key in Base64 format var keyS = arrayBufferToString(keyBytes); var keyB64 = btoa (keyS); console.log(keyB64); console.log('Key byte size: ', byteCount(keyB64)); console.log('Key bit size: ', byteCount(keyB64) * 8); var keyString = stringToArrayBuffer(keyB64); const iv = window.crypto.getRandomValues(new Uint8Array(12)); const algorithm = { name: 'AES-GCM', iv: iv, }; //Create CryptoKey for AES-GCM from import const key = await crypto.subtle.importKey( 'raw',//Provided key will be of type ArrayBuffer // keyString, keyBytes, // 1. Use keyBytes instead of keyString { name: "AES-GCM", }, false,//Key not extractable ['encrypt', 'decrypt'] ); //Convert data to ArrayBuffer var data = "The quick brown fox jumps over the lazy dog"; // 2. Define data const dataArrayBuffer = new TextEncoder().encode(data); const encryptedArrayBuffer = await crypto.subtle.encrypt(algorithm, key, dataArrayBuffer).catch(error => console.error(error)); var ivB64 = btoa(arrayBufferToString(iv)); console.log(ivB64); // 3. Display (Base64 encoded) IV var encB64 = btoa(arrayBufferToString(encryptedArrayBuffer)); console.log(encB64.replace(/(.{56})/g,'$1\n')); // 4. Display (Base64 encoded) ciphertext (different for each encryption, because of random salt and IV) }).catch(function(err) { console.error("Key derivation failed: " + err.message); }); } //Utility functions function stringToArrayBuffer(byteString){ var byteArray = new Uint8Array(byteString.length); for(var i=0; i < byteString.length; i++) { byteArray[i] = byteString.codePointAt(i); } return byteArray; } function arrayBufferToString(buffer){ var byteArray = new Uint8Array(buffer); var byteString = ''; for(var i=0; i < byteArray.byteLength; i++) { byteString += String.fromCodePoint(byteArray[i]); } return byteString; } function byteCount(s) { return encodeURI(s).split(/%..|./).length - 1; } var salt = window.crypto.getRandomValues(new Uint8Array(16)); var iterations = 5000; var hash = "SHA-512"; var password = "password"; deriveAKey(password, salt, iterations, hash);
除了密鑰,代碼還顯示IV和密文,每個Base64編碼。 例如,可以使用 Base64 編碼的密鑰和 IV 來驗證密文。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.