Laden...

Verschlüsselung von Zugangsdaten (ftp/db)

Erstellt von C#Gustl vor 11 Jahren Letzter Beitrag vor 11 Jahren 2.388 Views
C
C#Gustl Themenstarter:in
36 Beiträge seit 2012
vor 11 Jahren
Verschlüsselung von Zugangsdaten (ftp/db)

Hallo,

ich bin gerade dabei ein kleines Tool zu schreiben womit ich alle Bilder in einem Ordner "webfähig" umwandeln kann, das heißt in Vorschaubild (breite max 200) und das eigentliche Bild (breite max 600) und eben kleiner als 70kb. ein wenig geschärft wird es auch noch.

Danach sollen die fertigen Bilder auf der Webseite hochgeladen werden. Und eventuell für jedes Bild einen Datenbankeintrag geben, zwecks BEschreibung zu dem Bild.

Beim Start des Programms gibt es eine Passwortabfrage, das Passwort wird mit MD5 in einer Datei gespeichert und verglichen.

Dann sollen aber die Zugriffsdaten auch in einer Datei abgelegt werden, und zwar verschlüsselt. Anfangs dachte ich das ich die Verschlüsselung und Entschlüsselung dann abhängig von dem Passwort mache.
Dann habe ich dieses Verschlüsselungsverfahren entdeckt: Strings Verschlüsseln mit C#

Fragen:

  1. Ist dieses Verfahren sicher genug für mein Vorhaben?
  2. Würdet ihr das ganze vielleicht komplett anderes angehen?

Bin für jeden Tipp dankbar. 😃

Gruß Gustl

F
10.010 Beiträge seit 2004
vor 11 Jahren
49.485 Beiträge seit 2005
vor 11 Jahren

Hallo C#Gustl,

100%ig Sicherheit gibt es nicht. Ob es dir sicher genug ist, kannst nur du sagen. Allerdings gilt, grundsätzlich, was in der FAQ steht. Das heißt, wenn das Programm den Code und Key zum Entschlüsseln enthält, dann kann jeder (ernsthafte) Angreifer die Daten entschlüsseln. Damit wäre der Thread normalerweise beendet.

Anders sieht es nur aus, wenn - wie bei dir - zu Anfang ein Passwort eingegeben werden muss. Wenn du das Passtwort als Key verwendest, oder den Key zumindest daraus ableitest, dann kann ein Angreifer - vorausgesetzt das Passwort ist robust und du nimmst einen Verschlüsselungsalgorithmus, der als sicher gilt(*) - die Daten ohne Kenntnis des Passworts nicht entschlüsseln.

Wie weit du gehen willst, muss aber wie gesagt du selbst entscheiden.

herbivore

(*) Im .NET Framework sind solche enthalten.

C
C#Gustl Themenstarter:in
36 Beiträge seit 2012
vor 11 Jahren

Hallo, danke für die Antworten.

Ich habe es nun folgendermaßen mit einem kleinen Testprogramm gelöst:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Globalization;

namespace Konsole_Spielwiese
{
    class Program
    {
        static void Main(string[] args)
        {           
            byte[] iv = new byte[] { 65, 110, 68, 26, 69, 178, 200, 219 };
            byte[] passwort_key;
            // der Vergleichstext der das Passwort kontrolliert.
            string vergleichtext = "VERGLEICHTEXT";
            string passwort;
            string falsches_passwort = "FALSCHES_PASSWORT";
            string passwort_md5;
            string ftp_passwort;

            Console.WriteLine("Gebe ein Passwort ein, mit welchem verschlüsselt werden soll:");
            passwort = Console.ReadLine();
            passwort_md5 = GenerateHash(vergleichtext, passwort);

            //Passwort kontrollieren
            if (passwort_md5.Equals(GenerateHash(vergleichtext, passwort)))
            {
                Console.WriteLine("Passwort richtig!");
            }
            if (!passwort_md5.Equals(GenerateHash(vergleichtext, falsches_passwort)))
            {
                Console.WriteLine("Passwort falsch!");
            }

            Console.WriteLine("Gebe ein FTP-Passwort ein, dieses soll mit dem Passwort verschlüsselt werden:");
            ftp_passwort = Console.ReadLine();


            passwort_key = get_passwort_key(passwort);

            byte[] ftp_passwort_crypt_byte = StringVerschluesseln(ftp_passwort, passwort_key, iv);
            Console.Write("ftp_passwort_crypt_byte: ");
            foreach (byte b in ftp_passwort_crypt_byte)
            {
                Console.Write(b + ", ");
            }
            Console.WriteLine();
            string ftp_passwort_encrypt = StringEntschluesseln(ftp_passwort_crypt_byte, passwort_key, iv);
            Console.WriteLine("ftp_passwort_encrypt: " + ftp_passwort_encrypt);

            Console.ReadLine();

        }

        public static byte[] get_passwort_key(string passwort)
        {
            byte[] pwd = Encoding.Unicode.GetBytes(passwort);
            byte[] salt = CreateRandomSalt(7);
            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            try
            {
                PasswordDeriveBytes pdb = new PasswordDeriveBytes(pwd, salt);
                tdes.Key = pdb.CryptDeriveKey("TripleDES", "SHA1", 192, tdes.IV);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                ClearBytes(pwd);
                ClearBytes(salt);            
            }
            return tdes.Key;
        }
 
        public static byte[] CreateRandomSalt(int length)
        {
            byte[] randBytes;

            if (length >= 1)
            {
                randBytes = new byte[length];
            }
            else
            {
                randBytes = new byte[1];
            }

            RNGCryptoServiceProvider rand = new RNGCryptoServiceProvider();
            rand.GetBytes(randBytes);
            return randBytes;
        }

        // aus Speicher löschen
        public static void ClearBytes(byte[] buffer)
        {
            if (buffer == null)
            {
                throw new ArgumentException("buffer");
            }

            for (int x = 0; x < buffer.Length; x++)
            {
                buffer[x] = 0;
            }
        }

        // Generiert einen MD5 Hash mit Salt(Passwort)
        public static string GenerateHash(string value, string salt)
        {
            byte[] data = System.Text.Encoding.ASCII.GetBytes(salt + value);
            data = System.Security.Cryptography.MD5.Create().ComputeHash(data);
            return Convert.ToBase64String(data);
        }

        /// <summary>
        /// Verschlüsselt einen Eingabestring.
        /// </summary>
        /// <param name="input">Der zu verschlüsselnde String.</param>
        /// <returns>Byte-Array mit dem verschlüsselten String.</returns>
        public static byte[] StringVerschluesseln(string input, byte[] key, byte[] iv)
        {
            try
            {
                // MemoryStream Objekt erzeugen
                MemoryStream memoryStream = new MemoryStream();

                // CryptoStream Objekt erzeugen und den Initialisierungs-Vektor
                // sowie den Schlüssel übergeben.
                CryptoStream cryptoStream = new CryptoStream(
                memoryStream, new TripleDESCryptoServiceProvider().CreateEncryptor(key, iv), CryptoStreamMode.Write);

                // Eingabestring in ein Byte-Array konvertieren
                byte[] toEncrypt = new ASCIIEncoding().GetBytes(input);

                // Byte-Array in den Stream schreiben und flushen.
                cryptoStream.Write(toEncrypt, 0, toEncrypt.Length);
                cryptoStream.FlushFinalBlock();

                // Ein Byte-Array aus dem Memory-Stream auslesen
                byte[] ret = memoryStream.ToArray();

                // Stream schließen.
                cryptoStream.Close();
                memoryStream.Close();

                // Rückgabewert.
                return ret;
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(String.Format(CultureInfo.CurrentCulture, "Fehler beim Verschlüsseln: {0}", e.Message));
                return null;
            }
        }

