it-swarm-eu.dev

Lehren und Missverständnisse in Bezug auf Verschlüsselung und Kryptologie

Kryptologie ist ein so weit gefasstes Thema, dass selbst erfahrene Programmierer in den ersten paar Fällen fast immer Fehler machen. Die Verschlüsselung ist jedoch ein so wichtiges Thema, dass wir uns diese Fehler oft nicht leisten können.

Mit dieser Frage soll ermittelt und aufgelistet werden, was nicht mit einem bestimmten Algorithmus oder einer bestimmten API zu tun hat. Auf diese Weise können wir aus den Erfahrungen anderer lernen und die Verbreitung schlechter Praktiken verhindern.

Um diese Frage konstruktiv zu halten, bitte

  1. Fügen Sie ein "falsches" Beispiel hinzu
  2. Erklären Sie, was an diesem Beispiel falsch ist
  3. Stellen Sie eine korrekte Implementierung bereit (falls zutreffend).
  4. Geben Sie nach besten Kräften Referenzen zu Nr. 2 und Nr. 3 an.
68

Wirf keine eigene Krypto.

Erfinden Sie keinen eigenen Verschlüsselungsalgorithmus oder -protokoll. das ist extrem fehleranfällig. Wie Bruce Schneier gerne sagt:

"Jeder kann einen Verschlüsselungsalgorithmus erfinden, den er selbst nicht brechen kann. Es ist viel schwieriger, einen zu erfinden, den niemand sonst brechen kann.".

Krypto-Algorithmen sind sehr kompliziert und müssen intensiv überprüft werden, um sicherzustellen, dass sie sicher sind. Wenn Sie Ihre eigenen erfinden, werden Sie das nicht bekommen, und es ist sehr leicht, mit etwas Unsicherem zu enden, ohne es zu merken.

Verwenden Sie stattdessen einen kryptografischen Standardalgorithmus und ein Standardprotokoll. Es besteht die Möglichkeit, dass jemand anderes zuvor auf Ihr Problem gestoßen ist und einen geeigneten Algorithmus für diesen Zweck entwickelt hat.

Am besten verwenden Sie ein gut geprüftes Schema auf hoher Ebene: Verwenden Sie für die Kommunikationssicherheit TLS (oder SSL). Verwenden Sie für ruhende Daten GPG (oder PGP). Wenn Sie dies nicht tun können, verwenden Sie eine hochrangige Kryptobibliothek wie cryptlib , GPGME, Keyczar oder NaCL anstelle von a Low-Level-One wie OpenSSL, CryptoAPI, JCE usw. Vielen Dank an Nate Lawson für diesen Vorschlag.

76
D.W.

Verwenden Sie keine Verschlüsselung ohne Nachrichtenauthentifizierung

Es ist ein sehr häufiger Fehler, Daten zu verschlüsseln, ohne sie auch zu authentifizieren.

Beispiel: Der Entwickler möchte eine Nachricht geheim halten, verschlüsselt die Nachricht daher im AES-CBC-Modus. Der Fehler: Dies reicht für die Sicherheit bei aktiven Angriffen, Wiederholungsangriffen, Reaktionsangriffen usw. nicht aus. Es sind Angriffe auf die Verschlüsselung ohne Nachrichtenauthentifizierung bekannt, und die Angriffe können sehr schwerwiegend sein. Das Update besteht darin, die Nachrichtenauthentifizierung hinzuzufügen.

Dieser Fehler hat zu schwerwiegenden Sicherheitslücken in bereitgestellten Systemen geführt, die Verschlüsselung ohne Authentifizierung verwendeten, einschließlich ASP.NET , XML Verschlüsselung , Amazon EC2 , JavaServer Faces, Ruby on Rails, OWASP ESAPI , IPSEC , WEP , wieder ASP.NET und SSH2 Sie möchten nicht der nächste auf dieser Liste sein.

Um diese Probleme zu vermeiden, müssen Sie bei jeder Anwendung der Verschlüsselung die Nachrichtenauthentifizierung verwenden. Sie haben zwei Möglichkeiten, dies zu tun:

  • Die wahrscheinlich einfachste Lösung besteht darin, ein Verschlüsselungsschema zu verwenden, das authentifizierte Verschlüsselung bereitstellt, z. B. GCM, CWC, EAX, CCM, OCB. (Siehe auch: 1 .) Das authentifizierte Verschlüsselungsschema übernimmt dies für Sie, sodass Sie nicht darüber nachdenken müssen.

  • Alternativ können Sie Ihre eigene Nachrichtenauthentifizierung wie folgt anwenden. Verschlüsseln Sie zuerst die Nachricht unter Verwendung eines geeigneten Verschlüsselungsschemas mit symmetrischem Schlüssel (z. B. AES-CBC). Nehmen Sie dann den gesamten Chiffretext (einschließlich aller für die Entschlüsselung erforderlichen IVs, Nonces oder anderer Werte), wenden Sie einen Nachrichtenauthentifizierungscode an (z. B. AES-CMAC, SHA1-HMAC, SHA256-HMAC) und hängen Sie den resultierenden MAC-Digest an den an Chiffretext vor der Übertragung. Überprüfen Sie auf der Empfangsseite, ob der MAC-Digest gültig ist, bevor Sie ihn entschlüsseln. Dies wird als Verschlüsselungs- und Authentifizierungskonstruktion bezeichnet. (Siehe auch: 1 , 2 .) Dies funktioniert ebenfalls gut, erfordert jedoch etwas mehr Sorgfalt von Ihnen.

