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加密解密交互(三)
轉載于:https://www.cnblogs.com/lonelyxmas/p/5358922.html
總結
以上是生活随笔為你收集整理的C# Java间进行RSA加密解密交互的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Django中载入js和css文件
- 下一篇: Atitit.js模块化 atiImpo