目前一般帳號系統,都是 https 來傳輸賬户性息,申請一個 https 證書也不貴。但是網站的其它功能並不需要走 https 協議,https 和 http 混布比較麻煩,所以決定先實現一個 http 協議傳輸 RSA 非對稱金鑰演算法加密密碼的方案。這樣做只能説是保證不明文傳密碼,但是並不能防身份偽造,所以其實還是不安全的,只是目前產品能接受,算是一個過渡期吧。有需要的話還是要改成 https 的。
關於 rsa 演算法,具體參考維基百科相關的介紹。簡單來説,用 rsa 演算法產生一對公鑰和私鑰,通訊雙方 A 和 B,A 用公鑰加密要傳送的資料,B 用私鑰來解密 A 發過來的密文,從而獲得 a 想要發過來的資料。保證 rsa 密文不容易被破解的理論依據是對極大整數做因數分解的難度非常大。
下面具體看看實現過程。這裏前端用到 rsa 的 js 實現方案 jsencrpt.js ,後端用 php 的 open_pkey_new 等相關方法。

1.【後端】先看 php 生成公鑰金鑰對相關程式碼:

function generatePubPri() {
$config = array(“config” => ‘/path/to/openssl.cnf’);
$res = openssl_pkey_new($config);
openssl_pkey_export($res,$pri, null, $config);
$d= openssl_pkey_get_details($res);
$pub = $d[‘key’];

$pubFd = fopen(“pub.txt”, “w”);
fwrite($pubFd, $pub);
fclose($pubFd);

$priFd = fopen(“pri.txt”, “w”);
fwrite($priFd, $pri);
fclose($priFd);
}

這裏前提是要安裝 openssl,php 要載入 openssl 擴充套件。執行 generatePubPri 即可的到如下的公鑰金鑰對,每次執行生成的都不一樣。

[xxx@xxx makedemo]$ cat pri.txt
—–BEGIN RSA PRIVATE KEY—–
MIICXQIBAAKBgQCq/8HruBYhems80BluLiiP0uUTzM/NJSFktzxA1rfzjhEg8z0W
r0WAvIdbye2vTG0CYi6PGpjxgUkEVaaHLWEIMiA4g3TIFSUp5pmlWRpGNqilrxd4
sXM5wzL13WkN1j6gBfZNJt62mO35A2Ubl9fbNw/YU2KNPR0+EHP0Z6agmwIDAQAB
AoGAViPcllf3ngnDN7FE/kH2YO1GRMEp9Re9SLUdfzQrGl/4tPaTUXgdtQpDzbNd
Lq97QnYfKiul3BLaq3pSF0p+1AUHtJby/HT1Tqz0380x9Y+QKjJErePycTs28zIq
FXmCMnOqxhaWPB89hxCIG0g7bVt9qGRDUZGY05kMwSM9gvECQQDcWjQoBfb4IQls
RUQlprzizQD+S4cHJdxCq5qh7TqyH1IPoHq04tQsuYFVEH2+Z0Spimz/oluNuDnJ
NppKdJZdAkEAxqmbtzs9bPbyihb9qpsD8Sne1DIo5uRBJ7G4/RE4vazaAXX9HUIS
HZg/To5XSGHzgQteIUXJRjpX5sYLCS8zVwJAQxElbMUb/Tu47X5LlpYgSXuSANQm
HfPVDWnDn+NfiRVlWaJDlsivQYmYprZlP02ZJW0fbdMRwJnA5NA8t8qydQJBAKZH
dERLW0CG+b7HO46+rPAAAbhOO5n2VuqogJOhBIMN2HL8lN0WXh9TPTm9PiUhhzTt
lN34kV0snEJWZQpM7YUCQQCgKhoAlp4DpcYvqq569UI7IE4ZL4l9RlkiNG1UYyda
iZoNVN7ji8K2ZvOKykJBwDeKIn4JrknUHrjZXEweRKEl
—–END RSA PRIVATE KEY—–
[xxx@xxx makedemo]$ cat pub.txt
—–BEGIN PUBLIC KEY—–
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq/8HruBYhems80BluLiiP0uUT
zM/NJSFktzxA1rfzjhEg8z0Wr0WAvIdbye2vTG0CYi6PGpjxgUkEVaaHLWEIMiA4
g3TIFSUp5pmlWRpGNqilrxd4sXM5wzL13WkN1j6gBfZNJt62mO35A2Ubl9fbNw/Y
U2KNPR0+EHP0Z6agmwIDAQAB
—–END PUBLIC KEY—–

