C#与Java的RSA(3)

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介:

原创文章,转载请注明出处 http://boytnt.blog.51cto.com/966121/1351207


在上一篇文章里,我们已经成功的解析出了公钥加密至关重要的modulus和publicExponent,胜利在望,心急的同学肯定要开始这么写了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*********** C#代码 ***********/
                                                      
//设定RSA参数,用于指定modulus和exponent
var  parameter =  new  RSAParameters();
parameter.Modulus = modulusBytes;        //modulusBytes是转化后的byte[]
parameter.Exponent = exponentBytes;
                                                      
//加密
var  rsa = RSACryptoServiceProvider.Create( "RSA" );
rsa.ImportParameters(parameter);
byte [] result = rsa.EncryptValue(Encoding.UTF8.GetBytes( "PASSWORD" ));
                                                    
//把密文转化为HEX形式
string  resultHex = BitConverter.ToString(result).Replace( "-" "" );


对不起要无情的打击你了,这么做行不通,因为C#的RSA加密不是标准RSA,为了加强安全性,它强制使用了PKCS1填充(或OAEP填充),导致密文在Java端解密失败,因为Java端用的是无填充模式(RSA/ECB/NoPadding)。


怎么办? 自己实现标准RSA加密吧。modulus和publicExponent都有了,再加上密码,都转化成大整数,做一个ModPow操作,就得到结果密文了。正好.NetFramework从4.0起在System.Numerics命名空间下直接提供BigInterger类了,上手试试:

1
2
3
4
5
6
7
8
9
10
11
12
/*********** C#代码 ***********/
                                             
//把3个变量转化为System.Numerics.BigInteger
var  modulus =  new  BigInteger(modulusBytes);
var  exponent =  new  BigInteger(exponentBytes);
var  data =  new  BigInteger(Encoding.UTF8.GetBytes( "PASSWORD" ));
                                             
//做ModPow运算得到密文,也是BigInteger
var  result = BigInteger.ModPow(data, exponent, modulus);
                                             
//把密文BigInteger对应的byte[]转化为HEX形式
string  resultHex = BitConverter.ToString(result.ToByteArray()).Replace( "-" "" );


OH MY GOD!!!  还是不行,为什么?


是字节序在捣乱,我们上面分析ASN.1结构时得到的所有数据都是大字节序的,而System.Numerics.BigInteger是小字节序的,需要转化之后才能使用。这点很烦人,要转来转去的。

1
2
3
4
5
6
7
8
9
10
11
12
/*********** C#代码 ***********/
                                             
//把3个变量转化为System.Numerics.BigInteger
var  modulus =  new  BigInteger(modulusBytes.Reverse().ToArray());
var  exponent =  new  BigInteger(exponentBytes.Reverse().ToArray());
var  data =  new  BigInteger(Encoding.UTF8.GetBytes( "PASSWORD" ).Reverse().ToArray());
                                             
//做ModPow运算得到密文,也是BigInteger
var  result = BigInteger.ModPow(d, e, m);
                                             
//把密文BigInteger对应的byte[]转化为HEX形式
string  resultHex = BitConverter.ToString(result.ToByteArray().Reverse().ToArray()).Replace( "-" "" );


再试一下,这下终于OK了。


问题完美解决了吗? 很遗憾,没有,因为System.Numerics.BigInteger是4.0以上版本才提供的,低于此版本的只好去使用第三方的实现,比如这个:http://www.codeproject.com/Articles/2728/Csharp-BigInteger-Class,但要注意以下2点:


1、它默认只支持560bit,代码最开头有写:private const int maxLength = 70;

把maxLength改成256才能支持2048位的RSA运算了。

2、它是大字节序的,在使用时不用反转modulus和publicExponent对应的byte[]。

3、我们得到的modulus是257个字节,需要去掉首字节的0,用剩下的256个字节实例化BigInteger。



好,至此问题算是告一段落了,实测通过。以后想起来什么再继续补充吧。

我没有提供完整解决方案的代码,只给出了部分代码片断,希望对此问题有兴趣的同学把重点放在理解过程上,而不是仅仅搬代码。





     本文转自 BoyTNT 51CTO博客,原文链接:http://blog.51cto.com/boytnt/1351207,如需转载请自行联系原作者

相关文章
|
10月前
|
前端开发 Java C#
java/C#语言开发的医疗信息系统11套源码
java/C#语言开发的医疗信息系统11套源码
184 2
|
10月前
|
算法 安全 Java
Java 实现 RSA 非对称加密算法-加解密和签名验签
Java 实现 RSA 非对称加密算法-加解密和签名验签
364 0
|
5月前
|
开发框架 Java .NET
C#与Java
在动态且不断发展的软件开发世界中,Java 和 C# 是两个巨头,每个都有自己独特的优势、理念和生态系统。本文深入比较了 Java 和 C#,探讨了它们的历史背景、语言特性、性能指标、跨平台功能等。
208 19
C#与Java
|
7月前
|
Java C# 数据安全/隐私保护
如何 使 Java、C# md5 加密的值保持一致
如何 使 Java、C# md5 加密的值保持一致
122 0
|
7月前
|
Java C#
C# 和 java 基本数据类型
C# 和 java 基本数据类型
47 0
|
9月前
|
Java C# 数据安全/隐私保护
|
9月前
|
Java Go C#
编程语言C#、C++、Java、Python、go 选择哪个好?
我想说的是,不论选择哪种编程语言,决定选择的都是你最终的目的,做选择之前,先充分调研每一个选择项,再做选择思路就会非常清晰了。
196 3
|
9月前
|
Java BI C#
技术笔记:SM4加密算法实现Java和C#相互加密解密
技术笔记:SM4加密算法实现Java和C#相互加密解密
182 0
|
10月前
|
人工智能 搜索推荐 Java
C# 最有可能摘得“年度编程语言”,Python、Java 正在让位,TIOBE 12 月编程语言榜单最新预测来了!
C# 最有可能摘得“年度编程语言”,Python、Java 正在让位,TIOBE 12 月编程语言榜单最新预测来了!
74 1
|
10月前
|
XML 算法 安全
C# | 上位机开发新手指南(九)加密算法——RSA
RSA的特性 非对称性 RSA算法使用公钥和私钥两个不同的密钥,公钥用于加密数据,私钥用于解密数据。公钥可以公开,任何人都可以使用,而私钥只有密钥持有人可以访问。 安全性 RSA算法基于大数分解难题,即将一个大的合数分解成其质数因子的乘积。由于目前没有有效的算法可以在合理的时间内对大质数进行分解,因此RSA算法被认为是一种安全的加密算法。 可逆性 RSA算法既可以用于加密,也可以用于解密。加密和解密都是可逆的过程,只要使用正确的密钥,就可以还原原始数据。 签名 RSA算法可以用于数字签名,用于验证数据的完整性和真实性。签名过程是将数据使用私钥进行加密,验证过程是将签名使用公钥进行解密。
252 0
C# | 上位机开发新手指南(九)加密算法——RSA