最近遇到一個項目需要做單點,用戶方是采用java rsa公鑰加密傳遞信息的,我這邊是.net使用私鑰解密。而對方提供的解密源碼是java版本的,並且也沒有做過與.net平台的單點對接。
於是在網上找到了如下版本的c# 版本rsa私鑰解密方法
1 /// <summary> 2 /// RSA的解密函數 3 /// </summary> 4 /// <param name="xmlPrivateKey">私鑰</param> 5 /// <param name="decryptString">待解密的字符串</param> 6 /// <returns></returns> 7 public string RSADecrypt(string xmlPrivateKey, string decryptString) 8 { 9 byte[] PlainTextBArray;//解密前字節流 10 byte[] DypherTextBArray;//解密后字節流 11 string Result = ""; 12 System.Security.Cryptography.RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 13 rsa.FromXmlString(xmlPrivateKey); 14 PlainTextBArray = Convert.FromBase64String(decryptString); 15 DypherTextBArray = rsa.Decrypt(PlainTextBArray, false); 16 Result = Encoding.UTF8.GetString(DypherTextBArray); 17 return Result; 18 }
拿過來之后把私鑰和帶解密字符串傳入,發現報錯,於是研究發現,c#的rsa解密私鑰是xml格式的,而對方提供的是base64字符串,所以需要先把私鑰轉成xml格式,
轉換無法在c#中進行,需要打開在java下面轉換,可以下個exclipse把如下代碼復制進去就行。
1 package com; 2 3 import java.security.KeyFactory; 4 import java.security.PublicKey; 5 import java.security.interfaces.RSAPrivateCrtKey; 6 import java.security.interfaces.RSAPublicKey; 7 import java.security.spec.PKCS8EncodedKeySpec; 8 import java.security.spec.X509EncodedKeySpec; 9 //import org.castor.util.Base64Decoder; 10 //import org.castor.util.Base64Encoder; 11 12 public class test { 13 14 public static void main(String[] args) 15 { 16 String tes="MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAL8z2QlXCL6w7rvY0Gbl8ARtQSXY+pEW5hlUHlmspqHt4k8/SkoF796gDqk4yyOcoWhkZWLPPugK35Mn7V+m5Jyfu8C0gVKOfWOA8A0T4hxV2ThAoMUq7QtB2K6s9AoumrxDfAkMBbsXEHYwfD/hxr/3DQ3lUvSFB6BnhiHEOyzpAgMBAAECgYEAol/9qRjorEjF9XEjSr9rHddKxEGIST8RGeF+BNnCiTHkRziQdlykYIO876jzmsKhsG3STB+EZLsXM3ls9RZefcsPF5mLOCSOCow3DikfCtAy4hntsU9JwpuYE0V4A+Sgfd24fatqbu+JxE2nvpSbAPczDOgBFPNfYBkhMiuZ/iECQQDzUeq7lFcIE4uWhRGveVFjNAGuSsW+q9GOwO7tS5YwuAIQ2M+XgYGRFo8xMC6V/9SfqJtmSU1zk72pMlYufIqHAkEAySqkcKbWuobq5I9KSQISq2qCuGKtj/iUFho4PCD1YxhnQ7gcHA4OpS1dRFjtXJYQPTX9be+mmypsCFIyofE5DwJBAPGZ20wahTh9v9Lbmq3z9n5ce3bGxAcJsHDg3d09eooxi8uSnL5BV5frII+k2f0TI9rMnlE4Y/FpN5+zXaOXAi0CQQCs3Aqfjo23jJWtPv/LSo+2YnjfblPMAgNmFrO532xc8axSgZMN/HpTL28UewHD7GMZ5hnWbPcSIFrir5c4luq7AkEAi90WdnZVPxtSTqkkLYbnh4Ro2WhdwRjkfyBxBZZx8hfaM6MfLPi3A0rw9DPOSB4M/BMchtEh3bXuI7bue2tG+A=="; 17 byte[] temp=b64decode(tes); 18 String ver=getRSAPrivateKeyAsNetFormat(temp);//轉換私鑰 19 20 String tes1="MIGfMA0GCSqGSIb4DQEBAQUAA4GNADCBiQKBgQC/M9kJVwi+sO672NBm5fAEbUEl2PqRFuYZVB5ZrKah7eJPP0pKBe/eoA6pOMsjnKFoZGVizz7oCt+TJ+1fpuScn7vAtIFSjn1jgPANE+IcVdk4QKDFKu0LQdiurPQKLpq8Q3wJDAW7FxB2MHw/4ca/9w0N5VL0hQegZ4YhxDss6QIDAQAB"; 21 byte[] temp1=b64decode(tes1); 22 String ver1=getRSAPublicKeyAsNetFormat(temp1);//轉換公鑰 23 //String temp2= encodePublicKeyToXml(temp1); 24 25 } 26 27 private static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivkey) { 28 try { 29 StringBuffer buff = new StringBuffer(1024); 30 31 PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec( 32 encodedPrivkey); 33 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 34 RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory 35 .generatePrivate(pvkKeySpec); 36 37 buff.append("<RSAKeyValue>"); 38 buff.append("<Modulus>" 39 + b64encode(removeMSZero(pvkKey.getModulus().toByteArray())) 40 + "</Modulus>"); 41 42 buff.append("<Exponent>" 43 + b64encode(removeMSZero(pvkKey.getPublicExponent() 44 .toByteArray())) + "</Exponent>"); 45 46 buff.append("<P>" 47 + b64encode(removeMSZero(pvkKey.getPrimeP().toByteArray())) 48 + "</P>"); 49 50 buff.append("<Q>" 51 + b64encode(removeMSZero(pvkKey.getPrimeQ().toByteArray())) 52 + "</Q>"); 53 54 buff.append("<DP>" 55 + b64encode(removeMSZero(pvkKey.getPrimeExponentP() 56 .toByteArray())) + "</DP>"); 57 58 buff.append("<DQ>" 59 + b64encode(removeMSZero(pvkKey.getPrimeExponentQ() 60 .toByteArray())) + "</DQ>"); 61 62 buff.append("<InverseQ>" 63 + b64encode(removeMSZero(pvkKey.getCrtCoefficient() 64 .toByteArray())) + "</InverseQ>"); 65 66 buff.append("<D>" 67 + b64encode(removeMSZero(pvkKey.getPrivateExponent() 68 .toByteArray())) + "</D>"); 69 buff.append("</RSAKeyValue>"); 70 71 return buff.toString().replaceAll("[ \t\n\r]", ""); 72 } catch (Exception e) { 73 System.err.println(e); 74 return null; 75 } 76 } 77 78 private static String getRSAPublicKeyAsNetFormat(byte[] encodedPrivkey) { 79 try { 80 StringBuffer buff = new StringBuffer(1024); 81 82 PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(encodedPrivkey); 83 KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 84 RSAPublicKey pukKey=(RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(encodedPrivkey)); 85 // RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(pvkKeySpec); 86 //PublicKey publicKey =KeyFactory.getInstance("RSA").generatePublic(pvkKeySpec); 87 buff.append("<RSAKeyValue>"); 88 buff.append("<Modulus>" 89 + b64encode(removeMSZero(pukKey.getModulus().toByteArray())) 90 + "</Modulus>"); 91 buff.append("<Exponent>" 92 + b64encode(removeMSZero(pukKey.getPublicExponent() 93 .toByteArray())) + "</Exponent>"); 94 buff.append("</RSAKeyValue>"); 95 return buff.toString().replaceAll("[ \t\n\r]", ""); 96 } catch (Exception e) { 97 System.err.println(e); 98 return null; 99 } 100 } 101 public static String encodePublicKeyToXml(PublicKey key) { 102 if (!RSAPublicKey.class.isInstance(key)) { 103 return null; 104 } 105 RSAPublicKey pubKey = (RSAPublicKey) key; 106 StringBuilder sb = new StringBuilder(); 107 sb.append("<RSAKeyValue>"); 108 sb.append("<Modulus>") 109 .append(Base64.encode(pubKey.getModulus().toByteArray())) 110 .append("</Modulus>"); 111 sb.append("<Exponent>") 112 .append(Base64.encode(pubKey.getPublicExponent() 113 .toByteArray())).append("</Exponent>"); 114 sb.append("</RSAKeyValue>"); 115 return sb.toString(); 116 } 117 118 private static byte[] removeMSZero(byte[] data) { 119 byte[] data1; 120 int len = data.length; 121 if (data[0] == 0) { 122 data1 = new byte[data.length - 1]; 123 System.arraycopy(data, 1, data1, 0, len - 1); 124 } else 125 data1 = data; 126 return data1; 127 } 128 private static String b64encode(byte[] data) { 129 130 String b64str = new String(Base64.encode(data)); 131 return b64str; 132 } 133 134 private static byte[] b64decode(String data) { 135 byte[] decodeData = Base64.decode(data); 136 return decodeData; 137 } 138 }
參考:http://www.cnblogs.com/hvaning/p/3636288.html
現在拿到c#的私鑰了,發現解密還是報錯,又看了下,發現用戶給的加密文本是16進制文本,並不是base64文本,於是寫了個16進制轉字節的方法供調用。
16進制文本轉字節流方法如下
1 /// <summary> 2 /// 16進制文本轉字節流 3 /// </summary> 4 /// <param name="src">16進制文本</param> 5 /// <returns></returns> 6 public byte[] hexStr2ByteArr(string src) 7 { 8 int l = src.Length / 2;//2個16進制文本等於一個字節,所以字節數組長度是16進制文本長度的一半 9 String str; 10 byte[] ret = new byte[l]; 11 12 for (int i = 0; i < l; i++) 13 { 14 str = src.Substring(i * 2, 2); 15 ret[i] = Convert.ToByte(str, 16); 16 } 17 return ret; 18 }
然后下一個坑又出來了,rsa解密一次只能128個字節,所以又寫了個循環的方法,每次解密128個字節數組,最終再拼接起來,最終代碼如下:
1 /// <summary> 2 /// RSA的解密函數 3 /// </summary> 4 /// <param name="xmlPrivateKey">私鑰</param> 5 /// <param name="decryptString">待解密的字符串</param> 6 /// <returns></returns> 7 public string RSADecrypt(string xmlPrivateKey, string decryptString) 8 { 9 try 10 { 11 byte[] PlainTextBArray; 12 byte[] DypherTextBArray; 13 string Result = ""; 14 System.Security.Cryptography.RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 15 rsa.FromXmlString(xmlPrivateKey); 16 PlainTextBArray = hexStr2ByteArr(decryptString); 17 var outlength = PlainTextBArray.Length; 18 var i = 0; 19 while (true) { 20 if (outlength > 128) 21 { 22 var aa = new byte[128]; 23 Array.Copy(PlainTextBArray, i, aa, 0, 128); 24 DypherTextBArray = rsa.Decrypt(aa, false); 25 Result = Result + Encoding.UTF8.GetString(DypherTextBArray); 26 outlength = outlength - 128; 27 i = i + 128; 28 } 29 else { 30 var aa = new byte[outlength]; 31 Array.Copy(PlainTextBArray, i, aa, 0, outlength); 32 DypherTextBArray = rsa.Decrypt(aa, false); 33 Result = Result + Encoding.UTF8.GetString(DypherTextBArray); 34 break; 35 } 36 } 37 return Result; 38 } 39 catch (Exception ex) 40 { 41 throw ex; 42 } 43 }