2015-04-22 101 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實施。 –