47
D.W.

Seien Sie vorsichtig, wenn Sie mehrere Zeichenfolgen vor dem Hashing verketten.

Ein Fehler, den ich manchmal sehe: Leute wollen einen Hash der Strings S und T. Sie verketten sie, um einen einzelnen String S || T zu erhalten, und hashen ihn dann, um H (S || T) zu erhalten. Das ist fehlerhaft.

Das Problem: Durch die Verkettung wird die Grenze zwischen den beiden Zeichenfolgen nicht eindeutig. Beispiel: builtin || securely = built || insecurely. Anders ausgedrückt, der Hash H (S || T) identifiziert die Zeichenfolge S und T nicht eindeutig. Daher kann der Angreifer möglicherweise die Grenze zwischen den beiden Zeichenfolgen ändern, ohne den Hash zu ändern. Wenn Alice beispielsweise die beiden Zeichenfolgen builtin und securely senden wollte, konnte der Angreifer sie in die beiden Zeichenfolgen built und insecurely ändern, ohne die zu ungültig zu machen Hash.

Ähnliche Probleme treten auf, wenn eine digitale Signatur oder ein Nachrichtenauthentifizierungscode auf eine Verkettung von Zeichenfolgen angewendet wird.

Die Lösung: Verwenden Sie anstelle einer einfachen Verkettung eine Codierung, die eindeutig decodierbar ist. Anstatt H (S || T) zu berechnen, könnten Sie beispielsweise H (Länge (S) || S || T) berechnen, wobei Länge (S) ein 32-Bit-Wert ist, der die Länge von S in Bytes angibt. Oder eine andere Möglichkeit besteht darin, H (H (S) || H (T)) oder sogar H (H (S) || T) zu verwenden.

Ein reales Beispiel für diesen Fehler finden Sie unter dieser Fehler in Amazon Web Services oder dieser Fehler in Flickr [pdf].

36
D.W.

Nonces oder IVs nicht wiederverwenden

Viele Betriebsarten erfordern eine IV (Initialisierungsvektor). Sie dürfen denselben Wert niemals zweimal für eine IV wiederverwenden. Dies kann alle Sicherheitsgarantien aufheben und eine katastrophale Sicherheitsverletzung verursachen.

  • Für Stream-Cipher-Betriebsmodi wie den CTR-Modus oder den OFB-Modus ist die Wiederverwendung einer IV eine Sicherheitskatastrophe. Dies kann dazu führen, dass die verschlüsselten Nachrichten trivial wiederhergestellt werden können.

  • Bei anderen Betriebsarten wie dem CBC-Modus kann die Wiederverwendung einer IV in einigen Fällen auch Angriffe zur Wiederherstellung von Klartext erleichtern.

Unabhängig davon, welche Betriebsart Sie verwenden, sollten Sie die IV nicht wiederverwenden. Wenn Sie sich fragen, wie Sie es richtig machen sollen, finden Sie in NIST-Spezifikation eine detaillierte Dokumentation zur ordnungsgemäßen Verwendung der Blockverschlüsselungsmodi.

Das Tarsnap-Projekt ist ein gutes Beispiel für diese Gefahr. Tarsnap verschlüsselt Sicherungsdaten, indem es sie in Blöcke unterteilt und dann jeden Block mit AES im CTR-Modus verschlüsselt. In den Versionen 1.0.22 bis 1.0.27 von Tarsnap wurde dieselbe IV versehentlich wiederverwendet, wodurch die Wiederherstellung von Klartext ermöglicht wurde.

Wie ist es passiert? Um den Tarsnap-Code zu vereinfachen - und in der Hoffnung, das Fehlerpotential zu verringern - nutzte Colin Percival die Gelegenheit, den AES-CTR-Code in eine neue Datei (lib/crypto/crypto_aesctr.c im Tarsnap-Quellcode) umzuwandeln ) und modifizierte die vorhandenen Stellen, an denen AES-CTR verwendet wurde, um diese Routinen zu nutzen. Der neue Code sieht folgendermaßen aus:

/* Daten verschlüsseln. */
 - aes_ctr (& encr_aes-> key, encr_aes-> nonce ++, buf, len, 
 - filebuf + CRYPTO_FILE_HLEN); 
 + if ((stream = 
 + crypto_aesctr_init (& encr_aes-> key, encr_aes-> nonce)) == NULL) 
 + goto err0; 
 + crypto_aesctr_stream (stream, buf, filebuf + CRYPTO_FILE_HLEN, len); 
 + crypto_aesctr_free (Stream); 

Während des Refactorings wird das encr_aes->nonce++ wurde versehentlich in encr_aes->nonce, und als Ergebnis wurde der gleiche Nonce-Wert wiederholt verwendet . Insbesondere wird der CTR-Nonce-Wert nicht erhöht, nachdem jeder Block verschlüsselt wurde. (Der CTR-Zähler wird korrekt inkrementiert, nachdem jeweils 16 Datenbytes verarbeitet wurden. Dieser Zähler wird jedoch für jeden neuen Block auf Null zurückgesetzt.) Ausführliche Informationen werden von Colin Percival in: http: //www.daemonology) beschrieben. net/blog/2011-01-18-tarsnap-Critical-Security-Bug.html

29
Alex Holst

Stellen Sie sicher, dass Sie Zufallszahlengeneratoren mit genügend Entropie setzen.

Stellen Sie sicher, dass Sie Pseudozufallszahlengeneratoren mit Kryptostärke verwenden, um beispielsweise Schlüssel zu generieren, IVs/Nonces auszuwählen usw. Verwenden Sie nicht Rand(), random(), drand48() , usw.

Stellen Sie sicher, dass Sie den Pseudozufallszahlengenerator mit genügend Entropie versehen. Säe es nicht mit der Tageszeit; das ist erraten.

Beispiele: srand(time(NULL)) ist sehr schlecht. Eine gute Möglichkeit, Ihr PRNG] zu setzen, besteht darin, 128 Bits oder echte Zufallszahlen zu erfassen, z. B. von /dev/urandom, CryptGenRandom oder ähnliches. Verwenden Sie in Java SecureRandom und nicht Random. Verwenden Sie in .NET System.Security.Cryptography.RandomNumberGenerator, nicht System.Random. Verwenden Sie in Python random.SystemRandom, nicht random. Vielen Dank an Nate Lawson für einige Beispiele.

Beispiel aus der Praxis: siehe dieser Fehler in früheren Versionen des Browsers von Netscape , mit dem ein Angreifer SSL brechen konnte.

29
D.W.

Verwenden Sie keine Blockverschlüsselung mit EZB für die symmetrische Verschlüsselung

(Gilt für AES, 3DES, ...)

Hier ist ein Beitrag und ein sehr ähnlicher Microsoft KB-Artikel darüber, wie der EZB-Modus zu Code führt, der nicht verschlüsselt ist.

Siehe auch dieser ähnliche Beitrag von Turm

Einfache Textnachricht:

alt text

Dieselbe Nachricht, die im EZB-Modus verschlüsselt ist (egal welche Verschlüsselung Sie verwenden): alt text

Die GENAUE gleiche Nachricht im CBC-Modus (auch hier spielt es keine Rolle, welche Verschlüsselung Sie verwenden): alt text

Der falsche Weg

public static string Encrypt(string toEncrypt, string key, bool useHashing)
{

byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

if (useHashing)
    keyArray = new MD5CryptoServiceProvider().ComputeHash(keyArray);

var tdes = new TripleDESCryptoServiceProvider() 
    { Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };

ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(
    toEncryptArray, 0, toEncryptArray.Length);

return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

Der Fehler befindet sich in der folgenden Zeile

{Key = keyArray, Mode = CipherMode.ECB , Padding = PaddingMode.PKCS7};


Der richtige Weg

Die guten Leute von Microsoft haben mir den folgenden Code geschickt, um den oben verlinkten KB-Artikel zu korrigieren. Dies wird in Fall # 111021973179005 referenziert

Dieser Beispielcode verwendet AES zum Verschlüsseln von Daten, und der Schlüssel für die AES-Verschlüsselung ist der von SHA256 generierte Hashcode. AES ist der AES-Algorithmus (Advanced Encryption Standard). Der AES-Algorithmus basiert auf Permutationen und Substitutionen. Permutationen sind Umordnungen von Daten, und Substitutionen ersetzen eine Dateneinheit durch eine andere. AES führt Permutationen und Substitutionen mit verschiedenen Techniken durch. Weitere Informationen zu AES finden Sie im Artikel „Schützen Sie Ihre Daten mit dem neuen erweiterten Verschlüsselungsstandard“ im MSDN Magazine unter http://msdn.Microsoft.com/en-us/magazine/cc164055.aspx) .

SHA ist der Secure Hash-Algorithmus. SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512) wird jetzt empfohlen. Weitere Informationen zu Hash-Werten in .NET Framework finden Sie unter http://msdn.Microsoft.com/en-us/library/92f9ye3s.aspx#hash_values .

Der Standardwert des Betriebsmodus des symmetrischen Algorithmus für AesCryptoServiceProvider ist CBC. CBC ist der Cipher Block Chaining-Modus. Es führt Feedback ein. Bevor jeder Klartextblock verschlüsselt wird, wird er mit dem Chiffretext des vorherigen Blocks durch eine bitweise exklusive OR - Operation kombiniert. Dies stellt sicher, dass selbst wenn der Klartext viele identische Blöcke enthält, dies der Fall ist Jede Verschlüsselung in einen anderen Chiffretextblock. Der Initialisierungsvektor wird mit dem ersten Klartextblock durch eine bitweise exklusive OR - Operation kombiniert, bevor der Block verschlüsselt wird. Wenn ein einzelnes Bit des Chiffretextblocks Wird entstellt, wird auch der entsprechende Nur-Text-Block entstellt. Außerdem wird ein Bit im nachfolgenden Block an derselben Position wie das ursprüngliche entstellte Bit entstellt. Weitere Informationen zu CipherMode erhalten Sie Siehe http://msdn.Microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx .

Hier ist der Beispielcode.

// This function is used for encrypting the data with key and iv.
byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoProvider with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create encryptor from the AESCryptoProvider.
        using (ICryptoTransform encryptor = aesCryptoProvider.CreateEncryptor())
        {
            // Create memory stream to store the encrypted data.
            using (MemoryStream stream = new MemoryStream())
            {
                // Create a CryptoStream to encrypt the data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
                    // Encrypt the data.
                    cryptoStream.Write(data, 0, data.Length);

                // return the encrypted data.
                return stream.ToArray();
            }
        }
    }
}

