C# Java间进行RSA加密解密交互 .
来源:互联网 发布:python if false 编辑:程序博客网 时间:2024/06/01 07:39
这里,讲一下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; }
0 0
- C# Java间进行RSA加密解密交互
- C# Java间进行RSA加密解密交互(二)
- C# Java间进行RSA加密解密交互(三)
- C# Java间进行RSA加密解密交互 .
- C# Java间进行RSA加密解密交互(二) .
- C# Java间进行RSA加密解密交互 .
- C# Java间进行RSA加密解密交互(二)
- C# Java间进行RSA加密解密交互(三)
- C# Java间进行RSA加密解密交互 .
- C# Java间进行RSA加密解密交互(三)
- C# java 通用 RSA 加密/解密
- java C# RSA加密/解密 通用
- C# RSA加密解密
- java RSA加密解密
- Java RSA加密解密
- Java RSA加密解密
- java RSA 加密/解密
- java RSA加密解密
- 在自己博客上添加自己的“微博”栏目
- Android 拖动组件
- C++使用hash_map时警告
- 百度地图在设置中心时,背景变白
- python 科学计算库 - Numpy,Scipy,Pandas
- C# Java间进行RSA加密解密交互 .
- 洛谷 P1108 低价购买
- “J.U.C”:ReentrantLock之三unlock方法分析(r)
- HDU3792---Twin Prime Conjecture(树状数组)
- app/android:showAsAction的区别
- 基础(1)
- KMP算法的实现
- Leetcode 5 Longest Palindromic Substring
- rolling invalidation对子游标产生的影响