C#使用BouncyCastle生成PKCS#12数字证书

背景

  • 生成数字证书用于PDF文档数字签名
  • 数字证书需要考虑环境兼容性,如linux、windows
  • 网上资料不全或版本多样

本文章主要介绍了在C#中使用BouncyCastle生成PKCS#12个人信息交换语法标准的pfx证书、cer证书,旨在引导大家了解非对称加密算法,快速、轻松的使用证书对文本进行加密、解密,额外提供了RSAHelper类,包含加密、解密、签名、验签函数,支持无限长度、分段加解密,如有错误、欢迎留言指正;

pfx证书:含有公钥、私钥

cer证书:只含有公钥

非对称加密算法:常见的有很多,这其中最有名、最常用的还是RSA

RSA文件格式有很多中,PKCS#12只是其中一种,除此之外还有PKCS#1、PKCS#7、PKCS#8等,具体有什么区别,我这里不再进行阐述,自行百度;

不同语言采用的RSA文件格式不同,如java的私钥采用的是PKCS8,c#的私钥采用的是PKCS1,c#和java生成的私钥要让对方使用的就需要进行转换为对方语言适用的文件格式;

依赖

本文示例代码依赖于BouncyCastle.Crypto.dll,可以在项目中使用NuGet程序包引入。

源码

RSAHelper类

  1 public class RSAHelper
  2     {
  3         #region 使用私钥签名Sign(string data, string privateKey, RSAType rsaType, Encoding encoding)
  4         /// <summary>
  5         /// 使用私钥签名
  6         /// </summary>
  7         /// <param name="data">待签名串</param>
  8         /// <param name="privateKey">私钥</param>
  9         /// <param name="encoding">编码类型,推荐使用UTF8</param>
 10         /// <param name="rsaType">签名类型,默认RSA2</param>
 11         /// <returns></returns>
 12         public static string Sign(string data, string privateKey, Encoding encoding, RSAType rsaType = RSAType.RSA2)
 13         {
 14             encoding = encoding ?? Encoding.UTF8;
 15             byte[] dataBytes = encoding.GetBytes(data);
 16             RSA _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);
 17             HashAlgorithmName _hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256;
 18             var signatureBytes = _privateKeyRsaProvider.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
 19             return Convert.ToBase64String(signatureBytes);
 20         }
 21         /// <summary>
 22         /// 使用私钥签名,默认Encoding为Encoding.UTF8
 23         /// </summary>
 24         /// <param name="data">待签名串</param>
 25         /// <param name="privateKey">私钥</param>
 26         /// <param name="rsaType">签名类型,默认RSA2</param>
 27         /// <returns></returns>
 28         public static string Sign(string data, string privateKey, RSAType rsaType = RSAType.RSA2)
 29         {
 30             return Sign(data, privateKey, Encoding.UTF8, rsaType);
 31         }
 32         /// <summary>
 33         /// 使用私钥签名
 34         /// </summary>
 35         /// <param name="parameters">待签参数</param>
 36         /// <param name="privateKey">私钥</param>
 37         /// <param name="encoding">编码类型,推荐使用UTF8</param>
 38         /// <param name="rsaType">签名类型,默认RSA2</param>
 39         /// <param name="removeSign">是否移除签名串,默认移除名为“sign”的签名串</param>
 40         /// <returns></returns>
 41         public static string SignParameters(IDictionary<string, string> parameters, string privateKey, Encoding encoding, RSAType rsaType = RSAType.RSA2, bool removeSign = true)
 42         {
 43 
 44             string data = GetSignContent(parameters, removeSign);
 45             byte[] dataBytes = encoding.GetBytes(data);
 46             RSA _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);
 47             HashAlgorithmName _hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256;
 48             var signatureBytes = _privateKeyRsaProvider.SignData(dataBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
 49             return Convert.ToBase64String(signatureBytes);
 50         }
 51         /// <summary>
 52         /// 使用私钥签名,默认Encoding为Encoding.UTF8
 53         /// </summary>
 54         /// <param name="parameters">待签参数</param>
 55         /// <param name="privateKey">私钥</param>
 56         /// <param name="rsaType">签名类型,默认RSA2</param>
 57         /// <param name="removeSign">是否移除签名串,默认移除名为“sign”的签名串</param>
 58         /// <returns></returns>
 59         public static string SignParameters(IDictionary<string, string> parameters, string privateKey, RSAType rsaType = RSAType.RSA2, bool removeSign = true)
 60         {
 61             return SignParameters(parameters, privateKey, Encoding.UTF8, rsaType, removeSign);
 62         }
 63         #endregion
 64 
 65         #region 使用公钥验证签名Verify(string data, string sign,string publickey,RSAType rsaType,Encoding encoding)
 66         /// <summary>
 67         /// 使用公钥验证签名
 68         /// </summary>
 69         /// <param name="data">原始数据</param>
 70         /// <param name="sign">签名串</param>
 71         /// <param name="publickey">公钥</param>
 72         /// <param name="encoding">编码类型,推荐使用UTF8</param>
 73         /// <param name="rsaType">签名类型,推默认RSA2</param>
 74         /// <returns></returns>
 75         public static bool Verify(string data, string sign, string publickey, Encoding encoding, RSAType rsaType = RSAType.RSA2)
 76         {
 77             byte[] dataBytes = encoding.GetBytes(data);
 78             byte[] signBytes = Convert.FromBase64String(sign);
 79             RSA _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publickey);
 80             HashAlgorithmName _hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256;
 81             var verify = _publicKeyRsaProvider.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
 82             return verify;
 83         }
 84         /// <summary>
 85         /// 使用公钥验证签名 默认Encoding为Encoding.UTF8
 86         /// </summary>
 87         /// <param name="data">原始数据</param>
 88         /// <param name="sign">签名串</param>
 89         /// <param name="publickey">公钥</param>
 90         /// <param name="rsaType">签名类型,推默认RSA2</param>
 91         /// <returns></returns>
 92         public static bool Verify(string data, string sign, string publickey, RSAType rsaType = RSAType.RSA2)
 93         {
 94             return Verify(data, sign, publickey, Encoding.UTF8, rsaType);
 95         }
 96         /// <summary>
 97         /// 使用公钥验证签名
 98         /// </summary>
 99         /// <param name="parameters">代验签参数</param>
