0. 背景
最近,需要新做一个游戏demo,类似《部落冲突·皇室战争》的推塔玩法。客户端使用Unity,编程语言为C#,服务端使用C++。由于从零开始,需要建立基础部件,其中网络模块是最重要的模块之一。网络模块协议遵从如下图步骤时序图进行通信。
图1.通信步骤时序图
由上图可以看出网络通信主要分为两个步骤,第一步:客户端使用RSA加解密请求通信服务端,获取RC4秘钥;第二步:客户端与服务端使用RC4加解密通信。本文主要介绍第一步中在Server端(C++)的RSA加解密模块。
注:本文不叙述网络模块中的框架设计,只关注在客户端/服务端获得加密消息后,进行解密的技术环节。
1. RSA加密与解密
RSA为非对称加密方式,在C/C++中是基于使用OpenSSL库来实现。通过以下4个步骤来简单讲述。
a). 使用OpenSSL产生RSA秘钥
RSA的私钥包含了公钥的信息,所以首先通过以下命令产生长度为2048的RSA私钥。
openssl genrsa -out private.pem 2048
这样private.pem就会生成在当前目录下,使用以下命令就可以从private.pem提取出public.pem。
openssl rsa -in private.pem -outform PEM -pubout -out public.pem
如此,就产生两个秘钥,不难猜出:
public.pem是使用PEM格式的公钥,而private.pem是对应的私钥。
b). 公钥加密与私钥解密
RSA是一种非对称的加解密方式。基于它的特性(wiki),它可以以公钥加密,然后私钥解密;也可以以私钥加密,公钥解密。本小节罗列下OpenSSL对于RSA提供的接口:
int RSA_public_encrypt(int flen, unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
int RSA_private_decrypt(int flen, unsigned char *from,
unsigned char *to, RSA *rsa, int padding);
从函数名可以清晰地看出接口的功能。以RSA_public_encrypt
为例叙述参数,其他的接口可参考linux Doc:
- from: 待加密的字符串;
- flen: 待加密字符串长度;
- to: 加密完成后的字符串,其长度必须是RSA_size(rsa);
- rsa: 公钥;
- padding: 填充模式,有一下模式可供选择:
1)RSA_PKCS1_PADDING
:最常用的模式,待加密字符串长度flen < RSA_size(rsa)-11
;
2)RSA_PKCS1_OAEP_PADDING
:这种