ADOU-V

导航

cer, pfx 创建,并且读取公钥/密钥,加解密 (C#程序实现)

PKI技术(public key infrastructure)里面,cer文件和pfx文件是很常见的。通常cer文件里面保存着公钥以及用户的一些信息,pfx里面则含有私钥和公钥。

用makecert.exe可以创建公钥证书和私钥证书,具体看

http://msdn.microsoft.com/zh-cn/library/bfsktky3(v=vs.110).aspx

http://blog.csdn.net/hacode/article/details/4240238

 

这里使用程序的方法来创建。参考了http://www.cnblogs.com/luminji/archive/2010/10/28/1863179.html

下面的代码封装了一个类,可以在store里面创建一个认证,并且导出到cer,pfx,然后从store,cer,pfx读取信息

  1 public sealed class DataCertificate   
  2     {  
  3         #region 生成证书   
  4         /// <summary>   
  5         /// 根据指定的证书名和makecert全路径生成证书(包含公钥和私钥,并保存在MY存储区)   
  6         /// </summary>   
  7         /// <param name="subjectName"></param>   
  8         /// <param name="makecertPath"></param>   
  9         /// <returns></returns>   
 10         public static bool CreateCertWithPrivateKey(string subjectName, string makecertPath)   
 11         {   
 12             subjectName = "CN=" + subjectName;   
 13             string param = " -pe -ss my -n \"" + subjectName + "\" ";   
 14             try  
 15             {   
 16                 Process p = Process.Start(makecertPath, param);   
 17                 p.WaitForExit();   
 18                 p.Close();   
 19             }   
 20             catch (Exception e)   
 21             {   
 22                 return false;   
 23             }   
 24             return true;   
 25         }  
 26         #endregion  
 27  
 28         #region 文件导入导出   
 29         /// <summary>   
 30         /// 从WINDOWS证书存储区的个人MY区找到主题为subjectName的证书,   
 31         /// 并导出为pfx文件,同时为其指定一个密码   
 32         /// 并将证书从个人区删除(如果isDelFromstor为true)   
 33         /// </summary>   
 34         /// <param name="subjectName">证书主题,不包含CN=</param>   
 35         /// <param name="pfxFileName">pfx文件名</param>   
 36         /// <param name="password">pfx文件密码</param>   
 37         /// <param name="isDelFromStore">是否从存储区删除</param>   
 38         /// <returns></returns>   
 39         public static bool ExportToPfxFile(string subjectName, string pfxFileName,   
 40             string password, bool isDelFromStore)   
 41         {   
 42             subjectName = "CN=" + subjectName;   
 43             X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);   
 44             store.Open(OpenFlags.ReadWrite);   
 45             X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;   
 46             foreach (X509Certificate2 x509 in storecollection)   
 47             {   
 48                 if (x509.Subject == subjectName)   
 49                 {   
 50                     Debug.Print(string.Format("certificate name: {0}", x509.Subject));   
 51   
 52                     byte[] pfxByte = x509.Export(X509ContentType.Pfx, password);   
 53                     using (FileStream fileStream = new FileStream(pfxFileName, FileMode.Create))   
 54                     {   
 55                         // Write the data to the file, byte by byte.   
 56                         for (int i = 0; i < pfxByte.Length; i++)   
 57                             fileStream.WriteByte(pfxByte[i]);   
 58                         // Set the stream position to the beginning of the file.   
 59                         fileStream.Seek(0, SeekOrigin.Begin);   
 60                         // Read and verify the data.   
 61                         for (int i = 0; i < fileStream.Length; i++)   
 62                         {   
 63                             if (pfxByte[i] != fileStream.ReadByte())   
 64                             {   
 65                                 fileStream.Close();   
 66                                 return false;   
 67                             }   
 68                         }   
 69                         fileStream.Close();   
 70                     }   
 71                     if( isDelFromStore == true)   
 72                         store.Remove(x509);   
 73                 }   
 74             }   
 75             store.Close();   
 76             store = null;   
 77             storecollection = null;   
 78             return true;   
 79         }   
 80         /// <summary>   
 81         /// 从WINDOWS证书存储区的个人MY区找到主题为subjectName的证书,   
 82         /// 并导出为CER文件(即,只含公钥的)   
 83         /// </summary>   
 84         /// <param name="subjectName"></param>   
 85         /// <param name="cerFileName"></param>   
 86         /// <returns></returns>   
 87         public static bool ExportToCerFile(string subjectName, string cerFileName)   
 88         {   
 89             subjectName = "CN=" + subjectName;   
 90             X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);   
 91             store.Open(OpenFlags.ReadWrite);   
 92             X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;   
 93             foreach (X509Certificate2 x509 in storecollection)   
 94             {   
 95                 if (x509.Subject == subjectName)   
 96                 {   
 97                     Debug.Print(string.Format("certificate name: {0}", x509.Subject));   
 98                     //byte[] pfxByte = x509.Export(X509ContentType.Pfx, password);   
 99                     byte[] cerByte = x509.Export(X509ContentType.Cert);   
100                     using (FileStream fileStream = new FileStream(cerFileName, FileMode.Create))   
101                     {   
102                         // Write the data to the file, byte by byte.   
103                         for (int i = 0; i < cerByte.Length; i++)   
104                             fileStream.WriteByte(cerByte[i]);   
105                         // Set the stream position to the beginning of the file.   
106                         fileStream.Seek(0, SeekOrigin.Begin);   
107                         // Read and verify the data.   
108                         for (int i = 0; i < fileStream.Length; i++)   
109                         {   
110                             if (cerByte[i] != fileStream.ReadByte())   
111                             {   
112                                 fileStream.Close();   
113                                 return false;   
114                             }   
115                         }   
116                         fileStream.Close();   
117                     }   
118                 }   
119             }   
120             store.Close();   
121             store = null;   
122             storecollection = null;   
123             return true;   
124         }  
125         #endregion  
126  
127         #region 从证书中获取信息   
128         /// <summary>   
129         /// 根据私钥证书得到证书实体,得到实体后可以根据其公钥和私钥进行加解密   
130         /// 加解密函数使用DEncrypt的RSACryption类   
131         /// </summary>   
132         /// <param name="pfxFileName"></param>   
133         /// <param name="password"></param>   
134         /// <returns></returns>   
135         public static X509Certificate2 GetCertificateFromPfxFile(string pfxFileName,   
136             string password)   
137         {   
138             try  
139             {   
140                 return new X509Certificate2(pfxFileName, password, X509KeyStorageFlags.Exportable);   
141             }   
142             catch (Exception e)   
143             {   
144                 return null;   
145             }   
146         }   
147         /// <summary>   
148         /// 到存储区获取证书   
149         /// </summary>   
150         /// <param name="subjectName"></param>   
151         /// <returns></returns>   
152         public static X509Certificate2 GetCertificateFromStore(string subjectName)   
153         {   
154             subjectName = "CN=" + subjectName;   
155             X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);   
156             store.Open(OpenFlags.ReadWrite);   
157             X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;   
158             foreach (X509Certificate2 x509 in storecollection)   
159             {   
160                 if (x509.Subject == subjectName)   
161                 {   
162                     return x509;   
163                 }   
164             }   
165             store.Close();   
166             store = null;   
167             storecollection = null;   
168             return null;   
169         }   
170        /// <summary>   
171         /// 根据公钥证书,返回证书实体   
172         /// </summary>   
173         /// <param name="cerPath"></param>   
174         public static X509Certificate2 GetCertFromCerFile(string cerPath)   
175         {   
176             try  
177             {   
178                 return new X509Certificate2(cerPath);   
179             }   
180             catch (Exception e)   
181             {    
182                 return null;   
183             }               
184         }  
185         #endregion          
186     }  