100         /// <param name="publickey">公钥</param>
101         /// <param name="encoding">编码类型,推荐使用UTF8</param>
102         /// <param name="rsaType">签名类型,推荐使用RSA2</param>
103         /// <param name="removeSign">是否移除签名串,默认移除名为“sign”的签名串</param>
104         /// <returns></returns>
105         public static bool VerifyParameters(IDictionary<string, string> parameters, string publickey, Encoding encoding, RSAType rsaType = RSAType.RSA2, bool removeSign = true)
106         {
107             string sign = parameters["sign"];
108             parameters.Remove("sign");
109 
110             byte[] dataBytes = encoding.GetBytes(GetSignContent(parameters, removeSign));
111             byte[] signBytes = Convert.FromBase64String(sign);
112             RSA _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publickey);
113             HashAlgorithmName _hashAlgorithmName = rsaType == RSAType.RSA ? HashAlgorithmName.SHA1 : HashAlgorithmName.SHA256;
114             var verify = _publicKeyRsaProvider.VerifyData(dataBytes, signBytes, _hashAlgorithmName, RSASignaturePadding.Pkcs1);
115             return verify;
116         }
117         /// <summary>
118         /// 使用公钥验证签名 默认Encoding为Encoding.UTF8
119         /// </summary>
120         /// <param name="parameters">代验签参数</param>
121         /// <param name="publickey">公钥</param>
122         /// <param name="rsaType">签名类型,推荐使用RSA2</param>
123         /// <param name="removeSign">是否移除签名串,默认移除名为“sign”的签名串</param>
124         /// <returns></returns>
125         public static bool VerifyParameters(IDictionary<string, string> parameters, string publickey, RSAType rsaType = RSAType.RSA2, bool removeSign = true)
126         {
127             return VerifyParameters(parameters, publickey, Encoding.UTF8, rsaType, removeSign);
128         }
129         #endregion
130 
131         #region 获取/组装待签名串GetSignContent(IDictionary<string, string> parameters, bool removeSign = true)
132         /// <summary>
133         /// 获取/组装待签名串
134         /// </summary>
135         /// <param name="parameters">参数内容</param>
136         /// <param name="removeSign">是否移除签名串,默认移除名为“sign”的签名串</param>
137         /// <returns></returns>
138         public static string GetSignContent(IDictionary<string, string> parameters, bool removeSign = true)
139         {
140             if (removeSign && parameters.ContainsKey("sign"))
141             {
142                 parameters.Remove("sign");
143             }
144             // 第一步:把字典按Key的字母顺序排序
145             IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters);
146             IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator();
147 
148             // 第二步:把所有参数名和参数值串在一起
149             StringBuilder query = new StringBuilder("");
150             while (dem.MoveNext())
151             {
152                 string key = dem.Current.Key;
153                 string value = dem.Current.Value;
154                 if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) // 空字段不加入签名/验签
155                 {
156                     query.Append(key).Append("=").Append(value).Append("&");
157                 }
158             }
159             string content = query.ToString().Substring(0, query.Length - 1);
160 
161             return content;
162         }
163         #endregion
164 
165         #region 解密Decrypt(string cipherText,string privateKey)
166         /// <summary>
167         /// 解密(无限长度)
168         /// </summary>
169         /// <param name="cipherText">加密串</param>
170         /// <param name="privateKey">私钥</param>
171         /// <returns></returns>
172         public static string Decrypt(string cipherText, string privateKey)
173         {
174             RSA _privateKeyRsaProvider = CreateRsaProviderFromPrivateKey(privateKey);
175             if (_privateKeyRsaProvider == null)
176             {
177                 throw new Exception("_privateKeyRsaProvider is null");
178             }
179             var inputBytes = Convert.FromBase64String(cipherText);
180             int bufferSize = _privateKeyRsaProvider.KeySize / 8;
181             var buffer = new byte[bufferSize];
182             using (MemoryStream inputStream = new MemoryStream(inputBytes),
183                  outputStream = new MemoryStream())
184             {
185                 while (true)
186                 {
187                     int readSize = inputStream.Read(buffer, 0, bufferSize);
188                     if (readSize <= 0)
189                     {
190                         break;
191                     }
192 
193                     var temp = new byte[readSize];
194                     Array.Copy(buffer, 0, temp, 0, readSize);
195                     var rawBytes = _privateKeyRsaProvider.Decrypt(temp, RSAEncryptionPadding.Pkcs1);
196                     outputStream.Write(rawBytes, 0, rawBytes.Length);
197                 }
198                 return Encoding.UTF8.GetString(outputStream.ToArray());
199             }
200 
201             //return Encoding.UTF8.GetString(_privateKeyRsaProvider.Decrypt(Convert.FromBase64String(cipherText), RSAEncryptionPadding.Pkcs1));
202         }
203         /// <summary>
204         /// 分段解密
205         /// </summary>
206         /// <param name="encryptedInput"></param>
207         /// <param name="privateKey"></param>
208         /// <returns></returns>
209         private string RsaDecrypt(string encryptedInput, string privateKey)
210         {
211             if (string.IsNullOrEmpty(encryptedInput))
212             {
213                 return string.Empty;
214             }
215 
216             if (string.IsNullOrWhiteSpace(privateKey))
217             {
218                 throw new ArgumentException("Invalid Private Key");
219             }
220 
221             using (var rsaProvider = new RSACryptoServiceProvider())
222             {
223                 var inputBytes = Convert.FromBase64String(encryptedInput);
224                 rsaProvider.FromXmlString(privateKey);
225                 int bufferSize = rsaProvider.KeySize / 8;
226                 var buffer = new byte[bufferSize];
227                 using (MemoryStream inputStream = new MemoryStream(inputBytes),
228                      outputStream = new MemoryStream())
229                 {
230                     while (true)
231                     {
232                         int readSize = inputStream.Read(buffer, 0, bufferSize);
233                         if (readSize <= 0)
234                         {
235                             break;
236                         }
237 
238                         var temp = new byte[readSize];
239                         Array.Copy(buffer, 0, temp, 0, readSize);
240                         var rawBytes = rsaProvider.Decrypt(temp, false);
241                         outputStream.Write(rawBytes, 0, rawBytes.Length);
242                     }
243                     return Encoding.UTF8.GetString(outputStream.ToArray());
244                 }
245             }
246         }
247         #endregion
248 
249         #region 加密 Encrypt(string text,string publickey)
250         /// <summary>
251         /// 加密(无限长度)
252         /// </summary>
253         /// <param name="text">待加密串</param>
254         /// <param name="publickey">公钥</param>
255         /// <returns></returns>
256         public static string Encrypt(string text, string publickey)
257         {
258             RSA _publicKeyRsaProvider = CreateRsaProviderFromPublicKey(publickey);
259             if (_publicKeyRsaProvider == null)
260             {
261                 throw new Exception("_publicKeyRsaProvider is null");
262             }
263             var inputBytes = Encoding.UTF8.GetBytes(text);
264             int bufferSize = (_publicKeyRsaProvider.KeySize / 8) - 11;//单块最大长度
265             var buffer = new byte[bufferSize];
266             using (MemoryStream inputStream = new MemoryStream(inputBytes),
267                  outputStream = new MemoryStream())
268             {
269                 while (true)
270                 { //分段加密
271                     int readSize = inputStream.Read(buffer, 0, bufferSize);
272                     if (readSize <= 0)
273                     {
274                         break;
275                     }
276 
277                     var temp = new byte[readSize];
278                     Array.Copy(buffer, 0, temp, 0, readSize);
279                     var encryptedBytes = _publicKeyRsaProvider.Encrypt(temp, RSAEncryptionPadding.Pkcs1);
280                     outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
281                 }
282                 return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
283             }
284         }
285         /// <summary>
286         /// 分段加密
287         /// </summary>
288         /// <param name="rawInput"></param>
289         /// <param name="publicKey"></param>
290         /// <returns></returns>
291         private string RsaEncrypt(string rawInput, string publicKey)
292         {
293             if (string.IsNullOrEmpty(rawInput))
294             {
295                 return string.Empty;
296             }
297 
298             if (string.IsNullOrWhiteSpace(publicKey))
299             {
300                 throw new ArgumentException("Invalid Public Key");
301             }
302 
303             using (var rsaProvider = new RSACryptoServiceProvider())
304             {
305                 var inputBytes = Encoding.UTF8.GetBytes(rawInput);//有含义的字符串转化为字节流
306                 rsaProvider.FromXmlString(publicKey);//载入公钥
307                 int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
308                 var buffer = new byte[bufferSize];
309                 using (MemoryStream inputStream = new MemoryStream(inputBytes),
310                      outputStream = new MemoryStream())
311                 {
312                     while (true)
313                     { //分段加密
314                         int readSize = inputStream.Read(buffer, 0, bufferSize);
315                         if (readSize <= 0)
316                         {
317                             break;
318                         }
319 
320                         var temp = new byte[readSize];
321                         Array.Copy(buffer, 0, temp, 0, readSize);
322                         var encryptedBytes = rsaProvider.Encrypt(temp, false);
323                         outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
324                     }
325                     return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
326                 }
327             }
328         }
329         #endregion
330 
331         #region 私有方法
332         /// <summary>
333         /// 使用私钥创建RSA实例
334         /// </summary>
335         /// <param name="privateKey">私钥</param>
336         /// <returns></returns>
337         private static RSA CreateRsaProviderFromPrivateKey(string privateKey)
338         {
339             var privateKeyBits = Convert.FromBase64String(privateKey);
340 
341             var rsa = RSA.Create();
342             var rsaParameters = new RSAParameters();
343 
344             using (BinaryReader binr = new BinaryReader(new MemoryStream(privateKeyBits)))
345             {
346                 byte bt = 0;
347                 ushort twobytes = 0;
348                 twobytes = binr.ReadUInt16();
349                 if (twobytes == 0x8130)
350                     binr.ReadByte();
351                 else if (twobytes == 0x8230)
352                     binr.ReadInt16();
353                 else
354                     throw new Exception("Unexpected value read binr.ReadUInt16()");
355 
356                 twobytes = binr.ReadUInt16();
357                 if (twobytes != 0x0102)
358                     throw new Exception("Unexpected version");
359 
360                 bt = binr.ReadByte();
361                 if (bt != 0x00)
362                     throw new Exception("Unexpected value read binr.ReadByte()");
363 
364                 rsaParameters.Modulus = binr.ReadBytes(GetIntegerSize(binr));
365                 rsaParameters.Exponent = binr.ReadBytes(GetIntegerSize(binr));
366                 rsaParameters.D = binr.ReadBytes(GetIntegerSize(binr));
367                 rsaParameters.P = binr.ReadBytes(GetIntegerSize(binr));
368                 rsaParameters.Q = binr.ReadBytes(GetIntegerSize(binr));
369                 rsaParameters.DP = binr.ReadBytes(GetIntegerSize(binr));
370                 rsaParameters.DQ = binr.ReadBytes(GetIntegerSize(binr));
371                 rsaParameters.InverseQ = binr.ReadBytes(GetIntegerSize(binr));
372             }
373 
374             rsa.ImportParameters(rsaParameters);
375             return rsa;
376         }
377 
378         /// <summary>
379         /// 使用公钥创建RSA实例
380         /// </summary>
381         /// <param name="publicKeyString">公钥</param>
382         /// <returns></returns>
383         private static RSA CreateRsaProviderFromPublicKey(string publicKeyString)
384         {
385             // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
386             byte[] seqOid = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 };
387             byte[] seq = new byte[15];
388 
389             var x509Key = Convert.FromBase64String(publicKeyString);
390 
391             // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
392             using (MemoryStream mem = new MemoryStream(x509Key))
393             {
394                 using (BinaryReader binr = new BinaryReader(mem))  //wrap Memory Stream with BinaryReader for easy reading
395                 {
396                     byte bt = 0;
397                     ushort twobytes = 0;
398 
399                     twobytes = binr.ReadUInt16();
400                     if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
401                         binr.ReadByte();    //advance 1 byte
402                     else if (twobytes == 0x8230)
403                         binr.ReadInt16();   //advance 2 bytes
404                     else
405                         return null;
406 
407                     seq = binr.ReadBytes(15);       //read the Sequence OID
408                     if (!CompareBytearrays(seq, seqOid))    //make sure Sequence for OID is correct
409                         return null;
410 
411                     twobytes = binr.ReadUInt16();
412                     if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81)
413                         binr.ReadByte();    //advance 1 byte
414                     else if (twobytes == 0x8203)
415                         binr.ReadInt16();   //advance 2 bytes
416                     else
417                         return null;
418 
419                     bt = binr.ReadByte();
420                     if (bt != 0x00)     //expect null byte next
421                         return null;
422 
423                     twobytes = binr.ReadUInt16();
424                     if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
425                         binr.ReadByte();    //advance 1 byte
426                     else if (twobytes == 0x8230)
427                         binr.ReadInt16();   //advance 2 bytes
428                     else
429                         return null;
430 
431                     twobytes = binr.ReadUInt16();
432                     byte lowbyte = 0x00;
433                     byte highbyte = 0x00;
434 
435                     if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81)
436                         lowbyte = binr.ReadByte();  // read next bytes which is bytes in modulus
437                     else if (twobytes == 0x8202)
438                     {
439                         highbyte = binr.ReadByte(); //advance 2 bytes
440                         lowbyte = binr.ReadByte();
441                     }
442                     else
443                         return null;
444                     byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };   //reverse byte order since asn.1 key uses big endian order
445                     int modsize = BitConverter.ToInt32(modint, 0);
446 
447                     int firstbyte = binr.PeekChar();
448                     if (firstbyte == 0x00)
449                     {   //if first byte (highest order) of modulus is zero, don't include it
450                         binr.ReadByte();    //skip this null byte
451                         modsize -= 1;   //reduce modulus buffer size by 1
452                     }
453 
454                     byte[] modulus = binr.ReadBytes(modsize);   //read the modulus bytes
455 
456                     if (binr.ReadByte() != 0x02)            //expect an Integer for the exponent data
457                         return null;
458                     int expbytes = (int)binr.ReadByte();        // should only need one byte for actual exponent data (for all useful values)
459                     byte[] exponent = binr.ReadBytes(expbytes);
460 
461                     // ------- create RSACryptoServiceProvider instance and initialize with public key -----
462                     var rsa = RSA.Create();
463                     RSAParameters rsaKeyInfo = new RSAParameters
464                     {
465                         Modulus = modulus,
466                         Exponent = exponent
467                     };
468                     rsa.ImportParameters(rsaKeyInfo);
469 
470                     return rsa;
471                 }
472 
473             }
474         }
475 
476         /// <summary>
477         /// 导入密钥算法
478         /// </summary>
479         /// <param name="binr">BinaryReader</param>
480         /// <returns></returns>
481         private static int GetIntegerSize(BinaryReader binr)
482         {
483             byte bt = 0;
484             int count = 0;
485             bt = binr.ReadByte();
486             if (bt != 0x02)
487                 return 0;
488             bt = binr.ReadByte();
489 
490             if (bt == 0x81)
491                 count = binr.ReadByte();
492             else
493             if (bt == 0x82)
494             {
495                 var highbyte = binr.ReadByte();
496                 var lowbyte = binr.ReadByte();
497                 byte[] modint = { lowbyte, highbyte, 0x00, 0x00 };
498                 count = BitConverter.ToInt32(modint, 0);
499             }
500             else
501             {
502                 count = bt;
503             }
504 
505             while (binr.ReadByte() == 0x00)
506             {
507                 count -= 1;
508             }
509             binr.BaseStream.Seek(-1, SeekOrigin.Current);
510             return count;
511         }
512 
513         private static bool CompareBytearrays(byte[] a, byte[] b)
514         {
515             if (a.Length != b.Length)
516                 return false;
517             int i = 0;
518             foreach (byte c in a)
519             {
520                 if (c != b[i])
521                     return false;
522                 i++;
523             }
524             return true;
525         }
526 
527         #endregion
528     }
529 
530     public enum RSAType
531     {
532         /// <summary>
533         /// SHA1
534         /// </summary>
535         RSA = 0,
536         /// <summary>
537         /// RSA2 密钥长度至少为2048
538         /// SHA256
539         /// </summary>
540         RSA2
541     }

 