2.【前端】用公鑰加密一下密碼”123456″。





JS->jsencrypt.js RSA 加密實現





在瀏覽器裏訪問後,控制枱會列印出如下的加密字串:

SonHPbJpQBwygjZ5ZMtybfLEylnNCsd3poBsNxSt3QkUSDe+Pf7lf4JJIot9Ybd7mAXiOUgGZR7VctCSJhzzZQWNZp1or6h6dsYoFHE/dbDHIxJGcXMNfv5BqrfAMGqkQVvyrED3NHcrgXokataRJOrsU7yvKpQKW6e3j+zcZD8=

eRA40/RbbbqtuEC10Ee3NVDsnpfgibn8nRuTaPmvXI1XjVFX8pjwtMxiuT9xaBfX8K+LI/6ccgghYyJdxjd8V+DyxBPz6/QzT3f5eoOz9ULD85r0K//BuKvuTiyQ/NajProvPN3ns6UzxECmuFg0UNtrMNkOdFRpaAtueadKJDU=

Tqgagyx5DlDLI/tcxYsnN/3AbUPCX/EFE6yn5SoVMX3R/RQ6od6b4hT10LUctcBZ649RhHkwzxTFzIFfvbRS87OftOhebGXAP9JpN/xt9IsaXOU4wp8ZiyQKIrClnepXtRaSC10WF/ishsejgo3i7APXs7fWJiEMkoqRYwnbyPo=

。。。。。。奇怪的是每次重新整理列印的都不一樣。估計都可以用的。
3.【後端】解密前端傳送過來的密文
解密的方法:

/**
* rsa 解密
* @access public
* @param 密文
* @return 解密後的字串
*/
function decrypt($data, $privkey) {
if (openssl_private_decrypt(base64_decode($data), $decrypted, $privkey)){
$data = $decrypted;
}else {
$data = ”;
}
return $data;
}
priveKey=file g et c ontents(“pri.txt“);  priveKey=filegetcontents(“pri.txt”); data = “SonHPbJpQBwygjZ5ZMtybfLEylnNCsd3poBsNxSt3QkUSDe+Pf7lf4JJIot9Ybd7mAXiOUgGZR7VctCSJhzzZQWNZp1or6h6dsYoFHE/dbDHIxJGcXMNfv5BqrfAMGqkQVvyrED3NHcrgXokataRJOrsU7yvKpQKW6e3j+zcZD8=”;
echo decrypt(data, data, priveKey);
echo “n”;

最後是解密出”123456″

[xxx@xxx makedemo]$ php rsa.php
123456

試了一下另外兩個密文,非常棒,發現也是可以解出”123456″。
最後給一個完整的 demo,流程如下:

程式碼如下:
1.submitPassword.html





JS->jsencrypt.js RSA 加解密實現




2.getPublicKey.php

function generatePubPri() {
$config = array(“config” => ‘/home/users/zhutianpeng/.jumbo/etc/ssl/openssl.cnf’);
$res = openssl_pkey_new($config);
openssl_pkey_export($res,$pri, null, $config);
$d= openssl_pkey_get_details($res);
$pub = $d[‘key’];

$pubFd = fopen(“pub.txt”, “w”);
fwrite($pubFd, $pub);
fclose($pubFd);

$priFd = fopen(“pri.txt”, “w”);
fwrite($priFd, $pri);
fclose($priFd);

return $pub;
}

$publicKey = generatePubPri();
$data = array(“code” => 0,
“msg” => “success”,
“data” => array(“pubkey” => $publicKey));
echo json_encode($data);

3.recievePassword.php

$passWord = $_POST[‘password’];
$ret = array();
if(!empty($passWord)) {
$ret[‘code’] = 0;
$ret[‘msg’] = “success”;
}else {
$ret[‘code’] = 1;
$ret[‘msg’] = “not recieved a password”;
}
echo json_encode($ret);