c#rsa加密java解密_C# Java间进行RSA加密解密交互

本文介绍了如何在C#和Java之间使用RSA算法进行加密解密交互,涉及C#生成公钥私钥,Java提取公钥参数并进行加密,以及C#解密的过程。通过Base64编码处理解决了两者间格式不兼容问题,实现了数据的安全传输。
摘要由CSDN通过智能技术生成

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

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

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

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

接下来讲一下实现步骤:

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

/// 

/// 生成公钥、私钥

/// 

/// 公钥、私钥,公钥键"PUBLIC",私钥键"PRIVATE"

public Dictionary createKeyPair()

{

Dictionary keyPair = new Dictionary();

RSACryptoServiceProvider provider = new RSACryptoServiceProvider(1024);

keyPair.Add("PUBLIC", provider.ToXmlString(false));

keyPair.Add("PRIVATE", provider.ToXmlString(true));

return keyPair;

}

如此处生成的公钥为

t+56m5jXXonAJAKC7mgkhAZX5gWJTZojbSloLpLBGEWiebFaM+aUUKALfRx83/HaUV79ZiR3zuLJOLBdALx1cmcPk/b9fdNblLmzqi4cfSnfmMLWh05xf+ZS1pKHSKQtui3dfuu+3XH6Ak+S38dpIZUj/hihQQuKysN6GJ9h+c8=

AQAB

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

/**

* 返回包含模数modulus和指数exponent的haspMap

* @return

* @throws MalformedURLException

* @throws DocumentException

*/

public static HashMap rsaParameters(String xmlPublicKey) throws MalformedURLException, DocumentException{

HashMap map = new HashMap();

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#服务器端进行解密,当然,这里也要注意最大长度限制问题

/// 

/// RSA解密

/// 

/// 经过Base64编码的密文

/// 私钥

/// RSA解密后的数据

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;

}

/// 

/// 截取字节数组部分字节

/// 

/// 

/// 起始偏移位

/// 截取长度

/// 

private static byte[] getSplit(byte[] input, int offset, int length)

{

byte[] output = new byte[length];

for (int i = offset; i 

{

output[i - offset] = input[i];

}

return output;

}

这样,就顺利完成了。

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

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值