/xmlbench/trunk

To get this branch, use:
bzr branch http://darksoft.org/webbzr/xmlbench/trunk

« back to all changes in this revision

Viewing changes to security/tools/opensslkey.cs

  • Committer: Suren A. Chilingaryan
  • Date: 2009-10-08 03:17:59 UTC
  • Revision ID: csa@dside.dyndns.org-20091008031759-u5ys779huye7feni
LibXML Pull Parser, FAXPP Parser, Mono security benchmark, multiple fixes

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//**********************************************************************************
 
2
//
 
3
//OpenSSLKey
 
4
// .NET 2.0  OpenSSL Public & Private Key Parser
 
5
//
 
6
// Copyright (C) 2008   JavaScience Consulting
 
7
//
 
8
//***********************************************************************************
 
9
//
 
10
//  opensslkey.cs
 
11
//
 
12
//  Reads and parses:
 
13
//    (1) OpenSSL PEM or DER public keys
 
14
//    (2) OpenSSL PEM or DER traditional SSLeay private keys (encrypted and unencrypted)
 
15
//    (3) PKCS #8 PEM or DER encoded private keys (encrypted and unencrypted)
 
16
//  Keys in PEM format must have headers/footers .
 
17
//  Encrypted Private Key in SSLEay format not supported in DER
 
18
//  Removes header/footer lines.
 
19
//  For traditional SSLEAY PEM private keys, checks for encrypted format and
 
20
//  uses PBE to extract 3DES key.
 
21
//  For SSLEAY format, only supports encryption format: DES-EDE3-CBC
 
22
//  For PKCS #8, only supports PKCS#5 v2.0  3des.
 
23
//  Parses private and public key components and returns .NET RSA object.
 
24
//  Creates dummy unsigned certificate linked to private keypair and
 
25
//  optionally exports to pkcs #12
 
26
//
 
27
// See also: 
 
28
//  http://www.openssl.org/docs/crypto/pem.html#PEM_ENCRYPTION_FORMAT 
 
29
//**************************************************************************************
 
30
 
 
31
using System;
 
32
using System.IO;
 
33
using System.Text;
 
34
using System.Security.Cryptography;
 
35
using System.Security.Cryptography.X509Certificates;
 
36
using System.Runtime.InteropServices;
 
37
using System.Security;
 
38
using System.Diagnostics;
 
39
using System.ComponentModel;
 
40
 
 
41
 
 
42
namespace JavaScience {
 
43
 
 
44
public class Win32 {
 
45
 
 
46
 [DllImport("crypt32.dll", SetLastError=true)]
 
47
    public static extern IntPtr CertCreateSelfSignCertificate(
 
48
        IntPtr hProv,
 
49
        ref CERT_NAME_BLOB pSubjectIssuerBlob,
 
50
        uint dwFlagsm,
 
51
        ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
 
52
        IntPtr pSignatureAlgorithm,
 
53
        IntPtr pStartTime,
 
54
        IntPtr pEndTime,
 
55
        IntPtr other) ;
 
56
 
 
57
 
 
58
 [DllImport("crypt32.dll", SetLastError=true)]
 
59
   public static extern bool CertStrToName(
 
60
        uint dwCertEncodingType,
 
61
        String pszX500,
 
62
        uint dwStrType,
 
63
        IntPtr pvReserved,
 
64
        [In, Out] byte[] pbEncoded,
 
65
        ref uint pcbEncoded,
 
66
        IntPtr other);
 
67
 
 
68
 [DllImport("crypt32.dll", SetLastError=true)]
 
69
    public static extern bool CertFreeCertificateContext(
 
70
        IntPtr hCertStore) ;
 
71
 
 
72
}
 
73
 
 
74
 
 
75
 [StructLayout(LayoutKind.Sequential)]
 
76
  public struct CRYPT_KEY_PROV_INFO
 
77
  {
 
78
        [MarshalAs(UnmanagedType.LPWStr)]  public String pwszContainerName;  
 
79
        [MarshalAs(UnmanagedType.LPWStr)]  public String pwszProvName;  
 
80
        public uint dwProvType;  
 
81
        public uint dwFlags;  
 
82
        public uint cProvParam;
 
83
        public IntPtr rgProvParam;
 
84
        public uint dwKeySpec;
 
85
  }
 
86
 
 
87
 [StructLayout(LayoutKind.Sequential)]
 
88
  public struct CERT_NAME_BLOB
 
89
  {
 
90
        public int cbData;
 
91
        public IntPtr pbData;
 
92
  }
 
93
 
 
94
 
 
95
 
 
96
public class opensslkey {
 
97
 
 
98
 const  String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----" ;
 
99
 const  String pemprivfooter   = "-----END RSA PRIVATE KEY-----" ;
 
100
 const  String pempubheader = "-----BEGIN PUBLIC KEY-----" ;
 
101
 const  String pempubfooter   = "-----END PUBLIC KEY-----" ;
 
102
 const  String pemp8header = "-----BEGIN PRIVATE KEY-----" ;
 
103
 const  String pemp8footer   = "-----END PRIVATE KEY-----" ;
 
104
 const  String pemp8encheader = "-----BEGIN ENCRYPTED PRIVATE KEY-----" ;
 
105
 const  String pemp8encfooter   = "-----END ENCRYPTED PRIVATE KEY-----" ;
 
106
 
 
107
// static byte[] pempublickey;
 
108
// static byte[] pemprivatekey;
 
109
// static byte[] pkcs8privatekey;
 
110
// static byte[] pkcs8encprivatekey;
 
111
 
 
112
 static bool verbose = false;
 
113
 
 
114
 public static void Main(String[] args) {
 
115
  
 
116
  if(args.Length == 1)
 
117
        if(args[0].ToUpper() == "V")
 
118
                verbose = true;
 
119
 
 
120
  Console.ForegroundColor = ConsoleColor.Gray;
 
121
  Console.Write("\nRSA public, private or PKCS #8  key file to decode: ");
 
122
  String filename = Console.ReadLine().Trim();
 
123
  if (filename == "")  //exit while(true) loop
 
124
        return;
 
125
      if (!File.Exists(filename)) {
 
126
         Console.WriteLine("File \"{0}\" does not exist!\n", filename);
 
127
         return;        
 
128
      }
 
129
 
 
130
        StreamReader sr = File.OpenText(filename);
 
131
        String pemstr = sr.ReadToEnd().Trim();
 
132
        sr.Close();
 
133
        if(pemstr.StartsWith("-----BEGIN"))
 
134
                DecodePEMKey(pemstr);
 
135
        else
 
136
                DecodeDERKey(filename);
 
137
  }
 
138
 
 
139
 
 
140
 
 
141
 
 
142
 
 
143
// ------- Decode PEM pubic, private or pkcs8 key ----------------
 
144
public static void DecodePEMKey(String pemstr)
 
145
 {
 
146
        byte[] pempublickey;
 
147
        byte[] pemprivatekey;
 
148
        byte[] pkcs8privatekey;
 
149
        byte[] pkcs8encprivatekey;
 
150
 
 
151
        if(pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter))
 
152
        {
 
153
                Console.WriteLine("Trying to decode and parse a PEM public key ..");
 
154
                pempublickey = DecodeOpenSSLPublicKey(pemstr);
 
155
                if(pempublickey != null)
 
156
                {
 
157
                        if(verbose)
 
158
                          showBytes("\nRSA public key", pempublickey) ;
 
159
                        //PutFileBytes("rsapubkey.pem", pempublickey, pempublickey.Length) ;
 
160
                        RSACryptoServiceProvider rsa =  DecodeX509PublicKey(pempublickey);
 
161
                        Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
162
                        String xmlpublickey =rsa.ToXmlString(false) ;
 
163
                        Console.WriteLine("\nXML RSA public key:  {0} bits\n{1}\n", rsa.KeySize, xmlpublickey) ;
 
164
                }               
 
165
        }
 
166
 
 
167
 
 
168
 
 
169
 
 
170
        else if(pemstr.StartsWith(pemprivheader) && pemstr.EndsWith(pemprivfooter))
 
171
        {
 
172
                Console.WriteLine("Trying to decrypt and parse a PEM private key ..");
 
173
                pemprivatekey = DecodeOpenSSLPrivateKey(pemstr);
 
174
                if(pemprivatekey != null)
 
175
                {
 
176
                        if(verbose)
 
177
                          showBytes("\nRSA private key", pemprivatekey) ;
 
178
                        //PutFileBytes("rsaprivkey.pem", pemprivatekey, pemprivatekey.Length) ;
 
179
                        RSACryptoServiceProvider rsa =  DecodeRSAPrivateKey(pemprivatekey);
 
180
                        Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
181
                        String xmlprivatekey =rsa.ToXmlString(true) ;
 
182
                        Console.WriteLine("\nXML RSA private key:  {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ;
 
183
                        ProcessRSA(rsa);
 
184
                }
 
185
        }
 
186
 
 
187
 
 
188
 
 
189
        else if(pemstr.StartsWith(pemp8header) && pemstr.EndsWith(pemp8footer))
 
190
        {
 
191
                Console.WriteLine("Trying to decode and parse as PEM PKCS #8 PrivateKeyInfo ..");
 
192
                pkcs8privatekey = DecodePkcs8PrivateKey(pemstr);
 
193
                if(pkcs8privatekey != null)
 
194
                {
 
195
                        if(verbose)
 
196
                          showBytes("\nPKCS #8 PrivateKeyInfo", pkcs8privatekey) ;
 
197
                        //PutFileBytes("PrivateKeyInfo", pkcs8privatekey, pkcs8privatekey.Length) ;
 
198
                        RSACryptoServiceProvider rsa =  DecodePrivateKeyInfo(pkcs8privatekey);
 
199
                        if(rsa !=null) 
 
200
                        {
 
201
                         Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
202
                         String xmlprivatekey =rsa.ToXmlString(true) ;
 
203
                         Console.WriteLine("\nXML RSA private key:  {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ;
 
204
                         ProcessRSA(rsa) ; 
 
205
                        }
 
206
                        else
 
207
                        Console.WriteLine("\nFailed to create an RSACryptoServiceProvider");
 
208
                }               
 
209
        }
 
210
 
 
211
 
 
212
        else if(pemstr.StartsWith(pemp8encheader) && pemstr.EndsWith(pemp8encfooter))
 
213
        {
 
214
                Console.WriteLine("Trying to decode and parse as PEM PKCS #8 EncryptedPrivateKeyInfo ..");
 
215
                pkcs8encprivatekey = DecodePkcs8EncPrivateKey(pemstr);
 
216
                if(pkcs8encprivatekey != null)
 
217
                {
 
218
                        if(verbose)
 
219
                          showBytes("\nPKCS #8 EncryptedPrivateKeyInfo", pkcs8encprivatekey) ;
 
220
                        //PutFileBytes("EncryptedPrivateKeyInfo", pkcs8encprivatekey, pkcs8encprivatekey.Length) ;
 
221
                        RSACryptoServiceProvider rsa =  DecodeEncryptedPrivateKeyInfo(pkcs8encprivatekey);
 
222
                        if(rsa !=null) 
 
223
                        {
 
224
                         Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
225
                         String xmlprivatekey =rsa.ToXmlString(true) ;
 
226
                         Console.WriteLine("\nXML RSA private key:  {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ;
 
227
                          ProcessRSA(rsa) ;
 
228
                        }
 
229
                        else
 
230
                        Console.WriteLine("\nFailed to create an RSACryptoServiceProvider");
 
231
                }               
 
232
        }
 
233
 
 
234
 
 
235
        else
 
236
        {
 
237
                Console.WriteLine("Not a PEM public, private key or a PKCS #8");
 
238
                return;
 
239
        }
 
240
}
 
241
 
 
242
 
 
243
 
 
244
 
 
245
 
 
246
// ------- Decode PEM pubic, private or pkcs8 key ----------------
 
247
public static void DecodeDERKey(String filename)
 
248
 {
 
249
        RSACryptoServiceProvider rsa = null ;
 
250
        byte[] keyblob = GetFileBytes(filename);
 
251
        if(keyblob == null)
 
252
                return;
 
253
 
 
254
                rsa =  DecodeX509PublicKey(keyblob);
 
255
                if(rsa !=null)
 
256
                {
 
257
                 Console.WriteLine("\nA valid SubjectPublicKeyInfo\n") ;
 
258
                 Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
259
                 String xmlpublickey =rsa.ToXmlString(false) ;
 
260
                 Console.WriteLine("\nXML RSA public key:  {0} bits\n{1}\n", rsa.KeySize, xmlpublickey) ;
 
261
                 return;
 
262
                }               
 
263
 
 
264
                rsa =  DecodeRSAPrivateKey(keyblob);
 
265
                if(rsa != null)
 
266
                {
 
267
                Console.WriteLine("\nA valid RSAPrivateKey\n") ;
 
268
                Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
269
                String xmlprivatekey =rsa.ToXmlString(true) ;
 
270
                Console.WriteLine("\nXML RSA private key:  {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ;
 
271
                 ProcessRSA(rsa) ;
 
272
                return;
 
273
                }
 
274
 
 
275
                rsa =  DecodePrivateKeyInfo(keyblob);   //PKCS #8 unencrypted
 
276
                if(rsa !=null) 
 
277
                {
 
278
                 Console.WriteLine("\nA valid PKCS #8 PrivateKeyInfo\n") ;
 
279
                 Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
280
                 String xmlprivatekey =rsa.ToXmlString(true) ;
 
281
                 Console.WriteLine("\nXML RSA private key:  {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ;
 
282
                 ProcessRSA(rsa);
 
283
                return;
 
284
                }
 
285
 
 
286
                rsa =  DecodeEncryptedPrivateKeyInfo(keyblob);  //PKCS #8 encrypted
 
287
                if(rsa !=null) {
 
288
                 Console.WriteLine("\nA valid PKCS #8 EncryptedPrivateKeyInfo\n") ;
 
289
                 Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ;
 
290
                 String xmlprivatekey =rsa.ToXmlString(true) ;
 
291
                 Console.WriteLine("\nXML RSA private key:  {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ;
 
292
                 ProcessRSA(rsa);
 
293
                return;
 
294
                }
 
295
        Console.WriteLine("Not a binary DER public, private or PKCS #8 key");
 
296
        return;
 
297
}
 
298
 
 
299
 
 
300
 
 
301
 
 
302
 
 
303
public static void ProcessRSA(RSACryptoServiceProvider rsa)
 
304
 {
 
305
 if(verbose)
 
306
        showRSAProps(rsa);
 
307
 Console.Write("\n\nExport RSA private key to PKCS #12 file?  (Y or N) ");
 
308
 String resp = Console.ReadLine().ToUpper() ;
 
309
 if(resp == "Y"  || resp == "YES")
 
310
        RSAtoPKCS12(rsa) ;
 
311
}
 
312
 
 
313
 
 
314
 
 
315
 
 
316
//--------  Generate pkcs #12 from an RSACryptoServiceProvider  ---------
 
317
public static void RSAtoPKCS12(RSACryptoServiceProvider rsa)
 
318
 {
 
319
        CspKeyContainerInfo keyInfo = rsa.CspKeyContainerInfo;
 
320
        String keycontainer     = keyInfo.KeyContainerName;
 
321
        uint keyspec    = (uint) keyInfo.KeyNumber;
 
322
        String provider = keyInfo.ProviderName;
 
323
        uint cspflags = 0;  //CryptoAPI Current User store;   LM would be CRYPT_MACHINE_KEYSET  = 0x00000020
 
324
        String fname = keycontainer + ".p12" ;
 
325
        //---- need to pass in rsa since underlying keycontainer is not persisted and might be deleted too quickly ---
 
326
        byte[] pkcs12 = GetPkcs12(rsa, keycontainer, provider, keyspec , cspflags) ;
 
327
        if ( (pkcs12 !=null)  && verbose)
 
328
                showBytes("\npkcs #12", pkcs12);
 
329
        if(pkcs12 !=null){
 
330
                PutFileBytes(fname, pkcs12, pkcs12.Length) ;
 
331
                Console.WriteLine("\nWrote pkc #12 file '{0}'\n",  fname) ;
 
332
                }
 
333
        else
 
334
                Console.WriteLine("\nProblem getting pkcs#12") ;
 
335
}
 
336
 
 
337
 
 
338
 
 
339
 
 
340
//--------   Get the binary PKCS #8 PRIVATE key   --------
 
341
public static byte[] DecodePkcs8PrivateKey(String instr) 
 
342
  {
 
343
 const  String pemp8header = "-----BEGIN PRIVATE KEY-----" ;
 
344
 const  String pemp8footer   = "-----END PRIVATE KEY-----" ;
 
345
  String pemstr = instr.Trim() ;
 
346
  byte[] binkey;
 
347
       if(!pemstr.StartsWith(pemp8header) || !pemstr.EndsWith(pemp8footer))
 
348
        return null;
 
349
       StringBuilder sb = new StringBuilder(pemstr) ;
 
350
       sb.Replace(pemp8header, "") ;  //remove headers/footers, if present
 
351
       sb.Replace(pemp8footer, "") ;
 
352
 
 
353
String pubstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace
 
354
 
 
355
   try{  
 
356
     binkey = Convert.FromBase64String(pubstr) ;
 
357
    }
 
358
   catch(System.FormatException) {              //if can't b64 decode, data is not valid
 
359
        return null;
 
360
    }
 
361
  return binkey;
 
362
 }
 
363
 
 
364
 
 
365
//------- Parses binary asn.1 PKCS #8 PrivateKeyInfo; returns RSACryptoServiceProvider ---
 
366
public static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8)
 
367
 {
 
368
 // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
 
369
 // this byte[] includes the sequence byte and terminal encoded null 
 
370
   byte[] SeqOID = {0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00} ;
 
371
   byte[] seq = new byte[15];
 
372
 // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
 
373
  MemoryStream  mem = new MemoryStream(pkcs8) ;
 
374
  int lenstream = (int) mem.Length;
 
375
  BinaryReader binr = new BinaryReader(mem) ;    //wrap Memory Stream with BinaryReader for easy reading
 
376
  byte bt = 0;
 
377
  ushort twobytes = 0;
 
378
 
 
379
try{
 
380
 
 
381
twobytes = binr.ReadUInt16();
 
382
if(twobytes == 0x8130)  //data read as little endian order (actual data order for Sequence is 30 81)
 
383
        binr.ReadByte();        //advance 1 byte
 
384
else if(twobytes == 0x8230)
 
385
        binr.ReadInt16();       //advance 2 bytes
 
386
else
 
387
        return null;
 
388
 
 
389
 
 
390
bt = binr.ReadByte();
 
391
if(bt != 0x02)
 
392
        return null;
 
393
 
 
394
twobytes = binr.ReadUInt16();
 
395
 
 
396
if(twobytes != 0x0001)
 
397
        return null;
 
398
 
 
399
seq = binr.ReadBytes(15);               //read the Sequence OID
 
400
if(!CompareBytearrays(seq, SeqOID))     //make sure Sequence for OID is correct
 
401
        return null;
 
402
 
 
403
bt = binr.ReadByte();
 
404
if(bt != 0x04)  //expect an Octet string 
 
405
        return null;
 
406
 
 
407
bt = binr.ReadByte();           //read next byte, or next 2 bytes is  0x81 or 0x82; otherwise bt is the byte count
 
408
if(bt == 0x81)
 
409
        binr.ReadByte();
 
410
else
 
411
 if(bt == 0x82)
 
412
        binr.ReadUInt16();
 
413
//------ at this stage, the remaining sequence should be the RSA private key
 
414
 
 
415
  byte[] rsaprivkey = binr.ReadBytes((int)(lenstream -mem.Position)) ;
 
416
    RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey(rsaprivkey);
 
417
  return rsacsp;
 
418
}
 
419
 
 
420
 catch(Exception){
 
421
    return null; 
 
422
  }
 
423
 
 
424
 finally { binr.Close(); }
 
425
 
 
426
 }
 
427
 
 
428
 
 
429
 
 
430
 
 
431
 
 
432
 
 
433
 
 
434
 
 
435
//--------   Get the binary PKCS #8 Encrypted PRIVATE key   --------
 
436
public static byte[] DecodePkcs8EncPrivateKey(String instr) 
 
437
  {
 
438
 const  String pemp8encheader = "-----BEGIN ENCRYPTED PRIVATE KEY-----" ;
 
439
 const  String pemp8encfooter   = "-----END ENCRYPTED PRIVATE KEY-----" ;
 
440
  String pemstr = instr.Trim() ;
 
441
  byte[] binkey;
 
442
       if(!pemstr.StartsWith(pemp8encheader) || !pemstr.EndsWith(pemp8encfooter))
 
443
        return null;
 
444
       StringBuilder sb = new StringBuilder(pemstr) ;
 
445
       sb.Replace(pemp8encheader, "") ;  //remove headers/footers, if present
 
446
       sb.Replace(pemp8encfooter, "") ;
 
447
 
 
448
String pubstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace
 
449
 
 
450
   try{  
 
451
     binkey = Convert.FromBase64String(pubstr) ;
 
452
    }
 
453
   catch(System.FormatException) {              //if can't b64 decode, data is not valid
 
454
        return null;
 
455
    }
 
456
  return binkey;
 
457
 }
 
458
 
 
459
 
 
460
 
 
461
 
 
462
 
 
463
 
 
464
//------- Parses binary asn.1 EncryptedPrivateKeyInfo; returns RSACryptoServiceProvider ---
 
465
public static RSACryptoServiceProvider DecodeEncryptedPrivateKeyInfo(byte[] encpkcs8)
 
466
 {
 
467
 // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
 
468
 // this byte[] includes the sequence byte and terminal encoded null 
 
469
   byte[] OIDpkcs5PBES2 = {0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05,  0x0D } ;
 
470
   byte[] OIDpkcs5PBKDF2  = {0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05,  0x0C } ;
 
471
   byte[] OIDdesEDE3CBC = {0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07} ;
 
472
   byte[] seqdes = new byte[10] ;
 
473
   byte[] seq = new byte[11];
 
474
   byte[] salt ;
 
475
   byte[] IV;
 
476
   byte[] encryptedpkcs8;
 
477
   byte[] pkcs8;
 
478
 
 
479
   int saltsize, ivsize, encblobsize;
 
480
   int iterations;
 
481
 
 
482
 // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
 
483
  MemoryStream  mem = new MemoryStream(encpkcs8) ;
 
484
  int lenstream = (int) mem.Length;
 
485
  BinaryReader binr = new BinaryReader(mem) ;    //wrap Memory Stream with BinaryReader for easy reading
 
486
  byte bt = 0;
 
487
  ushort twobytes = 0;
 
488
 
 
489
try{
 
490
 
 
491
twobytes = binr.ReadUInt16();
 
492
if(twobytes == 0x8130)  //data read as little endian order (actual data order for Sequence is 30 81)
 
493
        binr.ReadByte();        //advance 1 byte
 
494
else if(twobytes == 0x8230)
 
495
        binr.ReadInt16();       //advance 2 bytes
 
496
else
 
497
        return null;
 
498
 
 
499
twobytes = binr.ReadUInt16();   //inner sequence
 
500
if(twobytes == 0x8130)
 
501
        binr.ReadByte();
 
502
else if(twobytes == 0x8230)
 
503
        binr.ReadInt16();
 
504
 
 
505
 
 
506
seq = binr.ReadBytes(11);               //read the Sequence OID
 
507
if(!CompareBytearrays(seq, OIDpkcs5PBES2))      //is it a OIDpkcs5PBES2 ?
 
508
        return null;
 
509
 
 
510
twobytes = binr.ReadUInt16();   //inner sequence for pswd salt
 
511
if(twobytes == 0x8130)
 
512
        binr.ReadByte();
 
513
else if(twobytes == 0x8230)
 
514
        binr.ReadInt16();
 
515
 
 
516
twobytes = binr.ReadUInt16();   //inner sequence for pswd salt
 
517
if(twobytes == 0x8130)
 
518
        binr.ReadByte();
 
519
else if(twobytes == 0x8230)
 
520
        binr.ReadInt16();
 
521
 
 
522
seq = binr.ReadBytes(11);               //read the Sequence OID
 
523
if(!CompareBytearrays(seq, OIDpkcs5PBKDF2))     //is it a OIDpkcs5PBKDF2 ?
 
524
        return null;
 
525
 
 
526
twobytes = binr.ReadUInt16();
 
527
if(twobytes == 0x8130)
 
528
        binr.ReadByte();
 
529
else if(twobytes == 0x8230)
 
530
        binr.ReadInt16();
 
531
 
 
532
bt = binr.ReadByte();
 
533
if(bt != 0x04)          //expect octet string for salt
 
534
        return null;
 
535
saltsize = binr.ReadByte();
 
536
salt = binr.ReadBytes(saltsize);
 
537
 
 
538
if(verbose)
 
539
        showBytes("Salt for pbkd", salt);
 
540
bt=binr.ReadByte();
 
541
if (bt != 0x02)         //expect an integer for PBKF2 interation count
 
542
        return null;
 
543
 
 
544
int itbytes = binr.ReadByte();  //PBKD2 iterations should fit in 2 bytes.
 
545
if(itbytes ==1)
 
546
        iterations = binr.ReadByte();
 
547
else if(itbytes == 2)
 
548
        iterations = 256*binr.ReadByte() + binr.ReadByte();
 
549
else
 
550
        return null;
 
551
if(verbose)
 
552
        Console.WriteLine("PBKD2 iterations {0}", iterations);
 
553
 
 
554
twobytes = binr.ReadUInt16();
 
555
if(twobytes == 0x8130)
 
556
        binr.ReadByte();
 
557
else if(twobytes == 0x8230)
 
558
        binr.ReadInt16();
 
559
 
 
560
 
 
561
seqdes = binr.ReadBytes(10);            //read the Sequence OID
 
562
if(!CompareBytearrays(seqdes, OIDdesEDE3CBC))   //is it a OIDdes-EDE3-CBC ?
 
563
        return null;
 
564
 
 
565
bt = binr.ReadByte();
 
566
if(bt != 0x04)          //expect octet string for IV
 
567
        return null;
 
568
ivsize = binr.ReadByte();       // IV byte size should fit in one byte (24 expected for 3DES)
 
569
IV= binr.ReadBytes(ivsize);
 
570
if(verbose)
 
571
        showBytes("IV for des-EDE3-CBC", IV);
 
572
 
 
573
bt=binr.ReadByte();
 
574
if(bt != 0x04)          // expect octet string for encrypted PKCS8 data
 
575
        return null;
 
576
 
 
577
 
 
578
bt = binr.ReadByte();
 
579
 
 
580
if(bt == 0x81)
 
581
        encblobsize = binr.ReadByte();  // data size in next byte
 
582
else if(bt == 0x82)
 
583
        encblobsize = 256*binr.ReadByte() + binr.ReadByte() ;
 
584
else
 
585
        encblobsize = bt;               // we already have the data size
 
586
 
 
587
 
 
588
encryptedpkcs8 = binr.ReadBytes(encblobsize) ;
 
589
//if(verbose)
 
590
//      showBytes("Encrypted PKCS8 blob", encryptedpkcs8) ;
 
591
 
 
592
 
 
593
SecureString secpswd = GetSecPswd("Enter password for Encrypted PKCS #8 ==>") ;
 
594
pkcs8 = DecryptPBDK2(encryptedpkcs8, salt, IV, secpswd, iterations) ;
 
595
if(pkcs8 == null)       // probably a bad pswd entered.
 
596
        return null;
 
597
 
 
598
//if(verbose)
 
599
//      showBytes("Decrypted PKCS #8", pkcs8) ;
 
600
 //----- With a decrypted pkcs #8 PrivateKeyInfo blob, decode it to an RSA ---
 
601
  RSACryptoServiceProvider rsa =  DecodePrivateKeyInfo(pkcs8) ;
 
602
  return rsa;
 
603
}
 
604
 
 
605
 catch(Exception){
 
606
    return null; 
 
607
  }
 
608
 
 
609
 finally { binr.Close(); }
 
610
 
 
611
 
 
612
 }
 
613
 
 
614
 
 
615
 
 
616
 
 
617
 
 
618
//  ------  Uses PBKD2 to derive a 3DES key and decrypts data --------
 
619
public static byte[] DecryptPBDK2(byte[] edata, byte[] salt, byte[]IV, SecureString secpswd, int iterations)
 
620
{
 
621
        CryptoStream decrypt = null;
 
622
 
 
623
        IntPtr unmanagedPswd = IntPtr.Zero;
 
624
        byte[] psbytes = new byte[secpswd.Length] ;
 
625
        unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd);
 
626
        Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length) ;
 
627
        Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd);
 
628
 
 
629
  try
 
630
        {
 
631
        Rfc2898DeriveBytes kd = new Rfc2898DeriveBytes(psbytes, salt, iterations);
 
632
        TripleDES decAlg = TripleDES.Create();
 
633
        decAlg.Key = kd.GetBytes(24);
 
634
        decAlg.IV = IV;
 
635
        MemoryStream memstr = new MemoryStream();
 
636
        decrypt = new CryptoStream(memstr,decAlg.CreateDecryptor(), CryptoStreamMode.Write);
 
637
        decrypt.Write(edata, 0, edata.Length);
 
638
        decrypt.Flush();
 
639
        decrypt.Close() ;       // this is REQUIRED.
 
640
        byte[] cleartext = memstr.ToArray();
 
641
        return cleartext;
 
642
        }
 
643
   catch (Exception e)
 
644
        { 
 
645
         Console.WriteLine("Problem decrypting: {0}", e.Message) ;
 
646
         return null;
 
647
        }
 
648
}
 
649
 
 
650
 
 
651
 
 
652
 
 
653
 
 
654
 
 
655
 
 
656
 
 
657
 
 
658
 
 
659
//--------   Get the binary RSA PUBLIC key   --------
 
660
public static byte[] DecodeOpenSSLPublicKey(String instr) 
 
661
  {
 
662
  const  String pempubheader = "-----BEGIN PUBLIC KEY-----" ;
 
663
  const  String pempubfooter   = "-----END PUBLIC KEY-----" ;
 
664
  String pemstr = instr.Trim() ;
 
665
  byte[] binkey;
 
666
       if(!pemstr.StartsWith(pempubheader) || !pemstr.EndsWith(pempubfooter))
 
667
        return null;
 
668
       StringBuilder sb = new StringBuilder(pemstr) ;
 
669
       sb.Replace(pempubheader, "") ;  //remove headers/footers, if present
 
670
       sb.Replace(pempubfooter, "") ;
 
671
 
 
672
String pubstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace
 
673
 
 
674
   try{  
 
675
     binkey = Convert.FromBase64String(pubstr) ;
 
676
    }
 
677
   catch(System.FormatException) {              //if can't b64 decode, data is not valid
 
678
        return null;
 
679
    }
 
680
  return binkey;
 
681
 }
 
682
 
 
683
 
 
684
 
 
685
//------- Parses binary asn.1 X509 SubjectPublicKeyInfo; returns RSACryptoServiceProvider ---
 
686
public static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key)
 
687
 {
 
688
 // encoded OID sequence for  PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1"
 
689
   byte[] SeqOID = {0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00} ;
 
690
   byte[] seq = new byte[15];
 
691
 // ---------  Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob  ------
 
692
  MemoryStream  mem = new MemoryStream(x509key) ;
 
693
  BinaryReader binr = new BinaryReader(mem) ;    //wrap Memory Stream with BinaryReader for easy reading
 
694
  byte bt = 0;
 
695
  ushort twobytes = 0;
 
696
 
 
697
try{
 
698
 
 
699
twobytes = binr.ReadUInt16();
 
700
if(twobytes == 0x8130)  //data read as little endian order (actual data order for Sequence is 30 81)
 
701
        binr.ReadByte();        //advance 1 byte
 
702
else if(twobytes == 0x8230)
 
703
        binr.ReadInt16();       //advance 2 bytes
 
704
else
 
705
        return null;
 
706
 
 
707
seq = binr.ReadBytes(15);               //read the Sequence OID
 
708
if(!CompareBytearrays(seq, SeqOID))     //make sure Sequence for OID is correct
 
709
        return null;
 
710
 
 
711
twobytes = binr.ReadUInt16();
 
712
if(twobytes == 0x8103)  //data read as little endian order (actual data order for Bit String is 03 81)
 
713
        binr.ReadByte();        //advance 1 byte
 
714
else if(twobytes == 0x8203)
 
715
        binr.ReadInt16();       //advance 2 bytes
 
716
else
 
717
        return null;
 
718
 
 
719
bt = binr.ReadByte();
 
720
if(bt != 0x00)          //expect null byte next
 
721
        return null;
 
722
 
 
723
twobytes = binr.ReadUInt16();
 
724
if(twobytes == 0x8130)  //data read as little endian order (actual data order for Sequence is 30 81)
 
725
        binr.ReadByte();        //advance 1 byte
 
726
else if(twobytes == 0x8230)
 
727
        binr.ReadInt16();       //advance 2 bytes
 
728
else
 
729
        return null;
 
730
 
 
731
twobytes = binr.ReadUInt16();
 
732
byte lowbyte = 0x00;
 
733
byte highbyte = 0x00;
 
734
 
 
735
if(twobytes == 0x8102)  //data read as little endian order (actual data order for Integer is 02 81)
 
736
        lowbyte = binr.ReadByte();      // read next bytes which is bytes in modulus
 
737
else if(twobytes == 0x8202) {
 
738
        highbyte = binr.ReadByte();     //advance 2 bytes
 
739
        lowbyte = binr.ReadByte();
 
740
        }
 
741
else
 
742
        return null;
 
743
 byte[] modint = {lowbyte, highbyte, 0x00, 0x00} ;   //reverse byte order since asn.1 key uses big endian order
 
744
 int modsize = BitConverter.ToInt32(modint, 0) ;
 
745
 
 
746
byte firstbyte = binr.ReadByte();
 
747
binr.BaseStream.Seek(-1, SeekOrigin.Current);
 
748
 
 
749
 if(firstbyte == 0x00)  {       //if first byte (highest order) of modulus is zero, don't include it
 
750
        binr.ReadByte();        //skip this null byte
 
751
        modsize -=1  ;  //reduce modulus buffer size by 1
 
752
        }
 
753
 
 
754
  byte[] modulus = binr.ReadBytes(modsize);     //read the modulus bytes
 
755
 
 
756
  if(binr.ReadByte() != 0x02)                   //expect an Integer for the exponent data
 
757
        return null;
 
758
  int expbytes = (int) binr.ReadByte() ;                // should only need one byte for actual exponent data (for all useful values)
 
759
  byte[] exponent = binr.ReadBytes(expbytes);
 
760
 
 
761
 
 
762
  showBytes("\nExponent", exponent);
 
763
  showBytes("\nModulus", modulus) ;    
 
764
 
 
765
 // ------- create RSACryptoServiceProvider instance and initialize with public key -----
 
766
  RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
 
767
  RSAParameters RSAKeyInfo = new RSAParameters();
 
768
  RSAKeyInfo.Modulus = modulus;
 
769
  RSAKeyInfo.Exponent = exponent;
 
770
  RSA.ImportParameters(RSAKeyInfo);
 
771
  return RSA;
 
772
 }
 
773
 catch(Exception){
 
774
    return null; 
 
775
  }
 
776
 
 
777
 finally { binr.Close(); }
 
778
 
 
779
}
 
780
 
 
781
 
 
782
 
 
783
//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider  ---
 
784
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
 
785
 {
 
786
  byte[] MODULUS, E, D, P, Q, DP, DQ, IQ ;
 
787
 
 
788
 // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
 
789
  MemoryStream  mem = new MemoryStream(privkey) ;
 
790
  BinaryReader binr = new BinaryReader(mem) ;    //wrap Memory Stream with BinaryReader for easy reading
 
791
  byte bt = 0;
 
792
  ushort twobytes = 0;
 
793
  int elems = 0;
 
794
try{
 
795
twobytes = binr.ReadUInt16();
 
796
if(twobytes == 0x8130)  //data read as little endian order (actual data order for Sequence is 30 81)
 
797
        binr.ReadByte();        //advance 1 byte
 
798
else if(twobytes == 0x8230)
 
799
        binr.ReadInt16();       //advance 2 bytes
 
800
else
 
801
        return null;
 
802
 
 
803
twobytes = binr.ReadUInt16();
 
804
if(twobytes != 0x0102)  //version number
 
805
        return null;
 
806
bt = binr.ReadByte();
 
807
if(bt !=0x00)
 
808
        return null;
 
809
 
 
810
 
 
811
//------  all private key components are Integer sequences ----
 
812
 elems = GetIntegerSize(binr);
 
813
 MODULUS = binr.ReadBytes(elems);
 
814
 
 
815
 elems = GetIntegerSize(binr);
 
816
 E = binr.ReadBytes(elems) ;
 
817
 
 
818
 elems = GetIntegerSize(binr);
 
819
 D = binr.ReadBytes(elems) ;
 
820
 
 
821
 elems = GetIntegerSize(binr);
 
822
 P = binr.ReadBytes(elems) ;
 
823
 
 
824
 elems = GetIntegerSize(binr);
 
825
 Q = binr.ReadBytes(elems) ;
 
826
 
 
827
 elems = GetIntegerSize(binr);
 
828
 DP = binr.ReadBytes(elems) ;
 
829
 
 
830
 elems = GetIntegerSize(binr);
 
831
 DQ = binr.ReadBytes(elems) ;
 
832
 
 
833
 elems = GetIntegerSize(binr);
 
834
 IQ = binr.ReadBytes(elems) ;
 
835
 
 
836
Console.WriteLine("showing components ..");
 
837
 if(verbose) {
 
838
  showBytes("\nModulus", MODULUS) ;    
 
839
  showBytes("\nExponent", E);
 
840
  showBytes("\nD", D);
 
841
  showBytes("\nP", P);
 
842
  showBytes("\nQ", Q);
 
843
  showBytes("\nDP", DP);
 
844
  showBytes("\nDQ", DQ);
 
845
  showBytes("\nIQ", IQ);
 
846
 }
 
847
 
 
848
 // ------- create RSACryptoServiceProvider instance and initialize with public key -----
 
849
  RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
 
850
  RSAParameters RSAparams = new RSAParameters();
 
851
  RSAparams.Modulus =MODULUS;
 
852
  RSAparams.Exponent = E;
 
853
  RSAparams.D = D;
 
854
  RSAparams.P = P;
 
855
  RSAparams.Q = Q;
 
856
  RSAparams.DP = DP;
 
857
  RSAparams.DQ = DQ;
 
858
  RSAparams.InverseQ = IQ;
 
859
  RSA.ImportParameters(RSAparams);
 
860
  return RSA;
 
861
 }
 
862
 catch(Exception){
 
863
    return null; 
 
864
  }
 
865
 finally { binr.Close(); }
 
866
}
 
867
 
 
868
 
 
869
 
 
870
private static int GetIntegerSize(BinaryReader binr) {
 
871
  byte bt = 0;
 
872
  byte lowbyte = 0x00;
 
873
  byte highbyte = 0x00;
 
874
  int count = 0;
 
875
 bt = binr.ReadByte();
 
876
if(bt != 0x02)          //expect integer
 
877
        return 0;
 
878
bt = binr.ReadByte();
 
879
 
 
880
if(bt == 0x81)
 
881
        count = binr.ReadByte();        // data size in next byte
 
882
else
 
883
if(bt == 0x82) {
 
884
        highbyte = binr.ReadByte();     // data size in next 2 bytes
 
885
        lowbyte = binr.ReadByte();
 
886
        byte[] modint = {lowbyte, highbyte, 0x00, 0x00} ;
 
887
        count = BitConverter.ToInt32(modint, 0) ;
 
888
        }
 
889
else {
 
890
        count = bt;             // we already have the data size
 
891
}
 
892
 
 
893
 
 
894
 
 
895
 while(binr.ReadByte() == 0x00) {       //remove high order zeros in data
 
896
        count -=1;
 
897
        }
 
898
 binr.BaseStream.Seek(-1, SeekOrigin.Current);          //last ReadByte wasn't a removed zero, so back up a byte
 
899
 return count;
 
900
}
 
901
 
 
902
 
 
903
 
 
904
 
 
905
//-----  Get the binary RSA PRIVATE key, decrypting if necessary ----
 
906
public static byte[] DecodeOpenSSLPrivateKey(String instr) 
 
907
  {
 
908
  const  String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----" ;
 
909
  const  String pemprivfooter   = "-----END RSA PRIVATE KEY-----" ;
 
910
  String pemstr = instr.Trim() ;
 
911
  byte[] binkey;
 
912
       if(!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter))
 
913
        return null;
 
914
 
 
915
       StringBuilder sb = new StringBuilder(pemstr) ;
 
916
        sb.Replace(pemprivheader, "") ;  //remove headers/footers, if present
 
917
        sb.Replace(pemprivfooter, "") ;
 
918
 
 
919
String pvkstr = sb.ToString().Trim();   //get string after removing leading/trailing whitespace
 
920
 
 
921
   try{        // if there are no PEM encryption info lines, this is an UNencrypted PEM private key
 
922
        binkey = Convert.FromBase64String(pvkstr) ;
 
923
        return binkey;
 
924
    }
 
925
   catch(System.FormatException) {              //if can't b64 decode, it must be an encrypted private key
 
926
        //Console.WriteLine("Not an unencrypted OpenSSL PEM private key");  
 
927
    }
 
928
 
 
929
 StringReader str = new StringReader(pvkstr);
 
930
 
 
931
//-------- read PEM encryption info. lines and extract salt -----
 
932
 if(!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED")) 
 
933
        return null;
 
934
 String saltline = str.ReadLine();
 
935
 if(!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,") )
 
936
        return null;
 
937
 String saltstr =  saltline.Substring(saltline.IndexOf(",") + 1).Trim() ;
 
938
 byte[] salt = new byte[saltstr.Length/2]; 
 
939
 for (int i=0; i <salt.Length; i++)  
 
940
        salt[i] = Convert.ToByte(saltstr.Substring (i*2, 2), 16); 
 
941
 if(! (str.ReadLine() == ""))
 
942
        return null;
 
943
 
 
944
//------ remaining b64 data is encrypted RSA key ----
 
945
String encryptedstr =  str.ReadToEnd() ;
 
946
 
 
947
 try{   //should have b64 encrypted RSA key now
 
948
        binkey = Convert.FromBase64String(encryptedstr) ;
 
949
 }
 
950
   catch(System.FormatException) {  // bad b64 data.
 
951
        return null;
 
952
    }
 
953
 
 
954
//------ Get the 3DES 24 byte key using PDK used by OpenSSL ----
 
955
 
 
956
    SecureString  despswd = GetSecPswd("Enter password to derive 3DES key==>") ;
 
957
   //Console.Write("\nEnter password to derive 3DES key: ");
 
958
   //String pswd = Console.ReadLine();
 
959
  byte[] deskey = GetOpenSSL3deskey(salt, despswd, 1, 2);    // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes
 
960
  if(deskey == null)
 
961
        return null;
 
962
  //showBytes("3DES key", deskey) ;
 
963
 
 
964
//------ Decrypt the encrypted 3des-encrypted RSA private key ------
 
965
 byte[] rsakey = DecryptKey(binkey, deskey, salt);      //OpenSSL uses salt value in PEM header also as 3DES IV
 
966
if(rsakey !=null) 
 
967
        return rsakey;  //we have a decrypted RSA private key
 
968
else {
 
969
        Console.WriteLine("Failed to decrypt RSA private key; probably wrong password.");
 
970
        return null;
 
971
   }
 
972
 }
 
973
 
 
974
 
 
975
 
 
976
 
 
977
// ----- Decrypt the 3DES encrypted RSA private key ----------
 
978
 
 
979
 public static byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV) 
 
980
      { 
 
981
        MemoryStream memst = new MemoryStream(); 
 
982
        TripleDES alg = TripleDES.Create(); 
 
983
        alg.Key = desKey; 
 
984
        alg.IV = IV; 
 
985
        try{
 
986
        CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write); 
 
987
        cs.Write(cipherData, 0, cipherData.Length); 
 
988
        cs.Close(); 
 
989
        }
 
990
        catch(Exception exc){
 
991
                Console.WriteLine(exc.Message); 
 
992
                return null ;}
 
993
        byte[] decryptedData = memst.ToArray(); 
 
994
        return decryptedData; 
 
995
      } 
 
996
 
 
997
 
 
998
 
 
999
 
 
1000
//-----   OpenSSL PBKD uses only one hash cycle (count); miter is number of iterations required to build sufficient bytes ---
 
1001
 private static byte[] GetOpenSSL3deskey(byte[] salt, SecureString secpswd, int count, int miter )  {
 
1002
        IntPtr unmanagedPswd = IntPtr.Zero;
 
1003
        int HASHLENGTH = 16;    //MD5 bytes
 
1004
        byte[] keymaterial = new byte[HASHLENGTH*miter] ;     //to store contatenated Mi hashed results
 
1005
 
 
1006
 
 
1007
        byte[] psbytes = new byte[secpswd.Length] ;
 
1008
        unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd);
 
1009
        Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length) ;
 
1010
        Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd);
 
1011
 
 
1012
        //UTF8Encoding utf8 = new UTF8Encoding();
 
1013
        //byte[] psbytes = utf8.GetBytes(pswd);
 
1014
 
 
1015
        // --- contatenate salt and pswd bytes into fixed data array ---
 
1016
        byte[] data00 = new byte[psbytes.Length + salt.Length] ;
 
1017
        Array.Copy(psbytes, data00, psbytes.Length);            //copy the pswd bytes
 
1018
        Array.Copy(salt, 0, data00, psbytes.Length, salt.Length) ;      //concatenate the salt bytes
 
1019
 
 
1020
        // ---- do multi-hashing and contatenate results  D1, D2 ...  into keymaterial bytes ----
 
1021
        MD5 md5 = new MD5CryptoServiceProvider();
 
1022
        byte[] result = null;
 
1023
        byte[] hashtarget = new byte[HASHLENGTH + data00.Length];   //fixed length initial hashtarget
 
1024
 
 
1025
        for(int j=0; j<miter; j++)
 
1026
        {
 
1027
        // ----  Now hash consecutively for count times ------
 
1028
        if(j == 0)
 
1029
                result = data00;        //initialize 
 
1030
        else {
 
1031
                Array.Copy(result, hashtarget, result.Length);
 
1032
                Array.Copy(data00, 0, hashtarget, result.Length, data00.Length) ;
 
1033
                result = hashtarget;
 
1034
                        //Console.WriteLine("Updated new initial hash target:") ;
 
1035
                        //showBytes(result) ;
 
1036
        }
 
1037
 
 
1038
        for(int i=0; i<count; i++)
 
1039
                result = md5.ComputeHash(result);
 
1040
         Array.Copy(result, 0, keymaterial, j*HASHLENGTH, result.Length);  //contatenate to keymaterial
 
1041
        }
 
1042
        //showBytes("Final key material", keymaterial);
 
1043
    byte[] deskey = new byte[24];
 
1044
   Array.Copy(keymaterial, deskey, deskey.Length) ;
 
1045
 
 
1046
   Array.Clear(psbytes, 0,  psbytes.Length);
 
1047
   Array.Clear(data00, 0, data00.Length) ;
 
1048
   Array.Clear(result, 0, result.Length) ;
 
1049
   Array.Clear(hashtarget, 0, hashtarget.Length) ;
 
1050
   Array.Clear(keymaterial, 0, keymaterial.Length) ;
 
1051
 
 
1052
   return deskey; 
 
1053
 }
 
1054
 
 
1055
 
 
1056
 
 
1057
 
 
1058
 
 
1059
 
 
1060
//------   Since we are using an RSA with nonpersisted keycontainer, must pass it in to ensure it isn't colledted  -----
 
1061
private static byte[] GetPkcs12(RSA rsa, String keycontainer, String cspprovider, uint KEYSPEC, uint cspflags)
 
1062
 {
 
1063
  byte[] pfxblob        = null;
 
1064
  IntPtr hCertCntxt     = IntPtr.Zero;
 
1065
 
 
1066
  String DN = "CN=Opensslkey Unsigned Certificate";
 
1067
 
 
1068
        hCertCntxt =  CreateUnsignedCertCntxt(keycontainer, cspprovider, KEYSPEC, cspflags, DN) ;
 
1069
        if(hCertCntxt == IntPtr.Zero){
 
1070
                Console.WriteLine("Couldn't create an unsigned-cert\n") ;
 
1071
                return null;
 
1072
        }
 
1073
 try{
 
1074
        X509Certificate cert = new X509Certificate(hCertCntxt) ;        //create certificate object from cert context.
 
1075
        X509Certificate2UI.DisplayCertificate(new X509Certificate2(cert)) ;     // display it, showing linked private key
 
1076
        SecureString pswd = GetSecPswd("Set PFX Password ==>") ;
 
1077
        pfxblob = cert.Export(X509ContentType.Pkcs12, pswd);
 
1078
  }
 
1079
 
 
1080
 catch(Exception exc) 
 
1081
 { 
 
1082
        Console.WriteLine( "BAD RESULT" + exc.Message);
 
1083
        pfxblob = null;
 
1084
 }
 
1085
        
 
1086
rsa.Clear() ;
 
1087
if(hCertCntxt != IntPtr.Zero)
 
1088
        Win32.CertFreeCertificateContext(hCertCntxt) ;
 
1089
  return pfxblob;
 
1090
}
 
1091
 
 
1092
 
 
1093
 
 
1094
 
 
1095
private static IntPtr CreateUnsignedCertCntxt(String keycontainer, String provider, uint KEYSPEC, uint cspflags, String DN) {
 
1096
 const uint AT_KEYEXCHANGE      = 0x00000001;
 
1097
 const uint AT_SIGNATURE                = 0x00000002;
 
1098
 const uint CRYPT_MACHINE_KEYSET        = 0x00000020;
 
1099
 const uint PROV_RSA_FULL       = 0x00000001;
 
1100
 const String MS_DEF_PROV               = "Microsoft Base Cryptographic Provider v1.0";
 
1101
 const String MS_STRONG_PROV    =  "Microsoft Strong Cryptographic Provider";
 
1102
 const String MS_ENHANCED_PROV  = "Microsoft Enhanced Cryptographic Provider v1.0";
 
1103
 const uint CERT_CREATE_SELFSIGN_NO_SIGN                = 1 ;
 
1104
 const uint X509_ASN_ENCODING   = 0x00000001;
 
1105
 const uint CERT_X500_NAME_STR  = 3;
 
1106
 IntPtr hCertCntxt = IntPtr.Zero;
 
1107
 byte[] encodedName = null;
 
1108
 uint cbName = 0;
 
1109
 
 
1110
 if( provider != MS_DEF_PROV && provider != MS_STRONG_PROV && provider != MS_ENHANCED_PROV)
 
1111
        return IntPtr.Zero;
 
1112
 if(keycontainer == "")
 
1113
        return IntPtr.Zero;
 
1114
 if( KEYSPEC != AT_SIGNATURE &&  KEYSPEC != AT_KEYEXCHANGE)
 
1115
        return IntPtr.Zero;
 
1116
 if(cspflags != 0 && cspflags != CRYPT_MACHINE_KEYSET)   //only 0 (Current User) keyset is currently used.
 
1117
        return IntPtr.Zero;
 
1118
if (DN == "")
 
1119
        return IntPtr.Zero;
 
1120
 
 
1121
 
 
1122
if(Win32.CertStrToName(X509_ASN_ENCODING, DN, CERT_X500_NAME_STR, IntPtr.Zero, null, ref cbName, IntPtr.Zero))
 
1123
 {
 
1124
        encodedName = new byte[cbName] ;
 
1125
        Win32.CertStrToName(X509_ASN_ENCODING, DN, CERT_X500_NAME_STR, IntPtr.Zero, encodedName, ref cbName, IntPtr.Zero);
 
1126
 }
 
1127
 
 
1128
  CERT_NAME_BLOB subjectblob = new CERT_NAME_BLOB();
 
1129
  subjectblob.pbData = Marshal.AllocHGlobal(encodedName.Length);
 
1130
  Marshal.Copy(encodedName, 0, subjectblob.pbData, encodedName.Length);
 
1131
  subjectblob.cbData = encodedName.Length;
 
1132
 
 
1133
  CRYPT_KEY_PROV_INFO pInfo = new CRYPT_KEY_PROV_INFO();
 
1134
  pInfo.pwszContainerName = keycontainer;
 
1135
  pInfo.pwszProvName = provider;
 
1136
  pInfo.dwProvType = PROV_RSA_FULL;
 
1137
  pInfo.dwFlags = cspflags;
 
1138
  pInfo.cProvParam = 0;
 
1139
  pInfo.rgProvParam = IntPtr.Zero;
 
1140
  pInfo.dwKeySpec = KEYSPEC;
 
1141
 
 
1142
 hCertCntxt = Win32.CertCreateSelfSignCertificate(IntPtr.Zero, ref subjectblob, CERT_CREATE_SELFSIGN_NO_SIGN, ref pInfo, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
 
1143
 if(hCertCntxt == IntPtr.Zero)
 
1144
     showWin32Error(Marshal.GetLastWin32Error());
 
1145
 Marshal.FreeHGlobal(subjectblob.pbData);
 
1146
 return hCertCntxt ;
 
1147
}
 
1148
 
 
1149
 
 
1150
 
 
1151
 
 
1152
 private static SecureString GetSecPswd(String prompt)
 
1153
  {
 
1154
                SecureString password = new SecureString();
 
1155
 
 
1156
                Console.ForegroundColor = ConsoleColor.Gray;
 
1157
                Console.Write(prompt);
 
1158
                Console.ForegroundColor = ConsoleColor.Magenta;
 
1159
 
 
1160
                while (true)
 
1161
                        {
 
1162
                        ConsoleKeyInfo cki = Console.ReadKey(true);
 
1163
                                if (cki.Key == ConsoleKey.Enter)
 
1164
                                {
 
1165
                                        Console.ForegroundColor = ConsoleColor.Gray;
 
1166
                                        Console.WriteLine();
 
1167
                                        return password;
 
1168
                                }
 
1169
                                else if (cki.Key == ConsoleKey.Backspace)
 
1170
                                {
 
1171
                                        // remove the last asterisk from the screen...
 
1172
                                        if (password.Length > 0)
 
1173
                                        {
 
1174
                                                Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
 
1175
                                                Console.Write(" ");
 
1176
                                                Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop);
 
1177
                                                password.RemoveAt(password.Length - 1);
 
1178
                                        }
 
1179
                                }
 
1180
                                else if (cki.Key == ConsoleKey.Escape)
 
1181
                                {
 
1182
                                        Console.ForegroundColor = ConsoleColor.Gray;
 
1183
                                        Console.WriteLine();
 
1184
                                        return password;
 
1185
                                }
 
1186
                                else if (Char.IsLetterOrDigit(cki.KeyChar) || Char.IsSymbol(cki.KeyChar))
 
1187
                                {
 
1188
                                        if (password.Length < 20)
 
1189
                                        {
 
1190
                                                password.AppendChar(cki.KeyChar);
 
1191
                                                Console.Write("*");
 
1192
                                        }
 
1193
                                        else
 
1194
                                        {
 
1195
                                                Console.Beep();
 
1196
                                        }
 
1197
                                } 
 
1198
                                else
 
1199
                                {
 
1200
                                        Console.Beep();
 
1201
                                }
 
1202
                        }
 
1203
  }
 
1204
 
 
1205
 
 
1206
 
 
1207
 
 
1208
 
 
1209
 private static bool CompareBytearrays(byte [] a, byte[] b)
 
1210
 {
 
1211
  if(a.Length != b.Length)
 
1212
        return false;
 
1213
  int i =0;
 
1214
  foreach(byte c in a)
 
1215
  {
 
1216
    if(c != b[i] ) 
 
1217
        return false;
 
1218
    i++;
 
1219
  }
 
1220
 return true;
 
1221
 } 
 
1222
 
 
1223
 
 
1224
 
 
1225
private static void showRSAProps(RSACryptoServiceProvider rsa) {
 
1226
        Console.WriteLine("RSA CSP key information:");
 
1227
        CspKeyContainerInfo keyInfo = rsa.CspKeyContainerInfo;
 
1228
        Console.WriteLine("Accessible property: " + keyInfo.Accessible);
 
1229
        Console.WriteLine("Exportable property: " + keyInfo.Exportable);
 
1230
        Console.WriteLine("HardwareDevice property: " + keyInfo.HardwareDevice);
 
1231
        Console.WriteLine("KeyContainerName property: " + keyInfo.KeyContainerName);
 
1232
        Console.WriteLine("KeyNumber property: " + keyInfo.KeyNumber.ToString());
 
1233
        Console.WriteLine("MachineKeyStore property: " + keyInfo.MachineKeyStore);
 
1234
        Console.WriteLine("Protected property: " + keyInfo.Protected);
 
1235
        Console.WriteLine("ProviderName property: " + keyInfo.ProviderName);
 
1236
        Console.WriteLine("ProviderType property: " + keyInfo.ProviderType);
 
1237
        Console.WriteLine("RandomlyGenerated property: " + keyInfo.RandomlyGenerated);
 
1238
        Console.WriteLine("Removable property: " + keyInfo.Removable);
 
1239
        Console.WriteLine("UniqueKeyContainerName property: " + keyInfo.UniqueKeyContainerName);
 
1240
}
 
