Lektion 1 in sicherer Programmierung: Verwenden Sie Ihre IVs nicht wieder

May 10 2023
Ich habe [hier] einen Artikel über die jüngste Samsung-Sicherheitslücke geschrieben und in einem Kommentar hieß es: „Es ist ein alter Fehler, die Wiederverwendung von IV (Initialisierungsvektoren) scheint ein sehr grundlegendes Problem zu sein.“ Auf den ersten Blick geht der Kommentar vielleicht nicht ins Detail, also versuche ich, den „Fehler“ zu erklären und hoffentlich zu zeigen, dass es sich um eine erschreckend schlechte Codierung handelt … fast fahrlässig in Bezug auf den Schutz und sogar sichtbar als absichtliche Hintertür.
Foto von Med Badr Chemmaoui auf Unsplash

Ich habe einen Artikel über die jüngste Sicherheitslücke bei Samsung geschrieben [ hier ], und in einem Kommentar hieß es: „Es ist ein alter Fehler, die Wiederverwendung von IV (Initialisierungsvektoren) scheint ein sehr grundlegendes Problem zu sein.“ Auf den ersten Blick geht der Kommentar vielleicht nicht ins Detail, also versuche ich, den „Fehler“ zu erklären und hoffentlich zu zeigen, dass es sich um eine erschreckend schlechte Codierung handelt … fast fahrlässig in Bezug auf den Schutz und sogar sichtbar als absichtliche Hintertür .

Und bei einem „sehr grundlegenden Problem“ sollte es sich möglicherweise um „extrem schlechte Codierung“ handeln, und dieser „Fehler“ sollte niemals in vertrauenswürdigen Umgebungen auftreten. Es zeigt einen nahezu völligen Mangel an Wissen darüber, wie Kryptographie funktioniert, mit einer Schwachstelle für Anfänger. Das Papier gibt es hier [1]:

Tatsächlich ist es wieder wie bei WEP, und die WEP-WLAN-Methode hatte einen kleinen IV (Initialisierungsvektor) und als sie eingeführt wurde, war es möglich, Verschlüsselungsströme einfach mit XOR zu verknüpfen und den Klartext zu entdecken. Das schlafende Programm könnte jeden Cisco Access Point in weniger als einem Tag knacken. Glücklicherweise verwenden wir jetzt WPA-2, und das hat keine Wiederverwendung von IV.

Ich hoffe zu zeigen, dass wir uns Sorgen machen sollten, wenn Code wie dieser jemals in die Nähe des Geräts eines Benutzers gelangt. Wenn es tatsächlich jemals eine Hintertür in einem Mobiltelefon gab, dann könnte es diese sein.

Wenn Sie mehr über den „Bug“ erfahren möchten, versuchen Sie es hier:

Krypto-Bug in Samsung Galaxy-Geräten: Zerstörung vertrauenswürdiger Ausführungsumgebungen (TEEs)

Ein schlimmer „Bug“

Jetzt werde ich erklären, wie schlimm dieser „Bug“ ist. Wenn Sie sich für Cybersicherheit interessieren, sollten Sie hoffentlich wissen, dass AES GCM eine Stream-Verschlüsselung ist. Damit nehmen wir einen geheimen Schlüsselwert und einen Salt-Wert (einen IV – Initialisierungsvektor) und generieren einen pseudo-unendlichen Schlüsselstrom. Unser Klartext wird dann einfach mit dem Schlüsselstrom XOR-verknüpft, um unseren Chiffretext zu erzeugen:

Der Salt-Wert sollte dann immer zufällig sein, da ein fester Salt-Wert immer denselben Schlüsselstrom für denselben Klartext erzeugt und wir den Schlüsselstrom durch XOR-Verknüpfung von Chiffrierströmen offenlegen und schließlich den Klartext offenlegen können. Bei der Schlüsselumhüllung ist der Klartext ein Verschlüsselungsschlüssel, und somit wird der vom TEE verwendete Verschlüsselungsschlüssel offengelegt.

Wenn wir IVs wiederverwenden, kann Eve Chiffrierströme XOR-verknüpfen und den Schlüsselstrom (K) offenlegen. Von dort aus kann sie jeden Chiffrierstrom entschlüsseln, indem sie den Chiffrierstrom einfach mit K XOR-verknüpft.

Codierung

AES GCM (Galois Counter Mode) ist ein Stream-Verschlüsselungsmodus für AES. Es basiert auf dem CTR-Modus, wird jedoch in eine Stream-Verschlüsselung umgewandelt. Dies sorgt für eine geringe Latenz beim Verschlüsselungs-/Entschlüsselungsprozess und ermöglicht eine schnelle Verarbeitung. Darüber hinaus ist der AEAD-Modus zur Authentifizierung integriert. Da es sich bei GCM jedoch um einen Stromverschlüsselungsmodus handelt, ist er anfällig für einen Wiederverwendungs-IV -Angriff. Damit ist der IV (Initialisierungsvektor) der Verschlüsselung für zwei Verschlüsselungsnachrichten gleich. Wir können dann die beiden Chiffrierströme zusammen XOR-verknüpfen, um den Chiffrierstromschlüssel ( K ) zu ermitteln. Wir können dann den Klartext enthüllen, indem wir einen beliebigen Chiffrierstrom mit K XOR-verknüpfen .

