Cryptography Engineering, Teil 2: AES auf PCs und Servern

Seite 3: Testing & Betriebsarten

Inhaltsverzeichnis

Mit CppUnit lassen sich diese grundlegenden Algorithmen nun verifizieren. Im Unterverzeichnis tests des Distributions-Tarballs liegen die betreffenden Unit-Tests.

Zunächst ist sicher zu stellen, ob das Konvertieren der Schlüssel aus Strings in das key-Array korrekt funktioniert. Klappt das nicht, kann man sich das Testen der eigentlichen Kryptoalgorithmen sparen – AesConversionTest.cpp enthält die betreffenden Tests. AesConversionTestRunner.cpp beheimatet den Test-Runner, der den Test ausführt. Zunächst erfolgt der Test verschiedener korrekter Schlüssel unterschiedlicher Länge. Anschließend erfolgen noch einige Testläufe mit fehlerhaften Schlüsseln.

In AesAtomicMethodTest.cpp findet der Test der einzelnen AES-Teilfunktionen statt. Als Sollwerte dienen die Operationen aus dem Chiffrebeispiel auf Seite 33 in [4] für den Test. Die Runden 1 bis 9 sowie die erste state-Matrix aus Runde 10 dienen als Referenzdaten. Sie sind als Tabelle in AesAtomicMethodTest::ref als Klassenattribut erfasst. Jede der 46 Zeilen entspricht einem state aus dem Chiffrebeispiel, das der Abbildung~~1 folgend eindimensional "ausgerollt" ist. Gemäß dem Chiffrebeispiel muss die SubBytes-Operation, angewendet auf ref[0], beispielsweise ref[1] ergeben. ShiftRows, angewendet auf ref[1], muss ref[2] ergeben und so fort. Die Tests in den Methoden von AesAtomicMethodTest sind damit weitestgehend selbst erklärend.

Bis zu diesem Punkt haben die Test einige (nicht repräsentative) Fälle durchlaufen. "Grobe Schnitzer" in der Implementierung decken diese sicherlich auf.

Nur die grundlegenden Methoden encipherState() und decipherState() implementieren jeweils die AES-Funktionen Cipher() und InvCipher(). Sie operieren nur über den fixen Blöcken von 128 Bit. Um nun einen vollständigen Chiffrieralgorithmus für beliebig lange Nachrichten zu erhalten, sind diese grundlegenden Methoden in umfassendere Methoden einzubetten. Einige solcher Bespiele sind die öffentlichen Methoden encipher*() und decipher*() in AesEncryption. Sie unterscheiden sich darin, welche Form von Eingabe (String, Vektor, Array) und welche Ausgabe (String, Vektor) sie erzeugen.

Grundsätzlich ist die Arbeitsweise der Methoden dieselbe. Beim Verschlüsseln füllen sie Nachrichten mit einer Länge, die kein Vielfaches von 16 (128-Bit-Block!) sind, mit Nullbytes auf die nächste 16er-Grenze auf. Anschließend wird die Nachricht Block für Block verarbeitet. Hierbei wird zunächst ein state befüllt, dieser mit encipherState() verschlüsselt und anschließend das Ergebnis in das Rückgabeobjekt geschrieben. Beim Entschlüsseln erfolgt das im Wesentlichen nach dem gleichen Schema, das Auffüllen mit Nullbytes entfällt hier.

Der Codeblock zum Ent- und Verschlüsseln in den Methoden besteht aus einem auffälligen switch, der die einzelnen Betriebsmodi der Chiffrierung unterscheidet. Das hier gezeigte Beispiel unterstützt die typischen Modi Electronic Code Book (ECB), Cipher Block Chaining (CBC), Cipher Feedback (CFB) und Output Feedback (OFB). Nähere Beschreibungen zu diesen Modi finden sich in [1] und [5] beziehungsweise bei Wikipedia ([6], [7], [8] und [9]). [5] enthält zudem weitere, hier im Code nicht implementierte Modi. Zudem geht [5] auf die Wahl des passenden Chiffriermodus ein.

Außer dem einfachen ECB benötigen CBC, CFB und OFB für ihren Betrieb noch einen Initialisierungsvektor (IV), um die Methoden setIvFrom*() zu setzen. Der Initialisierungsvektor ist nichts anderes als ein zusätzlicher 128-Bit-Block. Nähere Informationen enthalten die oben genannten Beschreibungen zu den Modi.

Die restlichen Methoden von AesEncryption dienen der Konvertierung beziehungsweise zur Ausgabe von Daten. Bleibt nun noch ein verbindlicher Abnahmetest. Auch dafür kann man mit CppUnit als Klasse AesAlgorithmTest gestalten. Für den Test verwendet man die offiziellen Testvektoren des National Institute of Standards (NIST). Diese sind eine Menge von bekannten Kryptogrammen für einen gegebenen Klartext und Schlüssel und sind als Known Answer Test (KAT) bekannt. Über die Seite des NIST können sie heruntergeladen werden (ZIP-Datei). Exakt diese Testvektoren des KAT liegen als Klassenattribut kat der Klasse AesAlgorithmTest bei. Da die Vektoren sehr umfangreich sind, ist das Array vom Typ AesAlgorithmTest::KatVector in der Datei kat.cpp des Beispielcodes ausgelagert. Die Testvektoren ziehen die Klasse AesAlgorithmTest heran, um einen umfangreichen und standardisierten Test über die Beispielimplementierung durchzuführen. Wie die Datei COMPATIBILITY ausweist, waren die Tests auf einer Vielzahl von Plattformen, 32- wie 64-Bit-Systeme mit Big- und Little-Endian-CPUs, erfolgreich. Der Code entspricht somit der Spezifikation von AES.