两个RSA加解密辅助函数:

 1         static string RSADecrypt(string xmlPrivateKey, string m_strDecryptString)   
 2         {   
 3             RSACryptoServiceProvider provider = new RSACryptoServiceProvider();   
 4             provider.FromXmlString(xmlPrivateKey);   
 5             byte[] rgb = Convert.FromBase64String(m_strDecryptString);   
 6             byte[] bytes = provider.Decrypt(rgb, false);   
 7             return new UnicodeEncoding().GetString(bytes);   
 8         }   
 9         /// <summary>   
10         /// RSA加密   
11         /// </summary>   
12         /// <param name="xmlPublicKey"></param>   
13         /// <param name="m_strEncryptString"></param>   
14         /// <returns></returns>   
15         static string RSAEncrypt(string xmlPublicKey, string m_strEncryptString)   
16         {   
17             RSACryptoServiceProvider provider = new RSACryptoServiceProvider();   
18             provider.FromXmlString(xmlPublicKey);   
19             byte[] bytes = new UnicodeEncoding().GetBytes(m_strEncryptString);   
20             return Convert.ToBase64String(provider.Encrypt(bytes, false));   
21         }  

使用例子,下面的代码做了几个事情

1. 在个人store里面创建了一个认证, 从认证里面读取信息得到一个X509Certificate2的对象,这个对象内部包含公钥和私钥,然后做了次rsa加解密测试。

