目前一般帐号系统,都是 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);