WebSocket 二进制传输 AES加密和解密

最近一直在弄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加密和解密。

你可能感兴趣的:(WebSocket 二进制传输 AES加密和解密)