// This function is used for decrypting the data with key and iv.
byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoServiceProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoServiceProvier with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create decryptor from the AESCryptoServiceProvider.
        using (ICryptoTransform decryptor = aesCryptoProvider.CreateDecryptor())
        {
            // Create a memory stream including the encrypted data.
            using (MemoryStream stream = new MemoryStream(data))
            {
                // Create a CryptoStream to decrypt the encrypted data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
                {
                    // Create a byte buffer array.
                    byte[] readData = new byte[1024];
                    int readDataCount = 0;

                    // Create a memory stream to store the decrypted data.
                    using (MemoryStream resultStream = new MemoryStream())
                    {
                        do
                        {
                            // Decrypt the data and write the data into readData buffer array.
                           readDataCount = cryptoStream.Read(readData, 0, readData.Length);
                            // Write the decrypted data to resultStream.
                            resultStream.Write(readData, 0, readDataCount);
                        }
                        // Check whether there is any more encrypted data in stream.
                        while (readDataCount > 0);
                        // Return the decrypted data.
                        return resultStream.ToArray();
                    }
                }
            }
        }
    }
}



// This function is used for generating a valid key binary with UTF8 encoding and SHA256 hash algorithm.
byte[] GetKey(string key)
{
    // Create SHA256 hash algorithm class.
    using (SHA256Managed sha256 = new SHA256Managed())

    // Decode the string key to binary and compute the hash binary of the key.
    return sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
}

Weitere Einzelheiten zu den Klassen im Beispielcode finden Sie unter den folgenden Links:

· AesCryptoServiceProvider-Klasse

· SHA256Managed Class

· CryptoStream-Klasse

Darüber hinaus gibt es mehrere Artikel, die zum besseren Verständnis der Kryptografie in .NET Framework beitragen können. Weitere Informationen finden Sie unter den folgenden Links:

· Cryptographic Services

· . NET Framework Cryptography Model

· Ein einfacher Leitfaden zur Kryptographie

· Verschlüsselung ohne Geheimnisse

20

Verwenden Sie nicht denselben Schlüssel für die Verschlüsselung und Authentifizierung. Verwenden Sie nicht denselben Schlüssel für die Verschlüsselung und das Signieren.

Ein Schlüssel sollte nicht für mehrere Zwecke wiederverwendet werden. das kann verschiedene subtile Angriffe eröffnen.

Wenn Sie beispielsweise ein RSA-Paar aus privatem und öffentlichem Schlüssel haben, sollten Sie es nicht sowohl zur Verschlüsselung (mit dem öffentlichen Schlüssel verschlüsseln, mit dem privaten Schlüssel entschlüsseln) als auch zum Signieren (mit dem privaten Schlüssel signieren, mit dem öffentlichen Schlüssel überprüfen) verwenden ): Wählen Sie einen einzelnen Zweck und verwenden Sie ihn nur für diesen einen Zweck. Wenn Sie beide Fähigkeiten benötigen, generieren Sie zwei Schlüsselpaare, eines zum Signieren und eines zum Ver-/Entschlüsseln.

In ähnlicher Weise sollten Sie bei der symmetrischen Kryptografie einen Schlüssel für die Verschlüsselung und einen separaten unabhängigen Schlüssel für die Nachrichtenauthentifizierung verwenden. Verwenden Sie nicht denselben Schlüssel für beide Zwecke.

20
D.W.

Kerckhoffs Prinzip: Ein Kryptosystem sollte sicher sein, auch wenn alles am System außer dem Schlüssel öffentlich bekannt ist

Ein falsches Beispiel: LANMAN-Hashes

Die LANMAN-Hashes wären schwer herauszufinden, wenn niemand den Algorithmus kennen würde. Sobald der Algorithmus jedoch bekannt war, ist es jetzt sehr trivial, ihn zu knacken.

Der Algorithmus lautet wie folgt ( aus Wikipedia ):

  1. Das Kennwort ASCII) des Benutzers wird in Großbuchstaben konvertiert.
  2. Dieses Passwort wird auf 14 Bytes null aufgefüllt
  3. Das Kennwort mit fester Länge ist in zwei Sieben-Byte-Hälften aufgeteilt.
  4. Diese Werte werden verwendet, um zwei DES Schlüssel, einen aus jeder 7-Byte-Hälfte) zu erstellen
  5. Jeder der beiden Schlüssel wird verwendet, um die Konstante ASCII string "KGS! @ # $%" DES-zu verschlüsseln, was zu zwei 8-Byte-Chiffretextwerten führt.
  6. Diese beiden Chiffretextwerte werden zu einem 16-Byte-Wert verkettet, bei dem es sich um den LM-Hash handelt

Da Sie jetzt den Chiffretext dieser Fakten kennen, können Sie den Chiffretext jetzt sehr einfach in zwei Chiffretexte aufteilen, von denen Sie wissen, dass sie in Großbuchstaben geschrieben sind, was zu einer begrenzten Anzahl von Zeichen führt, die das Passwort möglicherweise sein könnte.

Ein korrektes Beispiel: AES-Verschlüsselung

  • Bekannter Algorithmus
  • Skaliert mit Technologie. Erhöhen Sie die Schlüsselgröße, wenn Sie mehr kryptografischen Schwung benötigen
17
Chris Dale

Vermeiden Sie die Verwendung von Passwörtern als Verschlüsselungsschlüssel.

Eine häufige Schwachstelle in vielen Systemen besteht darin, ein Kennwort oder eine Passphrase oder einen Hash eines Kennworts oder einer Passphrase als Verschlüsselungs-/Entschlüsselungsschlüssel zu verwenden. Das Problem ist, dass dies sehr anfällig für Offline-Keysearch-Angriffe ist. Die meisten Benutzer wählen Passwörter, deren Entropie nicht ausreicht, um solchen Angriffen zu widerstehen.

Die beste Lösung besteht darin, einen wirklich zufälligen Verschlüsselungs-/Entschlüsselungsschlüssel zu verwenden, der nicht deterministisch aus einem Kennwort/einer Passphrase generiert wird.

Wenn Sie jedoch eines verwenden müssen, das auf einem Kennwort/einer Passphrase basiert, verwenden Sie ein geeignetes Schema, um die umfassende Schlüsselsuche zu verlangsamen. Ich empfehle PBKDF2 , das iteratives Hashing verwendet (im Sinne von H(H(H(....H(password)...)))) Um die Wörterbuchsuche zu verlangsamen, sorgen Sie dafür, dass ausreichend viele Iterationen verwendet werden, damit dieser Prozess beispielsweise 100 ms auf dem Computer des Benutzers benötigt, um den Schlüssel zu generieren.

13
D.W.

In einem kryptografischen Protokoll: Machen Sie jede authentifizierte Nachricht erkennbar: Keine zwei Nachrichten sollten gleich aussehen

Eine Verallgemeinerung/Variante von:

  • Seien Sie vorsichtig, wenn Sie mehrere Zeichenfolgen vor dem Hashing verketten.
  • Schlüssel nicht wiederverwenden.
  • Nonces nicht wiederverwenden.

Während eines kryptografischen Protokolls können viele Nachrichten ausgetauscht werden, die ohne ein Geheimnis (Schlüssel oder Nonce) nicht gefälscht werden können. Diese Nachrichten können vom Empfangenen überprüft werden, weil er einen öffentlichen (Signatur-) Schlüssel kennt oder weil nur er und der Absender einen symmetrischen Schlüssel oder Nonce kennen. Dadurch wird sichergestellt, dass diese Nachrichten nicht geändert wurden.

Dies stellt jedoch nicht sicher, dass diese Nachrichten während des gleichen Protokolllaufs ausgegeben wurden: Ein Gegner hat diese Nachrichten möglicherweise zuvor oder während eines Protokolls erfasst gleichzeitiger Lauf des Protokolls. Ein Gegner kann viele gleichzeitige Läufe eines kryptografischen Protokolls starten, um gültige Nachrichten zu erfassen und unverändert wiederzuverwenden.

Durch geschickte Wiedergabe von Nachrichten ist es möglicherweise möglich, ein Protokoll anzugreifen, ohne einen Primärschlüssel zu gefährden, ohne RNG, Chiffre usw. anzugreifen.

Indem jede authentifizierte Nachricht des Protokolls für den Empfänger offensichtlich eindeutig gemacht wird, werden die Möglichkeiten zur Wiedergabe nicht geänderter Nachrichten verringert (nicht beseitigt).

13
curiousguy

Verwenden Sie keine unsicheren Schlüssellängen.

Stellen Sie sicher, dass Sie Algorithmen mit einem ausreichend langen Schlüssel verwenden.

Für die Kryptografie mit symmetrischen Schlüsseln würde ich mindestens einen 80-Bit-Schlüssel empfehlen. Wenn möglich, ist ein 128-Bit-Schlüssel eine gute Idee. Verwenden Sie keine 40-Bit-Krypto. Es ist unsicher und kann von Amateuren leicht zerstört werden, indem einfach jeder mögliche Schlüssel ausgiebig ausprobiert wird. Verwenden Sie kein 56-Bit-DES. Es ist nicht trivial zu brechen, aber es liegt in der Reichweite engagierter Angreifer, DES zu brechen. Ein 128-Bit-Algorithmus wie AES ist nicht wesentlich langsamer als 40-Bit-Krypto, sodass Sie keine Entschuldigung für die Verwendung von mieser Krypto haben.

Bei der Kryptografie mit öffentlichen Schlüsseln hängen die Empfehlungen zur Schlüssellänge vom Algorithmus und der erforderlichen Sicherheitsstufe ab. Das Erhöhen der Schlüsselgröße beeinträchtigt auch die Leistung, sodass ein massiver Overkill nicht wirtschaftlich ist. Dies erfordert daher etwas mehr Überlegungen als die Auswahl der Schlüsselgrößen für symmetrische Schlüssel. Für RSA, El Gamal oder Diffie-Hellman würde ich empfehlen, dass der Schlüssel mindestens 1024 Bit beträgt. 1024-Bit-Schlüssel befinden sich jedoch am Rande dessen, was in naher Zukunft knackbar werden könnte, und werden für den modernen Gebrauch im Allgemeinen nicht empfohlen. Wenn möglich, würde ich 1536- oder sogar 2048-Bit-Schlüssel empfehlen. Für die Kryptographie mit elliptischen Kurven erscheinen 160-Bit-Schlüssel angemessen, und 224-Bit-Schlüssel sind besser. Sie können sich auch auf veröffentlichte Richtlinien beziehen, die grobe Äquivalenzen zwischen symmetrischen und öffentlichen Schlüsselgrößen festlegen festlegen.

8
D.W.

Verwenden Sie nicht denselben Schlüssel in beide Richtungen.

