今天在跟同事一塊兒調試TCP通信的時候,在RSA私鑰解密這塊,着實讓我費了一番心思。
流程大體是這樣的,終端登陸的時候使用固定的des密碼加密數據發送,平臺接收後確認登陸信息後,會返回一個字符串,
該字符串是使用rsa公鑰加密的一個字符串,做爲後續通信時使用的des密碼。平臺是使用JAVA開發的,該私鑰和公鑰文件會
在終端存一份。可是該文件是pem格式的,並且公鑰使用證書的方式,調試使用公鑰加密後的發送給平臺,平臺都是能夠解密的。
可是平臺發送回來的公鑰加密就是解密不正常。其中查找資料就很少說了,總算是解決了。這裏作一個記錄,也作個分享。
其中使用到一個第三方庫:BouncyCastle,能夠使用NuGet來安裝.
首先是RSA密鑰與Pem密鑰的互轉。c#
/// <summary> /// Pem密鑰轉RSA密鑰 /// </summary> /// <param name="pemKey">Pem密鑰</param> /// <param name="isPrivateKey">是不是私鑰</param> /// <returns>RSA密鑰</returns> public static string PemToRSAKey(string pemKeyFileName, bool isPrivateKey) { string rsaKey = string.Empty; object pemObject = null; RSAParameters rsaPara = new RSAParameters(); using (StreamReader sReader = new StreamReader(pemKeyFileName)) { var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(sReader); pemObject = pemReader.ReadObject(); } //RSA私鑰 if (isPrivateKey) { RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)pemObject; rsaPara = new RSAParameters { Modulus = key.Modulus.ToByteArrayUnsigned(), Exponent = key.PublicExponent.ToByteArrayUnsigned(), D = key.Exponent.ToByteArrayUnsigned(), P = key.P.ToByteArrayUnsigned(), Q = key.Q.ToByteArrayUnsigned(), DP = key.DP.ToByteArrayUnsigned(), DQ = key.DQ.ToByteArrayUnsigned(), InverseQ = key.QInv.ToByteArrayUnsigned(), }; } //RSA公鑰 else { RsaKeyParameters key = (RsaKeyParameters)pemObject; rsaPara = new RSAParameters { Modulus = key.Modulus.ToByteArrayUnsigned(), Exponent = key.Exponent.ToByteArrayUnsigned(), }; } RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.ImportParameters(rsaPara); using (StringWriter sw = new StringWriter()) { sw.Write(rsa.ToXmlString(isPrivateKey ? true : false)); rsaKey = sw.ToString(); } return rsaKey; } /// <summary> /// RSA密鑰轉Pem密鑰 /// </summary> /// <param name="RSAKey">RSA密鑰</param> /// <param name="isPrivateKey">是不是私鑰</param> /// <returns>Pem密鑰</returns> public static string RSAKeyToPem(string RSAKey, bool isPrivateKey) { string pemKey = string.Empty; RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(RSAKey); RSAParameters rsaPara = new RSAParameters(); RsaKeyParameters key = null; //RSA私鑰 if (isPrivateKey) { rsaPara = rsa.ExportParameters(true); key = new RsaPrivateCrtKeyParameters( new BigInteger(1, rsaPara.Modulus), new BigInteger(1, rsaPara.Exponent), new BigInteger(1, rsaPara.D), new BigInteger(1, rsaPara.P), new BigInteger(1, rsaPara.Q), new BigInteger(1, rsaPara.DP), new BigInteger(1, rsaPara.DQ), new BigInteger(1, rsaPara.InverseQ)); } //RSA公鑰 else { rsaPara = rsa.ExportParameters(false); key = new RsaKeyParameters(false, new BigInteger(1, rsaPara.Modulus), new BigInteger(1, rsaPara.Exponent)); } using (TextWriter sw = new StringWriter()) { var pemWriter = new PemWriter(sw); pemWriter.WriteObject(key); pemWriter.Writer.Flush(); pemKey = sw.ToString(); } return pemKey; }
公鑰加密,以證書方式打開pem密鑰文件ide
/// <summary> /// RSA公鑰加密 /// </summary> /// <param name="data"></param> /// <param name="publicKey"></param> /// <returns></returns> public static byte[] RSAPublicEncrypt(byte[] data, string publicKeyFileName) { X509Certificate2 x509Certificate2 = new X509Certificate2(publicKeyFileName); RSACryptoServiceProvider pubKey = (RSACryptoServiceProvider)x509Certificate2.PublicKey.Key; byte[] bys = pubKey.Encrypt(data, false); //string result = Convert.ToBase64String(bys); //return Encoding.UTF8.GetBytes(result); return bys; }
私鑰解密加密
/// <summary> /// RSA私鑰解密 /// </summary> /// <param name="data"></param> /// <param name="privateKey"></param> /// <returns></returns> public static byte[] RSAPrivateDecrypt(byte[] data, string privateKeyFileName) { string xml = PemToRSAKey(privateKeyFileName, true);//將pem密鑰轉爲RSA密鑰 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(xml); return rsa.Decrypt(data, false); }