一个完整的类用来读取OpenSSL生成的pem格式的x509证书

  1     internal static class CcbRsaHelper
  2     {
  3         private const string Begin = "-----BEGIN ";
  4         private const string End = "-----END ";
  5         private const string Private = "PRIVATE KEY";
  6
  7         /// <summary>Imports PEM formatted key or certificate into crypto provider</summary>
  8         /// <param name="data">Content of PEM-formatted object.</param>
  9         /// <returns>Crypto provider, defined by given argument.</returns>
 10         internal static RSACryptoServiceProvider FromPem(string data)
 11         {
 12             return FromPem(data, null);
 13         }
 14
 15         /// <summary>Imports PEM formatted key or certificate into crypto provider</summary>
 16         /// <param name="data">Content of PEM-formatted object.</param>
 17         /// <param name="passKey">Passkey for PEM-formatted object.</param>
 18         /// <returns>Crypto provider, defined by given argument.</returns>
 19         internal static RSACryptoServiceProvider FromPem(string data, string passKey)
 20         {
 21             using (var reader = new StringReader(data))
 22             {
 23                 var line = reader.ReadLine();
 24                 if (line.IsEmpty() || !line.StartsWith(Begin))
 25                 {
 26                     throw new ArgumentException("This is not valid PEM format", "data", new FormatException("PEM start identifier is invalid or not found."));
 27                 }
 28                 line = line.Substring(Begin.Length);
 29                 var idx = line.IndexOf(‘-‘);
 30                 if (idx <= 0)
 31                 {
 32                     throw new ArgumentException("This is not valid PEM format", "data", new FormatException("PEM start identifier is invalid or not found."));
 33                 }
 34                 var type = line.Before(idx);
 35                 return LoadPem(reader, type, passKey);
 36             }
 37         }
 38
 39         internal static RSAParameters FromPemPublicKey(string pemFileConent)
 40         {
 41             if (string.IsNullOrEmpty(pemFileConent))
 42             {
 43                 throw new ArgumentNullException("pemFileConent", "This arg cann‘t be empty.");
 44             }
 45
 46             pemFileConent = pemFileConent.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\n", "").Replace("\r", "");
 47             var keyData = Convert.FromBase64String(pemFileConent);
 48             var keySize1024 = (keyData.Length == 162);
 49             var keySize2048 = (keyData.Length == 294);
 50             if (!(keySize1024 || keySize2048))
 51             {
 52                 throw new ArgumentException("pem file content is incorrect, Only support the key size is 1024 or 2048");
 53             }
 54
 55             var pemModulus = (keySize1024 ? new byte[128] : new byte[256]);
 56             var pemPublicExponent = new byte[3];
 57             Array.Copy(keyData, (keySize1024 ? 29 : 33), pemModulus, 0, (keySize1024 ? 128 : 256));
 58             Array.Copy(keyData, (keySize1024 ? 159 : 291), pemPublicExponent, 0, 3);
 59             var para = new RSAParameters {Modulus = pemModulus, Exponent = pemPublicExponent};
 60             return para;
 61         }
 62
 63         private static RSACryptoServiceProvider LoadPem(TextReader reader, string type, string passkey)
 64         {
 65             var end = End + type;
 66             var headers = new PemHeaders();
 67             string line;
 68             var body = new StringBuilder();
 69             while ((line = reader.ReadLine()) != null && line.IndexOf(end, StringComparison.Ordinal) == -1)
 70             {
 71                 var d = line.IndexOf(‘:‘);
 72                 if (d >= 0)
 73                 {
 74                     // header
 75                     var n = line.Substring(0, d).Trim();
 76                     if (n.StartsWith("X-")) n = n.Substring(2);
 77                     var v = line.After(d).Trim();
 78                     if (!headers.ContainsKey(n))
 79                     {
 80                         headers.Add(n, v);
 81                     }
 82                     else
 83                     {
 84                         throw new FormatException("Duplicate header {0} in PEM data.".Substitute(n));
 85                     }
 86                 }
 87                 else
 88                 {
 89                     // body
 90                     body.Append(line);
 91                 }
 92             }
 93             if (body.Length%4 != 0)
 94             {
 95                 throw new FormatException("PEM data is invalid or truncated.");
 96             }
 97
 98             return CreatePem(type, headers, Convert.FromBase64String(body.ToString()), passkey);
 99         }
100
101         private static RSACryptoServiceProvider CreatePem(string type, PemHeaders headers, byte[] body, string passkey)
102         {
103             if (type.EndsWith(Private))
104             {
105                 return FromPrivateKey(type, headers, body, passkey);
106             }
107             throw new NotSupportedException("Import of {0} is not supported. Only RSA private key import is supported.".Substitute(type));
108         }
109
110
111         private static RSACryptoServiceProvider FromPrivateKey(string type, PemHeaders headers, byte[] body, string passkey)
112         {
113             if (type == null) throw new ArgumentNullException("type");
114             var pType = headers.TryGet("Proc-Type");
115             if (pType != "4,ENCRYPTED") return null;
116             if (passkey.IsEmpty())
117             {
118                 throw new ArgumentException("Passkey is mandatory for encrypted PEM object");
119             }
120
121             var dek = headers.TryGet("DEK-Info");
122             var tkz = dek.Split(‘,‘);
123             if (tkz.Length > 1)
124             {
125                 var alg = new Alg(tkz[0]);
126                 var saltLen = tkz[1].Length;
127                 var salt = new byte[saltLen/2];
128                 for (var i = 0; i < saltLen/2; i++)
129                 {
130                     var pair = tkz[1].Substring(2*i, 2);
131                     salt[i] = Byte.Parse(pair, NumberStyles.AllowHexSpecifier);
132                 }
133
134                 body = DecodePem(body, passkey, alg, salt);
135                 if (body != null)
136                 {
137                     return DecodeRsaPrivateKey(body);
138                 }
139             }
140             else
141             {
142                 throw new FormatException("DEK information is invalid or truncated.");
143             }
144
145             return null;
146         }
147
148         private static RSACryptoServiceProvider DecodeRsaPrivateKey(byte[] body)
149         {
150             using (var ms = new MemoryStream(body))
151             {
152                 using (var reader = new BinaryReader(ms))
153                 {
154                     try
155                     {
156                         var tb = reader.ReadUInt16(); // LE: x30 x81
157                         switch (tb)
158                         {
159                             case 0x8130:
160                                 reader.ReadByte(); // fw 1
161                                 break;
162                             case 0x8230:
163                                 reader.ReadInt16(); // fw 2
164                                 break;
165                             default:
166                                 return null;
167                         }
168
169                         tb = reader.ReadUInt16(); // version
170                         if (tb != 0x0102)
171                         {
172                             return null;
173                         }
174                         if (reader.ReadByte() != 0x00)
175                         {
176                             return null;
177                         }
178
179                         var modulus = ReadInt(reader);
180                         var e = ReadInt(reader);
181                         var d = ReadInt(reader);
182                         var p = ReadInt(reader);
183                         var q = ReadInt(reader);
184                         var dp = ReadInt(reader);
185                         var dq = ReadInt(reader);
186                         var iq = ReadInt(reader);
187
188                         var result = new RSACryptoServiceProvider();
189                         var param = new RSAParameters
190                         {
191                             Modulus = modulus,
192                             Exponent = e,
193                             D = d,
194                             P = p,
195                             Q = q,
196                             DP = dp,
197                             DQ = dq,
198                             InverseQ = iq
199                         };
200                         result.ImportParameters(param);
201                         return result;
202                     }
203                     finally
204                     {
205                         reader.Close();
206                     }
207                 }
208             }
209         }
210
211         private static readonly Func<BinaryReader, byte[]> ReadInt = r =>
212         {
213             var s = GetIntSize(r);
214             return r.ReadBytes(s);
215         };
216
217         private static readonly Func<BinaryReader, int> GetIntSize = r =>
218         {
219             int c;
220             var b = r.ReadByte();
221             if (b != 0x02)
222             {
223                 //int
224                 return 0;
225             }
226             b = r.ReadByte();
227
228             switch (b)
229             {
230                 case 0x81:
231                     c = r.ReadByte(); //size
232                     break;
233                 case 0x82:
234                     var hb = r.ReadByte();
235                     var lb = r.ReadByte();
236                     byte[] m = {lb, hb, 0x00, 0x00};
237                     c = BitConverter.ToInt32(m, 0);
238                     break;
239                 default:
240                     c = b; //got size
241                     break;
242             }
243
244             while (r.ReadByte() == 0x00)
245             {
246                 //remove high zero
247                 c -= 1;
248             }
249             r.BaseStream.Seek(-1, SeekOrigin.Current); // last byte is not zero, go back;
250             return c;
251         };
252
253         private static byte[] DecodePem(byte[] body, string passkey, Alg alg, byte[] salt)
254         {
255             if (alg == null) throw new ArgumentNullException("alg");
256             if (alg.AlgBase != Alg.BaseAlg.DES_EDE3 && alg.AlgMode != Alg.Mode.CBC)
257             {
258                 throw new NotSupportedException("Only 3DES-CBC keys are supported.");
259             }
260             var des = Get3DesKey(salt, passkey);
261             if (des == null)
262             {
263                 throw new ApplicationException("Unable to calculate 3DES key for decryption.");
264             }
265             var rsa = DecryptRsaKey(body, des, salt);
266             if (rsa == null)
267             {
268                 throw new ApplicationException("Unable to decrypt RSA private key.");
269             }
270             return rsa;
271         }
272
273         private static byte[] DecryptRsaKey(byte[] body, byte[] desKey, byte[] iv)
274         {
275             byte[] result;
276             using (var stream = new MemoryStream())
277             {
278                 var alg = TripleDES.Create();
279                 alg.Key = desKey;
280                 alg.IV = iv;
281                 using (var cs = new CryptoStream(stream, alg.CreateDecryptor(), CryptoStreamMode.Write))
282                 {
283                     cs.Write(body, 0, body.Length);
284                     cs.Close();
285                 }
286                 result = stream.ToArray();
287             }
288             return result;
289         }
290
291         private static byte[] Get3DesKey(byte[] salt, string passkey)
292         {
293             const int hashlength = 16;
294             const int m = 2; // 2 iterations for at least 24 bytes
295             const int c = 1; // 1 hash for Open SSL
296             var k = new byte[hashlength*m];
297
298             var pk = Encoding.ASCII.GetBytes(passkey);
299             var data = new byte[salt.Length + pk.Length];
300             Array.Copy(pk, data, pk.Length);
301             Array.Copy(salt, 0, data, pk.Length, salt.Length);
302             var md5 = new MD5CryptoServiceProvider();
303             byte[] result = null;
304             var hash = new byte[hashlength + data.Length];
305
306             for (var i = 0; i < m; i++)
307             {
308                 if (i == 0)
309                 {
310                     result = data;
311                 }
312                 else
313                 {
314                     Array.Copy(result, hash, result.Length);
315                     Array.Copy(data, 0, hash, result.Length, data.Length);
316                     result = hash;
317                 }
318
319                 for (var j = 0; j < c; j++)
320                 {
321                     result = md5.ComputeHash(result);
322                 }
323                 Array.Copy(result, 0, k, i*hashlength, result.Length);
324             }
325             var dk = new byte[24]; //final key
326             Array.Copy(k, dk, dk.Length);
327             return dk;
328         }
329
330         private class PemHeaders : Dictionary<string, string>
331         {
332         }
333
334         private sealed class Alg
335         {
336             public Alg(string alg)
337             {
338                 AlgMode = Mode.ECB;
339                 switch (alg.Trim())
340                 {
341                     //TK: DES-EDE based algorithms come only with ECB mode.
342                     case "DES-EDE":
343                         AlgBase = BaseAlg.DES_EDE;
344                         return;
345                     case "DES-EDE3":
346                         AlgBase = BaseAlg.DES_EDE3;
347                         return;
348                     default:
349                         var p = alg.LastIndexOf(‘-‘);
350                         if (p >= 0)
351                         {
352                             AlgBase = (BaseAlg) _parseVal(typeof (BaseAlg), alg.Before(p));
353                             AlgMode = (Mode) _parseVal(typeof (Mode), alg.After(p));
354                             return;
355                         }
356                         break;
357                 }
358                 throw new ArgumentException("Unknown DEK algorithm ‘{0}‘", alg);
359             }
360
361             public BaseAlg AlgBase { get; private set; }
362
363             public Mode AlgMode { get; private set; }
364
365             private readonly Func<Type, string, Enum> _parseVal = (t, s) =>
366             {
367                 s = s.Replace(‘-‘, ‘_‘);
368                 return (Enum) Enum.Parse(t, s);
369             };
370
371             public enum BaseAlg
372             {
373                 DES_EDE,
374                 DES_EDE3
375             };
376
377             public enum Mode
378             {
379                 CBC,
380                 ECB
381             };
382         }
383     }
384
385     internal static class Helper
386     {
387         public static bool IsEmpty(this string value)
388         {
389             return String.IsNullOrWhiteSpace(value);
390         }
391
392         public static string Before(this string value, int end)
393         {
394             return (end == 0 ? String.Empty : value.Between(0, end - 1));
395         }
396
397         public static string After(this string value, int start)
398         {
399             return value.Between(start + 1, Int32.MaxValue);
400         }
401
402         public static string Between(this string value, int start, int end)
403         {
404             var len = (String.IsNullOrEmpty(value) ? 0 : value.Length);
405             if (start < 0) start += len;
406             if (end < 0) end += len;
407             if (len == 0 || start > len - 1 || end < start)
408             {
409                 return String.Empty;
410             }
411             if (start < 0) start = 0;
412             if (end >= len) end = len - 1;
413             return value.Substring(start, end - start + 1);
414         }
415
416         public static string Substitute(this string format, params object[] args)
417         {
418             var value = String.Empty;
419             if (String.IsNullOrEmpty(format)) return value;
420             if (args.Length == 0) return format;
421             try
422             {
423                 return String.Format(format, args);
424             }
425             catch (FormatException)
426             {
427                 return format;
428             }
429             catch
430             {
431                 return "***";
432             }
433         }
434
435         public static TV TryGet<TK, TV>(this Dictionary<TK, TV> dictionary, TK key)
436         {
437             return dictionary.TryGet(key, default(TV));
438         }
439
440         public static TV TryGet<TK, TV>(this Dictionary<TK, TV> dictionary, TK key, TV defaultValue)
441         {
442             if (dictionary != null && dictionary.ContainsKey(key))
443             {
444                 return dictionary[key];
445             }
446             return defaultValue;
447         }
448     }
时间: 2024-11-09 02:08:40

