原文:C# Java间进行RSA加密解密交互

这里,讲一下RSA算法加解密在C#和Java之间交互的问题,这两天纠结了很久,也看了很多其他人写的文章,颇受裨益,但没能解决我的实际问题,终于,还是被我捣鼓出来了。

首先,介绍一下写这代码的目的:完成webService验证问题,服务器端采用C#开发,客户端采用Java开发。服务器端给客户端提供公钥,已进行数据加密,客户端加密后提数据提交给服务器,服务器用私钥对数据解密,进行验证。

这里遇到的主要问题是C# RSACryptoServiceProvider类产生的公钥、私钥都是xml字符串数据,而java RSA算法要求的 Modulus、Exponent都是BigInteger类型,两者间的转换才是问题所在。

关于Java 和 C#各自独立的进行RSA加密解密,大家可以看整两篇文章,java RSA加密解密实现() 和 C#中RSA加密解密和签名与验证的实现

接下来讲一下实现步骤:

首先由C# RSACryptoServiceProvider类生成公钥、私钥

 /// <summary>
/// 生成公钥、私钥
/// </summary>
/// <returns>公钥、私钥,公钥键"PUBLIC",私钥键"PRIVATE"</returns>
public Dictionary<string, string> createKeyPair()
{
Dictionary<string, string> keyPair = new Dictionary<string, string>();
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);
keyPair.Add("PUBLIC", provider.ToXmlString(false));
keyPair.Add("PRIVATE", provider.ToXmlString(true));
return keyPair;
}

如此处生成的公钥为

<RSAKeyValue>
<Modulus>t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>

在客户端(Java)对C#提供的公钥提取Modulus和Exponent

/**
* 返回包含模数modulus和指数exponent的haspMap
* @return
* @throws MalformedURLException
* @throws DocumentException
*/
public static HashMap<String,String> rsaParameters(String xmlPublicKey) throws MalformedURLException, DocumentException{
HashMap<String ,String> map = new HashMap<String, String>();
Document doc = DocumentHelper.parseText(xmlPublicKey);
String mudulus = (String) doc.getRootElement().element("Modulus").getData();
String exponent = (String) doc.getRootElement().element("Exponent").getData();
map.put("mudulus", mudulus);
map.put("exponent", exponent);
return map;
}

用Modulus和Exponent产生公钥RSAPublicKey(java)

这里有个关键步骤先对Mudolus和Exponent进行Base64解码,这个是由于C#生成的密钥对,其参数已经过Base64编码成String类型,而java
RSA参数是未经base64编码的byte[]类型。

至于Base64编码、解码方法,参考这篇文章,java 编码和解码,想详细。

public static byte[] decodeBase64(String input) throws Exception{
Class clazz=Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64");
Method mainMethod= clazz.getMethod("decode", String.class);
mainMethod.setAccessible(true);
Object retObj=mainMethod.invoke(null, input);
return (byte[])retObj;
} /**
* 返回RSA公钥
* @param modules
* @param exponent
* @return
*/
public static PublicKey getPublicKey(String modulus, String exponent){
try {
byte[] m = decodeBase64(modulus);
byte[] e = decodeBase64(exponent);
BigInteger b1 = new BigInteger(1,m);
BigInteger b2 = new BigInteger(1,e);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

获得公钥后就可以进行RSA加密处理了,这里还有一点需要提的是,RSA加密解密都有最大长度限制,加密最大长度为117字节,解密最大长度是128字节,此外,此处加密得到的数据是经过Base64编码处理的

public static String encrypt(byte[] source, PublicKey publicKey) throws Exception	{
String encryptData ="";
try {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int length = source.length;
int offset = 0;
byte[] cache;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
int i = 0;
while(length - offset > 0){
if(length - offset > MAXENCRYPTSIZE){
cache = cipher.doFinal(source, offset, MAXENCRYPTSIZE);
}else{
cache = cipher.doFinal(source, offset, length - offset);
}
outStream.write(cache, 0, cache.length);
i++;
offset = i * MAXENCRYPTSIZE;
}
return encodeBase64(outStream.toByteArray());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return encryptData;
}

加密后的数据提交给C#服务器端进行解密,当然,这里也要注意最大长度限制问题

/// <summary>
/// RSA解密
/// </summary>
/// <param name="encryptData">经过Base64编码的密文</param>
/// <param name="privateKey">私钥</param>
/// <returns>RSA解密后的数据</returns>
public static string decrypt(string encryptData, string privateKey)
{
string decryptData = "";
try
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString(privateKey);
byte[] bEncrypt = Convert.FromBase64String(encryptData);
int length = bEncrypt.Length;
int offset = 0;
string cache ;
int i = 0;
while (length - offset > 0)
{
if (length - offset > MAXDECRYPTSIZE)
{
cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, MAXDECRYPTSIZE), false));
}
else
{
cache = Encoding.UTF8.GetString(provider.Decrypt(getSplit(bEncrypt, offset, length - offset), false));
}
decryptData += cache;
i++;
offset = i*MAXDECRYPTSIZE;
}
}
catch(Exception e)
{
throw e;
}
return decryptData;
} /// <summary>
/// 截取字节数组部分字节
/// </summary>
/// <param name="input"></param>
/// <param name="offset">起始偏移位</param>
/// <param name="length">截取长度</param>
/// <returns></returns>
private static byte[] getSplit(byte[] input, int offset, int length)
{
byte[] output = new byte[length];
for (int i = offset; i < offset + length; i++)
{
output[i - offset] = input[i];
}
return output;
}