Bei der Netzwerkkommunikation besteht ein häufiger Fehler darin, für die Kommunikation in A-> B-Richtung denselben Schlüssel zu verwenden wie für die B-> A-Richtung. Dies ist eine schlechte Idee, da sie häufig Wiederholungsangriffe ermöglicht, bei denen etwas A, das an B gesendet wurde, an A zurückgespielt wird.

Am sichersten ist es, zwei unabhängige Schlüssel auszuhandeln, einen für jede Richtung. Alternativ können Sie einen einzelnen Schlüssel K aushandeln und dann K1 = AES (K, 00..0) für eine Richtung und K2 = AES (K, 11..1) für die andere Richtung verwenden.

8
D.W.

Ein einmaliges Pad ist kein einmaliges Pad, wenn die Taste durch einen Algorithmus gedehnt wird

Die Kennung "One-Time-Pad" (auch als Vernam-Chiffre bezeichnet) wird häufig auf verschiedene kryptografische Lösungen falsch angewendet, um unzerbrechliche Sicherheit zu beanspruchen. Aber per Definition ist eine Vernam-Chiffre genau dann sicher, wenn alle drei dieser Bedingungen erfüllt sind:

  • Das Schlüsselmaterial ist wirklich unvorhersehbar; UND
  • Das Schlüsselmaterial hat die gleiche Länge wie der Klartext. UND
  • Das Schlüsselmaterial wird niemals wiederverwendet.

Jeder Verstoß gegen diese Bedingungen bedeutet, dass es sich nicht mehr um eine einmalige Pad-Verschlüsselung handelt.

Der häufigste Fehler ist, dass eine kurze Taste mit einem Algorithmus gedehnt wird. Diese Aktion verstößt gegen die Unvorhersehbarkeitsregel (unabhängig von der Schlüssellängenregel). Sobald dies erledigt ist, wird das einmalige Pad mathematisch in den Algorithmus zum Strecken von Schlüsseln umgewandelt. Das Kombinieren des Kurzschlüssels mit zufälligen Bytes ändert nur den Suchraum, der erforderlich ist, um den Algorithmus zum Strecken der Schlüssel brutal zu erzwingen. In ähnlicher Weise verwandelt die Verwendung von "zufällig erzeugten" Bytes den Zufallszahlengeneratoralgorithmus in den Sicherheitsalgorithmus.

Hier ist ein einfaches Beispiel. Ich habe eine Nachricht, dass ich mit einem "One-Time-Pad" verschlüsseln werde, das eine kryptografisch sichere Funktion als Schlüsselgenerator verwendet. Ich habe einen geheimen Schlüssel ausgewählt und ihm dann eine Zufallszahl hinzugefügt, um sicherzustellen, dass er nicht wiederverwendet wird. Da ich den Schlüssel nicht wieder verwende, gibt es keine Möglichkeit, den Chiffretext durch Subtrahieren einer Nachricht von einer anderen anzugreifen.

          plaintext : 1234567890123456789012345678901234567890
       key material : 757578fbf23ffa4d748e0800dd7c424a46feb0cc
OTP function (xor)  : ----------
         ciphertext : 67412E83622DCE1B0C1E1A348B04D25872A8C85C

Das Schlüsselmaterial wurde sicher mit SHA-1 generiert, um mein geheimes Passwort (plus zufällig) zu hashen, um es zu erweitern. Jeder Angreifer, der den verwendeten Stretching-Algorithmus * kennt, kann SHA-1 angreifen, indem er verschiedene Eingaben in SHA-1 versucht und die Ausgabe mit dem Chiffretext XOR-verknüpft. Das Erraten des "OTP" -Schlüssels ist jetzt nicht schwieriger als das Erraten der kombinierten Eingaben in den kryptografischen Algorithmus. Diese Eigenschaft gilt unabhängig davon, welcher kryptografische Basisalgorithmus ausgewählt wurde, welche Komplexitätsmaße er enthält oder wie er implementiert oder festgelegt wird.

Möglicherweise haben Sie einen sehr guten Algorithmus zum Strecken von Schlüsseln. Möglicherweise haben Sie auch einen sehr sicheren Zufallszahlengenerator. Ihr Algorithmus ist jedoch per Definition kein einmaliges Pad und hat daher nicht die unzerbrechliche Eigenschaft eines einmaligen Pads.

* Die Anwendung des Kerckhoff-Prinzips bedeutet, dass Sie davon ausgehen müssen, dass der Angreifer immer die verwendeten Algorithmen bestimmen kann.

3
John Deters

Verwenden Sie den richtigen Modus

Verlassen Sie sich aus Sicherheitsgründen nicht auf die Standardeinstellungen der Bibliothek. Insbesondere implementieren viele Bibliotheken, die AES implementieren, den in FIPS 197) beschriebenen Algorithmus, der als EZB-Modus (Electronic Code Book) bezeichnet wird. Dies ist im Wesentlichen eine einfache Abbildung von:

AES(plaintext [32]byte, key [32]byte) -> ciphertext [32]byte

ist sehr unsicher. Die Argumentation ist einfach, während die Anzahl der möglichen Schlüssel im Schlüsselraum ziemlich groß ist, ist das schwache Glied hier die Menge der Entropie in der Nachricht. Wie immer beschreibt xkcd.com besser als ich http://xkcd.com/257/

Es ist sehr wichtig, etwas wie CBC (Cipher Block Chaining) zu verwenden, das Chiffretext [i] im Grunde genommen zu einem Mapping macht:

ciphertext[i] = SomeFunction(ciphertext[i-1], message[i], key)

