文章的内容来源于手头的一个项目。需求是在android手机(做客户端)和Windows(做服务器)之间进行低负载的加密通讯。
开发语言:客户端和服务器都用Java
加密方法选择的是RSA。说几句题外话。从道理上讲,RSA并不适合于数据加密,特别是数据量大的时候,因为比较慢,普通的使用方法是数据用对称加密,然后用RSA加密对称加密中使用的密钥,再分别交换。这样,用对称加密解决了速度的问题(对称加密和非对称加密,一般认为速度能差1000倍),用RSA解决了强度问题(到目前未为止,普遍认为1024位的RSA是安全的)。
手头这个项目因为通讯量很小,最长的不超过200字节,因此用RSA是比较合适的,而且,实际上个人认为秒级的延迟对于GUI用户而言还是可以忍受的。因此,在项目中采用了如下的方案:
1、生成RSA密钥对,公钥发给客户端使用,私钥由服务器使用;
2、客户端用公钥加密所有发出的数据,也用公钥解密所有收到的数据;
3、服务器用私钥加密所有发出的数据,也用私钥解密所有收到的数据;
其实很简单是吧。
遇到的问题是:服务器无法解密客户端发送的加密数据,客户端可以解密服务器发送的加密数据,但被填充过(解密出来的明文比原始明文长一截)。通过研究网上的帖子,终于找到管事儿的。http://my.oschina.net/cwalet/blog/35867
原来是windows上的java虚拟机和android上的java虚拟机对于RSA的实现不同,确切的说,是缺省算法不同造成的。处理步骤如下:
1、下一个jar包。http://www.bouncycastle.org/download/bcprov-jdk15on-148.jar
2、在Eclipse中将其引入构建路径;
3、修改jre下lib/security目录下的java.security文件,加入下面一行
security.provider.??=org.bouncycastle.jce.provider.BouncyCastleProvider
记得其中的问号用一个数字代替。根据java.security文件的内容可以确定这个数字。个人猜测,文件是按key-value方式组织的,所以不按顺序编号可能不行,但我懒得试验了。
这部分内容现在还存在一个疑点:在开发机上,像本节说的就可以了。但在生产环境中还必须再做一步:将bcprov-jdk15on-148.jar拷贝到jre\lib\ext目录下,不知道为什么。否则,会出现RSA失败,其实就是没找到算法。有关内容参考 http://blog.csdn.net/sx1116/article/details/5823677 写的很清楚。
4、修改服务器的源码(运行在windows上的),比如原来是
Cipher cipher=Cipher.getInstance("RSA");
则修改成
Cipher cipher=Cipher.getInstance("RSA",“BC”);
修改好在编译一次就行了,没有其它步骤。
相关的内容可以参考:
http://my.oschina.net/cwalet/blog/35867 作者 cwalet
http://www.gleisarbeiter.de/category/java/ 作者 未具名的老外
http://blog.csdn.net/sx1116/article/details/5823677 作者 sx1116
感谢他们,没有他们的文章,这问题也解决不了。也希望我这几行字对遇到同样问题的人有帮助。