在上文中瞭解到SHA和RSA,工做中剛好用到擴展應用:SHA256WithRSA,本文總結下學習過程,備忘の
再提供另一種方法,實現Java版pem密鑰和.Net版xml密鑰相互轉換的方法html
準備:引入BouncyCastle.Crypto.dlljava
public static string RSAKeyPemToXml(string pemKey, bool isPrivateKey) { string rsaKey = string.Empty; object pemObject = null; RSAParameters rsaPara = new RSAParameters(); using (var sReader = new StringReader(pemKey)) { var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(sReader); pemObject = pemReader.ReadObject();//(AsymmetricCipherKeyPair) } if (isPrivateKey)//RSA私鑰 { RsaPrivateCrtKeyParameters key = (RsaPrivateCrtKeyParameters)((AsymmetricCipherKeyPair)pemObject).Private; 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(), }; } else//RSA公鑰 { 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; }
public static string RSAKeyXmlToPem(string RSAKeyXml, bool isPrivateKey, bool replacefix) { string pemKey = string.Empty; var rsa = new RSACryptoServiceProvider(); rsa.FromXmlString(RSAKeyXml); 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 Org.BouncyCastle.OpenSsl.PemWriter(sw); pemWriter.WriteObject(key); pemWriter.Writer.Flush(); pemKey = sw.ToString(); } if (replacefix) { //去掉證書的頭部和尾部 pemKey = isPrivateKey ? pemKey.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "") : pemKey.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", ""); return pemKey.Replace("\n", "").Replace("\r", ""); } else { return pemKey; } }
注意,調用RSAKeyPemToXml()方法時,pemKey必須格式正確(帶先後綴且換行),不然調用報錯。ide
-----BEGIN RSA PRIVATE KEY----- ... -----END RSA PRIVATE KEY-----
此外,調用RSAKeyXmlToPem()方法作私鑰轉換時,結果與原Pem密鑰不一致,慎用。oop
綜上所述:pfx證書文件中比cer文件中多了私鑰。
經過pfx證書實現數據簽名和驗籤學習
public static string Sign(string dataForSign, string priKeyFile, string keyPwd) { var rsa = GetPrivateKey(priKeyFile, keyPwd); // Create a new RSACryptoServiceProvider var rsaClear = new RSACryptoServiceProvider(); // Export RSA parameters from 'rsa' and import them into 'rsaClear' var paras = rsa.ExportParameters(true); rsaClear.ImportParameters(paras); using (var sha256 = new SHA256CryptoServiceProvider()) { var signData = rsaClear.SignData(Encoding.UTF8.GetBytes(dataForSign), sha256); return BytesToHex(signData); } } public bool VerifySign(string dataForSign, string signedData, string pubKeyFile) { var rsa = GetPublicKey(pubKeyFile); using (var sha256 = new SHA256CryptoServiceProvider()) { return rsa.VerifyData(Encoding.UTF8.GetBytes(dataForSign), sha256, HexToBytes(signedData)); } }
其中,從.pfx證書中提取公鑰和私鑰的方法編碼
private static RSACryptoServiceProvider GetPrivateKey(string priKeyFile, string keyPwd) { var pc = new X509Certificate2(priKeyFile, keyPwd, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet); return (RSACryptoServiceProvider)pc.PrivateKey; //return cert.PrivateKey.ToXmlString(true); } private static RSACryptoServiceProvider GetPublicKey(string pubKeyFile) { var pc = new X509Certificate2(pubKeyFile); return (RSACryptoServiceProvider)pc.PublicKey.Key; //return cert.PublicKey.Key.ToXmlString(false); }
具體參見:.NET版SHA256WithRSA簽名驗籤,java版本參見:java版SHA256withRSA
關於如何生成數字證書,僅供參考:方法1,方法2
該文C#建立數字證書並導出爲pfx,並使用pfx進行非對稱加解密有時間能夠研究下。.net