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 }
浙公网安备 33010602011771号