Probieren wir also etwas Code aus, um dies zu tun. In diesem Fall werde ich Golang verwenden, um die Grundprinzipien der Methode zu zeigen. Ich verwende in diesem Fall einen statischen Schlüssel (da sich dies innerhalb des TEE nicht ändern würde) von „0123456789ABCDEF“ (16 Bytes – 128-Bit-Schlüssel) und eine statische Nonce von „0123456789AB“ (12 Bytes – 96 Bits) [ hier ]:

package main
import (
 "crypto/aes"
 "crypto/cipher"
 "fmt"
 "os"
)
func xor(a, b []byte, length int) []byte {
 c := make([]byte, len(a))
 for i := 0; i < length; i++ {
  c[i] = a[i] ^ b[i]
 }
 return (c)
}
func main() {
 nonce := []byte("0123456789AB")
 key := []byte("0123456789ABCDEF")
 block, err := aes.NewCipher(key)
 if err != nil {
  panic(err.Error())
 }
 msg1 := "hello"
 msg2 := "Hello"
 argCount := len(os.Args[1:])
 if argCount > 0 {
  msg1 = (os.Args[1])
 }
 if argCount > 1 {
  msg2 = (os.Args[2])
 }
 plaintext1 := []byte(msg1)
 plaintext2 := []byte(msg2)
 aesgcm, err := cipher.NewGCM(block)
 if err != nil {
  panic(err.Error())
 }
 ciphertext1 := aesgcm.Seal(nil, nonce, plaintext1, nil)
 ciphertext2 := aesgcm.Seal(nil, nonce, plaintext2, nil)
 xor_length := len(ciphertext1)
 if len(ciphertext1) > len(ciphertext2) {
  xor_length = len(ciphertext2)
 }
 ciphertext_res := xor(ciphertext1, ciphertext2, xor_length)
 fmt.Printf("Message 1:\t%s\n", msg1)
 fmt.Printf("Message 2:\t%s\n", msg2)
 fmt.Printf("Cipher 1:\t%x\n", ciphertext1)
 fmt.Printf("Cipher 2:\t%x\n", ciphertext2)
 fmt.Printf("Key:\t\t%x\n", key)
 fmt.Printf("Nonce:\t\t%x\n", nonce)
 fmt.Printf("XOR:\t\t%x\n", ciphertext_res)
 plain1, _ := aesgcm.Open(nil, nonce, ciphertext1, nil)
 plain2, _ := aesgcm.Open(nil, nonce, ciphertext2, nil)
 fmt.Printf("Decrypted:\t%s\n", plain1)
 fmt.Printf("Decrypted:\t%s\n", plain2)
}

Message 1:	hello
Message 2:	Hello
Cipher 1:	7fcbe7378c2b87a5dfb2803d4fcaca8d5cde86dbfa
Cipher 2:	5fcbe7378cf8c68b82a2b8d705354e8d6c0502cef2
Key:		30313233343536373839414243444546
Nonce:		303132333435363738394142
XOR:		2000000000d3412e5d1038ea4aff840030db841508
Decrypted:	hello
Decrypted:	Hello

Message 1: hello
Message 2: Cello
Cipher 1: 7fcbe7378c2b87a5dfb2803d4fcaca8d5cde86dbfa
Cipher 2: 54cbe7378c5638db82df34a46172abed62b887aa48
Key:  30313233343536373839414243444546
Nonce:  303132333435363738394142
XOR:  2b000000007dbf7e5d6db4992eb861603e660171b2
Decrypted: hello
Decrypted: Cello

Abschluss

Das ist eine äußerst schlechte Codierung , und ich würde von einem neuen Absolventen nicht dieses Maß an Umsetzung erwarten. Wenn ein Entwicklungsteam, das innerhalb eines TEE Code erstellt, einen Wiederverwendungs-IV-Angriff nicht versteht, muss es an einem Schulungskurs für sicheres Codieren teilnehmen, bevor es jemals mit vertrauenswürdigerem Code in Berührung kommt. Wenn dies eine absichtliche Hintertür war, ist das eine ganz andere Geschichte. Ich hoffe, es war nur ein Fehler, aber wir müssen unsere Kenntnisse in der Erstellung von TEEs wirklich verbessern, da diese auch in Cloud-basierten Systemen laufen.

Referenz

[1] Shakevsky, A., Ronen, E. & Wool, A. (2022). Vertrauen stirbt im Dunkeln: Licht ins Dunkel des TrustZone Keymaster-Designs von Samsung. Kryptologie-ePrint-Archiv .