Java与.Net环境下RSA加密解密交互不成功的问题解决

由于项目需要,我们要实现Java环境下面用RSA公钥对信息加密、然后在.Net环境下面用RSA私钥解密的这个功能;
由于以前没有深入接触过.Net,所以遇到这个问题的时候还是心里比较没底,但是我觉得这个问题肯定能够解决的,因为RSA的加密解密算法已经太成熟了,各语言应该都会提供标准支持才对;

但经过测试之后发现:原来跨平台间的交互还是存在很多障碍的,各平台对标准的支持度相差太多;直接体现就是本平台内加密之后解密没有问题,但是一方加密,另外一方解密就不行!!

由于经过加密的结果都是byte数组,所以对byte数组进行了base64编码,然后再进行传输;

问题解决过程中发现以下一些有趣的问题:
1、.Net下面对字符串转换成byte数组的方法有好几类,比如Encoding.Default.GetString、ByteConverter.GetBytes等;但这些方法并不是等效的,要谨慎使用,前者是符合我们期望结果的,每个字母会返回一个byte,后者每个字母会返回2个byte,其中第二个byte值为0;
2、.Net和Java环境下面byte取值范围不一样,Java中是-128-127;而.Net下面则是0-255;因为加密之后的byte数组中很多都是非可见字符,只能通过byte值来看,所以要注意两个平台内的差别,但是对相同字符的byte值相差256是正常的,只是各平台的实现不同而已;
3、.Net环境下面对同样一个字符串用相同的RSA公钥加密,居然每次的结果不一样!而Java环境下面则每次的结果是一样的;这点就是我们此次解决互通问题的关键!究其原因是这样的:.Net为了加强RSA加密算法的安全性,在每次加密的时候都会生成一定的随机数和原始数据一起被加密,这显然不是单纯标准的RSA加密;而Java中的RSA加密是完全标准化的,不添加随机数的;这样双方的加密标准就是不一样的,所以一方加密另一方解密肯定是不能成功的啦!
4、既然找到了双方不能互通的原因,那接下来就只能想办法消除这两者间的差别了;方法有二:其一是.Net方修改代码,放弃默认的RSA算法实现类,自己实现一套支持标准化的类;其二是Java方修改代码,保持和.Net方;两者比较的话方法二几乎没有可实施性,因为无法看到.Net的源代码,也就无法知道随机数的添加规则,另外,若java方修改的话,后续可能会导致很多新的问题,因为我们不仅要和.Net互通,还要和Php等其他语言互通;方法一可行但是难度不小,幸好已经有达人在.Net下实现了标准化的RSA算法,可以参考http://www.codeproject.com/csharp/biginteger.asp项目;
5、虽然找到了实现标准化RSA算法的类文件,但是他需要RSA私钥中的两个参数D和Modules;但我们是使用证书的,没法直接使用;幸好.Net下面提供了对证书pfx文件的导入和导出功能,通过X509Certificate2类搞定;注意初始参数哦,会有大用处的哦;
6、前面提到的.Net在加密时会自动添加一定的随机数,所以每次RSA加密时能够操作的数据块就会变小了,标准的RSA加密每次能操作128个byte,据实际测试结果显示,.Net下面最多只能加密117个byte,操作一位就不行,若需要加密大长度的字符串,则必须进行拼接才行;若只需要加密128byte以内的是数据,则可以考虑用BigInteger的RSA实现方法;

你可能感兴趣的:(JAVA)