您的位置:首页 > 其它

一个以ajax请求为主的应用,数据传输加密的解决方案

2018-01-11 11:29 459 查看
首先是密钥交换的过程,Diffie-Hellman密钥交换算法参考维基百科的文档:
http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange
client端js语言,服务端php语言 用DH密钥交换算法交换密钥。

var g = "2";
var p = "106025087133488299239129351247929016326438167258746469805890028339770628303789813787064911279666129";
function doStaff() {
var big_a = randBigInt(100);
var big_p = str2bigInt(p, 10, 0);
var big_g = str2bigInt(g, 10, 0);

var A = powMod(big_g, big_a, big_p);
var str_A = bigInt2str(A, 10);

var B;
var secret;

$.ajax({
url: 'server.php',
type: 'GET',
async: false,
data: {"A":str_A},
cache: false,
timeout: 5 * 1000,
dataType: 'json',
success: function(data, status, xhr) {
B = str2bigInt(data.B, 10, 0);
},
error: function() {
alert(2);
}
});

secret = powMod(B, big_a, big_p);
secret = bigInt2str(secret, 10);

上边的代码中,最后的到的secret,就是最终和服务端协商一致的密钥(这是一个很多位数字的字符串,我们的密钥使用16字节,那么我们可以考虑对它md5,作为对称加密的密钥)。 

上述代码中big int相关的js,直接使用的一个开源的bigint.js(js代码有不开源的吗?^_^) 。 参见这里:http://leemon.com/crypto/BigInt.js

服务端php代码:

<?php
$g = "2";
$p = "106025087133488299239129351247929016326438167258746469805890028339770628303789813787064911279666129";

$b = "86410430023"; // TODO: change this to a random generated number.

$A = $_REQUEST['A'];
$B = bcpowmod($g, $b, $p);

$secret = bcpowmod($A, $b, $p);

echo '{"B":"' . $B .'"}';
?>

可见我们采用固定的g和p,这2个变量是公开的,不怕泄漏。 

js端首先生成一个100bit长的整数a,并依据公式计算出A, 用ajax的形式发送到服务端php。 服务端收到A,自己生成变量b,依据公式计算出B,响应给客户端js。 

此时,服务端和客户端分别可以依据公式计算出一个相同的secret。 这个secret没有在网络中传输过,双方可说是“心照不宣”,且双方自己选定的a和b是保密的,第三方无法根据公开传输的数据推算出a,b,当然也无法得到secret。 这就是DH算法的原理。

======================================================华丽的分割线======================================================== 

密钥交换完成后,我们假定双方拥有了对称加密的密钥。 接下来是一个AES算法的demo。 分别有js加密php解密,和反过来php加密js解密。

这里采用了一个js库,叫做crypt-js.它的官方地址是 http://code.google.com/p/crypto-js/#CryptoJS_3.1 
js加密:

var pwd = "123456";
var key = CryptoJS.enc.Utf8.parse("96e79218965eb72c92a549dd5a330112"); //CryptoJS.MD5("111111");
var iv = CryptoJS.enc.Utf8.parse('1234567812345678');

var encrypted = CryptoJS.AES.encrypt(pwd, key, {iv:iv});
document.write(encrypted.toString());这里write出来的值,就是加密过后的密文,toString方法得到,按照crypto-js文档中说,是兼容openssl格式的可见文本形式。(加密通常得到的结果是byte数组,要以某种形式转换为可见字符,如base64,hex等方式。
这个形式转换也可以自定义)。 
此值在php端解密:
$iv='1234567812345678';
$key = "96e79218965eb72c92a549dd5a330112";
$data = "FBPJjTRA4MEkMcMDg7eOng==";
$data = base64_decode($data);
$ttt = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
echo "decrypted : $ttt";
接下来的代码demo是php端加密, js解密。 
php加密:
$svrMessage = "server message . .. adfasdfsdaf   adfasdfsdaf";

$iv='1234567812345678';
$key = "96e79218965eb72c92a549dd5a330112";

$enc = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $svrMessage, MCRYPT_MODE_CBC, $iv);
$enc = base64_encode($enc);
echo "<br/>$enc";


输出的结果是经过base64转换为可见字符的。

js解密:
var received = "UQhDUzgusxZiejMuuVjh78BcpoQt82swQvSqyCvnuTdb3drBJTPghFBmTORflU6h";
var eee = CryptoJS.enc.Base64.parse(received);

var ddd = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(received),
salt: ""
}, key, {iv:iv});
document.write(ddd.toString(CryptoJS.enc.Utf8) + "<br />");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ajax