跳到主要内容

传输加密

思路

TSRPC 的传输是二进制的,因此加解密算法应当也是基于二进制(Uint8Array)的。 已经有很多成熟算法可以直接使用(如 RC4AESRES 等),当然你也可以实现自己的私有算法。

在服务端和客户端,均有 preSendDataFlowpreRecvDataFlow 可以让你在发送和接收二进制前做处理。 所以只需要在 preSendDataFlow 将 Buffer 加密,在 preRecvDataFlow 将 Buffer 解密,即可实现传输加密。

如果加解密逻辑在前后端相同,你也可以把这部分代码放在 shared 目录共享。

实现

加解密算法

我们来实现一个简单的加密算法:

  • 加密:将二进制流中的每个字节都 +1
  • 解密:将二进制流中的每个字节都 -1
备注

Uint8Array 中,0 - 1 === 255255 + 1 === 0,所以上述算法在边界条件下也生效。

由于前后端都要进行同样的加解密操作,所以我们将这个算法放在 shared 目录下共享:

shared/models/EncryptUtil
export class EncryptUtil {

// 加密
static encrypt(buf: Uint8Array): Uint8Array {
for (let i = 0; i < buf.length; ++i) {
buf[i] -= 1;
}
return buf;
}

// 解密
static decrypt(buf: Uint8Array): Uint8Array {
for (let i = 0; i < buf.length; ++i) {
buf[i] += 1;
}
return buf;
}

}

使用 Flow 扩展工作流

加密算法实现好了,接下来使用 Flow 去扩展服务端和客户端,让它们在发送和接收二进制数据前,自动进行加解密操作。

服务端

// 发送前加密
server.flows.preSendDataFlow.push(v => {
if(v.data instanceof Uint8Array){
v.data = EncryptUtil.encrypt(v.data);
}
return v;
});
// 接收前解密
server.flows.preRecvDataFlow.push(v => {
if(v.data instanceof Uint8Array){
v.data = EncryptUtil.decrypt(v.data);
}
return v;
})

客户端

// 发送前加密
client.flows.preSendDataFlow.push(v => {
if(v.data instanceof Uint8Array){
v.data = EncryptUtil.encrypt(v.data);
}
return v;
});
// 接收前解密
client.flows.preRecvDataFlow.push(v => {
if(v.data instanceof Uint8Array){
v.data = EncryptUtil.decrypt(v.data);
}
return v;
})

如此,传输过程就会自动使用 EncryptUtil 进行加解密了,打开浏览器就可以看到结果。

加密前:

加密后:

这个例子的加密算法实现的非常简单,你可以自行实现更复杂的算法,返回一个全新的 Uint8Array 甚至改变长度都是可以的。

完整例子

参见:https://github.com/k8w/tsrpc-examples/tree/main/examples/transfer-encryption