Um nur auf einige Sprachbibliotheken hinzuweisen, bei denen diese Art von Fehler leicht zu begehen ist: http://golang.org/pkg/crypto/aes/ bietet eine AES-Implementierung, die bei naiver Verwendung funktioniert Ergebnis im EZB-Modus.

Die Pycrypto-Bibliothek verwendet beim Erstellen eines neuen AES-Objekts standardmäßig den EZB-Modus.

OpenSSL macht das richtig. Jeder AES-Aufruf bezieht sich explizit auf die Funktionsweise. Wirklich das Sicherste, was IMO ist, ist zu versuchen, keine Low-Level-Krypto wie diese selbst zu machen. Wenn Sie dazu gezwungen sind, gehen Sie so vor, als würden Sie (vorsichtig) auf Glasscherben gehen, und stellen Sie sicher, dass Ihre Benutzer berechtigt sind, Ihnen ihr Vertrauen zu schenken, um ihre Daten zu schützen.

3
Shane Hansen

Verwenden Sie auf vielen Geräten nicht denselben Schlüssel erneut.

Je häufiger Sie einen kryptografischen Schlüssel gemeinsam nutzen, desto weniger wahrscheinlich ist es, dass Sie ihn geheim halten können. Einige bereitgestellte Systeme haben auf jedem Gerät im System denselben symmetrischen Schlüssel wiederverwendet. Das Problem dabei ist, dass früher oder später jemand den Schlüssel von einem einzelnen Gerät extrahiert und dann alle anderen Geräte angreifen kann. Also tu das nicht.

Siehe auch "Symmetrische Verschlüsselung nicht # 6: Teilen Sie keinen einzelnen Schlüssel für viele Geräte" in dieser Blog-Artikel . Dank an Matthew Green.

3
D.W.

Verwenden Sie bei der Festplattenverschlüsselung kein OTP oder keine Stream-Verschlüsselung

Beispiel 1

Angenommen, zwei Dateien werden mithilfe einer Stream-Verschlüsselung/OTP gespeichert. Wenn die Datei nach einer geringfügigen Bearbeitung erneut gespeichert wird, kann ein Angreifer feststellen, dass nur bestimmte Bits geändert wurden, und auf Informationen zum Dokument schließen. (Stellen Sie sich vor, Sie ändern die Anrede "Lieber Bob" in "Liebe Alice").

Beispiel 2

Die Ausgabe enthält keine Integrität: Ein Angreifer kann den Chiffretext und den Inhalt der Daten ändern, indem er die Daten einfach XOR-verknüpft.

Take away: Änderungen am Chiffretext werden nicht erkannt und haben vorhersehbare Auswirkungen auf den Klartext.

Lösung

Verwenden Sie für diese Situationen eine Blockverschlüsselung, die Nachrichtenintegritätsprüfungen umfasst

1

Vertraue keinen Standards.

In der Kryptographie gibt es viele Standards, und manchmal müssen Sie sie verwenden. Aber nehmen Sie nicht an, dass die Leute, die die Standards schreiben, die Kryptographie, die sie brauchten, angemessen verstanden haben. Zum Beispiel wurde EAX in einem Netzwerkstandard überarbeitet. EAX hat einen Sicherheitsnachweis. Die überarbeitete Version nicht.

MD5 ist ein Standard. Es ist jetzt kaputt. Chip und PIN wurde dank einer Vielzahl gefährlicher Funktionen wiederholt gebrochen. GPG unterstützt weiterhin DSA-Schlüssel, die für den Komfort zu kurz sind. SSL verfügt über Optionen, die nicht verwendet werden sollten und erforderlich sind Vermeiden Sie sie.

Was kann man dagegen tun? Seien Sie vorsichtig, verstehen Sie die bekannten Risiken und halten Sie sich an die Erforschung neuer Risiken.

1
Watson Ladd

Verwenden Sie nur MACs, die nicht anfällig für Angriffe auf Nachrichtenerweiterungen sind.

Ein MAC ist ein Hash-Code, der die Nachrichtenintegrität (keine Änderungen usw.) eines bestimmten Klartextes sicherstellt. Viele Implementierungen und veröffentlichte Standards schützen einen MAC nicht vor einem Angreifer, der zusätzliche Daten an den MAC anfügt.

Die Lösung hierfür besteht darin, dass die MAC-Implementierung einen zweiten (anderen) Schlüssel verwendet und die endgültige Ausgabe neu verschlüsselt.

ECBC und NMAC sind Beispiele für Chiffren, die den Angriff auf die Nachrichtenerweiterung korrekt verhindern.

Lösung:

  • Verwenden Sie Encrypted CBC (ECBC) anstelle von raw CBC
  • Verwenden Sie NMAC anstelle von cascade
0

Verwenden Sie niemals ein One Time Pad (OTP) oder einen Stream-Chiffrierschlüssel mehr als einmal

Ein zweimal angewendetes OTP bedeutet, dass die mit "perfekter Geheimhaltung" verschlüsselten Daten entschlüsselt und klar sind. Dies geschieht, weil die Daten zweimal XOR'ed werden.

Beispiel

Angenommen, ein OTP/oder Stream mit demselben Schlüssel wird wiederverwendet.

Ein Angreifer sammelt viele Daten, die von einem Client an einen Server gesendet werden, und XORs einen Satz von zwei Paketen zusammen, bis sich die beiden Pakete gegenseitig entschlüsseln (oder eine Teilmenge darin).

