2012-07-16 17 views
18

Ho bisogno di caricare la seguente chiave pubblica RSA da un file da utilizzare con la classe RSACryptoServiceProvider. Come posso fare questo?Come caricare la chiave pubblica RSA dal file in C#

-----BEGIN PUBLIC KEY----- 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/syEKqEkMtQL0+d 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+izR 
KbGMRtur2TYklnyVkjeeHfAggo8vWQmWesnOG55vQYHbOOFoJbk0EkwEr5R/PbKm 
byXPPN8zwnS5/XXXXXXXXXXXX 
-----END PUBLIC KEY----- 

Questo codice funziona con la mia chiave pub: http://www.jensign.com/opensslkey/

Ecco il codice che sto usando

 static string RSA(string input) 
     { 
      RSACryptoServiceProvider rsa = DecodeX509PublicKey(Convert.FromBase64String(GetKey())); 

      return (Convert.ToBase64String(rsa.Encrypt(Encoding.ASCII.GetBytes(input), false))); 
     } 

     static string GetKey() 
     { 
      return File.ReadAllText("master.pub").Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", ""); 
      //.Replace("\n", ""); 
     } 

     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; 
     } 

     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); 

       // ------- 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(); } 

     } 

Basta chiamare il metodo 'RSA' con il testo che si desidera cripta e il gioco è fatto.

+0

Utilizzando un 'IO.StreamReader'? – Mr47

+1

possibile duplicazione? http://stackoverflow.com/questions/243646/how-to-read-a-pem-rsa-private-key-from-net – Phil

+0

Ho provato a convertire la stringa in byte utilizzando Convert.FromBase64String e quindi passare i byte al costruttore RSACryptoServiceProvider , ma lancia un'eccezione.Lo stesso accade con X509Certificate.CreateFromFile –

risposta

1

Se si sta parlando di un certificato X509:

FileStream fs = new FileStream("your_cert_file.crt", FileMode.Open); 
byte[] certBytes = new byte[fs.Length]; 
fs.Read(certBytes, 0, (Int32)fs.Length); 
fs.Close(); 
System.Security.Cryptography.X509Certificates.X509Certificate x509cert = 
    new X509Certificate(certBytes); 
Console.WriteLine(x509cert.GetPublicKey()); 
Console.WriteLine(x509cert.GetPublicKeyString()); 

modificato dopo il commento di @hkproj fatto in "2012/07/16 15:04:58 Z":

Guardandomi intorno ho trovato "Reading PEM RSA Public Key Only using Bouncy Castle". Credo che quello che vuoi è questo:

using (StreamReader reader = File.OpenText(@"c:\RSA.txt")) 
{ 
    Org.BouncyCastle.OpenSsl.PemReader pr = 
     new Org.BouncyCastle.OpenSsl.PemReader(reader); 
    Org.BouncyCastle.Utilities.IO.Pem.PemObject po = pr.ReadPemObject(); 

    Console.WriteLine("PemObject, Type: " + po.Type); 
    Console.WriteLine("PemObject, Length: " + po.Content.Length); 
} 

Tuttavia, con il file ottengo un errore: System.IO.IOException : base64 data appears to be truncated.

Quindi cambiare il vostro file in qualcosa tipo:

-----BEGIN PUBLIC KEY----- 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/syEKqEkMtQL0+d 
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+izR 
KbGMRtur2TYklnyVkjeeHfAggo8vWQmWesnOG55vQYHbOOFoJbk0EkwEr5R/PbKm 
byXPPN8zwnS5/XXXXXXXXXXXXZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 
-----END PUBLIC KEY----- 

Il risultato è:

PemObject, Type: PUBLIC KEY 
PemObject, Length: 192 
+1

già provato. Non ha funzionato Genera "CryptographicException" con questo messaggio: Impossibile trovare l'oggetto richiesto. –

3

Stai parlando di certificati memorizzati nel file di?

Se si dispone di un oggetto come:

X509Certificate2 certificate; 

è possibile utilizzare il codice seguente:

