RSA使用
今天在跟同事一起調試TCP通訊的時候,在RSA私鑰解密這塊,着實讓我費了一番心思。
流程大致是這樣的,終端登錄的時候使用固定的des密碼加密數據發送,平台接收后確認登錄信息后,會返回一個字符串,
該字符串是使用rsa公鑰加密的一個字符串,作為后續通訊時使用的des密碼。平台是使用JAVA開發的,該私鑰和公鑰文件會
在終端存一份。但是該文件是pem格式的,而且公鑰使用證書的方式,調試使用公鑰加密后的發送給平台,平台都是可以解密的。
但是平台發送回來的公鑰加密就是解密不正常。其中查找資料就不多說了,總算是解決了。這里做一個記錄,也做個分享。
其中使用到一個第三方庫:BouncyCastle,可以使用NuGet來安裝.
首先是RSA密鑰與Pem密鑰的互轉。
/// <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密鑰文件
/// <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);
}