最近一直在弄WebSocket,然后必然会遇到二进制传输
1.客户端设置
// 二进制方式接收数据
ws.binaryType = 'arraybuffer';
这样设置以后客户端接收的数据就是ArrayBuffer,注意大小写,我设置为区分大小写居然浏览器会警告。
2.php服务端发送和接收加密二进制数据
/**
* openssl aes 加密
*/
function crypto_encrypt($data, $key, $options = OPENSSL_RAW_DATA)
{
$iv = substr($key, 0, -16);
$encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, $options, $iv);
return $encrypted;
}
/**
* openssl aes 解密
*/
function crypto_decrypt($data, $key, $options = OPENSSL_RAW_DATA)
{
$iv = substr($key, 0, -16);
return openssl_decrypt($data, 'aes-256-cbc', $key, $options, $iv);
}
这是我写的两个函数,没有什么需要说明的很简单,唯一就是因为mcrypt被嫌弃了,所以我们当然要用openssl了。
3.js客户端数据加密传输和解密处理
/*
* CryptoJS AES 加密
*/
function encrypt(data) {
var key = CryptoJS.enc.Latin1.parse(secret_key);
var encrypted = CryptoJS.AES.encrypt(data, key, {
iv: key,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
return CryptoJS.enc.u8array.stringify(encrypted.ciphertext);
}
/*
* CryptoJS AES 解密
*/
function decrypt(data) {
// 接收的是ArrayBuffer
u8array = new Uint8Array(data);
// 将u8array转换成WordArray
data = CryptoJS.enc.u8array.parse(u8array);
// 要求密文是base64格式
data = data.toString(CryptoJS.enc.Base64);
// 解密key
var key = CryptoJS.enc.Latin1.parse(secret_key);
var decrypted = CryptoJS.AES.decrypt(data, key, {
iv: key,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
var message = decrypted.toString(CryptoJS.enc.Utf8);
return JSON.parse(message);
}
这里我使用的是CryptoJS,google很容易找到。
这里secret_key毫无疑问和服务端对应
坑一. 注意iv的处理,和secret_key是一样的
坑二.secret_key需要使用CryptoJS.enc.Latin1.parse,其他什么CryptoJS.enc.Utf8都不行千万注意
4.客户端加密部分
CryptoJS.enc.u8array.stringify(encrypted.ciphertext)
这里调用了一个u8array的自定义方法,最后给出代码,整个加密注意这里就行了,原理是将WordArray转换成u8array,然后send服务端收到的就是二进制加密数据了
5.客户端解密部分
主要说一下
data = CryptoJS.enc.u8array.parse(u8array)
将u8array转换成WordArray其实和CryptoJS.enc.u8array.stringify正好相反让CryptoJS能够处理,其他的就看代码注释吧。
最后给出u8array的两个方法,来自google
CryptoJS.enc.u8array = {
stringify: function (wordArray) {
var words = wordArray.words;
var sigBytes = wordArray.sigBytes;
var u8 = new Uint8Array(sigBytes);
for (var i = 0; i < sigBytes; i++) {
var byte = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
u8[i]=byte;
}
return u8;
},
parse: function(u8arr) {
var len = u8arr.length;
var words = [];
for (var i = 0; i < len; i++) {
words[i >>> 2] |= (u8arr[i] & 0xff) << (24 - (i % 4) * 8);
}
return CryptoJS.lib.WordArray.create(words, len);
}
};
结束语:因为坑太多,所以记录一下,写错的地方请指出,另外这里没有涉及WebSocket相关资料,主要是AES加密和解密。