2015-04-22 102 views
1

如何从一个公共字符串生成密钥和IV,以便它们可以在使用PHP中的AES的加密算法中提供服务?从CryptoJS和PHP的AES加密字符串导出密钥和IV

例子:

$key_string = derivate_in_valid_key("i love stackoverflow"); 
$iv_string = derivate__in_valid_iv("i love questions"); 

并在这我可以重复的推导过程中的JavaScript也是一个办法。

+0

我可以说我以前的答案(使用['hash_pbkdf2()'](http://php.net/manual/en/function.hash-pbkdf2.php))所说的相同的东西,但是这个不会帮助你,因为我从你之前的问题中知道这一点,所以你需要CryptoJS和PHP之间的互操作性。你为什么不让你的问题更完整? –

+0

@ ArtjomB。也许我正在努力表达自己..我会尝试重新解释:我有两个字符串,并精确地将它们转换为key和iv有效,因为如果使用正常字符串,它会导致我的错误 – thebestclass

+0

@ArtjomB。但同时我需要一个可以在JavaScript和PHP中工作的函数 – thebestclass

回答

6

您可以使用PBKDF2从密码派生密钥和IV。 CryptoJSPHP都提供了其实现。

AES支持密钥大小为128,192和256位,块大小为128位。 IV必须与CBC等模式的块大小相同。

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尺寸的输出并将其切断。下面的代码就是这样做的,所以只有一个salt必须和密文一起发送。

的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实现。

+0

请注意,对于高迭代次数,CryptoJS的PBKDF2实现速度非常慢。由于某种原因,它呈指数形式。我暂时推荐SJCL的PBKDF2实施。 –