RSA,JAVA私鑰加密,C#公鑰解密


做這個東西在坑里爬了3天才爬出來,記錄下供園友參考。C#程序員一枚,項目需要和Java做數據交互,對方甩了段密文和一個CER證書給我,然后我要對其密文進行解密。 RSA 非對稱加密,對方用私鑰加密,我用公鑰解密。關於證書的一點說明:證書類型有兩種 .pfx 和 .cer ,其中 .pfx 證書既包含公鑰也包含私鑰, 而 .cer 證書只包含公鑰。

C#默認RSA只支持公鑰加密,私鑰解密。而現在的需求正好相反,因此想要直接用C#內置加密類肯定是行不通的。而且C#和Java的RSA加密並不互通。經過多方資料查找,采用第三方類庫 BouncyCastle 實現了當前需求。具體來看代碼,這里貼出主要代碼段:

 

1. 從cer證書中讀取公鑰。C#中的公鑰格式是xml格式的字符串,與java中的公鑰格式是不一樣的。

/// <summary>
/// 從證書中獲取公鑰
/// </summary>
/// <param name="cerPath"></param>
/// <returns></returns>
private string GetPublicKeyFromCer(string cerPath)
{
     X509Certificate2 pubcrt = new X509Certificate2(cerPath);
     RSACryptoServiceProvider pubkey = (RSACryptoServiceProvider)pubcrt.PublicKey.Key;

     return pubkey.ToXmlString(false);
}

 

2. 將C#格式公鑰轉換成Java格式公鑰

/// <summary>
/// 將C#格式公鑰轉成Java格式公鑰
/// </summary>
/// <param name="publicKey"></param>
/// <returns></returns>
public static RsaKeyParameters RSAPublicKeyDotNet2Java(string publicKey)
{
     XmlDocument doc = new XmlDocument();
     doc.LoadXml(publicKey);
     BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
     BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
     RsaKeyParameters pub = new RsaKeyParameters(false, m, p);

     return pub;
}

 

3. 公鑰解密。因為對方給的密文是經過base64編碼的,所以要先解碼。而且加密填充模式要設置成和java那邊的一致,我這里設置的是 "RSA/ECB/PKCS1Padding"。

/// <summary>
/// 公鑰解密
/// </summary>
/// <param name="xmlPublicKey">C#格式公鑰</param>
/// <param name="strEncryptString">密文</param>
/// <returns></returns>
public static string RSADecryptByPublicKey(string xmlPublicKey, string strEncryptString)
{
      //得到公鑰
      RsaKeyParameters keyParams = RSAPublicKeyDotNet2Java(xmlPublicKey);

      //參數與Java中加密解密的參數一致
      IBufferedCipher c = CipherUtilities.GetCipher("RSA/ECB/PKCS1Padding");  

      //第一個參數 true-加密,false-解密;第二個參數表示密鑰
      c.Init(false, keyParams);

      //對密文進行base64解碼
      byte[] dataFromEncrypt = Convert.FromBase64String(strEncryptString);

      //解密
      byte[] outBytes = c.DoFinal(dataFromEncrypt);

      //明文
      string clearText = Encoding.Default.GetString(outBytes);

      return clearText;
}

 

以上代碼都依賴於 BouncyCastle 使用前記得先添加引用。為什么這樣一個問題在坑里呆了3天呢?原因是Java那邊返給我的密文格式是錯誤的,導致我怎么也解不出來。當時那個急的,還以為Java和C#實現不了互通加解密呢!最后這個問題還是我自己找出來的,丟了張截圖給他們

 

 

就是這個原因,導致我加了兩天班.... 當你解密時遇到 Unknown block type 錯誤時,很大可能性就是編碼的問題,即密文的格式不正確。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM