Created
December 10, 2013 08:19
-
-
Save stormwild/7887264 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//********************************************************************************** | |
// | |
//OpenSSLKey | |
// .NET 2.0 OpenSSL Public & Private Key Parser | |
// | |
// Copyright (C) 2008 JavaScience Consulting | |
// | |
//*********************************************************************************** | |
// | |
// opensslkey.cs | |
// | |
// Reads and parses: | |
// (1) OpenSSL PEM or DER public keys | |
// (2) OpenSSL PEM or DER traditional SSLeay private keys (encrypted and unencrypted) | |
// (3) PKCS #8 PEM or DER encoded private keys (encrypted and unencrypted) | |
// Keys in PEM format must have headers/footers . | |
// Encrypted Private Key in SSLEay format not supported in DER | |
// Removes header/footer lines. | |
// For traditional SSLEAY PEM private keys, checks for encrypted format and | |
// uses PBE to extract 3DES key. | |
// For SSLEAY format, only supports encryption format: DES-EDE3-CBC | |
// For PKCS #8, only supports PKCS#5 v2.0 3des. | |
// Parses private and public key components and returns .NET RSA object. | |
// Creates dummy unsigned certificate linked to private keypair and | |
// optionally exports to pkcs #12 | |
// | |
// See also: | |
// http://www.openssl.org/docs/crypto/pem.html#PEM_ENCRYPTION_FORMAT | |
//************************************************************************************** | |
using System; | |
using System.IO; | |
using System.Text; | |
using System.Security.Cryptography; | |
using System.Security.Cryptography.X509Certificates; | |
using System.Runtime.InteropServices; | |
using System.Security; | |
using System.Diagnostics; | |
using System.ComponentModel; | |
namespace JavaScience { | |
public class Win32 { | |
[DllImport("crypt32.dll", SetLastError=true)] | |
public static extern IntPtr CertCreateSelfSignCertificate( | |
IntPtr hProv, | |
ref CERT_NAME_BLOB pSubjectIssuerBlob, | |
uint dwFlagsm, | |
ref CRYPT_KEY_PROV_INFO pKeyProvInfo, | |
IntPtr pSignatureAlgorithm, | |
IntPtr pStartTime, | |
IntPtr pEndTime, | |
IntPtr other) ; | |
[DllImport("crypt32.dll", SetLastError=true)] | |
public static extern bool CertStrToName( | |
uint dwCertEncodingType, | |
String pszX500, | |
uint dwStrType, | |
IntPtr pvReserved, | |
[In, Out] byte[] pbEncoded, | |
ref uint pcbEncoded, | |
IntPtr other); | |
[DllImport("crypt32.dll", SetLastError=true)] | |
public static extern bool CertFreeCertificateContext( | |
IntPtr hCertStore) ; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public struct CRYPT_KEY_PROV_INFO | |
{ | |
[MarshalAs(UnmanagedType.LPWStr)] public String pwszContainerName; | |
[MarshalAs(UnmanagedType.LPWStr)] public String pwszProvName; | |
public uint dwProvType; | |
public uint dwFlags; | |
public uint cProvParam; | |
public IntPtr rgProvParam; | |
public uint dwKeySpec; | |
} | |
[StructLayout(LayoutKind.Sequential)] | |
public struct CERT_NAME_BLOB | |
{ | |
public int cbData; | |
public IntPtr pbData; | |
} | |
public class opensslkey { | |
const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----" ; | |
const String pemprivfooter = "-----END RSA PRIVATE KEY-----" ; | |
const String pempubheader = "-----BEGIN PUBLIC KEY-----" ; | |
const String pempubfooter = "-----END PUBLIC KEY-----" ; | |
const String pemp8header = "-----BEGIN PRIVATE KEY-----" ; | |
const String pemp8footer = "-----END PRIVATE KEY-----" ; | |
const String pemp8encheader = "-----BEGIN ENCRYPTED PRIVATE KEY-----" ; | |
const String pemp8encfooter = "-----END ENCRYPTED PRIVATE KEY-----" ; | |
// static byte[] pempublickey; | |
// static byte[] pemprivatekey; | |
// static byte[] pkcs8privatekey; | |
// static byte[] pkcs8encprivatekey; | |
static bool verbose = false; | |
public static void Main(String[] args) { | |
if(args.Length == 1) | |
if(args[0].ToUpper() == "V") | |
verbose = true; | |
Console.ForegroundColor = ConsoleColor.Gray; | |
Console.Write("\nRSA public, private or PKCS #8 key file to decode: "); | |
String filename = Console.ReadLine().Trim(); | |
if (filename == "") //exit while(true) loop | |
return; | |
if (!File.Exists(filename)) { | |
Console.WriteLine("File \"{0}\" does not exist!\n", filename); | |
return; | |
} | |
StreamReader sr = File.OpenText(filename); | |
String pemstr = sr.ReadToEnd().Trim(); | |
sr.Close(); | |
if(pemstr.StartsWith("-----BEGIN")) | |
DecodePEMKey(pemstr); | |
else | |
DecodeDERKey(filename); | |
} | |
// ------- Decode PEM pubic, private or pkcs8 key ---------------- | |
public static void DecodePEMKey(String pemstr) | |
{ | |
byte[] pempublickey; | |
byte[] pemprivatekey; | |
byte[] pkcs8privatekey; | |
byte[] pkcs8encprivatekey; | |
if(pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter)) | |
{ | |
Console.WriteLine("Trying to decode and parse a PEM public key .."); | |
pempublickey = DecodeOpenSSLPublicKey(pemstr); | |
if(pempublickey != null) | |
{ | |
if(verbose) | |
showBytes("\nRSA public key", pempublickey) ; | |
//PutFileBytes("rsapubkey.pem", pempublickey, pempublickey.Length) ; | |
RSACryptoServiceProvider rsa = DecodeX509PublicKey(pempublickey); | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlpublickey =rsa.ToXmlString(false) ; | |
Console.WriteLine("\nXML RSA public key: {0} bits\n{1}\n", rsa.KeySize, xmlpublickey) ; | |
} | |
} | |
else if(pemstr.StartsWith(pemprivheader) && pemstr.EndsWith(pemprivfooter)) | |
{ | |
Console.WriteLine("Trying to decrypt and parse a PEM private key .."); | |
pemprivatekey = DecodeOpenSSLPrivateKey(pemstr); | |
if(pemprivatekey != null) | |
{ | |
if(verbose) | |
showBytes("\nRSA private key", pemprivatekey) ; | |
//PutFileBytes("rsaprivkey.pem", pemprivatekey, pemprivatekey.Length) ; | |
RSACryptoServiceProvider rsa = DecodeRSAPrivateKey(pemprivatekey); | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlprivatekey =rsa.ToXmlString(true) ; | |
Console.WriteLine("\nXML RSA private key: {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ; | |
ProcessRSA(rsa); | |
} | |
} | |
else if(pemstr.StartsWith(pemp8header) && pemstr.EndsWith(pemp8footer)) | |
{ | |
Console.WriteLine("Trying to decode and parse as PEM PKCS #8 PrivateKeyInfo .."); | |
pkcs8privatekey = DecodePkcs8PrivateKey(pemstr); | |
if(pkcs8privatekey != null) | |
{ | |
if(verbose) | |
showBytes("\nPKCS #8 PrivateKeyInfo", pkcs8privatekey) ; | |
//PutFileBytes("PrivateKeyInfo", pkcs8privatekey, pkcs8privatekey.Length) ; | |
RSACryptoServiceProvider rsa = DecodePrivateKeyInfo(pkcs8privatekey); | |
if(rsa !=null) | |
{ | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlprivatekey =rsa.ToXmlString(true) ; | |
Console.WriteLine("\nXML RSA private key: {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ; | |
ProcessRSA(rsa) ; | |
} | |
else | |
Console.WriteLine("\nFailed to create an RSACryptoServiceProvider"); | |
} | |
} | |
else if(pemstr.StartsWith(pemp8encheader) && pemstr.EndsWith(pemp8encfooter)) | |
{ | |
Console.WriteLine("Trying to decode and parse as PEM PKCS #8 EncryptedPrivateKeyInfo .."); | |
pkcs8encprivatekey = DecodePkcs8EncPrivateKey(pemstr); | |
if(pkcs8encprivatekey != null) | |
{ | |
if(verbose) | |
showBytes("\nPKCS #8 EncryptedPrivateKeyInfo", pkcs8encprivatekey) ; | |
//PutFileBytes("EncryptedPrivateKeyInfo", pkcs8encprivatekey, pkcs8encprivatekey.Length) ; | |
RSACryptoServiceProvider rsa = DecodeEncryptedPrivateKeyInfo(pkcs8encprivatekey); | |
if(rsa !=null) | |
{ | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlprivatekey =rsa.ToXmlString(true) ; | |
Console.WriteLine("\nXML RSA private key: {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ; | |
ProcessRSA(rsa) ; | |
} | |
else | |
Console.WriteLine("\nFailed to create an RSACryptoServiceProvider"); | |
} | |
} | |
else | |
{ | |
Console.WriteLine("Not a PEM public, private key or a PKCS #8"); | |
return; | |
} | |
} | |
// ------- Decode PEM pubic, private or pkcs8 key ---------------- | |
public static void DecodeDERKey(String filename) | |
{ | |
RSACryptoServiceProvider rsa = null ; | |
byte[] keyblob = GetFileBytes(filename); | |
if(keyblob == null) | |
return; | |
rsa = DecodeX509PublicKey(keyblob); | |
if(rsa !=null) | |
{ | |
Console.WriteLine("\nA valid SubjectPublicKeyInfo\n") ; | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlpublickey =rsa.ToXmlString(false) ; | |
Console.WriteLine("\nXML RSA public key: {0} bits\n{1}\n", rsa.KeySize, xmlpublickey) ; | |
return; | |
} | |
rsa = DecodeRSAPrivateKey(keyblob); | |
if(rsa != null) | |
{ | |
Console.WriteLine("\nA valid RSAPrivateKey\n") ; | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlprivatekey =rsa.ToXmlString(true) ; | |
Console.WriteLine("\nXML RSA private key: {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ; | |
ProcessRSA(rsa) ; | |
return; | |
} | |
rsa = DecodePrivateKeyInfo(keyblob); //PKCS #8 unencrypted | |
if(rsa !=null) | |
{ | |
Console.WriteLine("\nA valid PKCS #8 PrivateKeyInfo\n") ; | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlprivatekey =rsa.ToXmlString(true) ; | |
Console.WriteLine("\nXML RSA private key: {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ; | |
ProcessRSA(rsa); | |
return; | |
} | |
rsa = DecodeEncryptedPrivateKeyInfo(keyblob); //PKCS #8 encrypted | |
if(rsa !=null) { | |
Console.WriteLine("\nA valid PKCS #8 EncryptedPrivateKeyInfo\n") ; | |
Console.WriteLine("\nCreated an RSACryptoServiceProvider instance\n") ; | |
String xmlprivatekey =rsa.ToXmlString(true) ; | |
Console.WriteLine("\nXML RSA private key: {0} bits\n{1}\n", rsa.KeySize, xmlprivatekey) ; | |
ProcessRSA(rsa); | |
return; | |
} | |
Console.WriteLine("Not a binary DER public, private or PKCS #8 key"); | |
return; | |
} | |
public static void ProcessRSA(RSACryptoServiceProvider rsa) | |
{ | |
if(verbose) | |
showRSAProps(rsa); | |
Console.Write("\n\nExport RSA private key to PKCS #12 file? (Y or N) "); | |
String resp = Console.ReadLine().ToUpper() ; | |
if(resp == "Y" || resp == "YES") | |
RSAtoPKCS12(rsa) ; | |
} | |
//-------- Generate pkcs #12 from an RSACryptoServiceProvider --------- | |
public static void RSAtoPKCS12(RSACryptoServiceProvider rsa) | |
{ | |
CspKeyContainerInfo keyInfo = rsa.CspKeyContainerInfo; | |
String keycontainer = keyInfo.KeyContainerName; | |
uint keyspec = (uint) keyInfo.KeyNumber; | |
String provider = keyInfo.ProviderName; | |
uint cspflags = 0; //CryptoAPI Current User store; LM would be CRYPT_MACHINE_KEYSET = 0x00000020 | |
String fname = keycontainer + ".p12" ; | |
//---- need to pass in rsa since underlying keycontainer is not persisted and might be deleted too quickly --- | |
byte[] pkcs12 = GetPkcs12(rsa, keycontainer, provider, keyspec , cspflags) ; | |
if ( (pkcs12 !=null) && verbose) | |
showBytes("\npkcs #12", pkcs12); | |
if(pkcs12 !=null){ | |
PutFileBytes(fname, pkcs12, pkcs12.Length) ; | |
Console.WriteLine("\nWrote pkc #12 file '{0}'\n", fname) ; | |
} | |
else | |
Console.WriteLine("\nProblem getting pkcs#12") ; | |
} | |
//-------- Get the binary PKCS #8 PRIVATE key -------- | |
public static byte[] DecodePkcs8PrivateKey(String instr) | |
{ | |
const String pemp8header = "-----BEGIN PRIVATE KEY-----" ; | |
const String pemp8footer = "-----END PRIVATE KEY-----" ; | |
String pemstr = instr.Trim() ; | |
byte[] binkey; | |
if(!pemstr.StartsWith(pemp8header) || !pemstr.EndsWith(pemp8footer)) | |
return null; | |
StringBuilder sb = new StringBuilder(pemstr) ; | |
sb.Replace(pemp8header, "") ; //remove headers/footers, if present | |
sb.Replace(pemp8footer, "") ; | |
String pubstr = sb.ToString().Trim(); //get string after removing leading/trailing whitespace | |
try{ | |
binkey = Convert.FromBase64String(pubstr) ; | |
} | |
catch(System.FormatException) { //if can't b64 decode, data is not valid | |
return null; | |
} | |
return binkey; | |
} | |
//------- Parses binary asn.1 PKCS #8 PrivateKeyInfo; returns RSACryptoServiceProvider --- | |
public static RSACryptoServiceProvider DecodePrivateKeyInfo(byte[] pkcs8) | |
{ | |
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" | |
// this byte[] includes the sequence byte and terminal encoded null | |
byte[] SeqOID = {0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00} ; | |
byte[] seq = new byte[15]; | |
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ | |
MemoryStream mem = new MemoryStream(pkcs8) ; | |
int lenstream = (int) mem.Length; | |
BinaryReader binr = new BinaryReader(mem) ; //wrap Memory Stream with BinaryReader for easy reading | |
byte bt = 0; | |
ushort twobytes = 0; | |
try{ | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
binr.ReadByte(); //advance 1 byte | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
bt = binr.ReadByte(); | |
if(bt != 0x02) | |
return null; | |
twobytes = binr.ReadUInt16(); | |
if(twobytes != 0x0001) | |
return null; | |
seq = binr.ReadBytes(15); //read the Sequence OID | |
if(!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct | |
return null; | |
bt = binr.ReadByte(); | |
if(bt != 0x04) //expect an Octet string | |
return null; | |
bt = binr.ReadByte(); //read next byte, or next 2 bytes is 0x81 or 0x82; otherwise bt is the byte count | |
if(bt == 0x81) | |
binr.ReadByte(); | |
else | |
if(bt == 0x82) | |
binr.ReadUInt16(); | |
//------ at this stage, the remaining sequence should be the RSA private key | |
byte[] rsaprivkey = binr.ReadBytes((int)(lenstream -mem.Position)) ; | |
RSACryptoServiceProvider rsacsp = DecodeRSAPrivateKey(rsaprivkey); | |
return rsacsp; | |
} | |
catch(Exception){ | |
return null; | |
} | |
finally { binr.Close(); } | |
} | |
//-------- Get the binary PKCS #8 Encrypted PRIVATE key -------- | |
public static byte[] DecodePkcs8EncPrivateKey(String instr) | |
{ | |
const String pemp8encheader = "-----BEGIN ENCRYPTED PRIVATE KEY-----" ; | |
const String pemp8encfooter = "-----END ENCRYPTED PRIVATE KEY-----" ; | |
String pemstr = instr.Trim() ; | |
byte[] binkey; | |
if(!pemstr.StartsWith(pemp8encheader) || !pemstr.EndsWith(pemp8encfooter)) | |
return null; | |
StringBuilder sb = new StringBuilder(pemstr) ; | |
sb.Replace(pemp8encheader, "") ; //remove headers/footers, if present | |
sb.Replace(pemp8encfooter, "") ; | |
String pubstr = sb.ToString().Trim(); //get string after removing leading/trailing whitespace | |
try{ | |
binkey = Convert.FromBase64String(pubstr) ; | |
} | |
catch(System.FormatException) { //if can't b64 decode, data is not valid | |
return null; | |
} | |
return binkey; | |
} | |
//------- Parses binary asn.1 EncryptedPrivateKeyInfo; returns RSACryptoServiceProvider --- | |
public static RSACryptoServiceProvider DecodeEncryptedPrivateKeyInfo(byte[] encpkcs8) | |
{ | |
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" | |
// this byte[] includes the sequence byte and terminal encoded null | |
byte[] OIDpkcs5PBES2 = {0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0D } ; | |
byte[] OIDpkcs5PBKDF2 = {0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x05, 0x0C } ; | |
byte[] OIDdesEDE3CBC = {0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x03, 0x07} ; | |
byte[] seqdes = new byte[10] ; | |
byte[] seq = new byte[11]; | |
byte[] salt ; | |
byte[] IV; | |
byte[] encryptedpkcs8; | |
byte[] pkcs8; | |
int saltsize, ivsize, encblobsize; | |
int iterations; | |
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ | |
MemoryStream mem = new MemoryStream(encpkcs8) ; | |
int lenstream = (int) mem.Length; | |
BinaryReader binr = new BinaryReader(mem) ; //wrap Memory Stream with BinaryReader for easy reading | |
byte bt = 0; | |
ushort twobytes = 0; | |
try{ | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
binr.ReadByte(); //advance 1 byte | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
twobytes = binr.ReadUInt16(); //inner sequence | |
if(twobytes == 0x8130) | |
binr.ReadByte(); | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); | |
seq = binr.ReadBytes(11); //read the Sequence OID | |
if(!CompareBytearrays(seq, OIDpkcs5PBES2)) //is it a OIDpkcs5PBES2 ? | |
return null; | |
twobytes = binr.ReadUInt16(); //inner sequence for pswd salt | |
if(twobytes == 0x8130) | |
binr.ReadByte(); | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); | |
twobytes = binr.ReadUInt16(); //inner sequence for pswd salt | |
if(twobytes == 0x8130) | |
binr.ReadByte(); | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); | |
seq = binr.ReadBytes(11); //read the Sequence OID | |
if(!CompareBytearrays(seq, OIDpkcs5PBKDF2)) //is it a OIDpkcs5PBKDF2 ? | |
return null; | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8130) | |
binr.ReadByte(); | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); | |
bt = binr.ReadByte(); | |
if(bt != 0x04) //expect octet string for salt | |
return null; | |
saltsize = binr.ReadByte(); | |
salt = binr.ReadBytes(saltsize); | |
if(verbose) | |
showBytes("Salt for pbkd", salt); | |
bt=binr.ReadByte(); | |
if (bt != 0x02) //expect an integer for PBKF2 interation count | |
return null; | |
int itbytes = binr.ReadByte(); //PBKD2 iterations should fit in 2 bytes. | |
if(itbytes ==1) | |
iterations = binr.ReadByte(); | |
else if(itbytes == 2) | |
iterations = 256*binr.ReadByte() + binr.ReadByte(); | |
else | |
return null; | |
if(verbose) | |
Console.WriteLine("PBKD2 iterations {0}", iterations); | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8130) | |
binr.ReadByte(); | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); | |
seqdes = binr.ReadBytes(10); //read the Sequence OID | |
if(!CompareBytearrays(seqdes, OIDdesEDE3CBC)) //is it a OIDdes-EDE3-CBC ? | |
return null; | |
bt = binr.ReadByte(); | |
if(bt != 0x04) //expect octet string for IV | |
return null; | |
ivsize = binr.ReadByte(); // IV byte size should fit in one byte (24 expected for 3DES) | |
IV= binr.ReadBytes(ivsize); | |
if(verbose) | |
showBytes("IV for des-EDE3-CBC", IV); | |
bt=binr.ReadByte(); | |
if(bt != 0x04) // expect octet string for encrypted PKCS8 data | |
return null; | |
bt = binr.ReadByte(); | |
if(bt == 0x81) | |
encblobsize = binr.ReadByte(); // data size in next byte | |
else if(bt == 0x82) | |
encblobsize = 256*binr.ReadByte() + binr.ReadByte() ; | |
else | |
encblobsize = bt; // we already have the data size | |
encryptedpkcs8 = binr.ReadBytes(encblobsize) ; | |
//if(verbose) | |
// showBytes("Encrypted PKCS8 blob", encryptedpkcs8) ; | |
SecureString secpswd = GetSecPswd("Enter password for Encrypted PKCS #8 ==>") ; | |
pkcs8 = DecryptPBDK2(encryptedpkcs8, salt, IV, secpswd, iterations) ; | |
if(pkcs8 == null) // probably a bad pswd entered. | |
return null; | |
//if(verbose) | |
// showBytes("Decrypted PKCS #8", pkcs8) ; | |
//----- With a decrypted pkcs #8 PrivateKeyInfo blob, decode it to an RSA --- | |
RSACryptoServiceProvider rsa = DecodePrivateKeyInfo(pkcs8) ; | |
return rsa; | |
} | |
catch(Exception){ | |
return null; | |
} | |
finally { binr.Close(); } | |
} | |
// ------ Uses PBKD2 to derive a 3DES key and decrypts data -------- | |
public static byte[] DecryptPBDK2(byte[] edata, byte[] salt, byte[]IV, SecureString secpswd, int iterations) | |
{ | |
CryptoStream decrypt = null; | |
IntPtr unmanagedPswd = IntPtr.Zero; | |
byte[] psbytes = new byte[secpswd.Length] ; | |
unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd); | |
Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length) ; | |
Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd); | |
try | |
{ | |
Rfc2898DeriveBytes kd = new Rfc2898DeriveBytes(psbytes, salt, iterations); | |
TripleDES decAlg = TripleDES.Create(); | |
decAlg.Key = kd.GetBytes(24); | |
decAlg.IV = IV; | |
MemoryStream memstr = new MemoryStream(); | |
decrypt = new CryptoStream(memstr,decAlg.CreateDecryptor(), CryptoStreamMode.Write); | |
decrypt.Write(edata, 0, edata.Length); | |
decrypt.Flush(); | |
decrypt.Close() ; // this is REQUIRED. | |
byte[] cleartext = memstr.ToArray(); | |
return cleartext; | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine("Problem decrypting: {0}", e.Message) ; | |
return null; | |
} | |
} | |
//-------- Get the binary RSA PUBLIC key -------- | |
public static byte[] DecodeOpenSSLPublicKey(String instr) | |
{ | |
const String pempubheader = "-----BEGIN PUBLIC KEY-----" ; | |
const String pempubfooter = "-----END PUBLIC KEY-----" ; | |
String pemstr = instr.Trim() ; | |
byte[] binkey; | |
if(!pemstr.StartsWith(pempubheader) || !pemstr.EndsWith(pempubfooter)) | |
return null; | |
StringBuilder sb = new StringBuilder(pemstr) ; | |
sb.Replace(pempubheader, "") ; //remove headers/footers, if present | |
sb.Replace(pempubfooter, "") ; | |
String pubstr = sb.ToString().Trim(); //get string after removing leading/trailing whitespace | |
try{ | |
binkey = Convert.FromBase64String(pubstr) ; | |
} | |
catch(System.FormatException) { //if can't b64 decode, data is not valid | |
return null; | |
} | |
return binkey; | |
} | |
//------- Parses binary asn.1 X509 SubjectPublicKeyInfo; returns RSACryptoServiceProvider --- | |
public static RSACryptoServiceProvider DecodeX509PublicKey(byte[] x509key) | |
{ | |
// encoded OID sequence for PKCS #1 rsaEncryption szOID_RSA_RSA = "1.2.840.113549.1.1.1" | |
byte[] SeqOID = {0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00} ; | |
byte[] seq = new byte[15]; | |
// --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ | |
MemoryStream mem = new MemoryStream(x509key) ; | |
BinaryReader binr = new BinaryReader(mem) ; //wrap Memory Stream with BinaryReader for easy reading | |
byte bt = 0; | |
ushort twobytes = 0; | |
try{ | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
binr.ReadByte(); //advance 1 byte | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
seq = binr.ReadBytes(15); //read the Sequence OID | |
if(!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct | |
return null; | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) | |
binr.ReadByte(); //advance 1 byte | |
else if(twobytes == 0x8203) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
bt = binr.ReadByte(); | |
if(bt != 0x00) //expect null byte next | |
return null; | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
binr.ReadByte(); //advance 1 byte | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
twobytes = binr.ReadUInt16(); | |
byte lowbyte = 0x00; | |
byte highbyte = 0x00; | |
if(twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) | |
lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus | |
else if(twobytes == 0x8202) { | |
highbyte = binr.ReadByte(); //advance 2 bytes | |
lowbyte = binr.ReadByte(); | |
} | |
else | |
return null; | |
byte[] modint = {lowbyte, highbyte, 0x00, 0x00} ; //reverse byte order since asn.1 key uses big endian order | |
int modsize = BitConverter.ToInt32(modint, 0) ; | |
byte firstbyte = binr.ReadByte(); | |
binr.BaseStream.Seek(-1, SeekOrigin.Current); | |
if(firstbyte == 0x00) { //if first byte (highest order) of modulus is zero, don't include it | |
binr.ReadByte(); //skip this null byte | |
modsize -=1 ; //reduce modulus buffer size by 1 | |
} | |
byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes | |
if(binr.ReadByte() != 0x02) //expect an Integer for the exponent data | |
return null; | |
int expbytes = (int) binr.ReadByte() ; // should only need one byte for actual exponent data (for all useful values) | |
byte[] exponent = binr.ReadBytes(expbytes); | |
showBytes("\nExponent", exponent); | |
showBytes("\nModulus", modulus) ; | |
// ------- create RSACryptoServiceProvider instance and initialize with public key ----- | |
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); | |
RSAParameters RSAKeyInfo = new RSAParameters(); | |
RSAKeyInfo.Modulus = modulus; | |
RSAKeyInfo.Exponent = exponent; | |
RSA.ImportParameters(RSAKeyInfo); | |
return RSA; | |
} | |
catch(Exception){ | |
return null; | |
} | |
finally { binr.Close(); } | |
} | |
//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider --- | |
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey) | |
{ | |
byte[] MODULUS, E, D, P, Q, DP, DQ, IQ ; | |
// --------- Set up stream to decode the asn.1 encoded RSA private key ------ | |
MemoryStream mem = new MemoryStream(privkey) ; | |
BinaryReader binr = new BinaryReader(mem) ; //wrap Memory Stream with BinaryReader for easy reading | |
byte bt = 0; | |
ushort twobytes = 0; | |
int elems = 0; | |
try{ | |
twobytes = binr.ReadUInt16(); | |
if(twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) | |
binr.ReadByte(); //advance 1 byte | |
else if(twobytes == 0x8230) | |
binr.ReadInt16(); //advance 2 bytes | |
else | |
return null; | |
twobytes = binr.ReadUInt16(); | |
if(twobytes != 0x0102) //version number | |
return null; | |
bt = binr.ReadByte(); | |
if(bt !=0x00) | |
return null; | |
//------ all private key components are Integer sequences ---- | |
elems = GetIntegerSize(binr); | |
MODULUS = binr.ReadBytes(elems); | |
elems = GetIntegerSize(binr); | |
E = binr.ReadBytes(elems) ; | |
elems = GetIntegerSize(binr); | |
D = binr.ReadBytes(elems) ; | |
elems = GetIntegerSize(binr); | |
P = binr.ReadBytes(elems) ; | |
elems = GetIntegerSize(binr); | |
Q = binr.ReadBytes(elems) ; | |
elems = GetIntegerSize(binr); | |
DP = binr.ReadBytes(elems) ; | |
elems = GetIntegerSize(binr); | |
DQ = binr.ReadBytes(elems) ; | |
elems = GetIntegerSize(binr); | |
IQ = binr.ReadBytes(elems) ; | |
Console.WriteLine("showing components .."); | |
if(verbose) { | |
showBytes("\nModulus", MODULUS) ; | |
showBytes("\nExponent", E); | |
showBytes("\nD", D); | |
showBytes("\nP", P); | |
showBytes("\nQ", Q); | |
showBytes("\nDP", DP); | |
showBytes("\nDQ", DQ); | |
showBytes("\nIQ", IQ); | |
} | |
// ------- create RSACryptoServiceProvider instance and initialize with public key ----- | |
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); | |
RSAParameters RSAparams = new RSAParameters(); | |
RSAparams.Modulus =MODULUS; | |
RSAparams.Exponent = E; | |
RSAparams.D = D; | |
RSAparams.P = P; | |
RSAparams.Q = Q; | |
RSAparams.DP = DP; | |
RSAparams.DQ = DQ; | |
RSAparams.InverseQ = IQ; | |
RSA.ImportParameters(RSAparams); | |
return RSA; | |
} | |
catch(Exception){ | |
return null; | |
} | |
finally { binr.Close(); } | |
} | |
private static int GetIntegerSize(BinaryReader binr) { | |
byte bt = 0; | |
byte lowbyte = 0x00; | |
byte highbyte = 0x00; | |
int count = 0; | |
bt = binr.ReadByte(); | |
if(bt != 0x02) //expect integer | |
return 0; | |
bt = binr.ReadByte(); | |
if(bt == 0x81) | |
count = binr.ReadByte(); // data size in next byte | |
else | |
if(bt == 0x82) { | |
highbyte = binr.ReadByte(); // data size in next 2 bytes | |
lowbyte = binr.ReadByte(); | |
byte[] modint = {lowbyte, highbyte, 0x00, 0x00} ; | |
count = BitConverter.ToInt32(modint, 0) ; | |
} | |
else { | |
count = bt; // we already have the data size | |
} | |
while(binr.ReadByte() == 0x00) { //remove high order zeros in data | |
count -=1; | |
} | |
binr.BaseStream.Seek(-1, SeekOrigin.Current); //last ReadByte wasn't a removed zero, so back up a byte | |
return count; | |
} | |
//----- Get the binary RSA PRIVATE key, decrypting if necessary ---- | |
public static byte[] DecodeOpenSSLPrivateKey(String instr) | |
{ | |
const String pemprivheader = "-----BEGIN RSA PRIVATE KEY-----" ; | |
const String pemprivfooter = "-----END RSA PRIVATE KEY-----" ; | |
String pemstr = instr.Trim() ; | |
byte[] binkey; | |
if(!pemstr.StartsWith(pemprivheader) || !pemstr.EndsWith(pemprivfooter)) | |
return null; | |
StringBuilder sb = new StringBuilder(pemstr) ; | |
sb.Replace(pemprivheader, "") ; //remove headers/footers, if present | |
sb.Replace(pemprivfooter, "") ; | |
String pvkstr = sb.ToString().Trim(); //get string after removing leading/trailing whitespace | |
try{ // if there are no PEM encryption info lines, this is an UNencrypted PEM private key | |
binkey = Convert.FromBase64String(pvkstr) ; | |
return binkey; | |
} | |
catch(System.FormatException) { //if can't b64 decode, it must be an encrypted private key | |
//Console.WriteLine("Not an unencrypted OpenSSL PEM private key"); | |
} | |
StringReader str = new StringReader(pvkstr); | |
//-------- read PEM encryption info. lines and extract salt ----- | |
if(!str.ReadLine().StartsWith("Proc-Type: 4,ENCRYPTED")) | |
return null; | |
String saltline = str.ReadLine(); | |
if(!saltline.StartsWith("DEK-Info: DES-EDE3-CBC,") ) | |
return null; | |
String saltstr = saltline.Substring(saltline.IndexOf(",") + 1).Trim() ; | |
byte[] salt = new byte[saltstr.Length/2]; | |
for (int i=0; i <salt.Length; i++) | |
salt[i] = Convert.ToByte(saltstr.Substring (i*2, 2), 16); | |
if(! (str.ReadLine() == "")) | |
return null; | |
//------ remaining b64 data is encrypted RSA key ---- | |
String encryptedstr = str.ReadToEnd() ; | |
try{ //should have b64 encrypted RSA key now | |
binkey = Convert.FromBase64String(encryptedstr) ; | |
} | |
catch(System.FormatException) { // bad b64 data. | |
return null; | |
} | |
//------ Get the 3DES 24 byte key using PDK used by OpenSSL ---- | |
SecureString despswd = GetSecPswd("Enter password to derive 3DES key==>") ; | |
//Console.Write("\nEnter password to derive 3DES key: "); | |
//String pswd = Console.ReadLine(); | |
byte[] deskey = GetOpenSSL3deskey(salt, despswd, 1, 2); // count=1 (for OpenSSL implementation); 2 iterations to get at least 24 bytes | |
if(deskey == null) | |
return null; | |
//showBytes("3DES key", deskey) ; | |
//------ Decrypt the encrypted 3des-encrypted RSA private key ------ | |
byte[] rsakey = DecryptKey(binkey, deskey, salt); //OpenSSL uses salt value in PEM header also as 3DES IV | |
if(rsakey !=null) | |
return rsakey; //we have a decrypted RSA private key | |
else { | |
Console.WriteLine("Failed to decrypt RSA private key; probably wrong password."); | |
return null; | |
} | |
} | |
// ----- Decrypt the 3DES encrypted RSA private key ---------- | |
public static byte[] DecryptKey(byte[] cipherData, byte[] desKey, byte[] IV) | |
{ | |
MemoryStream memst = new MemoryStream(); | |
TripleDES alg = TripleDES.Create(); | |
alg.Key = desKey; | |
alg.IV = IV; | |
try{ | |
CryptoStream cs = new CryptoStream(memst, alg.CreateDecryptor(), CryptoStreamMode.Write); | |
cs.Write(cipherData, 0, cipherData.Length); | |
cs.Close(); | |
} | |
catch(Exception exc){ | |
Console.WriteLine(exc.Message); | |
return null ;} | |
byte[] decryptedData = memst.ToArray(); | |
return decryptedData; | |
} | |
//----- OpenSSL PBKD uses only one hash cycle (count); miter is number of iterations required to build sufficient bytes --- | |
private static byte[] GetOpenSSL3deskey(byte[] salt, SecureString secpswd, int count, int miter ) { | |
IntPtr unmanagedPswd = IntPtr.Zero; | |
int HASHLENGTH = 16; //MD5 bytes | |
byte[] keymaterial = new byte[HASHLENGTH*miter] ; //to store contatenated Mi hashed results | |
byte[] psbytes = new byte[secpswd.Length] ; | |
unmanagedPswd = Marshal.SecureStringToGlobalAllocAnsi(secpswd); | |
Marshal.Copy(unmanagedPswd, psbytes, 0, psbytes.Length) ; | |
Marshal.ZeroFreeGlobalAllocAnsi(unmanagedPswd); | |
//UTF8Encoding utf8 = new UTF8Encoding(); | |
//byte[] psbytes = utf8.GetBytes(pswd); | |
// --- contatenate salt and pswd bytes into fixed data array --- | |
byte[] data00 = new byte[psbytes.Length + salt.Length] ; | |
Array.Copy(psbytes, data00, psbytes.Length); //copy the pswd bytes | |
Array.Copy(salt, 0, data00, psbytes.Length, salt.Length) ; //concatenate the salt bytes | |
// ---- do multi-hashing and contatenate results D1, D2 ... into keymaterial bytes ---- | |
MD5 md5 = new MD5CryptoServiceProvider(); | |
byte[] result = null; | |
byte[] hashtarget = new byte[HASHLENGTH + data00.Length]; //fixed length initial hashtarget | |
for(int j=0; j<miter; j++) | |
{ | |
// ---- Now hash consecutively for count times ------ | |
if(j == 0) | |
result = data00; //initialize | |
else { | |
Array.Copy(result, hashtarget, result.Length); | |
Array.Copy(data00, 0, hashtarget, result.Length, data00.Length) ; | |
result = hashtarget; | |
//Console.WriteLine("Updated new initial hash target:") ; | |
//showBytes(result) ; | |
} | |
for(int i=0; i<count; i++) | |
result = md5.ComputeHash(result); | |
Array.Copy(result, 0, keymaterial, j*HASHLENGTH, result.Length); //contatenate to keymaterial | |
} | |
//showBytes("Final key material", keymaterial); | |
byte[] deskey = new byte[24]; | |
Array.Copy(keymaterial, deskey, deskey.Length) ; | |
Array.Clear(psbytes, 0, psbytes.Length); | |
Array.Clear(data00, 0, data00.Length) ; | |
Array.Clear(result, 0, result.Length) ; | |
Array.Clear(hashtarget, 0, hashtarget.Length) ; | |
Array.Clear(keymaterial, 0, keymaterial.Length) ; | |
return deskey; | |
} | |
//------ Since we are using an RSA with nonpersisted keycontainer, must pass it in to ensure it isn't colledted ----- | |
private static byte[] GetPkcs12(RSA rsa, String keycontainer, String cspprovider, uint KEYSPEC, uint cspflags) | |
{ | |
byte[] pfxblob = null; | |
IntPtr hCertCntxt = IntPtr.Zero; | |
String DN = "CN=Opensslkey Unsigned Certificate"; | |
hCertCntxt = CreateUnsignedCertCntxt(keycontainer, cspprovider, KEYSPEC, cspflags, DN) ; | |
if(hCertCntxt == IntPtr.Zero){ | |
Console.WriteLine("Couldn't create an unsigned-cert\n") ; | |
return null; | |
} | |
try{ | |
X509Certificate cert = new X509Certificate(hCertCntxt) ; //create certificate object from cert context. | |
X509Certificate2UI.DisplayCertificate(new X509Certificate2(cert)) ; // display it, showing linked private key | |
SecureString pswd = GetSecPswd("Set PFX Password ==>") ; | |
pfxblob = cert.Export(X509ContentType.Pkcs12, pswd); | |
} | |
catch(Exception exc) | |
{ | |
Console.WriteLine( "BAD RESULT" + exc.Message); | |
pfxblob = null; | |
} | |
rsa.Clear() ; | |
if(hCertCntxt != IntPtr.Zero) | |
Win32.CertFreeCertificateContext(hCertCntxt) ; | |
return pfxblob; | |
} | |
private static IntPtr CreateUnsignedCertCntxt(String keycontainer, String provider, uint KEYSPEC, uint cspflags, String DN) { | |
const uint AT_KEYEXCHANGE = 0x00000001; | |
const uint AT_SIGNATURE = 0x00000002; | |
const uint CRYPT_MACHINE_KEYSET = 0x00000020; | |
const uint PROV_RSA_FULL = 0x00000001; | |
const String MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0"; | |
const String MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider"; | |
const String MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0"; | |
const uint CERT_CREATE_SELFSIGN_NO_SIGN = 1 ; | |
const uint X509_ASN_ENCODING = 0x00000001; | |
const uint CERT_X500_NAME_STR = 3; | |
IntPtr hCertCntxt = IntPtr.Zero; | |
byte[] encodedName = null; | |
uint cbName = 0; | |
if( provider != MS_DEF_PROV && provider != MS_STRONG_PROV && provider != MS_ENHANCED_PROV) | |
return IntPtr.Zero; | |
if(keycontainer == "") | |
return IntPtr.Zero; | |
if( KEYSPEC != AT_SIGNATURE && KEYSPEC != AT_KEYEXCHANGE) | |
return IntPtr.Zero; | |
if(cspflags != 0 && cspflags != CRYPT_MACHINE_KEYSET) //only 0 (Current User) keyset is currently used. | |
return IntPtr.Zero; | |
if (DN == "") | |
return IntPtr.Zero; | |
if(Win32.CertStrToName(X509_ASN_ENCODING, DN, CERT_X500_NAME_STR, IntPtr.Zero, null, ref cbName, IntPtr.Zero)) | |
{ | |
encodedName = new byte[cbName] ; | |
Win32.CertStrToName(X509_ASN_ENCODING, DN, CERT_X500_NAME_STR, IntPtr.Zero, encodedName, ref cbName, IntPtr.Zero); | |
} | |
CERT_NAME_BLOB subjectblob = new CERT_NAME_BLOB(); | |
subjectblob.pbData = Marshal.AllocHGlobal(encodedName.Length); | |
Marshal.Copy(encodedName, 0, subjectblob.pbData, encodedName.Length); | |
subjectblob.cbData = encodedName.Length; | |
CRYPT_KEY_PROV_INFO pInfo = new CRYPT_KEY_PROV_INFO(); | |
pInfo.pwszContainerName = keycontainer; | |
pInfo.pwszProvName = provider; | |
pInfo.dwProvType = PROV_RSA_FULL; | |
pInfo.dwFlags = cspflags; | |
pInfo.cProvParam = 0; | |
pInfo.rgProvParam = IntPtr.Zero; | |
pInfo.dwKeySpec = KEYSPEC; | |
hCertCntxt = Win32.CertCreateSelfSignCertificate(IntPtr.Zero, ref subjectblob, CERT_CREATE_SELFSIGN_NO_SIGN, ref pInfo, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); | |
if(hCertCntxt == IntPtr.Zero) | |
showWin32Error(Marshal.GetLastWin32Error()); | |
Marshal.FreeHGlobal(subjectblob.pbData); | |
return hCertCntxt ; | |
} | |
private static SecureString GetSecPswd(String prompt) | |
{ | |
SecureString password = new SecureString(); | |
Console.ForegroundColor = ConsoleColor.Gray; | |
Console.Write(prompt); | |
Console.ForegroundColor = ConsoleColor.Magenta; | |
while (true) | |
{ | |
ConsoleKeyInfo cki = Console.ReadKey(true); | |
if (cki.Key == ConsoleKey.Enter) | |
{ | |
Console.ForegroundColor = ConsoleColor.Gray; | |
Console.WriteLine(); | |
return password; | |
} | |
else if (cki.Key == ConsoleKey.Backspace) | |
{ | |
// remove the last asterisk from the screen... | |
if (password.Length > 0) | |
{ | |
Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop); | |
Console.Write(" "); | |
Console.SetCursorPosition(Console.CursorLeft - 1, Console.CursorTop); | |
password.RemoveAt(password.Length - 1); | |
} | |
} | |
else if (cki.Key == ConsoleKey.Escape) | |
{ | |
Console.ForegroundColor = ConsoleColor.Gray; | |
Console.WriteLine(); | |
return password; | |
} | |
else if (Char.IsLetterOrDigit(cki.KeyChar) || Char.IsSymbol(cki.KeyChar)) | |
{ | |
if (password.Length < 20) | |
{ | |
password.AppendChar(cki.KeyChar); | |
Console.Write("*"); | |
} | |
else | |
{ | |
Console.Beep(); | |
} | |
} | |
else | |
{ | |
Console.Beep(); | |
} | |
} | |
} | |
private static bool CompareBytearrays(byte [] a, byte[] b) | |
{ | |
if(a.Length != b.Length) | |
return false; | |
int i =0; | |
foreach(byte c in a) | |
{ | |
if(c != b[i] ) | |
return false; | |
i++; | |
} | |
return true; | |
} | |
private static void showRSAProps(RSACryptoServiceProvider rsa) { | |
Console.WriteLine("RSA CSP key information:"); | |
CspKeyContainerInfo keyInfo = rsa.CspKeyContainerInfo; | |
Console.WriteLine("Accessible property: " + keyInfo.Accessible); | |
Console.WriteLine("Exportable property: " + keyInfo.Exportable); | |
Console.WriteLine("HardwareDevice property: " + keyInfo.HardwareDevice); | |
Console.WriteLine("KeyContainerName property: " + keyInfo.KeyContainerName); | |
Console.WriteLine("KeyNumber property: " + keyInfo.KeyNumber.ToString()); | |
Console.WriteLine("MachineKeyStore property: " + keyInfo.MachineKeyStore); | |
Console.WriteLine("Protected property: " + keyInfo.Protected); | |
Console.WriteLine("ProviderName property: " + keyInfo.ProviderName); | |
Console.WriteLine("ProviderType property: " + keyInfo.ProviderType); | |
Console.WriteLine("RandomlyGenerated property: " + keyInfo.RandomlyGenerated); | |
Console.WriteLine("Removable property: " + keyInfo.Removable); | |
Console.WriteLine("UniqueKeyContainerName property: " + keyInfo.UniqueKeyContainerName); | |
} | |
private static void showBytes(String info, byte[] data){ | |
Console.WriteLine("{0} [{1} bytes]", info, data.Length); | |
for(int i=1; i<=data.Length; i++){ | |
Console.Write("{0:X2} ", data[i-1]) ; | |
if(i%16 == 0) | |
Console.WriteLine(); | |
} | |
Console.WriteLine("\n\n"); | |
} | |
private static byte[] GetFileBytes(String filename){ | |
if(!File.Exists(filename)) | |
return null; | |
Stream stream=new FileStream(filename,FileMode.Open); | |
int datalen = (int)stream.Length; | |
byte[] filebytes =new byte[datalen]; | |
stream.Seek(0,SeekOrigin.Begin); | |
stream.Read(filebytes,0,datalen); | |
stream.Close(); | |
return filebytes; | |
} | |
private static void PutFileBytes(String outfile, byte[] data, int bytes) { | |
FileStream fs = null; | |
if(bytes > data.Length) { | |
Console.WriteLine("Too many bytes"); | |
return; | |
} | |
try{ | |
fs = new FileStream(outfile, FileMode.Create); | |
fs.Write(data, 0, bytes); | |
} | |
catch(Exception e) { | |
Console.WriteLine(e.Message) ; | |
} | |
finally { | |
fs.Close(); | |
} | |
} | |
private static void showWin32Error(int errorcode) | |
{ | |
Win32Exception myEx=new Win32Exception(errorcode); | |
Console.ForegroundColor = ConsoleColor.Red; | |
Console.WriteLine("Error code:\t 0x{0:X}", myEx.ErrorCode); | |
Console.WriteLine("Error message:\t {0}\n", myEx.Message); | |
Console.ForegroundColor = ConsoleColor.Gray; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment