.NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书
簡介
加解密現(xiàn)狀,編寫此系列文章的背景:
需要考慮系統(tǒng)環(huán)境兼容性問題(Linux、Windows)
語言互通問題(如C#、Java等)(加解密本質上沒有語言之分,所以原則上不存在互通性問題)
網上資料版本不一、或不全面
.NET官方庫密碼算法提供不全面,很難針對其他語言(Java)進行適配
本系列文章主要介紹如何在 .NET Core 中使用非對稱加密算法、編碼算法、消息摘要算法、簽名算法、對稱加密算法、國密算法等一系列算法,如有錯誤之處,還請大家批評指正。
本系列文章旨在引導大家能快速、輕松的了解接入加解密,乃至自主組合搭配使用BouncyCastle密碼術包中提供的算法。
本系列代碼項目地址:https://github.com/fuluteam/ICH.BouncyCastle.git
上一篇文章《.NET Core加解密實戰(zhàn)系列之——對稱加密算法》:https://www.cnblogs.com/fulu/p/13650079.html
功能依賴
BouncyCastle(https://www.bouncycastle.org/csharp) 是一個開放源碼的輕量級密碼術包;它支持大量的密碼術算法,它提供了很多 .NET Core標準庫沒有的算法。
支持 .NET 4,.NET Standard 1.0-2.0,WP,Silverlight,MonoAndroid,Xamarin.iOS,.NET Core
| 功能 | 依賴 |
| Portable.BouncyCastle | Portable.BouncyCastle ? 1.8.6 |
前言
在工作中我們難免會接觸對接外部系統(tǒng)(如銀行、支付寶、微信等),對接過程中又無可避免會對數據的加解密和加簽驗簽。一般第三方會提供一個授權證書,讓我們自行解密提取秘鑰。為了讓你拿到證書后不會像我當初一樣一臉懵逼,咱們來看看如何使用C#代碼制作使用p12證書。
當然,比較常見的,還是推薦大家使用OpenSSL。
OpenSSL是目前最流行的 SSL密碼庫工具,其提供了一個通用、健壯、功能完備的工具套件,用以支持SSL/TLS 協(xié)議的實現(xiàn)。
官網:https://www.openssl.org/source/
什么是p12證書
公鑰加密技術12號標準(Public Key Cryptography Standards #12,PKCS#12)為存儲和傳輸用戶或服務器私鑰、公鑰和證書指定了一個可移植的格式。它是一種二進制格式,這些文件也稱為PFX文件。
P12證書包含了私鑰、公鑰并且有口令保護,在證書泄露后還有最后一道保障。沒有證書口令無法提取秘鑰。
對PKCS標準感興趣的小伙伴可以參考百度百科PKCS介紹
什么是X.509格式
在密碼學中,X.509是定義公鑰證書格式的標準。X.509證書用于許多Internet協(xié)議,包括TLS/SSL,它是HTTPS(用于瀏覽web的安全協(xié)議)的基礎。它們也用于離線應用程序,比如電子簽名。一個X.509證書包含一個公鑰和一個標識(主機名、組織或個人),由證書頒發(fā)機構簽名或自簽名。當證書由受信任的證書頒發(fā)機構簽名時,或者通過其他方法進行驗證時,持有該證書的人可以依賴于它包含的公鑰來與另一方建立安全通信,或者驗證由相應私鑰數字簽名的文檔。
X.509還定義了證書撤銷列表,這是一種分發(fā)被簽名機構認為無效的證書信息的方法,以及認證路徑驗證算法,該算法允許證書由中間CA證書簽名,而中間CA證書又由其他證書簽名,最終到達信任錨。
X.509由國際電信聯(lián)盟標準化部門(ITU-T)定義,并基于ITU-T的另一個標準ASN.1。
SSL Certificate (編碼)格式
SSL Certificate實際上就是X.509 Certificate。X.509是一個定義了certificate結構的標準。它在SSL certificate中定義了一個數據域。X.509使用名為 Abstract Syntax Notation One (ASN.1)的通用語言來描述certificate的數據結構。
X.509 certificate 有幾種不同的格式,例如 PEM,DER,PKCS#7 和 PKCS#12。PEM和PKCS#7格式使用Base64 ASCII編碼,而DER和PKCS#12使用二進制編碼。certificate文件基于不同的編碼格式有不同的文件擴展名。
如下圖就展示了X.509證書的編碼方式和文件擴展名。
X.509 證書結構
X.509證書的結構是用ASN.1(Abstract Syntax Notation One:抽象語法標記)來描述其數據結構,并使用ASN1語法進行編碼。
X.509 v3數字證書的結構如下:
certificate 證書
Version Number版本號
Serial Number序列號
ID Signature Algorithm ID簽名算法
Issuer Name頒發(fā)者名稱
Validity period 有效期
Not before起始日期
Not after截至日期
Subject Name主題名稱
Subject pbulic Key Info 主題公鑰信息
Public Key Algorithm公鑰算法
Subject Public Key主題公鑰
Issuer Unique Identifier (optional)頒發(fā)者唯一標識符(可選)
Subject Unique Identifier (optional)主題唯一標識符(可選)
Extensions (optional) 證書的擴展項(可選)
Certificate Sigature Algorithm證書簽名算法
Certificate Signature證書的簽名
證書操作
證書生成
/// <summary>/// 生成證書/// </summary>/// <param name="notAfter">證書失效時間</param>/// <param name="keyStrength">密鑰長度</param>/// <param name="password">證書密碼</param>/// <param name="signatureAlgorithm">設置將用于簽署此證書的簽名算法</param>/// <param name="issuer">設置此證書頒發(fā)者的DN</param>/// <param name="subject">設置此證書使用者的DN</param>/// <param name="friendlyName">設置證書友好名稱(可選)</param>/// <param name="notBefore">證書生效時間</param>public static void GenerateCertificate(string filename, string password, string signatureAlgorithm, X509Name issuer, X509Name subject, DateTime notBefore, DateTime notAfter, string friendlyName, int keyStrength = 2048){SecureRandom random = new SecureRandom(new CryptoApiRandomGenerator());var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);var keyPairGenerator = new RsaKeyPairGenerator(); //RSA密鑰對生成器keyPairGenerator.Init(keyGenerationParameters);var subjectKeyPair = keyPairGenerator.GenerateKeyPair();ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, subjectKeyPair.Private, random);//the certificate generatorX509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();var spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public);//設置一些擴展字段//允許作為一個CA證書(可以頒發(fā)下級證書或進行簽名)certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));//使用者密鑰標識符certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(spki));//授權密鑰標識符certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(spki));certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, true, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth));//證書序列號BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);certificateGenerator.SetSerialNumber(serialNumber);certificateGenerator.SetIssuerDN(issuer); //頒發(fā)者信息certificateGenerator.SetSubjectDN(subject); //使用者信息certificateGenerator.SetNotBefore(notBefore); //證書生效時間certificateGenerator.SetNotAfter(notAfter); //證書失效時間certificateGenerator.SetPublicKey(subjectKeyPair.Public);Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);//生成cer證書,公鑰證書//var certificate2 = new X509Certificate2(DotNetUtilities.ToX509Certificate(certificate))//{// FriendlyName = friendlyName, //設置友好名稱//};cer公鑰文件//var bytes = certificate2.Export(X509ContentType.Cert);//using (var fs = new FileStream(certPath, FileMode.Create))//{// fs.Write(bytes, 0, bytes.Length);//}//另一種代碼生成p12證書的方式(要求使用.net standard 2.1)//certificate2 =// certificate2.CopyWithPrivateKey(DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)keyPair.Private));//var bytes2 = certificate2.Export(X509ContentType.Pfx, password);//using (var fs = new FileStream(pfxPath, FileMode.Create))//{// fs.Write(bytes2, 0, bytes2.Length);//}var certEntry = new X509CertificateEntry(certificate);var store = new Pkcs12StoreBuilder().Build();store.SetCertificateEntry(friendlyName, certEntry); //設置證書var chain = new X509CertificateEntry[1];chain[0] = certEntry;store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), chain); //設置私鑰using (var fs = File.Create(filename)){store.Save(fs, password.ToCharArray(), random); //保存};}private static void Certificate_Sample(){//頒發(fā)者DNvar issuer = new X509Name(new ArrayList{X509Name.C,X509Name.O,X509Name.OU,X509Name.L,X509Name.ST}, new Hashtable{[X509Name.C] = "CN",[X509Name.O] = "Fulu Newwork",[X509Name.OU] = "Fulu RSA CA 2020",[X509Name.L] = "Wuhan",[X509Name.ST] = "Hubei",});//使用者DNvar subject = new X509Name(new ArrayList{X509Name.C,X509Name.O,X509Name.CN}, new Hashtable{[X509Name.C] = "CN",[X509Name.O] = "ICH",[X509Name.CN] = "*.fulu.com"});var password = "123456"; //證書密碼var signatureAlgorithm = "SHA256WITHRSA"; //簽名算法//生成證書CertificateUtilities.GenerateCertificate("fuluca.pfx", password, signatureAlgorithm, issuer, subject, DateTime.UtcNow.AddDays(-1), DateTime.UtcNow.AddYears(2), "fulu passport");//加載證書X509Certificate2 pfx = new X509Certificate2("fuluca.pfx", password, X509KeyStorageFlags.Exportable);var keyPair = DotNetUtilities.GetKeyPair(pfx.PrivateKey);var subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);var privateKey = Base64.ToBase64String(privateKeyInfo.ParsePrivateKey().GetEncoded());var publicKey = Base64.ToBase64String(subjectPublicKeyInfo.GetEncoded());Console.ForegroundColor = ConsoleColor.DarkYellow;Console.WriteLine("Pfx證書私鑰:");Console.WriteLine(privateKey);Console.WriteLine("Pfx證書公鑰:");Console.WriteLine(publicKey);var data = "hello rsa";Console.WriteLine($"加密原文:{data}");var pkcs1data = RSA.EncryptToBase64(data, AsymmetricKeyUtilities.GetAsymmetricKeyParameterFormPublicKey(publicKey), Algorithms.RSA_ECB_PKCS1Padding);Console.WriteLine("加密結果:");Console.WriteLine(pkcs1data);Console.WriteLine("解密結果:");var datares = RSA.DecryptFromBase64(pkcs1data,AsymmetricKeyUtilities.GetAsymmetricKeyParameterFormPrivateKey(privateKey), Algorithms.RSA_ECB_PKCS1Padding);Console.WriteLine(datares);}生成的證書文件:
證書安裝
雙擊證書文件進行安裝,存儲位置選擇當前用戶。
證書存儲選擇個人
查看安裝的證書
可以在MMC的證書管理單元中對證書存儲區(qū)進行管理。Windows沒有給我們準備好直接的管理證書的入口。自己在MMC中添加,步驟如下:
開始→運行→MMC,打開一個空的MMC控制臺。
在控制臺菜單,文件→添加/刪除管理單元→添加按鈕→選”證書”→添加→選”我的用戶賬戶”→關閉→確定
展開 證書控制臺根節(jié)點→證書-當前用戶→個人→證書,找到證書,可以看到下圖中選中的即為我們創(chuàng)建的證書文件
雙擊證書,可以看到證書的相關信息
OpenSSL安裝
工具:openssl
安裝軟件:Win64 OpenSSL v1.1.1g Light
下載地址:http://slproweb.com/products/Win32OpenSSL.html
PFX文件提取公鑰私鑰
openssl pkcs12 -in fulusso.pfx -nocerts -nodes -out private.key輸入密碼openssl rsa -in private.key -out pfx_pri.pemopenssl rsa -in private.key -pubout -out pfx_pub.pem安裝好OpenSSL后,打開Win64 OpenSSL Command Prompt,讀取到證書文件所在目錄,按上述命令執(zhí)行
打開證書所在目錄,可以看到文件 private.key、pfx_pri.pem、pfx_pub.pem 已經生成好了。
用文本工具打開私鑰文件pfx_pri.pem,如下圖:
打開公約文件pfx_pub.pem,如下圖:
比對與上文控制臺打印出的公鑰、私鑰一致。
下期預告
下一篇將介紹國密算法,敬請期待。。。
?
總結
以上是生活随笔為你收集整理的.NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于REACT和.NET CORE集成W
- 下一篇: ASP.NET Core 3.x启动时运