Encryption Key speichern C#

  • C#

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von jvbsl.

    Encryption Key speichern C#

    Hi,

    Ich schreibe zur Zeit an einer Anwendung mit der der Nutzer teilweise private Daten ablegt. Um ein gewisses Maß an Sicherheit zu gewährleisten verschlüssele ich den Content mit rfc2898derivebytes, hierzu soll der Nutzer selbst den Key wählen können. Funktioniert alles soweit, ist sicher.
    Jetzt handelt es sich allerdings um eine Anwendung die im Stundentakt den Content abspeichert und ich will nicht jede Stunde ein Fenster anzeigen in das der Nutzer den Key eingeben muss. Das heißt ich muss den Key irgendwo speichern - entweder Registry oder in den App Settings. In beiden Fällen würde ich über das Passwort noch einmal eine Verschlüsselung werfen, da sowohl Registry als auch Settings ausgelesen werden können. Das Problem ist allerdings dass selbst obfucated Apps natürlich dekompilierbar sind.

    Deswegen die Frage: Was ist der sicherste/optimalste Weg um ein Nutzerpasswort zu speichern?

    8-) faxe1008 8-)
    verschlüssele ich den Content mit rfc2898derivebytes

    Bitte erkläre genauer. Ich hoffe, ich bin da jetzt nicht zu pendantisch, aber rfc2898derivebytes ansich ist ja keine Verschlüsselung.

    Das Passwort irgendwo abzuspeichern ist immer dann ein Problem, wenn der User dafür nicht erst recht wieder ein Passwort eingeben muss. Denn wenn das Programm das Passwort auslesen und verwenden kann, dann kann es jeder.
    Es gibt dafür keine perfekte Lösung, sonst würden Passwort-Manager ja auch kein Master-Passwort benötigen.
    Aber es gibt Kompromisse:
    Jetzt handelt es sich allerdings um eine Anwendung die im Stundentakt den Content abspeichert

    Das hört sich so an, als würde das Programm recht lange laufen. Das Passwort, solange das Programm läuft, einfach im RAM liegen zu lassen, ist kein Problem*.
    Erst wenn das Programm gestartet wird, solltest Du einmal nach dem Passwort fragen, und Dir die Eingabe dann merken und für spätere Ver-/Entschlüsselungen wiederverwenden.


    *Es ist dann ein Problem, wenn z.B. Malware im Speicher Deines Programms rumpfuscht, oder wenn ein MemoryDump erstellt wird, weil da theoretisch das Passwort dann im Klartext drin steht. Aber dieses Problem besteht immer.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils

    C#-Quellcode

    1. private static SymmetricAlgorithm encryption = new RijndaelManaged();
    2. private static readonly byte[] iv = { 23, 43, 134, 255, 123,67,21, 55 };
    3. private static void Init(String key) {
    4. var ckey = new Rfc2898DeriveBytes(key, iv);
    5. encryption.Key = ckey.GetBytes(encryption.KeySize / 8);
    6. encryption.IV = ckey.GetBytes(encryption.BlockSize / 8);
    7. encryption.Padding = PaddingMode.PKCS7;
    8. }
    9. public static void serialize(Element element, String path, String key) {
    10. Init(key);
    11. var encryptor = encryption.CreateEncryptor();
    12. MemoryStream stream = new MemoryStream();
    13. IFormatter formatter = new BinaryFormatter();
    14. formatter.Serialize(stream, element);
    15. stream.Position = 0;
    16. using (FileStream fs= new FileStream(path, FileMode.Create)) {
    17. var encryptStream = new CryptoStream(fs, encryptor, CryptoStreamMode.Write);
    18. stream.CopyTo(encryptStream);
    19. encryptStream.FlushFinalBlock();
    20. encryptStream.Close();
    21. }
    22. }


    Niko Ortner schrieb:

    Das Passwort irgendwo abzuspeichern ist immer dann ein Problem, wenn der User dafür nicht erst recht wieder ein Passwort eingeben muss. Denn wenn das Programm das Passwort auslesen und verwenden kann, dann kann es jeder.
    Es gibt dafür keine perfekte Lösung, sonst würden Passwort-Manager ja auch kein Master-Passwort benötigen.


    Dessen bin ich mir vollkommen bewusst. Ich suche eine Lösung die es einem Angreifer möglichst schwer macht.

    Niko Ortner schrieb:

    als würde das Programm recht lange laufen. Das Passwort, solange das Programm läuft, einfach im RAM liegen zu lassen, ist kein Problem*


    Ja das tut es und der Rechner auf dem das Programm zum Einsatz kommt ist relativ gut gegen Schadsoftware gesichert.

    Niko Ortner schrieb:

    Erst wenn das Programm gestartet wird, solltest Du einmal nach dem Passwort fragen, und Dir die Eingabe dann merken und für spätere Ver-/Entschlüsselungen wiederverwenden.


    Das ist eine Lösung, die ich mir auch überlegt habe und das Maximum dessen ist was ich dem Nutzer "zumuten" möchte, denn das Programm liegt im Autostart. Problem der Lösung ist allerdings das der Nutzer bei einer Änderung des Passwortes nicht mehr auf ältere Daten zugreifen kann, da er nicht mehr weiß, zu welchem Zeitpunkt er welches Kennwort eingegeben hat.
    Szenario:
    Tag 1: Nutzer erstellt Daten, wählt als Passwort qwertz
    Tag 2-18: Nutzer wechselt jeden Tag das Passwort
    Tag 20: Nutzer will Daten von Tag 1 wieder ansehen können, hat aber keine Ahnung mehr was das Passwort war.

    Wie kann ich das System gegenüber solchen Szenarien idiotensicher machen?

    8-) faxe1008 8-)
    Problem der Lösung ist allerdings das der Nutzer bei einer Änderung des Passwortes nicht mehr auf ältere Daten zugreifen kann

    Verstehe.
    Das Problem ließe sich lösen, wenn Du die bestehenden Daten beim Ändern des Passwortes mit dem alten Passwort entschlüsselst und mit dem neuen direkt wieder verschlüsselst*.
    Aber irgend ein Passwort muss sich der User immer merken, und ein Wechsel sollte für den User auch ganz klar als solcher gekennzeichnet sein (anstatt einfach nur Daten mit dem neuen Passwort zu verschlüsseln).

    *Du kannst auch einen Zwischenschritt einbauen.
    Die Daten werden mit einem generierten Schlüssel und IV (nicht Passwort und Salt) verschlüsselt und in die Datei geschrieben. Dieser generierte Schlüssel und IV werden dann durch das vom User eingegebene Passwort und einen generierten Salt verschlüsselt und neben die verschlüsselten Daten geschrieben. (Der Salt wird dann natürlich auch noch hineingeschrieben.)
    Wenn Du das Passwort ändern willst, musst Du nur den verschlüsselten Schlüssel und IV auslesen, mit dem alten Passwort entschlüsseln, mit dem neuen Passwort verschlüsseln und wieder zurückschreiben, anstatt das mit den ganzen Daten zu machen.

    Ganz nebenbei:

    Das Byte-Array, das Du "iv" genannt hast, ist eigentlich ein Salt. Der sollte pro Verschlüsselung zufällig generiert werden und dann im Klartext neben den verschlüsselten Daten abgespeichert werden. Siehe dazu auch AES Verschlüsselung
    Der Sinn ist, dass, falls jemand den Key und IV für eine Datei gefunden hat, derjenige nicht auch alle anderen Dateien entschlüsseln kann, die mit dem gleichen Passwort erstellt wurden. Denn ohne Angabe eines Salts wird aus dem gleichen Passwort immer der gleiche Schlüssel. Wirft man bei DeriveBytes noch einen zufällig generierten Salt rein (bei Dir ist der im Moment immer gleich), kommt zwar für die selbe Salt+Passwort-Kombination immer der gleiche Key und IV heraus (macht ja Sinn, sonst kann mans nicht mehr entschlüsseln), aber da der Salt pro Datei neu generiert wird, ist auch der Schlüssel und IV pro Datei unterschiedlich.

    Und Du hast viele Dinge noch offen, die IDisposable implementieren: ckey, encryptor und stream (encryption auch, wiederverwendest Du ja).
    Dagegen wird encryptStream.FlushFinalBlock(); und encryptStream.Close(); nicht benötigt, das Dispose durch den Using-Block aufgerufen wird, welches das dann intern auch macht.
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils
    @faxe1008 Wenn das Programm permanent läuft, musste nix speichern, da kannste alles im Ram halten.
    Nur beim Start musste Deinen Key eingeben.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Meine Idee:
    Daten mit dem Passwort entschlüsseln. Daten mit einem randomisierten Passwort verschlüsseln und so im Ram halten, das randomisierte Passwort in einem SecureString halten.

    Natürlich sind trotzallem die Daten nicht wirklich sicher, aber ich denke da kommst du auch nicht drum herum.

    Durch diese Vorgehensweise hast du den Vorteil, dass ein Hacker zumindest nicht an das Ursprüngliche Passwort kommt(außer er holt es genau im richtigen Moment ausm Speicher). Und er immernoch den SecureString entschlüsseln muss, der vom Betriebssystem gehandhabt wird. Der SecureString ist aber natürlich auch nicht wirklich Secure, mit genügend Aufwand kommt man dann auch an das randomisierte Passwort und kommt an die Daten. Aber hey immerhin nicht an das Ursprüngliche Passwort, somit ist immerhin keine Manipulation der Daten möglich.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---