原创文章,转载请注明出处 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,如需转载请自行联系原作者