C# Java间进行RSA加密解密交互
這里,講一下RSA算法加解密在C#和Java之間交互的問題,這兩天糾結(jié)了很久,也看了很多其他人寫的文章,頗受裨益,但沒能解決我的實(shí)際問題,終于,還是被我搗鼓出來了。
首先,介紹一下寫這代碼的目的:完成webService驗(yàn)證問題,服務(wù)器端采用C#開發(fā),客戶端采用Java開發(fā)。服務(wù)器端給客戶端提供公鑰,已進(jìn)行數(shù)據(jù)加密,客戶端加密后提數(shù)據(jù)提交給服務(wù)器,服務(wù)器用私鑰對(duì)數(shù)據(jù)解密,進(jìn)行驗(yàn)證。?
這里遇到的主要問題是C#?RSACryptoServiceProvider類產(chǎn)生的公鑰、私鑰都是xml字符串?dāng)?shù)據(jù),而java?RSA算法要求的?Modulus、Exponent都是BigInteger類型,兩者間的轉(zhuǎn)換才是問題所在。?
關(guān)于Java?和?C#各自獨(dú)立的進(jìn)行RSA加密解密,大家可以看整兩篇文章,java?RSA加密解密實(shí)現(xiàn)()?和?C#中RSA加密解密和簽名與驗(yàn)證的實(shí)現(xiàn)。?
接下來講一下實(shí)現(xiàn)步驟:
首先由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)對(duì)C#提供的公鑰提取Modulus和Exponent/*** 返回包含模數(shù)modulus和指數(shù)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產(chǎn)生公鑰RSAPublicKey(java)
這里有個(gè)關(guān)鍵步驟先對(duì)Mudolus和Exponent進(jìn)行Base64解碼,這個(gè)是由于C#生成的密鑰對(duì),其參數(shù)已經(jīng)過Base64編碼成String類型,而java RSA參數(shù)是未經(jīng)base64編碼的byte[]類型。
至于Base64編碼、解碼方法,參考這篇文章,java 編碼和解碼,想詳細(xì)。
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; } }獲得公鑰后就可以進(jìn)行RSA加密處理了,這里還有一點(diǎn)需要提的是,RSA加密解密都有最大長(zhǎng)度限制,加密最大長(zhǎng)度為117字節(jié),解密最大長(zhǎng)度是128字節(jié),此外,此處加密得到的數(shù)據(jù)是經(jīng)過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; }加密后的數(shù)據(jù)提交給C#服務(wù)器端進(jìn)行解密,當(dāng)然,這里也要注意最大長(zhǎng)度限制問題
/// <summary>/// RSA解密/// </summary>/// <param name="encryptData">經(jīng)過Base64編碼的密文</param>/// <param name="privateKey">私鑰</param>/// <returns>RSA解密后的數(shù)據(jù)</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>/// 截取字節(jié)數(shù)組部分字節(jié)/// </summary>/// <param name="input"></param>/// <param name="offset">起始偏移位</param>/// <param name="length">截取長(zhǎng)度</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;}這樣,就順利完成了。經(jīng)過測(cè)試,這樣做的確得到了正確的結(jié)果。
若是有什么地方有問題,還望大家指正!
----------------------------------------------------------------------------------------
C# Java間進(jìn)行RSA加密解密交互(二)
C# Java間進(jìn)行RSA加密解密交互(三)
轉(zhuǎn)載于:https://www.cnblogs.com/lonelyxmas/p/5358922.html
總結(jié)
以上是生活随笔為你收集整理的C# Java间进行RSA加密解密交互的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Django中载入js和css文件
- 下一篇: Atitit.js模块化 atiImpo