最近在参与一个项目的开发,其中需要使用RSA加密传输数据,写一下遇到的一些问题。
介绍
RSA加密算法本质上为欧拉定理的应用,使用RSA加密算法需要生成一串公钥及一串私钥,一般来说私钥由服务提供者保存,公钥写进服务程序中,程序使用公钥对要传输的信息进行加密,服务提供者使用私钥解密获得信息。
由于公钥加密私钥解密和私钥加密公钥解密是对称的,所以使用私钥加密的数据可以唯一地由对应的公钥解密出来,问题就产生在这里。
加密
使用C#中自带的加密库System.Security.Cryptography
来实现数据的加解密,由于C#中的公钥和私钥均为Xml格式,而以其他编程语言生成的公钥和私钥一般为Base64格式的字符串,所以首先需要进行预处理,将Base64格式转成Xml格式,代码如下:
1 | public string ToXmlPublicKey(string publicKey) |
然后使用Xml格式的公钥对信息进行加密:
1 | /// <param name="xmlPublicKey">公钥</param> |
这里都还比较正常,要注意的是将encryptString转换为[]byte时可以直接使用System.Text
库的Encoding函数,一开始的时候使用了另一个转码库(忘了是什么了),会在转换之后的byte数组中插入\u0000
字符。
接下来就掉坑里了,在最上面的时候我说了,公钥加密私钥解密和私钥加密公钥解密是对称过程,并且在很多编程语言中也都是能实现的,所以呢在这个项目中负责后端的小姐姐一开始也是这么想的。
因为有一部分数据需要加密后在客户端存储,所以后端一开始的计划就是用RSA的私钥进行加密,然后发到客户端再使用公钥解密。
悲剧发生了,调了两个多小时的bug,我非常确定我的解密函数没有写错(因为我尝试过使用私钥是可以正常解密的),但是一旦使用公钥解密,就会抛出值不存在
的错误,即解密结果为null
。
然后就是各种改啊查资料啊,最后查到一个解释是:公钥解密的功能是为了对数据进行签名验证,C#的System.Security.Cryptography
库自带验签函数,所以并不支持使用公钥对数据进行解密。
😂好么我这掉一大坑里浪费俩小时。又查了一圈,发现有一个开源库BouncyCastle.Crypto
是支持公钥解密操作的,不过相关资料少之又少。
跟项目主管沟通了一下,项目主管说让我和后端沟通一下使用哪种加密,要能双向解密的(那这不就对称式加密吗,这安全性瞬间就下来了),再深入的沟通了一下,其实这部分需要加密发回来的数据,只是为了存储在本地的时候数据不要是明文存储,于是我提出“明文发到客户端,客户端使用对称式加密对数据加密后再进行存储”的解决方案,得到采用,算是变相地将问题解决了,毕竟要加密的那部分数据,实际上并没有包含什么重要信息,就是一个类似过期时间的东西。
End
谨以此文作个记录,如果有C#大神就当看看小白的笑话了,基本上算是第二天熟悉代码就开始开发了,C#也不太熟悉,只在大一的时候做程序设计课设的时候用过而已,到现在基本算是重新了解了。
不过给到我的任务(实现将数据进行RSA加密后发送到服务端再将接收到的response展示出来)也不太难,如果不是踩坑里了应该两三个小时可以解决。网络请求使用的是BestHttp
库,因为这个项目是Unity的所以用的这个库,基本实现完成,除了将response的数据格式化成json并拿到其中一个值还没做以外都没啥问题了。
整个从踩坑到基本完成用时5小时(还是太菜了😂),还要继续学习。