最近在做一个东西,服务端是用 Python 写的 API,客户端是其他语言写的,比如 C#。客户端与服务端之间有个数据通信的需求是通过 RSA 做加解密。例如客户端 C# 使用公钥加密数据,服务端 Python 使用私钥解密数据。因此需要让不同语言的 RSA 加密后的数据兼容,能够互相解密。
在 C# 中 RSA 的私钥和公钥文件是使用 XML 格式存储的,而 Python 的 pycrypto 是使用 PEM 格式,第一个要解决的问题是密钥文件的一致性问题。使用 openssl 生成的 RSA 密钥文件,C# 无法读取。研究了很久 C# 读取 PEM 的方法,但是没有找到简单高效的方法,最后的妥协方法是使用 C# 生成 RSA 的密钥,然后再转成 PEM 格式。
生成 xml 格式的 RSA 密钥
使用如下代码,用 C# 生成 RSA 的密钥
1 | public void GenerateRSAKey() |
将 RSA 密钥由 xml 转成 pem 格式
可以使用这个在线工具,但是在线工具毕竟有数据泄露的风险,最后参考了这篇文章,代码在这里 XMLSec2PEM.java。
编译代码
javac XMLSec2PEM.java
转换 XML 到 PEM
java XMLSec2PEM your_key.xml
将上述输出的内容保存到 rsa_key.pem。在 Python 中调用会提示不支持的 RSA Key 格式
,需要进一步做转换
openssl pkcs8 -topk8 -in rsa_key.pem -nocrypt -out rsa.key
最后得到可用的 rsa.key,使用 openssl 提取出公钥
openssl rsa -in rsa.key -pubout -out rsa_pub.key
不同语言兼容的 RSA 加解密
要做到 C# 和 Python 相互兼容的 RSA 加解密还是有很多细节问题的,例如 C# 默认会做随机的填充,因此每次加密得到的数据都不同,以及 Unicode 和 UTF8的编码问题等。
关于 C# 和 Python 之间相互加解密,可以参考这篇文章,代码在这。以下代码经过测试,C# 加密的数据,Python 可以正确解密,反之亦然。
Python 版的完整代码
需要先安装依赖
pip install pycrypto
1 | # -*- coding: utf-8 -*- |
C# 版的完整代码
1 | using System; |