• BouncyCastle产生一个PKCS#12规范的PFX/p12证书


    RT,在C#中实现,依赖.netFramework2.0

    BouncyCastle中提供了PKCS12Store,Pkcs12StoreBuilder,AsymmetricKeyEntry,X509CertificateEntry等接口

    其中Pkcs12StoreBuilder建立一个PKCS12Store对象,PKCS12Store对象来产生一个pfx/p12格式的证书,该证书符合PKCS#12规范

    PKCS#12的ref,见RSA给出的文档:PKCS #12: Personal Information Exchange Syntax Standard

    PKCS12Store中方法load()和save(),加载和保存证书,其中的实现比较复杂,处理过程主要是对PKCS12证书内容的一组SafeBag进行判断和解包。一个PKCS12结构分析的文档:http://cid-780607117452312e.office.live.com/self.aspx/.Public/PKCS%5E3l2%E7%BB%93%E6%9E%84%E5%88%86%E6%9E%90.pdf

    AsymmetricKeyEntry中封装了私钥,支持属性包的附加,attributeBag,可以方便获得私钥或封装私钥

    类似的,X509CertificateEntry封装了公钥证书,支持属性包的附加和x509certificateV3的扩展,可以从中方便获得公钥等

    这样,就可以通过产生一个pfx证书,保存CA的密钥对。这里pfx的certBag中证书采用的是x509certificateV1格式,因为没有用到v3格式证书的扩展

    思路如下:

    1、产生一对密钥对,其产生方法和保存方法之前有说过

         产生密钥对:用Bouncy Castle的C#版API产生公钥和私钥

         保存方法:在C#中保存Bouncy Castle生成的密钥对

    2、配置自定义的x509Name对象,BouncyCastle中采用HashTable这种结构。

    3、X509CertificateEntry封装公钥证书时,添加一个该公钥证书的alias。在测试过程(测试2)中,我导入该pfx证书到电脑的当前用户my证书存储区中,用微软的接口去读取时,用FriendlyName(就是该alias)来查找比较方便。另外(测试1),在store.Aliases这个属性去查找相匹配的alias,然后通过该alias从store中获取AsymmetricKeyEntry和X509CertificateEntry,从而获取私钥和公钥。

         属性包FriendlyName,RSA的pkcs#9文档中提到过,不过不详细。链接:PKCS #9: Selected Attribute Types

         另外,上面提到的属性包attributeBag和SafeBag,BouncyCastle中的PkcsObjectIdentifiers这个源代码中全部定义,可以参考下,其命名空间为:Org.BouncyCastle.Asn1.Pkcs.PkcsObjectIdentifiers(根据该命名空间的命名方式,可以在源代码中快速定位到该源文件)

    生成的代码:

    1. char[] passwd = "123456".ToCharArray();   //pfx密码  
    2. IAsymmetricCipherKeyPairGenerator keyGen = GeneratorUtilities.GetKeyPairGenerator("RSA");  
    3. RsaKeyGenerationParameters genPar = new RsaKeyGenerationParameters(  
    4.     BigInteger.ValueOf(0x10001), new SecureRandom(), 2048, 25);  
    5. keyGen.Init(genPar);  
    6. AsymmetricCipherKeyPair keypair = keyGen.GenerateKeyPair();  
    7. RsaKeyParameters pubKey = (RsaKeyParameters)keypair.Public; //CA公钥  
    8. RsaKeyParameters priKey = (RsaKeyParameters)keypair.Private;    //CA私钥  
    9. Hashtable attrs = new Hashtable();  
    10. ArrayList order = new ArrayList();  
    11. attrs.Add(X509Name.C, "CN");    //country code  
    12. //attrs.Add(X509Name.ST, "Guangdong province");   //province name  
    13. //attrs.Add(X509Name.L, "Guangzhou city");    //locality name        
    14. attrs.Add(X509Name.O, "South China Normal University"); //organization  
    15. attrs.Add(X509Name.OU, "South China Normal University");    //organizational unit name              
    16. attrs.Add(X509Name.CN, "CAcert");   //common name  
    17. attrs.Add(X509Name.E, "popozhude@qq.com");  
    18. order.Add(X509Name.C);  
    19. //order.Add(X509Name.ST);  
    20. //order.Add(X509Name.L);  
    21. order.Add(X509Name.O);  
    22. order.Add(X509Name.OU);  
    23. order.Add(X509Name.CN);  
    24. order.Add(X509Name.E);  
    25. X509Name issuerDN = new X509Name(order, attrs);  
    26. X509Name subjectDN = issuerDN;  //自签证书,两者一样  
    27. X509V1CertificateGenerator v1certGen = new X509V1CertificateGenerator();  
    28. v1certGen.SetSerialNumber(new BigInteger(128, new Random()));   //128位  
    29. v1certGen.SetIssuerDN(issuerDN);  
    30. v1certGen.SetNotBefore(DateTime.UtcNow.AddDays(-1));  
    31. v1certGen.SetNotAfter(DateTime.UtcNow.AddDays(365));  
    32. v1certGen.SetSubjectDN(subjectDN);  
    33. v1certGen.SetPublicKey(pubKey); //公钥  
    34. v1certGen.SetSignatureAlgorithm("SHA1WithRSAEncryption");  
    35. Org.BouncyCastle.X509.X509Certificate CAcert = v1certGen.Generate(priKey);  
    36. CAcert.CheckValidity();  
    37. CAcert.Verify(pubKey);  
    38.   
    39. //属性包  
    40. /* 
    41. Hashtable bagAttr = new Hashtable(); 
    42. bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtFriendlyName.Id, 
    43.     new DerBmpString("CA's Primary Certificate")); 
    44. bagAttr.Add(PkcsObjectIdentifiers.Pkcs9AtLocalKeyID.Id, 
    45.     new SubjectKeyIdentifierStructure(pubKey)); 
    46.  
    47. X509CertificateEntry certEntry = new X509CertificateEntry(CAcert,bagAttr); 
    48. */  
    49. X509CertificateEntry certEntry = new X509CertificateEntry(CAcert);  
    50. Pkcs12Store store = new Pkcs12StoreBuilder().Build();  
    51. store.SetCertificateEntry("CA's Primary Certificate", certEntry);   //设置证书  
    52. X509CertificateEntry[] chain = new X509CertificateEntry[1];  
    53. chain[0] = certEntry;  
    54. store.SetKeyEntry("CA's Primary Certificate"new AsymmetricKeyEntry(priKey), chain);   //设置私钥  
    55. FileStream fout = File.Create("CA.pfx");      
    56. store.Save(fout, passwd, new SecureRandom());   //保存  
    57. fout.Close();  

    测试1 ,把生成的pfx证书导入到计算机的证书store中,用微软提供的api去查找该证书。怎么通过MMC的证书管理单元对证书存储区进行管理:在MMC的证书管理单元中对证书存储区进行管理

    1. X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);  
    2.             store.Open(OpenFlags.ReadOnly);  
    3.             X509Certificate2Collection storeCollection = (X509Certificate2Collection)store.Certificates;  
    4.             X509Certificate2 x509cert = null;  
    5.             foreach (X509Certificate2 cert in storeCollection)  
    6.             {  
    7.                 //if(cert.Subject==" E = popozhude@qq.com, CN = CAcert, OU = South China Normal University, O = South China Normal University, C = CN")  
    8.                 if (cert.FriendlyName == "CA's Primary Certificate")  
    9.                 {  
    10.                     x509cert = cert;  
    11.                     //break;  
    12.                 }  
    13.             }  
    14.             store.Close();  
    15.             if (x509cert == null)  
    16.             {  
    17.                 Console.WriteLine("找不到指定的证书");  
    18.             }  
    19.             Console.WriteLine(x509cert.ToString());  
    20.             Console.ReadLine();  

    测试2 :读取本地的pfx证书,获取其公钥和私钥,这里主要用BouncyCastle的API,然后又把公钥证书转换成byte数组,再用微软的证书类api读取,成功。

    1. FileStream fs = File.OpenRead("CA.pfx");      //debug文件夹下的证书           
    2.             char[] passwd = "123456".ToCharArray();  
    3.             Pkcs12Store store = new Pkcs12StoreBuilder().Build();  
    4.             store.Load(fs, passwd); //加载证书  
    5.             string alias = null;  
    6.             foreach (string str in store.Aliases)  
    7.             {  
    8.                 if (store.IsKeyEntry(str))  
    9.                     alias = str;  
    10.             }  
    11.             if (alias == null)  
    12.             {  
    13.                 Console.WriteLine("alias 为空");  
    14.             }  
    15.             else  
    16.                 Console.WriteLine(alias);  
    17.             AsymmetricKeyEntry keyEntry = store.GetKey(alias);  
    18.             RsaKeyParameters priKey = (RsaKeyParameters)keyEntry.Key;   //取得私钥  
    19.             X509CertificateEntry certEntry = store.GetCertificate(alias);  
    20.             Org.BouncyCastle.X509.X509Certificate x509cert = certEntry.Certificate;  
    21.             RsaKeyParameters pubKey = (RsaKeyParameters)x509cert.GetPublicKey();    //取得公钥  
    22.             x509cert.Verify(pubKey);    //test ok  
    23.             byte[] certByte = x509cert.GetEncoded();    //把该证书转换成字节数组  
    24.             X509Certificate2 cert2 = new X509Certificate2(certByte);    //微软的类X509Certificate2  
    25.             Console.WriteLine(cert2.ToString());    //显示正常,说明可以把BouncyCastle产生的数字v3证书,转换成X509Certificate2处理的证  
    26.             Console.Read();  

     
  • 相关阅读:
    Celery ---- 分布式队列神器 ---- 入门
    如何使用Python快速制作可视化报表----pyecharts
    django 使用 可视化包-Pyechart
    git & github 快速入门
    开发效率进阶
    windows编译 obs-studio
    python 控制vbox虚拟机
    pyqt实践——从裸机到打包安装
    测试darwin calendar 服务器
    centos 搭建 darwin calendar 服务器
  • 原文地址:https://www.cnblogs.com/adylee/p/3625798.html
Copyright © 2020-2023  润新知