.NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书
简介
加解密现状,编写此系列文章的背景:
- 需要考虑系统环境兼容性问题(Linux、Windows)
- 语言互通问题(如C#、Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题)
- 网上资料版本不一、或不全面
- .NET官方库密码算法提供不全面,很难针对其他语言(Java)进行适配
本系列文章主要介绍如何在 .NET Core 中使用非对称加密算法、编码算法、消息摘要算法、签名算法、对称加密算法、国密算法等一系列算法,如有错误之处,还请大家批评指正。
本系列文章旨在引导大家能快速、轻松的了解接入加解密,乃至自主组合搭配使用BouncyCastle密码术包中提供的算法。
本系列代码项目地址:https://github.com/fuluteam/ICH.BouncyCastle.git
上一篇文章《.NET Core加解密实战系列之——对称加密算法》: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 |
前言
在工作中我们难免会接触对接外部系统(如银行、支付宝、微信等),对接过程中又无可避免会对数据的加解密和加签验签。一般第三方会提供一个授权证书,让我们自行解密提取秘钥。为了让你拿到证书后不会像我当初一样一脸懵逼,咱们来看看如何使用C#代码制作使用p12证书。
当然,比较常见的,还是推荐大家使用OpenSSL。
OpenSSL是目前最流行的 SSL密码库工具,其提供了一个通用、健壮、功能完备的工具套件,用以支持SSL/TLS 协议的实现。
官网: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协议,包括TLS/SSL,它是HTTPS(用于浏览web的安全协议)的基础。它们也用于离线应用程序,比如电子签名。一个X.509证书包含一个公钥和一个标识(主机名、组织或个人),由证书颁发机构签名或自签名。当证书由受信任的证书颁发机构签名时,或者通过其他方法进行验证时,持有该证书的人可以依赖于它包含的公钥来与另一方建立安全通信,或者验证由相应私钥数字签名的文档。
X.509还定义了证书撤销列表,这是一种分发被签名机构认为无效的证书信息的方法,以及认证路径验证算法,该算法允许证书由中间CA证书签名,而中间CA证书又由其他证书签名,最终到达信任锚。
X.509由国际电信联盟标准化部门(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颁发者名称
- Validity period 有效期
- Not before起始日期
- Not after截至日期
- Subject Name主题名称
- Subject pbulic Key Info 主题公钥信息
- Public Key Algorithm公钥算法
- Subject Public Key主题公钥
- Issuer Unique Identifier (optional)颁发者唯一标识符(可选)
- 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">设置此证书颁发者的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 generator
X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
var spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public);
//设置一些扩展字段
//允许作为一个CA证书(可以颁发下级证书或进行签名)
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); //颁发者信息
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()
{
//颁发者DN
var 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",
});
//使用者DN
var 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的证书管理单元中对证书存储区进行管理。Windows没有给我们准备好直接的管理证书的入口。自己在MMC中添加,步骤如下:
- 开始→运行→MMC,打开一个空的MMC控制台。
- 在控制台菜单,文件→添加/删除管理单元→添加按钮→选”证书”→添加→选”我的用户账户”→关闭→确定
展开 证书控制台根节点→证书-当前用户→个人→证书,找到证书,可以看到下图中选中的即为我们创建的证书文件
双击证书,可以看到证书的相关信息
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.pem
openssl rsa -in private.key -pubout -out pfx_pub.pem
安装好OpenSSL后,打开Win64 OpenSSL Command Prompt,读取到证书文件所在目录,按上述命令执行
打开证书所在目录,可以看到文件 private.key、pfx_pri.pem、pfx_pub.pem 已经生成好了。
用文本工具打开私钥文件pfx_pri.pem,如下图:
打开公约文件pfx_pub.pem,如下图:
比对与上文控制台打印出的公钥、私钥一致。
下期预告
下一篇将介绍国密算法,敬请期待。。。
福禄娃
.NET Core加解密实战系列之——使用BouncyCastle制作p12(.pfx)数字证书的更多相关文章
- .NET Core加解密实战系列之——消息摘要与数字签名算法
目录 简介 功能依赖 消息摘要算法 MD算法 家族发展史 应用场景 代码实现 MD5 示例代码 SHA算法 应用场景 代码实现 SHA1 SHA256 示例代码 MAC算法 HMAC算法的典型应用 H ...
- .NET Core加解密实战系列之——对称加密算法
简介 加解密现状,编写此系列文章的背景: 需要考虑系统环境兼容性问题(Linux.Windows) 语言互通问题(如C#.Java等)(加解密本质上没有语言之分,所以原则上不存在互通性问题) 网上资料 ...
- .NET Core加解密实战系列之——RSA非对称加密算法
目录 简介 功能依赖 生成RSA秘钥 PKCS1格式 PKCS8格式 私钥操作 PKCS1与PKCS8格式互转 PKCS1与PKCS8私钥中提取公钥 PEM操作 PEM格式密钥读取 PEM格式密钥写入 ...
- Java 加解密技术系列文章
Java 加解密技术系列之 总结 Java 加解密技术系列之 DH Java 加解密技术系列之 RSA Java 加解密技术系列之 PBE Java 加解密技术系列之 AES Java 加解密技术系列 ...
- 11.Java 加解密技术系列之 总结
Java 加解密技术系列之 总结 序 背景 分类 常用算法 原理 关于代码 结束语 序 上一篇文章中简单的介绍了第二种非对称加密算法 — — DH,这种算法也经常被叫做密钥交换协议,它主要是针对密钥的 ...
- 10.Java 加解密技术系列之 DH
Java 加解密技术系列之 DH 序 概念 原理 代码实现 结果 结束语 序 上一篇文章中简单的介绍了一种非对称加密算法 — — RSA,今天这篇文章,继续介绍另一种非对称加密算法 — — DH.当然 ...
- 9.Java 加解密技术系列之 RSA
Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项 ...
- 8.Java 加解密技术系列之 PBE
Java 加解密技术系列之 PBE 序 概念 原理 代码实现 结束语 序 前 边的几篇文章,已经讲了几个对称加密的算法了,今天这篇文章再介绍最后一种对称加密算法 — — PBE,这种加密算法,对我的认 ...
- 7.java 加解密技术系列之 AES
java 加解密技术系列之 AES 序 概念 原理 应用 代码实现 结束语 序 这篇文章继续介绍对称加密算法,至于今天的主角,不用说,也是个厉害的角色 — — AES.AES 的出现,就是为了来替代原 ...
随机推荐
- linux下的scp传输文件
转载于:http://moyu2010.blog.163.com/blog/static/177439041201112710243064/,再次谢谢作者. 1.功能说明scp就是security c ...
- FastStone Capture注册破解码
原文链接:https://blog.csdn.net/lxq_9532/article/details/82893170 faststone-capture下载链接: https://en.softo ...
- Linux权限之/etc/passwd文件
在Linux /etc/passwd文件中每个用户都有一个对应的记录行,它记录了这个用户的一些基本属性.系统管理员经常会接触到这个文件的修改以完成对用户的管理工作.这个文件对所有用户都是可读的.但是L ...
- 表单和 v-model
思维导图 form 做表单一定要用 form+button组合 <template> <div id="app"> 登录 <form @submit. ...
- muduo源码解析5-mutex相关类
mutexlock和mutexlockguard class mutexlock:noncopyable { }: class mutexlockguard:noncopyable { }: 作用: ...
- (数据科学学习手札94)QGIS+Conda+jupyter玩转Python GIS
本文完整代码及数据已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 QGIS随着近些年的发展,得益于其开源免费 ...
- CSS 段落/换行/缩进
CSS 段落/换行/缩进 1.盒模型 box-sizing: content-box|border-box|inherit; content-box(默认) : 实际宽度/高度 = width/hei ...
- vs _ 用户代码片段 _ html模板
自定义模板:首选项 -> 用户代码片段 - >(如果没有自己创个)html.json t : 表示缩进 n:表示换行 ----------------------------------- ...
- docker 创建mysql和redis
1 镜像加速 创建docker 目录 sudo mkdir -p /etc/docker 镜像加速: sudo tee /etc/docker/daemon.json <<-'E ...
- 用 Java 拿下 HTML 分分钟写个小爬虫
本文适合有 Java 基础知识的人群 本文作者:HelloGitHub-秦人 HelloGitHub 推出的<讲解开源项目>系列,今天给大家带来一款开源 Java 版一款网页元素解析框架- ...