Die ASCII-Codierung weist eine ausreichende Redundanz auf, was bedeutet, dass bei ausreichendem Chiffretext die ursprünglichen Nachrichten (zusammen mit dem geheimen OTP-Schlüssel) decodiert werden können.

Beispiele aus der Praxis

  • Projekt Verona (1941-46) für ein Beispiel eines von den Russen verwendeten OTP, das anschließend vom US-Geheimdienst entschlüsselt wurde

  • Microsoft PPTPv1 verschlüsselt sowohl den Client als auch den Server Daten mit demselben Schlüssel.

  • WEP verwendet denselben Schlüssel erneut, sobald 2 ^ 24 Pakete gesendet wurden oder wenn eine NIC -Karte zurückgesetzt wurde. Das erste Problem ist darauf zurückzuführen, dass die IV 24 Bit lang ist, was nach 16 Millionen Frames der Fall ist Es wird ein Zwei-Zeit-Pad erstellt. Das zweite Problem tritt bei Hardware-Implementierungen auf, bei denen die IV nach einem Aus- und Wiedereinschalten auf Null zurückgesetzt wird, was zu einem Zwei-Zeit-Pad führt. Dieses Problem ist leicht zu erkennen, da die IV im Klartext gesendet wird.

Empfehlungen

  • Für jede Sitzung sollte ein neuer Schlüssel erstellt werden (z. B. TLS).

  • Der Client sollte ein OTP (oder eine Stream-Verschlüsselung mit PRG) mit dem Server verwenden, und der Server sollte beim Verschlüsseln von Daten mit dem Client ein anderer Schlüssel verwenden

  • Anstatt viele, viele Schlüssel zu generieren, ist es möglich, einen einzelnen Schlüssel mithilfe eines PRG (vorausgesetzt, Sie vertrauen dem PRG) zu einem langen Stream zu erweitern und jedes Segment dieser Erweiterung als Schlüssel zu verwenden.

  • Beachten Sie, dass nicht alle PRGs im Inkrementierungsmodus arbeiten und möglicherweise zufällige Eingaben erforderlich sind. (RC4 hat dieses Problem im Inkrement-Modus)

0

Verwenden Sie nicht RC4

RC4 wurde 1987 für die Verwendung als Stream-Chiffre entwickelt. Es wird in HTTPS und WEP verwendet.

Es gibt Schwächen

  1. Die anfängliche Ausgabe weist eine Vorspannung auf: Pr [2. Byte = 0] = 2/256
  2. Die Wahrscheinlichkeit, dass 16 Bits gleich Null sind, beträgt 1/256 ^ 2 + 1/256 ^ 3. Dies geschieht, nachdem mehrere Gigs von Daten verschlüsselt wurden.
  3. Anfällig für verwandte Schlüsselangriffe, bei denen sich nur die IV ändert, der Schlüssel jedoch gleich bleibt.

Take away Wenn Sie RC4 verwenden müssen, ignorieren Sie die ersten 256 Bytes, da diese voreingenommen sind. Wenn Sie RC4 für Datenauftritte verwenden, ermöglicht die Verzerrung in RC4 Angriffe auf alle zuvor verschlüsselten Daten.

0

Verwenden Sie moderne Stream-Prozessoren, die in Hardware oder Software ordnungsgemäß funktionieren

Nicht alle Stream-Chiffren sind für die Implementierung in Hardware oder Software ausgelegt. Linear Feedback Shift Register (LFSR) ist ein Beispiel für eine weit verbreitete Hardware-Verschlüsselung, die leicht beschädigt werden kann.

LFSR wird verwendet in:

  • DVD-Verschlüsselung (auch als CSS bekannt) 2 LFSR
  • GSM-Verschlüsselung (A5/1.2) 3 LSFR
  • Bluetooth (E0): 4 LFSR

Die Hardware für die oben genannten Zwecke ist weit verbreitet und daher schwer zu aktualisieren oder auf den neuesten Stand zu bringen. Alle oben genannten Punkte sind stark beschädigt und sollten für eine sichere Kommunikation nicht als vertrauenswürdig eingestuft werden.

Angriff:

Da der Schlüssel während der Verschlüsselung in zwei Abschnitte unterteilt wird (17 Bit und 25 Bit) und diese Bits zum Verschlüsseln desselben Chiffretextes verwendet werden, ist es möglich, Kenntnisse des MPEG-Formats zu verwenden und einen 17-Bit-Schlüssel zur Extrapolation des 25-Bit-Schlüssels zu erzwingen ist.

Dies ist kaum neu, aber FOSS ist leicht zu finden, was dieses Problem demonstriert.

Lösung:

Das eStream-Projekt (2008) qualifizierte 5 Stream-Chiffren, die verwendet werden sollten. Ein bemerkenswerter Unterschied besteht darin, dass die Chiffren anstelle eines Schlüssels mit einer IV einen Schlüssel, eine Nonce und einen Zähler verwenden. Salsa20 funktioniert auf diese Weise und ist so konzipiert, dass es sowohl in Hardware als auch in Software problemlos verwendet werden kann. Insbesondere ist es im x86 SSE2-Befehlssatz enthalten.

Nebenbei

Die modernen Chiffren sind nicht nur sicherer, sondern auch schneller:

PRG          Speed (MB/sec)
RC4              126         (obsolete)
Salsa20/12       643         (modern)
Sosemaunk        727         (modern)
0