一个完整的类用来读取OpenSSL生成的pem格式的x509证书的相关文章

一个完整的类用来生成RSACryptoServiceProvider单例类(.NET)

1 internal class CcbRsaCryptProvider 2 { 3 private static RSACryptoServiceProvider _providerForSign; 4 private static RSACryptoServiceProvider _providerForVerifySign; 5 private static readonly object SignObj = new object(); 6 private static readonly

用openssl生成SSL使用的私钥和证书,并自己做CA签名(转)

本 文记叙的是一次基于SSL的socket通讯程序开发中,有关证书,签名,身份验证相关的步骤. 我们的场景下,socket服务端是java语言编写的,客户端是c语言.使用了一个叫做matrixssl的c语言库.自己做CA签名,不等同于“自签 名”. 自签名的情况,RSA的公钥私钥只有一对,用私钥对公钥证书做签名.而我们的场景是,自己做CA,有一个CA的公钥私钥对. 而socket的服务端也有一个公钥私钥对. 用CA的私钥对socket服务端的公钥证书做签名. openssl genrsa -ou

用openssl生成SSL使用的私钥和证书,并自己做CA签名

自签名的情况,RSA的公钥私钥只有一对,用私钥对公钥证书做签名.而我们的场景是,自己做CA,有一个CA的公钥私钥对. 而socket的服务端也有一个公钥私钥对. 用CA的私钥对socket服务端的公钥证书做签名.1.创建key,没有用des3加密 openssl genrsa -out ca.key 1024 2.需要在提示之下输入许多信息,包括国家代码,省份,城市,公司机构名等 openssl req -new -x509 -days 36500 -key ca.key -out ca.crt

.NET使用OpenSSL生成的pem密钥文件[1024位]

using System; using System.Text; using System.Security.Cryptography; using System.Web; using System.IO; namespace Thinhunan.Cnblogs.Com.RSAUtility { public class PemConverter { /// <summary> /// 将pem格式公钥转换为RSAParameters /// </summary> /// <

我写的一个ExcelHelper通用类,可用于读取或生成数据

读取或生成EXCEL数据的方法有很多,一般常见的有: 1.通过OFFICE EXCEL组件,优点:读取与生成EXCEL文件方便,缺点:服务器上必须安装OFFICE软件,且进程无法及时释放 2.通过第三方组件(比如:NPOI),优点:无需安装OFFICE软件,缺点:需要引入第三方组件,当然这个还是比较强的 3.通过把EXCEL当成数据库,连接后运用SQL语句读取,写入的话就自行拼接成HTML表格,优点:无需另外的组件,缺点:需要会SQL及拼接HTML表格较麻烦: 三种方法我都有用过,若开发BS网站

设计一个串口装饰类(1)

团队正在开发一个仪器控制软件的框架,希望该框架能兼容/容忍一些硬件的变换,以及灵活定制建立在该硬件平台之上的工作流.目标仪器使用了很多的串口通信(Serial Port),所以大家觉得应该设计/封装一个统一的串口类来管理串口通信的一致性.就我个人的意见来说,我不是建议在System.IO.Port.SerialPort上再做封装的.串口通信逻辑很简单,基本就是I/O.该类已经提供了同步阻塞模型.基于事件的异步模型,各种I/O快捷方法,所以不认为封装该类可以获得什么更多好处.但是面对框架的 一些其

开发一个完整的JavaScript组件

作为一名开发者,大家应该都知道在浏览器中存在一些内置的控件:Alert,Confirm等,但是这些控件通常根据浏览器产商的不同而形态各异,视觉效果往往达不到UI设计师的要求.更重要的是,这类内置控件的风格很难与形形色色的各种风格迥异的互联网产品的设计风格统一.因此,优秀的前端开发者们各自开发自己的个性化控件来替代浏览器内置的这些控件.当然,这类组件在网络上已经有不计其数相当优秀的,写这篇文章的目的不是为了说明我开发的这个组件有多优秀,也不是为了炫耀什么,只是希望通过这种方式,与更多的开发者互相交

【原创】开发一个完整的JavaScript组件

作为一名开发者,大家应该都知道在浏览器中存在一些内置的控件:Alert,Confirm等,但是这些控件通常根据浏览器产商的不同而形态各异,视觉效果往往达不到UI设计师的要求.更重要的是,这类内置控件的风格很难与形形色色的各种风格迥异的互联网产品的设计风格统一.因此,优秀的前端开发者们各自开发自己的个性化控件来替代浏览器内置的这些控件.当然,这类组件在网络上已经有不计其数相当优秀的,写这篇文章的目的不是为了说明我开发的这个组件有多优秀,也不是为了炫耀什么,只是希望通过这种方式,与更多的开发者互相交

[转]开发一个完整的JavaScript组件

原创:http://www.admin10000.com/document/5961.html 作为一名开发者,大家应该都知道在浏览器中存在一些内置的控件:Alert,Confirm等,但是这些控件通常根据浏览器产商的不同而形态各异,视觉效果往往达不到UI设计师的要求.更重要的是,这类内置控件的风格很难与形形色色的各种风格迥异的互联网产品的设计风格统一.因此,优秀的前端开发者们各自开发自己的个性化控件来替代浏览器内置的这些控件.当然,这类组件在网络上已经有不计其数相当优秀的,写这篇文章的目的不是