Rsa 加密标准的制定已经过去了十多年了. 这两天在看rsa 加密的文章,基本上都是在说 .net 与 java 之间的 rsa加密是不能互通的.因为项目有用到,所以花了点时间对rsa加密做了一点点了解,发现,不管是java 还是 C# 都对 rsa 的标准加密进行了实现, 是 对于标准是实现,不能互通就讲不过去了. 今天特意写了一段java 代码试了一下,发现是完全可以的.

密钥的描述: C#(.net) 中有三种方式导出密钥,一种是blob,一种是 xml 另一种是参数,其中xml 的方式是把 参数进行了 xml序列化.blob 的形式我没看懂是什么意思,只知道文档上说是给微软的什么api用的,下面给出其参数的形式.

RSAParameters   字段

Contains

对应的 PKCS #1 字段

D

d,私钥指数

privateExponent

DP

d mod (p - 1)

exponent1

DQ

d mod (q - 1)

exponent2

Exponent

e,公钥指数

publicExponent

InverseQ

(InverseQ)(q) = 1 mod p

coefficient

Modulus

n

modulus

P

p

prime1

Q

q

prime2

RSA 算法

若要生成密钥对,可以从创建名为 p 和 q 的两个大的质数开始; 这两个数相乘,结果称为 n; 因为 p 和 q 都是质数,所以 n 的全部因数为 1、p、q 和 n;

如果仅考虑小于 n 的数,则与 n 为互质数(即与 n 没有公因数)的数的个数等于 (p - 1)(q - 1);

现在,选择一个数 e,它与计算的值为互质数; 则公钥表示为 {e, n};

若要创建私钥,则必须计算 d,它是满足 (d)(e) mod n = 1 的一个数; 根据 Euclidean 算法,私钥为 {d, n};

纯文本 m 到密码文本 c 的加密定义为 c = (m ^ e) mod n; 解密则定义为 m = (c ^ d) mod n;

总之,我们可以从 .net 的rsa 中拿 到合适的密钥描述就是了,至于 java的,我想也是可以做到的,而且通常密钥是应该放在密钥容器的.

接下来我们用.net 生成一个  rsa 的密钥,以十六进制的方式输出的(new 一个RSACryptoServiceProvider,把密钥导出就可以了)

D: 2FE7479CF4CFEE63218C44D763C3E552DC5FBC94A31F944B88AE8E58F0ED16874B8BED35307B143F413761B2ECFFC95F48DF0D0A29FC155C0B968EFE9FFF36E7
DP: 6777B761BC29637622FC63682243BB2E05CCFC6FF710ADE1DCE6B0C843B17C4F
DQ: 68771CCDA40F0DA0B504C438BB03F7DF30F77364094D475E70270D148260D247
Exponent: 010001
InverseQ: 5665AB47697008CC2CECB544B582B9C50628281C400846C1E736629B03FE5C85
Modulus: B3F276C8EDF515FD3248CCF4163480B9F77443A666522D66B89411EC6DFE11DEA917A97C977750EE777DACBD4D2C11BC363FDC110E5CCA0A1361D51AFA4A7ADD
P: ECC60A01B1BDCBA1C5422D8A0A34FC0E46727DB4ED5089E54C356F052E0AB573
Q: C28F233948483D0CD0E3FA7B5D2955F2B15E831B38876FB0E7180D873EDF7A6F

为了方便写.net 代码,这里贴一下blob的密钥

0702000000A40000525341320002000001000100DD7A4AFA1AD561130ACA5C0E11DC3F36BC112C4DBDAC7D77EE5077977CA917A9DE11FE6DEC1194B8662D5266A64374F7B9803416F4CC4832FD15F5EDC876F2B373B50A2E056F354CE58950EDB47D72460EFC340A8A2D42C5A1CBBDB1010AC6EC6F7ADF3E870D18E7B06F87381B835EB1F255295D7BFAE3D00C3D484839238FC24F7CB143C8B0E6DCE1AD10F76FFCCC052EBB43226863FC22766329BC61B7776747D26082140D27705E474D096473F730DFF703BB38C404B5A00D0FA4CD1C7768855CFE039B6236E7C14608401C282806C5B982B544B5EC2CCC08706947AB6556E736FF9FFE8E960B5C15FC290A0DDF485FC9FFECB26137413F147B3035ED8B4B8716EDF0588EAE884B941FA394BC5FDC52E5C363D7448C2163EECFF49C47E72F