RSACryptoServiceProvider rsaprovider = 
        (RSACryptoServiceProvider)certificate.PublicKey.Key; 

e quindi utilizzare il RSACryptoServiceProvider di classe (vedi http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx).

Per caricare un X509Certificato2 utilizzare il suo costruttore (vedere http://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.x509certificate2.aspx).

Questo programma funziona bene per me:

static void Main(string[] args) 
    { 
     try 
     { 
      X509Certificate2 certificate = 
       new X509Certificate2("<PFX Certificate Path", "<Certificate-Password>"); 
      RSACryptoServiceProvider rsaprovider = (RSACryptoServiceProvider)certificate.PublicKey.Key; 
     } 
     catch(Exception e) 
     { 

     } 
    } 
+0

L'ho già provato senza successo. –

+0

Quale problema hai avuto? – iSamnium

+0

Lanci 'CryptographicException' con questo messaggio: Impossibile trovare l'oggetto richiesto –

24

È possibile ottenere RSACryptoServiceProvider da file PEM utilizzando la seguente classe (metodo GetRSAProviderFromPemFile). Copyright (c) 2000 JavaScience Consulting, Michel Gallant

Usage:

RSACryptoServiceProvider provider = PemKeyUtils.GetRSAProviderFromPemFile( @"public_key.pem"); 


public class PemKeyUtils 
{ 
    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 bool verbose = false; 

    public static RSACryptoServiceProvider GetRSAProviderFromPemFile(String pemfile) 
    { 
     bool isPrivateKeyFile = true; 
     string pemstr = File.ReadAllText(pemfile).Trim(); 
     if (pemstr.StartsWith(pempubheader) && pemstr.EndsWith(pempubfooter)) 
      isPrivateKeyFile = false; 

     byte[] pemkey; 
     if (isPrivateKeyFile) 
      pemkey = DecodeOpenSSLPrivateKey(pemstr); 
     else 
      pemkey = DecodeOpenSSLPublicKey(pemstr); 

     if (pemkey == null) 
      return null; 

     if (isPrivateKeyFile) 
      return DecodeRSAPrivateKey(pemkey); 
     else 
      return DecodeX509PublicKey(pemkey); 

    } 



    //-------- Get the binary RSA PUBLIC key -------- 
    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; 
    } 

    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 }; 
     // --------- Set up stream to read the asn.1 encoded SubjectPublicKeyInfo blob ------ 
     using (var mem = new MemoryStream(x509Key)) 
     { 
      using (var binr = new BinaryReader(mem)) //wrap Memory Stream with BinaryReader for easy reading 
      { 
       try 
       { 
        var twobytes = binr.ReadUInt16(); 
        switch (twobytes) 
        { 
         case 0x8130: 
          binr.ReadByte(); //advance 1 byte 
          break; 
         case 0x8230: 
          binr.ReadInt16(); //advance 2 bytes 
          break; 
         default: 
          return null; 
        } 

        var seq = binr.ReadBytes(15); 
        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; 

        var 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 = binr.ReadByte();  // should only need one byte for actual exponent data (for all useful values) 
        byte[] exponent = binr.ReadBytes(expbytes); 

        // We don't really need to print anything but if we insist to... 
        //showBytes("\nExponent", exponent); 
        //showBytes("\nModulus", modulus); 

        // ------- create RSACryptoServiceProvider instance and initialize with public key ----- 
        RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 
        RSAParameters rsaKeyInfo = new RSAParameters 
        { 
         Modulus = modulus, 
         Exponent = exponent 
        }; 
        rsa.ImportParameters(rsaKeyInfo); 
        return rsa; 
       } 
       catch (Exception) 
       { 
        return null; 
       } 
      } 
     } 
    } 

    //------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider --- 
    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 ---- 
    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 ---------- 

    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 --- 
    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; 
    } 

    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(); 
      } 
     } 
    } 

    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; 
    } 

    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"); 
    } 

} 
+1

Mi dispiace per te che l'OP non ha contrassegnato la tua risposta come accettata. È davvero buono. –

+0

Grande codice. Ha funzionato perfettamente –

Problemi correlati