生成证书源码:

  1 static void Main(string[] args)
  2         {
  3             /*
  4                 前言:最近有个需求是需要对文档进行签名,考虑到数字签名证书问题,所以生成一个自签名的数字证书;
  5                 描述:本示例基于BouncyCastle.Crypto组件提供的算法生成证书,
  6                         演示了生成了cer证书、pfx证书及加载pfx证书对字符串加密解密
  7                 
  8             */
  9 
 10             var takeEffect = DateTime.Now;  // 生效时间
 11             var loseEffect = DateTime.Now.AddYears(2);  // 失效时间
 12             var password = "ABCD123456";    //证书密码
 13             var signatureAlgorithm = "SHA256WITHRSA";  //签名算法
 14             var friendlyName = $"{Guid.NewGuid().ToString("N")}dpps.fun"; // 别名
 15 
 16             // 获取颁发者DN
 17             X509Name issuer = GetIssuer();
 18 
 19             // 获取使用者DN
 20             X509Name subject = GetSubject();
 21 
 22             // 证书存放目录
 23             string file = System.Environment.CurrentDirectory + "\\Cert\\";
 24             if (!Directory.Exists(file))
 25             {
 26                 Directory.CreateDirectory(file);
 27             }
 28             string pfxPath = $"{file}{friendlyName}.pfx";
 29             string certPath = $"{file}{friendlyName}.cer";
 30 
 31             // 生成证书
 32             GenerateCertificate(certPath, pfxPath, password, signatureAlgorithm, issuer, subject, takeEffect, loseEffect, friendlyName);
 33 
 34             // 加载PFX证书
 35             LoadingPfxCertificate(pfxPath, password);
 36 
 37             Console.WriteLine("OK");
 38             Console.ReadLine();
 39         }
 40 
 41         /// <summary>
 42         /// 获取使用者DN.
 43         /// </summary>
 44         /// <returns>使用者DN.</returns>
 45         private static X509Name GetSubject()
 46         {
 47             // 使用者DN
 48             return new X509Name(
 49                 new ArrayList
 50                 {
 51                     X509Name.C,
 52                     X509Name.O,
 53                     X509Name.CN
 54                 },
 55                 new Hashtable
 56                 {
 57                     [X509Name.C] = "CN",
 58                     [X509Name.O] = "ICH",
 59                     [X509Name.CN] = "*.dpps.fun"
 60                 }
 61             );
 62         }
 63 
 64         /// <summary>
 65         /// 获取颁发者DN.
 66         /// </summary>
 67         /// <returns>颁发者DN.</returns>
 68         private static X509Name GetIssuer()
 69         {
 70             // 颁发者DN
 71             return new X509Name(
 72                 new ArrayList
 73                 {
 74                     X509Name.C,
 75                     X509Name.O,
 76                     X509Name.OU,
 77                     X509Name.L,
 78                     X509Name.ST,
 79                     X509Name.E,
 80                 },
 81                 new Hashtable
 82                 {
 83                     [X509Name.C] = "CN",// 证书的语言
 84                     [X509Name.O] = "dpps.fun",//设置证书的办法者
 85                     [X509Name.OU] = "dpps.fun Fulu RSA CA 2020",
 86                     [X509Name.L] = "dpps",
 87                     [X509Name.ST] = "dpps",
 88                     [X509Name.E] = "472067093@qq.com",
 89                 }
 90             );
 91         }
 92 
 93 
 94         /// <summary>
 95         /// 生成证书
 96         /// </summary>
 97         /// <param name="certPath">certPath(只含公钥)</param>
 98         /// <param name="pfxPath">pfxPath(含公私钥)</param>
 99         /// <param name="password">证书密码</param>
100         /// <param name="signatureAlgorithm">设置将用于签署此证书的签名算法</param>
101         /// <param name="issuer">设置此证书颁发者的DN</param>
102         /// <param name="subject">设置此证书使用者的DN</param>
103         /// <param name="takeEffect">证书生效时间</param>
104         /// <param name="loseEffect">证书失效时间</param>
105         /// <param name="friendlyName">设置证书友好名称(可选)</param>
106         /// <param name="keyStrength">密钥长度</param>
107         public static void GenerateCertificate(
108             string certPath,
109             string pfxPath,
110             string password,
111             string signatureAlgorithm,
112             X509Name issuer,
113             X509Name subject,
114             DateTime takeEffect,
115             DateTime loseEffect,
116             string friendlyName,
117             int keyStrength = 2048)
118         {
119             SecureRandom random = new SecureRandom(new CryptoApiRandomGenerator());
120             var keyGenerationParameters = new KeyGenerationParameters(random, keyStrength);
121             var keyPairGenerator = new RsaKeyPairGenerator(); //RSA密钥对生成器
122             keyPairGenerator.Init(keyGenerationParameters);
123             var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
124             ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, subjectKeyPair.Private, random);
125             //the certificate generator
126 
127             X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator();
128 
129             var spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public);
130 
131             //允许作为一个CA证书(可以颁发下级证书或进行签名)
132             certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true));
133 
134             //使用者密钥标识符
135             certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(spki));
136 
137             //授权密钥标识符
138             certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(spki));
139 
140             certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage.Id, true, new ExtendedKeyUsage(KeyPurposeID.IdKPServerAuth));
141 
142             //证书序列号
143             BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
144 
145             certificateGenerator.SetSerialNumber(serialNumber);
146 
147             certificateGenerator.SetIssuerDN(issuer);   //颁发者信息
148 
149             certificateGenerator.SetSubjectDN(subject); //使用者信息
150 
151             certificateGenerator.SetNotBefore(takeEffect); //证书生效时间
152 
153             certificateGenerator.SetNotAfter(loseEffect); //证书失效时间
154 
155             certificateGenerator.SetPublicKey(subjectKeyPair.Public);
156 
157             Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(signatureFactory);
158 
159             //生成cer证书,公钥证
160             var certificate2 = new X509Certificate2(DotNetUtilities.ToX509Certificate(certificate))
161             {
162                 FriendlyName = friendlyName, //设置友好名称
163             };
164             // cer公钥文件
165             var bytes = certificate2.Export(X509ContentType.Cert);
166             using (var fs = new FileStream(certPath, FileMode.Create))
167             {
168                 fs.Write(bytes, 0, bytes.Length);
169             }
170 
171             //另一种代码生成p12证书的方式(要求使用.net standard 2.1)
172             //certificate2 = certificate2.CopyWithPrivateKey(DotNetUtilities.ToRSA((RsaPrivateCrtKeyParameters)keyPair.Private));
173             //var bytes2 = certificate2.Export(X509ContentType.Pfx, password);
174             //using (var fs = new FileStream(pfxPath, FileMode.Create))
175             //{
176             //    fs.Write(bytes2, 0, bytes2.Length);
177             //}
178 
179             // 生成pfx证书,公私钥证
180             var certEntry = new X509CertificateEntry(certificate);
181             var store = new Pkcs12StoreBuilder().Build();
182             store.SetCertificateEntry(friendlyName, certEntry);   //设置证书
183             var chain = new X509CertificateEntry[1];
184             chain[0] = certEntry;
185             store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), chain);   //设置私钥
186             using (var fs = File.Create(pfxPath))
187             {
188                 store.Save(fs, password.ToCharArray(), random); //保存
189             };
190         }
191 
192         /// <summary>
193         /// 加载证书
194         /// </summary>
195         /// <param name="pfxPath"></param>
196         /// <param name="password"></param>
197         private static void LoadingPfxCertificate(string pfxPath, string password)
198         {
199             //加载证书
200             X509Certificate2 pfx = new X509Certificate2(pfxPath, password, X509KeyStorageFlags.Exportable);
201             var keyPair = DotNetUtilities.GetKeyPair(pfx.PrivateKey);
202             var subjectPublicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public);
203             var privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private);
204             var privateKey = Base64.ToBase64String(privateKeyInfo.ParsePrivateKey().GetEncoded());
205             var publicKey = Base64.ToBase64String(subjectPublicKeyInfo.GetEncoded());
206             Console.ForegroundColor = ConsoleColor.DarkYellow;
207 
208             Console.WriteLine("Pfx证书私钥:");
209             Console.WriteLine(privateKey);
210             Console.WriteLine("Pfx证书公钥:");
211             Console.WriteLine(publicKey);
212 
213             var beEncryptedData = "hello rsa";
214             Console.WriteLine($"加密原文:{beEncryptedData}");
215             var cipherText = RSAHelper.Encrypt(beEncryptedData, publicKey);
216             Console.WriteLine("加密结果:");
217             Console.WriteLine(cipherText);
218 
219             var datares = RSAHelper.Decrypt(cipherText, privateKey);
220             Console.WriteLine($"解密结果:{datares}");
221         }

 

完全源码地址:https://github.com/daileass/CreateSelfSignedCertificateByBouncyCastle.git  

posted @ 2022-08-31 12:00  旅途。  阅读(1691)  评论(1编辑  收藏  举报