因为是私钥,所以同时可以加密和解密.下面上  C# 代码,比较简单

using System;
using System.Security.Cryptography; class Program
{
public static void Main(string[] args)
{ byte[] plainText = new byte[]{,,,,,};
byte[] cipherText;
byte[] key = String2Bytes("0702000000A40000525341328001000001000100D3D10816051881319774576B67B1D24F3AA303471A4402AB625208EC1CB04D508AF2098227C5EE185890ECB83E6971C12BDCF4F8AB0FD729167C815D3404C1AD1C0628E3544C89E9F9044A6869447310C72D7CDEB5E3582AB28BCC5069D60CD4AB5A1BB8C754AEB544FA65FB990ADB68F5AA37D7AC2CCDBF19058A2A4CF18FC29577D184E75EFD0ABEC1263893262F40C89AB2831B20B52B477770BA95FA02A71339911EBBF8630AD1AEECC205888440037D580B18AEF11FC5F35EB74E434E5A9302823BF795A34DADDFE0C6D55BC7997E667ADBE511BA06");
using(var rsa = new RSACryptoServiceProvider())
{
rsa.ImportCspBlob(key);
Console.WriteLine("OAEP:");
Console.WriteLine(Bytes2String(rsa.Encrypt(plainText, true)));
Console.WriteLine("PCSK1-v1_5:");
Console.WriteLine(Bytes2String(rsa.Encrypt(plainText, false)));
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
} const string pattern = @"[^0-9a-fA-F]+";
static byte[] String2Bytes(string str)
{
str = System.Text.RegularExpressions.Regex.Replace(str, pattern, "");
if (str == string.Empty)
return null;
byte[] data = new byte[str.Length / ]; for (int i = ; i < data.Length; ++i)
data[i] = byte.Parse(str.Substring( * i, ), System.Globalization.NumberStyles.HexNumber);
return data;
}
static string Bytes2String(byte[] data)
{
System.Text.StringBuilder builder = new System.Text.StringBuilder();
foreach (var element in data) {
builder.AppendFormat("{0:X2}",element);
}
return builder.ToString();
}
}

运行后输出(rsa加密,密文每次都不一定一样):

OAEP:
87F04B0F28B81D23E63DA71C8278E0B7E357F40583BDDCAB493D44A58080EB178EC8E0DB0DCD4BE5427FDB8190229B8DF2511BDA1082607C92BD03B0615D5AD3
PCSK1-v1_5:
358AB4D336D0C35DAE3895E8A125F4F5AD0FB58117A4100FAF15DE95FF8615F01FFB1A59C9B579792B7C14E93E54A3E7E236D464DDB93D8DF9D96F63F46BACD7

现在我们有密文了,至于.net 的解密 .net 加密后的密文,我没兴趣去看,反正铁定可以的就是了.

下面我们写java 的解密部分

package rsatest;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher; public class RsaTest { public static void main(String[] args) throws Exception {
//前面补了个0,符号位为0,表示非负
BigInteger n = new BigInteger("B3F276C8EDF515FD3248CCF4163480B9F77443A666522D66B89411EC6DFE11DEA917A97C977750EE777DACBD4D2C11BC363FDC110E5CCA0A1361D51AFA4A7ADD", 16);
BigInteger e = new BigInteger("010001", 16);
BigInteger d = new BigInteger("2FE7479CF4CFEE63218C44D763C3E552DC5FBC94A31F944B88AE8E58F0ED16874B8BED35307B143F413761B2ECFFC95F48DF0D0A29FC155C0B968EFE9FFF36E7", 16);
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(n, e);
PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(keySpec);
RSAPrivateKeySpec prvKeySpec = new RSAPrivateKeySpec(n, d);
PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(prvKeySpec); //现在key 准备好了,把前面的密文放这里解密
byte[] oaepCiphertext = Hex2Bytes("87F04B0F28B81D23E63DA71C8278E0B7E357F40583BDDCAB493D44A58080EB178EC8E0DB0DCD4BE5427FDB8190229B8DF2511BDA1082607C92BD03B0615D5AD3"); //解密OAEP 加密的数据
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPADDING");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] plaintext = cipher.doFinal(oaepCiphertext);
System.out.println(Bytes2Hex(plaintext)); //解密PKCS1-v1_5 加密的数据
byte[] ciphertext = Hex2Bytes("358AB4D336D0C35DAE3895E8A125F4F5AD0FB58117A4100FAF15DE95FF8615F01FFB1A59C9B579792B7C14E93E54A3E7E236D464DDB93D8DF9D96F63F46BACD7");
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
plaintext = cipher.doFinal(ciphertext);
System.out.println(Bytes2Hex(plaintext)); } public static byte[] Hex2Bytes(String hexStr) {
if (hexStr.length() % 2 != 0) {
hexStr = "0" + hexStr;
}
byte[] bytes = new byte[hexStr.length() / 2];
for (int i = 0; i < bytes.length; ++i) {
bytes[i] = (byte) Integer.parseUnsignedInt(hexStr.substring(i * 2, i * 2 + 2), 16);
}
return bytes;
} public static String Bytes2Hex(byte[] bytes) {
StringBuilder builder = new StringBuilder();
for (byte b : bytes) {
builder.append(String.format("%02X", b));
}
return builder.toString();
}
}

程序运行后输出:

000102030405
000102030405

跟我们预期的是一样的.

我们再用java 对明文加密,代码片段

// plaintext {0,1,2,3,4,5}
cipher = Cipher.getInstance("RSA/ECB/OAEPPADDING");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
oaepCiphertext = cipher.doFinal(plaintext);
System.out.println("OAEP:");
System.out.println(Bytes2Hex(oaepCiphertext)); cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
ciphertext = cipher.doFinal(plaintext);
System.out.println("PCSK1-v1_5:");
System.out.println(Bytes2Hex(ciphertext));

对应输出(rsa加密,密文每次都不一定一样):

OAEP:
3144C4CB06C7F49D31E65D09C840069F7CCF602487908CCEAB33D473B949199E1795530B69E1FA20EB59E392B2B934024D46E979DEA1682BDFA61D6FDD980F9C
PCSK1-v1_5:
699A694BEB75616879C6B8D311CC10D987EA109D494EE6C9380CD2C02A124613F130C440CB1CA6D3405E50B62CF96A79EB43C3370253E5D8C1A9132CFE01D686

接下来用C# 对数据解密,代码片段

//还是用之前那个rsa对象
//OAEP
cipherText = String2Bytes("3144C4CB06C7F49D31E65D09C840069F7CCF602487908CCEAB33D473B949199E1795530B69E1FA20EB59E392B2B934024D46E979DEA1682BDFA61D6FDD980F9C");
Console.WriteLine(Bytes2String(rsa.Decrypt(cipherText, true)));
//PCSK1-v1_5
cipherText = String2Bytes("699A694BEB75616879C6B8D311CC10D987EA109D494EE6C9380CD2C02A124613F130C440CB1CA6D3405E50B62CF96A79EB43C3370253E5D8C1A9132CFE01D686");
Console.WriteLine(Bytes2String(rsa.Decrypt(cipherText, false)));

对应的输出:

000102030405
000102030405

解密也成功了.

或许该头疼的问题是,已知  {e,n} 或者  {d,n} 怎么生成.net 使用的密钥.

C# 与 Java Rsa加密与解密互通的更多相关文章

  1. IOS, Android, Java Web Rest : RSA 加密和解密问题

    IOS, Android, Java Web Rest :  RSA 加密和解密问题 一对公钥私钥可以使用 OpenSSL创建, 通常 1024位长度够了. 注意: 1. 公钥私钥是BASE64编码的 ...

  2. 【转】 java RSA加密解密实现

    [转] java RSA加密解密实现 该工具类中用到了BASE64,需要借助第三方类库:javabase64-1.3.1.jar 下载地址:http://download.csdn.net/detai ...

  3. RSA加密和解密工具类

    import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import java.security.*; i ...

  4. 通过ios实现RSA加密和解密

    在加密和解密中,我们需要了解的知识有什么事openssl:RSA加密算法的基本原理:如何通过openssl生成最后我们需要的der和p12文件. 废话不多说,直接写步骤: 第一步:openssl来生成 ...

  5. Java Base64加密、解密原理Java代码

    Java Base64加密.解密原理Java代码 转自:http://blog.csdn.net/songylwq/article/details/7578905 Base64是什么: Base64是 ...

  6. java c# 加密与解密对照

    原文 java c# 加密与解密对照 最近一直烦恼,java , c# 加密的不同,然后整理了一下,留个备份的轮子: 其中在 java.c#加密转换时,最重要的是 IV 的确定,我常常用如下方法使得j ...

  7. C#实现RSA加密和解密详解

    原文:C#实现RSA加密和解密详解 RSA加密解密源码: Code highlighting produced by Actipro CodeHighlighter (freeware) http:/ ...

  8. ASP.NET Core RSA加密或解密

    前言 这两天主要是公司同事用到了RSA加密,事后也看了下,以为很简单,最终利用RSACryptoServiceProvider来实现RSA加密,然后大致了解到RSACryptoServiceProvi ...

  9. C#实现RSA加密与解密、签名与认证(转)

    一.RSA简介 RSA公钥加密算法是1977年由Ron Rivest.Adi Shamirh和LenAdleman在(美国麻省理工学院)开发的.RSA取名来自开发他们三者的名字.RSA是目前最有影响力 ...

随机推荐

  1. Ubuntu系统配置apt-get软件更新源

    从别人那摘录的Ubuntu源,测的很好用 # 电子科技大学 (教育网) deb http://ubuntu.uestc.edu.cn/ubuntu/ oneiric main restricted u ...

  2. Oozie_02安装遇到错误【20161116】

    [错误原因]hadoop的core-site.xml配置错误  把用户名hadoop配置成了主机名hadoop01 <!-- OOZIE --><property> <n ...

  3. 使用UNetbootin制作U盘启动

    制作Ubuntu系统启动U盘,可以用软碟通UltraISO,也能用UNetbootin这个软件. UNetbootin的好处是有windows客户端,也有Linux的客户端,也就是说可以很方便的在Li ...

  4. php中隐形字符65279(utf-8的BOM头)问题和fwrite写入文件bom头导致的乱码问题解决

     php中隐形字符65279(utf-8的BOM头)问题 今天在CSDN看到一个php输出空白隐形字符65279的问题,在网上找了下,发下这个65279字符是php用来标记文件是utf-8编码的,输出 ...

  5. bzoj2330糖果

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2330 差分约束裸题.练习用spfa判正环(一个点入队超过n次). 据说有1e5个点连成一条链 ...

  6. Python 中函数和方法

    函数与方法 class Foo(object): def __init__(self): self.name = 'lcg' def func(self): print(self.name) obj ...

  7. 02 - Unit09:动态SQL

    动态SQL 什么是? 系统运行过程中,动态生成的SQL语句 为什么? 当我们不能确定用户操作,所要使用的具体SQL的时候. 案例: 搜索笔记功能 按用户名 笔记本名 笔记名 搜索 搜索功能 按用户 A ...

  8. 手淘flexible.js框架使用和源代码讲解

    手淘框架是一个用来适配移动端的js框架,下面我们来讲解一下如何使用手淘的这套框架. 其实手淘框架的核心原理就是根据不同的width给网页中html跟节点设置不同的font-size,然后所有的距离大小 ...

  9. QT 控制LED实验

    1.实验准备 在PC 机D:盘下创建文件夹qt-led,将光盘qt_led_exp 文件夹下的images 文件夹拷贝到E:盘下qt-led 文件夹qt-led 内 2.新建工程 新建一个Empty ...

  10. 微博短链接的生成算法(Java版本)

    最近看到微博的短链接真是很火啊,新浪.腾讯.搜狐等微博网站都加入了短链接的功能.之所以要是使用短链接,主要是因为微博只允许发140 字,如果链接地址太长的话,那么发送的字数将大大减少.短链接的主要职责 ...