2013-05-12 96 views
2

我在服務器上創建一個公鑰/私鑰,將密鑰發送到JavaScript客戶端,在其中加密用戶密碼。客戶端將密碼發送到服務器,服務器使用私鑰對其解密,但密碼返回爲空。我已經驗證了支持這種情況的所有值都是正確的,所以這是專門用於加密/解密的東西。我哪裏錯了?使用Cryptico.js加密,使用OpenSSL進行解密

可能是cryptico.js與php openssl不兼容?

庫信息:

https://github.com/wwwtyro/cryptico

http://www.php.net/manual/en/function.openssl-pkey-new.php

下面是相關的代碼片段:

PHP - 創建公鑰/私鑰

$config = array(
    "digest_alg" => "sha512", 
    "private_key_bits" => 2048, 
    "private_key_type" => OPENSSL_KEYTYPE_RSA, 
); 

// Create the private and public key 
$res = openssl_pkey_new($config); 

// Extract the private key from $res to $privateKey 
openssl_pkey_export($res, $privateKey); 

// Extract the public key from $res to $publicKey 
$publicKey = openssl_pkey_get_details($res); 
$publicKey = $publicKey["key"]; 

JavaScript - 客戶端用公鑰加密數據。

var xhr = new XMLHttpRequest(); 
var data = new FormData(); 
xhr.open('POST', '/signUp2.php'); 
data.append('user', User); 

var encryptedPassword = cryptico.encrypt(password, localStorage["publicKey"]); 
data.append('password', encryptedPassword.cipher); 

xhr.onreadystatechange = function() 
{ 
    if(xhr.readyState == 4 && xhr.status == 200) 
    { 
     var jsonArray = JSON.parse(xhr.responseText); 

     if(jsonArray[0] == "0") 
     { 
      alert("Account created. You may now sign in."); 
     } 
     else 
      alert("Error Code: " + jsonArray[0]); 
    } 
} 
xhr.send(data); 

PHP - 服務器臨危加密的密碼和attemps解密失敗

openssl_private_decrypt($encryptedPassword, $decryptedPassword, $row[1]); 
+0

您使用在服務器端SHA512。不過,我讀到本機Javascript僅支持AES 256位加密,並且在文檔中提供了與aes 256位密鑰的互操作性示例:http://code.google.com/p/crypto-js/#Interoperability – mondjunge 2013-06-25 14:49:41

回答

4

cryptico.js可以與OpenSSL的工作,但我們必須修改它一下。

它不直接識別pem格式的公鑰(openssl使用)。我們要提取的「n」和在PHP側的公共密鑰的「E」部分:

$key = openssl_pkey_new(array( 
    'private_key_bits' => 1024, 
    'private_key_type' => OPENSSL_KEYTYPE_RSA, 
    'digest_alg' => 'sha256' 
)); 

$detail = openssl_pkey_get_details($key); 
$n = base64_encode($detail['rsa']['n']); 
$e = bin2hex($detail['rsa']['e']); 

也cryptico.js硬編碼的公鑰的「E」部分(見API publicKeyFromString的定義.js文件),所以我們需要解決這個問題:

my.publicKeyFromString = function(string) 
{ 
    var tokens = string.split("|"); 
    var N = my.b64to16(tokens[0]); 
    var E = tokens.length > 1 ? tokens[1] : "03"; 
    var rsa = new RSAKey(); 
    rsa.setPublic(N, E); 
    return rsa 
} 

現在我們能夠加密字符串:

var publicKey = "{$n}|{$e}", 
    encrypted = cryptico.encrypt("plain text", publicKey); 

工作還沒有完成。 cryptico.encrypt的結果不僅僅是由RSA加密的。實際上,它由兩部分組成:由RSA加密的aes密鑰和由AES用aes密鑰加密的明文密碼。如果我們只需要RSA,我們可以修改my.encrypt:

my.encrypt = function(plaintext, publickeystring, signingkey) 
{ 
    var cipherblock = ""; 
    try 
    { 
    var publickey = my.publicKeyFromString(publickeystring); 
    cipherblock += my.b16to64(publickey.encrypt(plaintext)); 
    } 
    catch(err) 
    { 
    return {status: "Invalid public key"}; 
    } 
    return {status: "success", cipher: cipherblock}; 
} 

現在我們可以使用OpenSSL解密密碼:

$private = openssl_pkey_get_private("YOUR PRIVATE KEY STRING IN PEM"); 
// $encrypted is the result of cryptico.encrypt() in javascript side 
openssl_private_decrypt(base64_decode($encrypted), $decrypted, $private); 
// now $decrypted holds the decrypted plain text 
+0

這非常適用於我,謝謝你! – citizenslave 2014-03-01 22:05:25

+0

我得到一個空字符串'$ e = bin2hex($ detail ['rsa'] ['e']);'。這是否可以預料? – JVE999 2014-06-22 05:03:06

+0

@ JVE999也許你的openssl擴展沒有正確安裝?如果php找不到openssl.conf,它不能生成密鑰,但仍然能夠執行加密/解密的東西。檢查http://us1.php。net/manual/en/openssl.installation.php – Nowgoo 2014-06-24 03:04:27