这样,就顺利完成了。

经过测试,这样做的确得到了正确的结果。

若是有什么地方有问题,还望大家指正!

----------------------------------------------------------------------------------------

C# Java间进行RSA加密解密交互(二)

C# Java间进行RSA加密解密交互(三)

C# Java间进行RSA加密解密交互的更多相关文章

  1. C# Java间进行RSA加密解密交互(二)

    原文:C# Java间进行RSA加密解密交互(二) 接着前面一篇文章C# Java间进行RSA加密解密交互,继续探讨这个问题. 在前面,虽然已经实现了C# Java间进行RSA加密解密交互,但是还是与 ...

  2. C# Java间进行RSA加密解密交互(三)

    原文:C# Java间进行RSA加密解密交互(三) 接着前面一篇C# Java间进行RSA加密解密交互(二)说吧,在上篇中为了实现 /** * RSA加密 * @param text--待加密的明文 ...

  3. C# 与JAVA 的RSA 加密解密交互,互通,C#使用BouncyCastle来实现私钥加密,公钥解密的方法

    因为C#的RSA加密解密只有公钥加密,私钥解密,没有私钥加密,公钥解密.在网上查了很久也没有很好的实现.BouncyCastle的文档少之又少.很多人可能会说,C#也是可以的,通过Biginteger ...

  4. RSA加密解密与加签验签

    RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年7月首次在美国公布 ...

  5. Java & PHP & Javascript 通用 RSA 加密 解密 (长字符串)

    系统与系统的数据交互中,有些敏感数据是不能直接明文传输的,所以在发送数据之前要进行加密,在接收到数据时进行解密处理:然而由于系统与系统之间的开发语言不同. 本次需求是生成二维码是通过java生成,由p ...

  6. java rsa加密解密

  7. RSA 加密 解密 (长字符串) JAVA JS版本加解密

    系统与系统的数据交互中,有些敏感数据是不能直接明文传输的,所以在发送数据之前要进行加密,在接收到数据时进行解密处理:然而由于系统与系统之间的开发语言不同. 本次需求是生成二维码是通过java生成,由p ...

  8. RSA加密解密及数字签名Java实现--转

    RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.当时他们三人都在麻省理工学院 ...

  9. Java使用RSA加密解密签名及校验

    RSA加密解密类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ...

随机推荐

  1. Linq--扩展方法

    如果现在有一个这样的需求,求筛选出来的大于20MB的进程的和,常用的方法是写一个静态方法传进去一个ProcessData列表 比如: public static Int64 TotalMemory( ...

  2. Ztack学习笔记(2)-系统初始化分析

    main函数先执行初始化工作,包括硬件.网络层.任务等的初始化. 一 系统初始化 系统初始化函数主要完成内存分配.消息队列头.定时器.电源管理.任务系统及内存栈等的初始化,具体如下代码所示: //os ...

  3. 【nodejs】jade模板入门

    使用jetbrians webstom创建空项目 1.创建package.json 引用依赖配置 { "name": "demojade", "des ...

  4. 如何在LINUX VPS上安装VPN详细步骤

    在vps上安装vpn是个难点,很多朋友都不会,这儿结合一位朋友的安装经验做下介绍.注意你的vps要安装做vpn使用,一定要注意你的流量限制,使用Vpn上游戏上youtube看视频等都比较耗费资源,否则 ...

  5. quartus ii 中文注释乱码解决办法

    转载自:http://bbs.ednchina.com/BLOG_ARTICLE_3027549.HTM 有些时候我们用Quartus ii 打开不同版本创建的工程文件时,往往会出现下列提示 点yes ...

  6. margin-top相对谁的问题

    根据规范,一个盒子如果没有上补白(padding-top)和上边框(border-top),那么这个盒子的上边距会和其内部文档流中的第一个子元素的上边距重叠.意思便是:如果你只想margin相对于父标 ...

  7. Linux - 升级+编译kernel

    For upgrading present kernel to linux-next kernel, we need to follow below steps. 1. Check present k ...

  8. 配置 RAILS FOR JRUBY1.7.4

    1. 去JRUBY官方网站下载JRUBY http://www.jruby.org/ 目前最新版本是1.7.4,解压到C:\目录下 2. 设置环境变量 JRUBY_HOME = C:\jruby-1. ...

  9. [转载+原创]Emgu CV on C# (七) —— Emgu CV on 轮廓检测

    轮廓检测 对于查找轮廓我们一般要对图像Canny检测.但是对于很特殊的场合其实我们还可以直接对二值化的图像进行轮廓的提取. 关键函数 1. cvFindContours Retrieves conto ...

  10. 关于12306登陆页面dynamicJs的获取

    今天帮与一个朋友探讨此事,刚开始一直是以为访问404,但是发现返回为200,没有问题,后来才知道朋友想了解的是为何浏览器可以获取到/otn/dynamicJs,但是自己手动获取就获取不到了 找了很久r ...