C# Java間進行RSA加密解密互動

來源:互聯網
上載者:User

標籤:split   text   intern   span   lan   tsp   參數   create   turn   

引用:http://blog.csdn.net/dslinmy/article/details/37362661

這裡,講一下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加密解密互動

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.