2. 从store里面导出一个cer文件,因为cer文件并没有私钥,只有公钥。测试代码就是用公钥加密然后用前面得到的私钥解密。

3. 导出一个pfx文件,pfx包括公钥和私钥,可以自己加解密。

这是个很简单的例子,但是对于理解cer文件和pfx文件已经公钥私钥应该有帮助。

 1             // 在personal(个人)里面创建一个foo的证书
 2             DataCertificate.CreateCertWithPrivateKey("foo", "C:\\Program Files (x86)\\Windows Kits\\8.1\\bin\\x64\\makecert.exe");
 3 
 4             // 获取证书
 5             X509Certificate2 c1 = DataCertificate.GetCertificateFromStore("foo");
 6 
 7             string keyPublic = c1.PublicKey.Key.ToXmlString(false);  // 公钥
 8             string keyPrivate = c1.PrivateKey.ToXmlString(true);  // 私钥
 9 
10             string cypher = RSAEncrypt(keyPublic, "程序员");  // 加密
11             string plain = RSADecrypt(keyPrivate, cypher);  // 解密
12 
13             Debug.Assert(plain == "程序员");
14 
15             // 生成一个cert文件
16             DataCertificate.ExportToCerFile("foo", "d:\\mycert\\foo.cer");
17 
18             X509Certificate2 c2 = DataCertificate.GetCertFromCerFile("d:\\mycert\\foo.cer");
19 
20             string keyPublic2 = c2.PublicKey.Key.ToXmlString(false);
21 
22             bool b = keyPublic2 == keyPublic;
23             string cypher2 = RSAEncrypt(keyPublic2, "程序员2");  // 加密
24             string plain2 = RSADecrypt(keyPrivate, cypher2);  // 解密, cer里面并没有私钥,所以这里使用前面得到的私钥来解密
25 
26             Debug.Assert(plain2 == "程序员2");
27 
28             // 生成一个pfx, 并且从store里面删除
29             DataCertificate.ExportToPfxFile("foo", "d:\\mycert\\foo.pfx", "111", true);
30 
31             X509Certificate2 c3 = DataCertificate.GetCertificateFromPfxFile("d:\\mycert\\foo.pfx", "111");
32 
33             string keyPublic3 = c3.PublicKey.Key.ToXmlString(false);  // 公钥
34             string keyPrivate3 = c3.PrivateKey.ToXmlString(true);  // 私钥
35 
36             string cypher3 = RSAEncrypt(keyPublic3, "程序员3");  // 加密
37             string plain3 = RSADecrypt(keyPrivate3, cypher3);  // 解密
38 
39             Debug.Assert(plain3 == "程序员3");

附:完整代码

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Diagnostics;
  4 using System.IO;
  5 using System.Linq;
  6 using System.Security.Cryptography;
  7 using System.Security.Cryptography.X509Certificates;
  8 using System.Text;
  9 
 10 
 11 namespace ConsoleApplication1
 12 {
 13     public sealed class DataCertificate   
 14     {  
 15         #region 生成证书   
 16         /// <summary>   
 17         /// 根据指定的证书名和makecert全路径生成证书(包含公钥和私钥,并保存在MY存储区)   
 18         /// </summary>   
 19         /// <param name="subjectName"></param>   
 20         /// <param name="makecertPath"></param>   
 21         /// <returns></returns>   
 22         public static bool CreateCertWithPrivateKey(string subjectName, string makecertPath)   
 23         {   
 24             subjectName = "CN=" + subjectName;   
 25             string param = " -pe -ss my -n \"" + subjectName + "\" ";   
 26             try  
 27             {   
 28                 Process p = Process.Start(makecertPath, param);   
 29                 p.WaitForExit();   
 30                 p.Close();   
 31             }   
 32             catch (Exception e)   
 33             {   
 34                 return false;   
 35             }   
 36             return true;   
 37         }  
 38         #endregion  
 39  
 40         #region 文件导入导出   
 41         /// <summary>   
 42         /// 从WINDOWS证书存储区的个人MY区找到主题为subjectName的证书,   
 43         /// 并导出为pfx文件,同时为其指定一个密码   
 44         /// 并将证书从个人区删除(如果isDelFromstor为true)   
 45         /// </summary>   
 46         /// <param name="subjectName">证书主题,不包含CN=</param>   
 47         /// <param name="pfxFileName">pfx文件名</param>   
 48         /// <param name="password">pfx文件密码</param>   
 49         /// <param name="isDelFromStore">是否从存储区删除</param>   
 50         /// <returns></returns>   
 51         public static bool ExportToPfxFile(string subjectName, string pfxFileName,   
 52             string password, bool isDelFromStore)   
 53         {   
 54             subjectName = "CN=" + subjectName;   
 55             X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);   
 56             store.Open(OpenFlags.ReadWrite);   
 57             X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;   
 58             foreach (X509Certificate2 x509 in storecollection)   
 59             {   
 60                 if (x509.Subject == subjectName)   
 61                 {   
 62                     Debug.Print(string.Format("certificate name: {0}", x509.Subject));   
 63   
 64                     byte[] pfxByte = x509.Export(X509ContentType.Pfx, password);   
 65                     using (FileStream fileStream = new FileStream(pfxFileName, FileMode.Create))   
 66                     {   
 67                         // Write the data to the file, byte by byte.   
 68                         for (int i = 0; i < pfxByte.Length; i++)   
 69                             fileStream.WriteByte(pfxByte[i]);   
 70                         // Set the stream position to the beginning of the file.   
 71                         fileStream.Seek(0, SeekOrigin.Begin);   
 72                         // Read and verify the data.   
 73                         for (int i = 0; i < fileStream.Length; i++)   
 74                         {   
 75                             if (pfxByte[i] != fileStream.ReadByte())   
 76                             {   
 77                                 fileStream.Close();   
 78                                 return false;   
 79                             }   
 80                         }   
 81                         fileStream.Close();   
 82                     }   
 83                     if( isDelFromStore == true)   
 84                         store.Remove(x509);   
 85                 }   
 86             }   
 87             store.Close();   
 88             store = null;   
 89             storecollection = null;   
 90             return true;   
 91         }   
 92         /// <summary>   
 93         /// 从WINDOWS证书存储区的个人MY区找到主题为subjectName的证书,   
 94         /// 并导出为CER文件(即,只含公钥的)   
 95         /// </summary>   
 96         /// <param name="subjectName"></param>   
 97         /// <param name="cerFileName"></param>   
 98         /// <returns></returns>   
 99         public static bool ExportToCerFile(string subjectName, string cerFileName)   
100         {   
101             subjectName = "CN=" + subjectName;   
102             X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);   
103             store.Open(OpenFlags.ReadWrite);   
104             X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;   
105             foreach (X509Certificate2 x509 in storecollection)   
106             {   
107                 if (x509.Subject == subjectName)   
108                 {   
109                     Debug.Print(string.Format("certificate name: {0}", x509.Subject));   
110                     //byte[] pfxByte = x509.Export(X509ContentType.Pfx, password);   
111                     byte[] cerByte = x509.Export(X509ContentType.Cert);   
112                     using (FileStream fileStream = new FileStream(cerFileName, FileMode.Create))   
113                     {   
114                         // Write the data to the file, byte by byte.   
115                         for (int i = 0; i < cerByte.Length; i++)   
116                             fileStream.WriteByte(cerByte[i]);   
117                         // Set the stream position to the beginning of the file.   
118                         fileStream.Seek(0, SeekOrigin.Begin);   
119                         // Read and verify the data.   
120                         for (int i = 0; i < fileStream.Length; i++)   
121                         {   
122                             if (cerByte[i] != fileStream.ReadByte())   
123                             {   
124                                 fileStream.Close();   
125                                 return false;   
126                             }   
127                         }   
128                         fileStream.Close();   
129                     }   
130                 }   
131             }   
132             store.Close();   
133             store = null;   
134             storecollection = null;   
135             return true;   
136         }  
137         #endregion  
138  
139         #region 从证书中获取信息   
140         /// <summary>   
141         /// 根据私钥证书得到证书实体,得到实体后可以根据其公钥和私钥进行加解密   
142         /// 加解密函数使用DEncrypt的RSACryption类   
143         /// </summary>   
144         /// <param name="pfxFileName"></param>   
145         /// <param name="password"></param>   
146         /// <returns></returns>   
147         public static X509Certificate2 GetCertificateFromPfxFile(string pfxFileName,   
148             string password)   
149         {   
150             try  
151             {   
152                 return new X509Certificate2(pfxFileName, password, X509KeyStorageFlags.Exportable);   
153             }   
154             catch (Exception e)   
155             {   
156                 return null;   
157             }   
158         }   
159         /// <summary>   
160         /// 到存储区获取证书   
161         /// </summary>   
162         /// <param name="subjectName"></param>   
163         /// <returns></returns>   
164         public static X509Certificate2 GetCertificateFromStore(string subjectName)   
165         {   
166             subjectName = "CN=" + subjectName;   
167             X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);   
168             store.Open(OpenFlags.ReadWrite);   
169             X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;   
170             foreach (X509Certificate2 x509 in storecollection)   
171             {   
172                 if (x509.Subject == subjectName)   
173                 {   
174                     return x509;   
175                 }   
176             }   
177             store.Close();   
178             store = null;   
179             storecollection = null;   
180             return null;   
181         }   
182        /// <summary>   
183         /// 根据公钥证书,返回证书实体   
184         /// </summary>   
185         /// <param name="cerPath"></param>   
186         public static X509Certificate2 GetCertFromCerFile(string cerPath)   
187         {   
188             try  
189             {   
190                 return new X509Certificate2(cerPath);   
191             }   
192             catch (Exception e)   
193             {    
194                 return null;   
195             }               
196         }  
197         #endregion          
198     }  
199 
200     class Program
201     {
202         static string RSADecrypt(string xmlPrivateKey, string m_strDecryptString)   
203         {   
204             RSACryptoServiceProvider provider = new RSACryptoServiceProvider();   
205             provider.FromXmlString(xmlPrivateKey);   
206             byte[] rgb = Convert.FromBase64String(m_strDecryptString);   
207             byte[] bytes = provider.Decrypt(rgb, false);   
208             return new UnicodeEncoding().GetString(bytes);   
209         }   
210         /// <summary>   
211         /// RSA加密   
212         /// </summary>   
213         /// <param name="xmlPublicKey"></param>   
214         /// <param name="m_strEncryptString"></param>   
215         /// <returns></returns>   
216         static string RSAEncrypt(string xmlPublicKey, string m_strEncryptString)   
217         {   
218             RSACryptoServiceProvider provider = new RSACryptoServiceProvider();   
219             provider.FromXmlString(xmlPublicKey);   
220             byte[] bytes = new UnicodeEncoding().GetBytes(m_strEncryptString);   
221             return Convert.ToBase64String(provider.Encrypt(bytes, false));   
222         }  
223 
224         static void Main(string[] args)
225         {
226             // 在personal(个人)里面创建一个foo的证书
227             DataCertificate.CreateCertWithPrivateKey("foo", "C:\\Program Files (x86)\\Windows Kits\\8.1\\bin\\x64\\makecert.exe");
228 
229             // 获取证书
230             X509Certificate2 c1 = DataCertificate.GetCertificateFromStore("foo");
231 
232             string keyPublic = c1.PublicKey.Key.ToXmlString(false);  // 公钥
233             string keyPrivate = c1.PrivateKey.ToXmlString(true);  // 私钥
234 
235             string cypher = RSAEncrypt(keyPublic, "程序员");  // 加密
236             string plain = RSADecrypt(keyPrivate, cypher);  // 解密
237 
238             Debug.Assert(plain == "程序员");
239 
240             // 生成一个cert文件
241             DataCertificate.ExportToCerFile("foo", "d:\\mycert\\foo.cer");
242 
243             X509Certificate2 c2 = DataCertificate.GetCertFromCerFile("d:\\mycert\\foo.cer");
244 
245             string keyPublic2 = c2.PublicKey.Key.ToXmlString(false);
246 
247             bool b = keyPublic2 == keyPublic;
248             string cypher2 = RSAEncrypt(keyPublic2, "程序员2");  // 加密
249             string plain2 = RSADecrypt(keyPrivate, cypher2);  // 解密, cer里面并没有私钥,所以这里使用前面得到的私钥来解密
250 
251             Debug.Assert(plain2 == "程序员2");
252 
253             // 生成一个pfx, 并且从store里面删除
254             DataCertificate.ExportToPfxFile("foo", "d:\\mycert\\foo.pfx", "111", true);
255 
256             X509Certificate2 c3 = DataCertificate.GetCertificateFromPfxFile("d:\\mycert\\foo.pfx", "111");
257 
258             string keyPublic3 = c3.PublicKey.Key.ToXmlString(false);  // 公钥
259             string keyPrivate3 = c3.PrivateKey.ToXmlString(true);  // 私钥
260 
261             string cypher3 = RSAEncrypt(keyPublic3, "程序员3");  // 加密
262             string plain3 = RSADecrypt(keyPrivate3, cypher3);  // 解密
263 
264             Debug.Assert(plain3 == "程序员3");
265         }
266     }
267 }

 

posted on 2016-07-15 10:08  a-dou  阅读(1354)  评论(0)    收藏  举报