Free cookie consent management tool by TermsFeed Policy Generator

source: branches/CodeEditor/HeuristicLab.ExtLibs/HeuristicLab.NRefactory/5.5.0/NRefactory.CSharp-5.5.0/Parser/mcs/CryptoConvert.cs @ 11700

Last change on this file since 11700 was 11700, checked in by jkarder, 9 years ago

#2077: created branch and added first version

File size: 20.9 KB
Line 
1//
2// CryptoConvert.cs - Crypto Convertion Routines
3//
4// Author:
5//  Sebastien Pouliot  <sebastien@ximian.com>
6//
7// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
9//
10// Permission is hereby granted, free of charge, to any person obtaining
11// a copy of this software and associated documentation files (the
12// "Software"), to deal in the Software without restriction, including
13// without limitation the rights to use, copy, modify, merge, publish,
14// distribute, sublicense, and/or sell copies of the Software, and to
15// permit persons to whom the Software is furnished to do so, subject to
16// the following conditions:
17//
18// The above copyright notice and this permission notice shall be
19// included in all copies or substantial portions of the Software.
20//
21// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28//
29
30using System;
31using System.Globalization;
32using System.Security.Cryptography;
33using System.Text;
34
35namespace Mono.Security.Cryptography {
36
37#if INSIDE_CORLIB
38  internal
39#else
40  public
41#endif
42  sealed class CryptoConvert {
43
44    private CryptoConvert ()
45    {
46    }
47
48    static private int ToInt32LE (byte [] bytes, int offset)
49    {
50      return (bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset];
51    }
52
53    static private uint ToUInt32LE (byte [] bytes, int offset)
54    {
55      return (uint)((bytes [offset+3] << 24) | (bytes [offset+2] << 16) | (bytes [offset+1] << 8) | bytes [offset]);
56    }
57
58    static private byte [] GetBytesLE (int val)
59    {
60      return new byte [] {
61        (byte) (val & 0xff),
62        (byte) ((val >> 8) & 0xff),
63        (byte) ((val >> 16) & 0xff),
64        (byte) ((val >> 24) & 0xff)
65      };
66                }
67
68    static private byte[] Trim (byte[] array)
69    {
70      for (int i=0; i < array.Length; i++) {
71        if (array [i] != 0x00) {
72          byte[] result = new byte [array.Length - i];
73          Buffer.BlockCopy (array, i, result, 0, result.Length);
74          return result;
75        }
76      }
77      return null;
78    }
79
80    // convert the key from PRIVATEKEYBLOB to RSA
81    // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/Security/private_key_blobs.asp
82    // e.g. SNK files, PVK files
83    static public RSA FromCapiPrivateKeyBlob (byte[] blob)
84    {
85      return FromCapiPrivateKeyBlob (blob, 0);
86    }
87
88    static public RSA FromCapiPrivateKeyBlob (byte[] blob, int offset)
89    {
90      if (blob == null)
91        throw new ArgumentNullException ("blob");
92      if (offset >= blob.Length)
93        throw new ArgumentException ("blob is too small.");
94
95      RSAParameters rsap = new RSAParameters ();
96      try {
97        if ((blob [offset]   != 0x07) ||        // PRIVATEKEYBLOB (0x07)
98            (blob [offset+1] != 0x02) ||        // Version (0x02)
99            (blob [offset+2] != 0x00) ||        // Reserved (word)
100            (blob [offset+3] != 0x00) ||
101            (ToUInt32LE (blob, offset+8) != 0x32415352))  // DWORD magic = RSA2
102          throw new CryptographicException ("Invalid blob header");
103       
104        // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
105        // int algId = ToInt32LE (blob, offset+4);
106
107        // DWORD bitlen
108        int bitLen = ToInt32LE (blob, offset+12);
109
110        // DWORD public exponent
111        byte[] exp = new byte [4];
112        Buffer.BlockCopy (blob, offset+16, exp, 0, 4);
113        Array.Reverse (exp);
114        rsap.Exponent = Trim (exp);
115     
116        int pos = offset+20;
117        // BYTE modulus[rsapubkey.bitlen/8];
118        int byteLen = (bitLen >> 3);
119        rsap.Modulus = new byte [byteLen];
120        Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
121        Array.Reverse (rsap.Modulus);
122        pos += byteLen;
123
124        // BYTE prime1[rsapubkey.bitlen/16];
125        int byteHalfLen = (byteLen >> 1);
126        rsap.P = new byte [byteHalfLen];
127        Buffer.BlockCopy (blob, pos, rsap.P, 0, byteHalfLen);
128        Array.Reverse (rsap.P);
129        pos += byteHalfLen;
130
131        // BYTE prime2[rsapubkey.bitlen/16];
132        rsap.Q = new byte [byteHalfLen];
133        Buffer.BlockCopy (blob, pos, rsap.Q, 0, byteHalfLen);
134        Array.Reverse (rsap.Q);
135        pos += byteHalfLen;
136
137        // BYTE exponent1[rsapubkey.bitlen/16];
138        rsap.DP = new byte [byteHalfLen];
139        Buffer.BlockCopy (blob, pos, rsap.DP, 0, byteHalfLen);
140        Array.Reverse (rsap.DP);
141        pos += byteHalfLen;
142
143        // BYTE exponent2[rsapubkey.bitlen/16];
144        rsap.DQ = new byte [byteHalfLen];
145        Buffer.BlockCopy (blob, pos, rsap.DQ, 0, byteHalfLen);
146        Array.Reverse (rsap.DQ);
147        pos += byteHalfLen;
148
149        // BYTE coefficient[rsapubkey.bitlen/16];
150        rsap.InverseQ = new byte [byteHalfLen];
151        Buffer.BlockCopy (blob, pos, rsap.InverseQ, 0, byteHalfLen);
152        Array.Reverse (rsap.InverseQ);
153        pos += byteHalfLen;
154
155        // ok, this is hackish but CryptoAPI support it so...
156        // note: only works because CRT is used by default
157        // http://bugzilla.ximian.com/show_bug.cgi?id=57941
158        rsap.D = new byte [byteLen]; // must be allocated
159        if (pos + byteLen + offset <= blob.Length) {
160          // BYTE privateExponent[rsapubkey.bitlen/8];
161          Buffer.BlockCopy (blob, pos, rsap.D, 0, byteLen);
162          Array.Reverse (rsap.D);
163        }
164      }
165      catch (Exception e) {
166        throw new CryptographicException ("Invalid blob.", e);
167      }
168
169#if NET_2_1
170      RSA rsa = RSA.Create ();
171      rsa.ImportParameters (rsap);
172#else
173      RSA rsa = null;
174      try {
175        rsa = RSA.Create ();
176        rsa.ImportParameters (rsap);
177      }
178      catch (CryptographicException ce) {
179        // this may cause problem when this code is run under
180        // the SYSTEM identity on Windows (e.g. ASP.NET). See
181        // http://bugzilla.ximian.com/show_bug.cgi?id=77559
182        try {
183          CspParameters csp = new CspParameters ();
184          csp.Flags = CspProviderFlags.UseMachineKeyStore;
185          rsa = new RSACryptoServiceProvider (csp);
186          rsa.ImportParameters (rsap);
187        }
188        catch {
189          // rethrow original, not the later, exception if this fails
190          throw ce;
191        }
192      }
193#endif
194      return rsa;
195    }
196
197    static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob)
198    {
199      return FromCapiPrivateKeyBlobDSA (blob, 0);
200    }
201
202    static public DSA FromCapiPrivateKeyBlobDSA (byte[] blob, int offset)
203    {
204      if (blob == null)
205        throw new ArgumentNullException ("blob");
206      if (offset >= blob.Length)
207        throw new ArgumentException ("blob is too small.");
208
209      DSAParameters dsap = new DSAParameters ();
210      try {
211        if ((blob [offset] != 0x07) ||        // PRIVATEKEYBLOB (0x07)
212            (blob [offset + 1] != 0x02) ||      // Version (0x02)
213            (blob [offset + 2] != 0x00) ||      // Reserved (word)
214            (blob [offset + 3] != 0x00) ||
215            (ToUInt32LE (blob, offset + 8) != 0x32535344))  // DWORD magic
216          throw new CryptographicException ("Invalid blob header");
217
218        int bitlen = ToInt32LE (blob, offset + 12);
219        int bytelen = bitlen >> 3;
220        int pos = offset + 16;
221
222        dsap.P = new byte [bytelen];
223        Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
224        Array.Reverse (dsap.P);
225        pos += bytelen;
226
227        dsap.Q = new byte [20];
228        Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
229        Array.Reverse (dsap.Q);
230        pos += 20;
231
232        dsap.G = new byte [bytelen];
233        Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
234        Array.Reverse (dsap.G);
235        pos += bytelen;
236
237        dsap.X = new byte [20];
238        Buffer.BlockCopy (blob, pos, dsap.X, 0, 20);
239        Array.Reverse (dsap.X);
240        pos += 20;
241
242        dsap.Counter = ToInt32LE (blob, pos);
243        pos += 4;
244
245        dsap.Seed = new byte [20];
246        Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
247        Array.Reverse (dsap.Seed);
248        pos += 20;
249      }
250      catch (Exception e) {
251        throw new CryptographicException ("Invalid blob.", e);
252      }
253
254#if NET_2_1
255      DSA dsa = (DSA)DSA.Create ();
256      dsa.ImportParameters (dsap);
257#else
258      DSA dsa = null;
259      try {
260        dsa = (DSA)DSA.Create ();
261        dsa.ImportParameters (dsap);
262      }
263      catch (CryptographicException ce) {
264        // this may cause problem when this code is run under
265        // the SYSTEM identity on Windows (e.g. ASP.NET). See
266        // http://bugzilla.ximian.com/show_bug.cgi?id=77559
267        try {
268          CspParameters csp = new CspParameters ();
269          csp.Flags = CspProviderFlags.UseMachineKeyStore;
270          dsa = new DSACryptoServiceProvider (csp);
271          dsa.ImportParameters (dsap);
272        }
273        catch {
274          // rethrow original, not the later, exception if this fails
275          throw ce;
276        }
277      }
278#endif
279      return dsa;
280    }
281
282    static public byte[] ToCapiPrivateKeyBlob (RSA rsa)
283    {
284      RSAParameters p = rsa.ExportParameters (true);
285      int keyLength = p.Modulus.Length; // in bytes
286      byte[] blob = new byte [20 + (keyLength << 2) + (keyLength >> 1)];
287
288      blob [0] = 0x07;  // Type - PRIVATEKEYBLOB (0x07)
289      blob [1] = 0x02;  // Version - Always CUR_BLOB_VERSION (0x02)
290      // [2], [3]   // RESERVED - Always 0
291      blob [5] = 0x24;  // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
292      blob [8] = 0x52;  // Magic - RSA2 (ASCII in hex)
293      blob [9] = 0x53;
294      blob [10] = 0x41;
295      blob [11] = 0x32;
296
297      byte[] bitlen = GetBytesLE (keyLength << 3);
298      blob [12] = bitlen [0]; // bitlen
299      blob [13] = bitlen [1];
300      blob [14] = bitlen [2];
301      blob [15] = bitlen [3];
302
303      // public exponent (DWORD)
304      int pos = 16;
305      int n = p.Exponent.Length;
306      while (n > 0)
307        blob [pos++] = p.Exponent [--n];
308      // modulus
309      pos = 20;
310      byte[] part = p.Modulus;
311      int len = part.Length;
312      Array.Reverse (part, 0, len);
313      Buffer.BlockCopy (part, 0, blob, pos, len);
314      pos += len;
315      // private key
316      part = p.P;
317      len = part.Length;
318      Array.Reverse (part, 0, len);
319      Buffer.BlockCopy (part, 0, blob, pos, len);
320      pos += len;
321
322      part = p.Q;
323      len = part.Length;
324      Array.Reverse (part, 0, len);
325      Buffer.BlockCopy (part, 0, blob, pos, len);
326      pos += len;
327
328      part = p.DP;
329      len = part.Length;
330      Array.Reverse (part, 0, len);
331      Buffer.BlockCopy (part, 0, blob, pos, len);
332      pos += len;
333
334      part = p.DQ;
335      len = part.Length;
336      Array.Reverse (part, 0, len);
337      Buffer.BlockCopy (part, 0, blob, pos, len);
338      pos += len;
339
340      part = p.InverseQ;
341      len = part.Length;
342      Array.Reverse (part, 0, len);
343      Buffer.BlockCopy (part, 0, blob, pos, len);
344      pos += len;
345
346      part = p.D;
347      len = part.Length;
348      Array.Reverse (part, 0, len);
349      Buffer.BlockCopy (part, 0, blob, pos, len);
350
351      return blob;
352    }
353
354    static public byte[] ToCapiPrivateKeyBlob (DSA dsa)
355    {
356      DSAParameters p = dsa.ExportParameters (true);
357      int keyLength = p.P.Length; // in bytes
358
359      // header + P + Q + G + X + count + seed
360      byte[] blob = new byte [16 + keyLength + 20 + keyLength + 20 + 4 + 20];
361
362      blob [0] = 0x07;  // Type - PRIVATEKEYBLOB (0x07)
363      blob [1] = 0x02;  // Version - Always CUR_BLOB_VERSION (0x02)
364      // [2], [3]   // RESERVED - Always 0
365      blob [5] = 0x22;  // ALGID
366      blob [8] = 0x44;  // Magic
367      blob [9] = 0x53;
368      blob [10] = 0x53;
369      blob [11] = 0x32;
370
371      byte[] bitlen = GetBytesLE (keyLength << 3);
372      blob [12] = bitlen [0];
373      blob [13] = bitlen [1];
374      blob [14] = bitlen [2];
375      blob [15] = bitlen [3];
376
377      int pos = 16;
378      byte[] part = p.P;
379      Array.Reverse (part);
380      Buffer.BlockCopy (part, 0, blob, pos, keyLength);
381      pos += keyLength;
382
383      part = p.Q;
384      Array.Reverse (part);
385      Buffer.BlockCopy (part, 0, blob, pos, 20);
386      pos += 20;
387
388      part = p.G;
389      Array.Reverse (part);
390      Buffer.BlockCopy (part, 0, blob, pos, keyLength);
391      pos += keyLength;
392
393      part = p.X;
394      Array.Reverse (part);
395      Buffer.BlockCopy (part, 0, blob, pos, 20);
396      pos += 20;
397
398      Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
399      pos += 4;
400
401      part = p.Seed;
402      Array.Reverse (part);
403      Buffer.BlockCopy (part, 0, blob, pos, 20);
404
405      return blob;
406    }
407
408    static public RSA FromCapiPublicKeyBlob (byte[] blob)
409    {
410      return FromCapiPublicKeyBlob (blob, 0);
411    }
412
413    static public RSA FromCapiPublicKeyBlob (byte[] blob, int offset)
414    {
415      if (blob == null)
416        throw new ArgumentNullException ("blob");
417      if (offset >= blob.Length)
418        throw new ArgumentException ("blob is too small.");
419
420      try {
421        if ((blob [offset]   != 0x06) ||        // PUBLICKEYBLOB (0x06)
422            (blob [offset+1] != 0x02) ||        // Version (0x02)
423            (blob [offset+2] != 0x00) ||        // Reserved (word)
424            (blob [offset+3] != 0x00) ||
425            (ToUInt32LE (blob, offset+8) != 0x31415352))  // DWORD magic = RSA1
426          throw new CryptographicException ("Invalid blob header");
427
428        // ALGID (CALG_RSA_SIGN, CALG_RSA_KEYX, ...)
429        // int algId = ToInt32LE (blob, offset+4);
430
431        // DWORD bitlen
432        int bitLen = ToInt32LE (blob, offset+12);
433
434        // DWORD public exponent
435        RSAParameters rsap = new RSAParameters ();
436        rsap.Exponent = new byte [3];
437        rsap.Exponent [0] = blob [offset+18];
438        rsap.Exponent [1] = blob [offset+17];
439        rsap.Exponent [2] = blob [offset+16];
440     
441        int pos = offset+20;
442        // BYTE modulus[rsapubkey.bitlen/8];
443        int byteLen = (bitLen >> 3);
444        rsap.Modulus = new byte [byteLen];
445        Buffer.BlockCopy (blob, pos, rsap.Modulus, 0, byteLen);
446        Array.Reverse (rsap.Modulus);
447#if NET_2_1
448        RSA rsa = RSA.Create ();
449        rsa.ImportParameters (rsap);
450#else
451        RSA rsa = null;
452        try {
453          rsa = RSA.Create ();
454          rsa.ImportParameters (rsap);
455        }
456        catch (CryptographicException) {
457          // this may cause problem when this code is run under
458          // the SYSTEM identity on Windows (e.g. ASP.NET). See
459          // http://bugzilla.ximian.com/show_bug.cgi?id=77559
460          CspParameters csp = new CspParameters ();
461          csp.Flags = CspProviderFlags.UseMachineKeyStore;
462          rsa = new RSACryptoServiceProvider (csp);
463          rsa.ImportParameters (rsap);
464        }
465#endif
466        return rsa;
467      }
468      catch (Exception e) {
469        throw new CryptographicException ("Invalid blob.", e);
470      }
471    }
472
473    static public DSA FromCapiPublicKeyBlobDSA (byte[] blob)
474    {
475      return FromCapiPublicKeyBlobDSA (blob, 0);
476    }
477
478    static public DSA FromCapiPublicKeyBlobDSA (byte[] blob, int offset)
479    {
480      if (blob == null)
481        throw new ArgumentNullException ("blob");
482      if (offset >= blob.Length)
483        throw new ArgumentException ("blob is too small.");
484
485      try {
486        if ((blob [offset] != 0x06) ||        // PUBLICKEYBLOB (0x06)
487            (blob [offset + 1] != 0x02) ||      // Version (0x02)
488            (blob [offset + 2] != 0x00) ||      // Reserved (word)
489            (blob [offset + 3] != 0x00) ||
490            (ToUInt32LE (blob, offset + 8) != 0x31535344))  // DWORD magic
491          throw new CryptographicException ("Invalid blob header");
492
493        int bitlen = ToInt32LE (blob, offset + 12);
494        DSAParameters dsap = new DSAParameters ();
495        int bytelen = bitlen >> 3;
496        int pos = offset + 16;
497
498        dsap.P = new byte [bytelen];
499        Buffer.BlockCopy (blob, pos, dsap.P, 0, bytelen);
500        Array.Reverse (dsap.P);
501        pos += bytelen;
502
503        dsap.Q = new byte [20];
504        Buffer.BlockCopy (blob, pos, dsap.Q, 0, 20);
505        Array.Reverse (dsap.Q);
506        pos += 20;
507
508        dsap.G = new byte [bytelen];
509        Buffer.BlockCopy (blob, pos, dsap.G, 0, bytelen);
510        Array.Reverse (dsap.G);
511        pos += bytelen;
512
513        dsap.Y = new byte [bytelen];
514        Buffer.BlockCopy (blob, pos, dsap.Y, 0, bytelen);
515        Array.Reverse (dsap.Y);
516        pos += bytelen;
517
518        dsap.Counter = ToInt32LE (blob, pos);
519        pos += 4;
520
521        dsap.Seed = new byte [20];
522        Buffer.BlockCopy (blob, pos, dsap.Seed, 0, 20);
523        Array.Reverse (dsap.Seed);
524        pos += 20;
525
526        DSA dsa = (DSA)DSA.Create ();
527        dsa.ImportParameters (dsap);
528        return dsa;
529      }
530      catch (Exception e) {
531        throw new CryptographicException ("Invalid blob.", e);
532      }
533    }
534
535    static public byte[] ToCapiPublicKeyBlob (RSA rsa)
536    {
537      RSAParameters p = rsa.ExportParameters (false);
538      int keyLength = p.Modulus.Length; // in bytes
539      byte[] blob = new byte [20 + keyLength];
540
541      blob [0] = 0x06;  // Type - PUBLICKEYBLOB (0x06)
542      blob [1] = 0x02;  // Version - Always CUR_BLOB_VERSION (0x02)
543      // [2], [3]   // RESERVED - Always 0
544      blob [5] = 0x24;  // ALGID - Always 00 24 00 00 (for CALG_RSA_SIGN)
545      blob [8] = 0x52;  // Magic - RSA1 (ASCII in hex)
546      blob [9] = 0x53;
547      blob [10] = 0x41;
548      blob [11] = 0x31;
549
550      byte[] bitlen = GetBytesLE (keyLength << 3);
551      blob [12] = bitlen [0]; // bitlen
552      blob [13] = bitlen [1];
553      blob [14] = bitlen [2];
554      blob [15] = bitlen [3];
555
556      // public exponent (DWORD)
557      int pos = 16;
558      int n = p.Exponent.Length;
559      while (n > 0)
560        blob [pos++] = p.Exponent [--n];
561      // modulus
562      pos = 20;
563      byte[] part = p.Modulus;
564      int len = part.Length;
565      Array.Reverse (part, 0, len);
566      Buffer.BlockCopy (part, 0, blob, pos, len);
567      pos += len;
568      return blob;
569    }
570
571    static public byte[] ToCapiPublicKeyBlob (DSA dsa)
572    {
573      DSAParameters p = dsa.ExportParameters (false);
574      int keyLength = p.P.Length; // in bytes
575
576      // header + P + Q + G + Y + count + seed
577      byte[] blob = new byte [16 + keyLength + 20 + keyLength + keyLength + 4 + 20];
578
579      blob [0] = 0x06;  // Type - PUBLICKEYBLOB (0x06)
580      blob [1] = 0x02;  // Version - Always CUR_BLOB_VERSION (0x02)
581      // [2], [3]   // RESERVED - Always 0
582      blob [5] = 0x22;  // ALGID
583      blob [8] = 0x44;  // Magic
584      blob [9] = 0x53;
585      blob [10] = 0x53;
586      blob [11] = 0x31;
587
588      byte[] bitlen = GetBytesLE (keyLength << 3);
589      blob [12] = bitlen [0];
590      blob [13] = bitlen [1];
591      blob [14] = bitlen [2];
592      blob [15] = bitlen [3];
593
594      int pos = 16;
595      byte[] part;
596
597      part = p.P;
598      Array.Reverse (part);
599      Buffer.BlockCopy (part, 0, blob, pos, keyLength);
600      pos += keyLength;
601
602      part = p.Q;
603      Array.Reverse (part);
604      Buffer.BlockCopy (part, 0, blob, pos, 20);
605      pos += 20;
606
607      part = p.G;
608      Array.Reverse (part);
609      Buffer.BlockCopy (part, 0, blob, pos, keyLength);
610      pos += keyLength;
611
612      part = p.Y;
613      Array.Reverse (part);
614      Buffer.BlockCopy (part, 0, blob, pos, keyLength);
615      pos += keyLength;
616
617      Buffer.BlockCopy (GetBytesLE (p.Counter), 0, blob, pos, 4);
618      pos += 4;
619
620      part = p.Seed;
621      Array.Reverse (part);
622      Buffer.BlockCopy (part, 0, blob, pos, 20);
623
624      return blob;
625    }
626
627    // PRIVATEKEYBLOB
628    // PUBLICKEYBLOB
629    static public RSA FromCapiKeyBlob (byte[] blob)
630    {
631      return FromCapiKeyBlob (blob, 0);
632    }
633
634    static public RSA FromCapiKeyBlob (byte[] blob, int offset)
635    {
636      if (blob == null)
637        throw new ArgumentNullException ("blob");
638      if (offset >= blob.Length)
639        throw new ArgumentException ("blob is too small.");
640
641      switch (blob [offset]) {
642        case 0x00:
643          // this could be a public key inside an header
644          // like "sn -e" would produce
645          if (blob [offset + 12] == 0x06) {
646            return FromCapiPublicKeyBlob (blob, offset + 12);
647          }
648          break;
649        case 0x06:
650          return FromCapiPublicKeyBlob (blob, offset);
651        case 0x07:
652          return FromCapiPrivateKeyBlob (blob, offset);
653      }
654      throw new CryptographicException ("Unknown blob format.");
655    }
656
657    static public DSA FromCapiKeyBlobDSA (byte[] blob)
658    {
659      return FromCapiKeyBlobDSA (blob, 0);
660    }
661
662    static public DSA FromCapiKeyBlobDSA (byte[] blob, int offset)
663    {
664      if (blob == null)
665        throw new ArgumentNullException ("blob");
666      if (offset >= blob.Length)
667        throw new ArgumentException ("blob is too small.");
668
669      switch (blob [offset]) {
670        case 0x06:
671          return FromCapiPublicKeyBlobDSA (blob, offset);
672        case 0x07:
673          return FromCapiPrivateKeyBlobDSA (blob, offset);
674      }
675      throw new CryptographicException ("Unknown blob format.");
676    }
677
678    static public byte[] ToCapiKeyBlob (AsymmetricAlgorithm keypair, bool includePrivateKey)
679    {
680      if (keypair == null)
681        throw new ArgumentNullException ("keypair");
682
683      // check between RSA and DSA (and potentially others like DH)
684      if (keypair is RSA)
685        return ToCapiKeyBlob ((RSA)keypair, includePrivateKey);
686      else if (keypair is DSA)
687        return ToCapiKeyBlob ((DSA)keypair, includePrivateKey);
688      else
689        return null;  // TODO
690    }
691
692    static public byte[] ToCapiKeyBlob (RSA rsa, bool includePrivateKey)
693    {
694      if (rsa == null)
695        throw new ArgumentNullException ("rsa");
696
697      if (includePrivateKey)
698        return ToCapiPrivateKeyBlob (rsa);
699      else
700        return ToCapiPublicKeyBlob (rsa);
701    }
702
703    static public byte[] ToCapiKeyBlob (DSA dsa, bool includePrivateKey)
704    {
705      if (dsa == null)
706        throw new ArgumentNullException ("dsa");
707
708      if (includePrivateKey)
709        return ToCapiPrivateKeyBlob (dsa);
710      else
711        return ToCapiPublicKeyBlob (dsa);
712    }
713
714    static public string ToHex (byte[] input)
715    {
716      if (input == null)
717        return null;
718
719      StringBuilder sb = new StringBuilder (input.Length * 2);
720      foreach (byte b in input) {
721        sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
722      }
723      return sb.ToString ();
724    }
725
726    static private byte FromHexChar (char c)
727    {
728      if ((c >= 'a') && (c <= 'f'))
729        return (byte) (c - 'a' + 10);
730      if ((c >= 'A') && (c <= 'F'))
731        return (byte) (c - 'A' + 10);
732      if ((c >= '0') && (c <= '9'))
733        return (byte) (c - '0');
734      throw new ArgumentException ("invalid hex char");
735    }
736
737    static public byte[] FromHex (string hex)
738    {
739      if (hex == null)
740        return null;
741      if ((hex.Length & 0x1) == 0x1)
742        throw new ArgumentException ("Length must be a multiple of 2");
743
744      byte[] result = new byte [hex.Length >> 1];
745      int n = 0;
746      int i = 0;
747      while (n < result.Length) {
748        result [n] = (byte) (FromHexChar (hex [i++]) << 4);
749        result [n++] += FromHexChar (hex [i++]);
750      }
751      return result;
752    }
753  }
754}
Note: See TracBrowser for help on using the repository browser.