        /// <summary>
        /// Entschlüsselt einen String aus einem Byte-Array.
        /// </summary>
        /// <param name="data">Das verscghlüsselte Byte-Array.</param>
        /// <returns>Entschlüsselter String.</returns>
        public static string StringEntschluesseln(byte[] data, byte[] key, byte[] iv)
        {
            try
            {
                // Ein MemoryStream Objekt erzeugen und das Byte-Array
                // mit den verschlüsselten Daten zuweisen.
                MemoryStream memoryStream = new MemoryStream(data);

                // Ein CryptoStream Objekt erzeugen und den MemoryStream hinzufügen.
                // Den Schlüssel und Initialisierungsvektor zum entschlüsseln verwenden.
                CryptoStream cryptoStream = new CryptoStream(
                memoryStream,
                new TripleDESCryptoServiceProvider().CreateDecryptor(key, iv), CryptoStreamMode.Read);
                // Buffer erstellen um die entschlüsselten Daten zuzuweisen.
                byte[] fromEncrypt = new byte[data.Length];

                // Read the decrypted data out of the crypto stream
                // and place it into the temporary buffer.
                // Die entschlüsselten Daten aus dem CryptoStream lesen
                // und im temporären Puffer ablegen.
                cryptoStream.Read(fromEncrypt, 0, fromEncrypt.Length);

                // Den Puffer in einen String konvertieren und zurückgeben.
                return new ASCIIEncoding().GetString(fromEncrypt);
            }
            catch (CryptographicException e)
            {
                Console.WriteLine(String.Format(CultureInfo.CurrentCulture, "Fehler beim Entschlüsseln: {0}", e.Message));
                return null;
            }
        }
    }
}

Anfangs wird ein Passwort gefragt welches ich als salt in GenerateHash() benutze und einen Vergleichtext habe, der festist. kommt dann der gleiche hash wert raus ist das Passwort richtig.

Von diesem Passwort generiere ich ein byte array ( get_passwort_key() ), also einen key welchen ich für das ftp-Passwort zum verschlüsseln benutze. Dafür benutze ich dann StringVerschluesseln() und StringEntschluesseln().
Die 2 Werte (passwort_md5 und ftp_passwort_crypt_byte) speichere ich dann in einer Datei ab.

Das Passwort muss dann als Klartext dann immer im Speicher stehen (Variable). Oder ich rufe dies dann bei jeder Aktion wo ich die verschlüsselten Daten benötige jedesmal erneut ab. Das möchte ich aber nicht.

Zudem kann man das Passwort oder User dann aber auch bei der Internetübertragung herausfiltern. Oder?

So wäre es zumindest von irgendwelchen Trojaner die die Festplatte ausspionieren sicher... Aber da wird wohl auch keiner extra wegen meinem kleinen Programm einen Bot erstellen. 😃

Wenn wer noch einen bessere Idee hat, würde ich mich freuen die hier zu lesen. 😃

Gruß Gustl

16.840 Beiträge seit 2008
vor 11 Jahren

Kommt drauf an, wie sicher das Passwort sein muss. Es gibt immer eine Stelle im Programmablauf, in der das Passwort als Klartext existieren muss. Hinweis: das Framework bietet die Klasse SecureString an.

Mit MD5 würde ich nichts mehr machen: dank Rainbow-Tables und der geringen Ausführzeit ist sowas irgendwann einfach durch probieren zu knacken.
Zudem ein festes, statisches Salt zu verwenden ist nicht ratsam.

Bei Benutzerregistrierungen nimmt man gerne weitere Dinge mit in den Salt als nur einen statischen Text (zB die Uhrzeit, die derzeit in Togo ist, und dann noch die BenutzerID, die aber umgewandelt in eine Hex etc etc... man muss eben einfallsreich sein).
Solange die Art und Weise der Generierung des Hashs geheim ist und dessen Generierung möglichst über mehrere Ecken stattfinden, desto sicherer ist das ganze auch.

Laut BSI und laut Industrie-Standards ist ein Passwort mit einem statischen Salt und MD5 nur ungenügend und darf in vielen Bereichen auch so nicht eingesetzt werden (Behörden, Militär etc etc..).