~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/CryptoConvert.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
30
 
using System;
31
 
using System.Globalization;
32
 
using System.Security.Cryptography;
33
 
using System.Text;
34
 
 
35
 
namespace 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
 
}