1241
 
 
1242
 
 
1243
 
 
1244
private static void showBytes(String info, byte[] data){
 
1245
  Console.WriteLine("{0}  [{1} bytes]", info, data.Length);
 
1246
  for(int i=1; i<=data.Length; i++){    
 
1247
        Console.Write("{0:X2}  ", data[i-1]) ;
 
1248
        if(i%16 == 0)
 
1249
         Console.WriteLine();
 
1250
        }
 
1251
  Console.WriteLine("\n\n");
 
1252
  }
 
1253
 
 
1254
 
 
1255
 private static byte[] GetFileBytes(String filename){
 
1256
        if(!File.Exists(filename))
 
1257
         return null;
 
1258
        Stream stream=new FileStream(filename,FileMode.Open);
 
1259
        int datalen = (int)stream.Length;
 
1260
        byte[] filebytes =new byte[datalen];
 
1261
        stream.Seek(0,SeekOrigin.Begin);
 
1262
        stream.Read(filebytes,0,datalen);
 
1263
        stream.Close();
 
1264
        return filebytes;
 
1265
  }
 
1266
 
 
1267
 
 
1268
 private static void PutFileBytes(String outfile, byte[] data, int bytes) {
 
1269
  FileStream fs = null;
 
1270
        if(bytes > data.Length) {
 
1271
           Console.WriteLine("Too many bytes");
 
1272
           return;
 
1273
          }
 
1274
        try{
 
1275
         fs = new FileStream(outfile, FileMode.Create);
 
1276
         fs.Write(data, 0, bytes);
 
1277
        }
 
1278
        catch(Exception e) {
 
1279
         Console.WriteLine(e.Message) ; 
 
1280
        }
 
1281
        finally {
 
1282
         fs.Close();
 
1283
        }
 
1284
  }
 
1285
 
 
1286
 
 
1287
 
 
1288
 private static void showWin32Error(int errorcode)
 
1289
 {
 
1290
        Win32Exception myEx=new Win32Exception(errorcode);
 
1291
        Console.ForegroundColor = ConsoleColor.Red;
 
1292
        Console.WriteLine("Error code:\t 0x{0:X}", myEx.ErrorCode);
 
1293
        Console.WriteLine("Error message:\t {0}\n", myEx.Message);
 
1294
        Console.ForegroundColor = ConsoleColor.Gray;
 
1295
 }
 
1296
 
 
1297
 
 
1298
 }
 
1299
}
 
1300