从字符串派生密钥和 IV,用于 CryptoJS 和 PHP 中的 AES 加密
Derive key and IV from string for AES encryption in CryptoJS and PHP
如何从一个公共字符串生成密钥和 IV,以便它们可以在 PHP 中使用 AES 的加密算法中使用?
示例:
$key_string = derivate_in_valid_key("i love Whosebug");
$iv_string = derivate__in_valid_iv("i love questions");
并且我可以在 JavaScript 中重复推导过程。
您可以使用 PBKDF2 从密码中导出密钥和 IV。 CryptoJS and PHP 都提供了其实现。
AES 支持 128、192 和 256 位的密钥大小,以及 128 位的块大小。对于 CBC 等模式,IV 必须与块大小相同。
单次调用 PBKDF2 仅生成密钥
以下代码也可以生成 IV。这样做需要第二个随机盐,它必须与密文一起发送。
JavaScript (DEMO):
var password = "test";
var iterations = 500;
var keySize = 256;
var salt = CryptoJS.lib.WordArray.random(128/8);
console.log(salt.toString(CryptoJS.enc.Base64));
var output = CryptoJS.PBKDF2(password, salt, {
keySize: keySize/32,
iterations: iterations
});
console.log(output.toString(CryptoJS.enc.Base64));
示例输出:
CgxEDCi5z4ju1ycmKRh6aw==
7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU=
PHP:
$password = "test";
$expected = "7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU=";
$salt = 'CgxEDCi5z4ju1ycmKRh6aw==';
$hasher = "sha1"; // CryptoJS uses SHA1 by default
$iterations = 500;
$outsize = 256;
$out = hash_pbkdf2($hasher, $password, base64_decode($salt), $iterations, $outsize/8, true);
echo "expected: ".$expected."\ngot: ".base64_encode($out);
输出:
expected: 7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU=
got: 7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU=
单次调用 PBKDF2 生成密钥和 IV
上一节有点笨拙,因为需要生成两个盐并执行两次 PBKDF2 调用。 PBKDF2 支持可变输出,因此可以简单地使用一种盐,请求密钥大小加上 iv 大小的输出并将它们切掉。下面的代码就是这样做的,所以只有一个盐必须与密文一起发送。
JavaScript (DEMO):
var password = "test";
var iterations = 1000;
// sizes must be a multiple of 32
var keySize = 256;
var ivSize = 128;
var salt = CryptoJS.lib.WordArray.random(128/8);
console.log(salt.toString(CryptoJS.enc.Base64));
var output = CryptoJS.PBKDF2(password, salt, {
keySize: (keySize+ivSize)/32,
iterations: iterations
});
// the underlying words arrays might have more content than was asked: remove insignificant words
output.clamp();
// split key and IV
var key = CryptoJS.lib.WordArray.create(output.words.slice(0, keySize/32));
var iv = CryptoJS.lib.WordArray.create(output.words.slice(keySize/32));
console.log(key.toString(CryptoJS.enc.Base64));
console.log(iv.toString(CryptoJS.enc.Base64));
示例输出:
0Iulef2TncciKGmdwvQX3Q==
QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg=
L1YNlFe54+Cvepp/pXsHtg==
PHP:
$password = "test";
$expectedKey = "QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg=";
$expectedIV = "L1YNlFe54+Cvepp/pXsHtg==";
$salt = '0Iulef2TncciKGmdwvQX3Q==';
$hasher = "sha1";
$iterations = 1000;
$keysize = 256;
$ivsize = 128;
$out = hash_pbkdf2($hasher, $password, base64_decode($salt), $iterations, ($keysize+$ivsize)/8, true);
// split key and IV
$key = substr($out, 0, $keysize/8);
$iv = substr($out, $keysize/8, $ivsize/8);
// print for demonstration purposes
echo "expected key: ".$expectedKey."\ngot: ".base64_encode($key);
echo "\nexpected iv: ".$expectedIV."\ngot: ".base64_encode($iv);
输出:
expected key: QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg=
got: QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg=
expected iv: L1YNlFe54+Cvepp/pXsHtg==
got: L1YNlFe54+Cvepp/pXsHtg==
CryptoJS 默认使用 SHA1,因此您可以通过将哈希函数作为 hasher
对象 属性 传递来使用不同的哈希函数。您可能还应该使用更高的迭代次数。
我没有可用的 PHP 5.5+ 版本,所以我使用了 here.
的 PBKDF2 实现
如何从一个公共字符串生成密钥和 IV,以便它们可以在 PHP 中使用 AES 的加密算法中使用?
示例:
$key_string = derivate_in_valid_key("i love Whosebug");
$iv_string = derivate__in_valid_iv("i love questions");
并且我可以在 JavaScript 中重复推导过程。
您可以使用 PBKDF2 从密码中导出密钥和 IV。 CryptoJS and PHP 都提供了其实现。
AES 支持 128、192 和 256 位的密钥大小,以及 128 位的块大小。对于 CBC 等模式,IV 必须与块大小相同。
单次调用 PBKDF2 仅生成密钥
以下代码也可以生成 IV。这样做需要第二个随机盐,它必须与密文一起发送。
JavaScript (DEMO):
var password = "test";
var iterations = 500;
var keySize = 256;
var salt = CryptoJS.lib.WordArray.random(128/8);
console.log(salt.toString(CryptoJS.enc.Base64));
var output = CryptoJS.PBKDF2(password, salt, {
keySize: keySize/32,
iterations: iterations
});
console.log(output.toString(CryptoJS.enc.Base64));
示例输出:
CgxEDCi5z4ju1ycmKRh6aw== 7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU=
PHP:
$password = "test";
$expected = "7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU=";
$salt = 'CgxEDCi5z4ju1ycmKRh6aw==';
$hasher = "sha1"; // CryptoJS uses SHA1 by default
$iterations = 500;
$outsize = 256;
$out = hash_pbkdf2($hasher, $password, base64_decode($salt), $iterations, $outsize/8, true);
echo "expected: ".$expected."\ngot: ".base64_encode($out);
输出:
expected: 7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU= got: 7G3+NUWtbOooVeTDyLqMaDgnqCkiQCjZi3wnspRPabU=
单次调用 PBKDF2 生成密钥和 IV
上一节有点笨拙,因为需要生成两个盐并执行两次 PBKDF2 调用。 PBKDF2 支持可变输出,因此可以简单地使用一种盐,请求密钥大小加上 iv 大小的输出并将它们切掉。下面的代码就是这样做的,所以只有一个盐必须与密文一起发送。
JavaScript (DEMO):
var password = "test";
var iterations = 1000;
// sizes must be a multiple of 32
var keySize = 256;
var ivSize = 128;
var salt = CryptoJS.lib.WordArray.random(128/8);
console.log(salt.toString(CryptoJS.enc.Base64));
var output = CryptoJS.PBKDF2(password, salt, {
keySize: (keySize+ivSize)/32,
iterations: iterations
});
// the underlying words arrays might have more content than was asked: remove insignificant words
output.clamp();
// split key and IV
var key = CryptoJS.lib.WordArray.create(output.words.slice(0, keySize/32));
var iv = CryptoJS.lib.WordArray.create(output.words.slice(keySize/32));
console.log(key.toString(CryptoJS.enc.Base64));
console.log(iv.toString(CryptoJS.enc.Base64));
示例输出:
0Iulef2TncciKGmdwvQX3Q== QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg= L1YNlFe54+Cvepp/pXsHtg==
PHP:
$password = "test";
$expectedKey = "QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg=";
$expectedIV = "L1YNlFe54+Cvepp/pXsHtg==";
$salt = '0Iulef2TncciKGmdwvQX3Q==';
$hasher = "sha1";
$iterations = 1000;
$keysize = 256;
$ivsize = 128;
$out = hash_pbkdf2($hasher, $password, base64_decode($salt), $iterations, ($keysize+$ivsize)/8, true);
// split key and IV
$key = substr($out, 0, $keysize/8);
$iv = substr($out, $keysize/8, $ivsize/8);
// print for demonstration purposes
echo "expected key: ".$expectedKey."\ngot: ".base64_encode($key);
echo "\nexpected iv: ".$expectedIV."\ngot: ".base64_encode($iv);
输出:
expected key: QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg= got: QeTc3zHuG3JcdtOCkzU2uJWTnrMEggvF1dNUbgNMyzg= expected iv: L1YNlFe54+Cvepp/pXsHtg== got: L1YNlFe54+Cvepp/pXsHtg==
CryptoJS 默认使用 SHA1,因此您可以通过将哈希函数作为 hasher
对象 属性 传递来使用不同的哈希函数。您可能还应该使用更高的迭代次数。
我没有可用的 PHP 5.5+ 版本,所以我使用了 here.
的 PBKDF2 实现