window.crypto returns 352 位密钥而不是 256 位?
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"]
);
但是在我 exportKey
之后我最终得到了这个密钥 edi5Fou4yCdSdx3DX3Org+L2XFAsVdomVgpVqUGjJ1g=
并将它从 ArrayBuffer
转换为长度为 [=21= 的 string
] 字节和 352
位...
这可以解释错误,但是我如何从 window.crypto
的 PBKDF2
创建一个实际的 256
位密钥?
JSFiddle:https://jsfiddle.net/6Lyaoudc/1/
显示的长度是指 Base64 编码的密钥。根据显示的值,32 字节的密钥具有 44 字节(352 位)的 Base64 编码长度,因此是正确的,参见例如here.
错误在于第二个 importKey
(参见评论 从导入 为 AES-GCM 创建加密密钥)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,'\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 编码。可以验证密文,例如here 使用 Base64 编码密钥和 IV。
我正在尝试使用 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"]
);
但是在我 exportKey
之后我最终得到了这个密钥 edi5Fou4yCdSdx3DX3Org+L2XFAsVdomVgpVqUGjJ1g=
并将它从 ArrayBuffer
转换为长度为 [=21= 的 string
] 字节和 352
位...
这可以解释错误,但是我如何从 window.crypto
的 PBKDF2
创建一个实际的 256
位密钥?
JSFiddle:https://jsfiddle.net/6Lyaoudc/1/
显示的长度是指 Base64 编码的密钥。根据显示的值,32 字节的密钥具有 44 字节(352 位)的 Base64 编码长度,因此是正确的,参见例如here.
错误在于第二个 importKey
(参见评论 从导入 为 AES-GCM 创建加密密钥)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,'\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 编码。可以验证密文,例如here 使用 Base64 编码密钥和 IV。