Lezione 1 nella programmazione sicura: non riutilizzare i tuoi IV
Ho scritto un articolo sulla recente vulnerabilità di Samsung [ qui ], e un commento diceva... "è un vecchio bug, il riutilizzo di IV (Initialisation Vector) sembra un problema molto semplice". A prima vista, il commento forse non entra abbastanza nei dettagli, quindi cercherò di spiegare il "bug" e, si spera, di mostrare che si tratta di una codifica incredibilmente cattiva... quasi negligente in termini di protezione, e potrebbe anche essere vista come backdoor intenzionale .
E per un "problema molto semplice", dovrebbe forse essere "codifica estremamente scadente", e questo "bug" non dovrebbe mai, mai essere visto all'interno di ambienti affidabili. Mostra una quasi totale mancanza di conoscenza su come funziona la crittografia, con una vulnerabilità da principiante. Il documento è qui [1]:
In effetti, è di nuovo come WEP, e dove il metodo WEP Wifi aveva un piccolo IV (Vettore di inizializzazione), e quando è stato implementato, era possibile solo XOR cifrare i flussi e scoprire il testo in chiaro. Il programma addormentato potrebbe violare qualsiasi punto di accesso Cisco in meno di un giorno. Fortunatamente ora usiamo WPA-2 e che non ha il riutilizzo dell'IV.
Spero di dimostrare che dovremmo essere preoccupati se un codice come questo si avvicina mai al dispositivo di un utente. Infatti, se c'è mai stata una backdoor in un telefono cellulare, potrebbe essere questa.
Se vuoi leggere del "bug", prova qui:
Bug crittografico nei dispositivi Samsung Galaxy: violazione degli ambienti di esecuzione attendibili (TEE)Un brutto "bug"
Ora spiegherò quanto sia grave questo "bug". Se sei interessato alla sicurezza informatica, dovresti sapere che AES GCM è un cifrario a flusso. Con questo, prendiamo un valore chiave segreto e un valore salt (un vettore di inizializzazione IV) e generiamo un keystream pseudo infinito. Il nostro testo in chiaro viene quindi semplicemente sottoposto a XOR con il flusso di chiavi per produrre il nostro testo cifrato:
Il valore salt dovrebbe quindi essere sempre casuale, poiché un valore salt fisso produrrà sempre lo stesso keystream per lo stesso testo in chiaro, e dove possiamo rivelare il keystream mediante XOR-ing di flussi di cifratura e infine rivelare il testo in chiaro. Nel caso del key wrapping, il testo in chiaro è una chiave di cifratura, e quindi verrà rivelata la chiave di cifratura utilizzata dal TEE.
Se riutilizziamo gli IV, Eve sarà in grado di XOR cifrare insieme i flussi e rivelare il keystream (K). Da lì può decrittografare ogni flusso di cifratura, ma semplicemente XOR-ing il flusso di cifratura con K.
Codifica
AES GCM (Galois Counter Mode) è una modalità di cifratura a flusso per AES. Si basa sulla modalità CTR ma si converte in un cifrario a flusso. Ciò fornisce una bassa latenza nel processo di crittografia/decrittografia ed è veloce da elaborare. Insieme a questo, integra la modalità AEAD per l'autenticazione. Ma poiché GCM è una modalità di cifratura a flusso, è aperta a un attacco IV di riutilizzo . Con questo, l'IV (Initialization Vector) del cifrario è lo stesso per due messaggi cifrati. Possiamo quindi eseguire lo XOR sui due flussi di cifratura insieme per rivelare la chiave del flusso di cifratura ( K ). Possiamo quindi rivelare il testo in chiaro eseguendo lo XOR su qualsiasi flusso di cifratura con K .
Quindi, proviamo un po' di codice per farlo. In questo caso, userò Golang per mostrare i principi di base del metodo. Userò una chiave statica in questo caso (poiché non cambierebbe all'interno del TEE) di "0123456789ABCDEF" (16 byte - chiave a 128 bit) e un nonce statico di "0123456789AB" (12 byte - 96 bit) [ qui ]:
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
Conclusione
Questa è una codifica estremamente negativa e non mi aspetterei questo livello di implementazione da un neolaureato. Se un team di sviluppo che crea codice all'interno di un TEE non comprende un attacco IV di riutilizzo, deve seguire un corso di formazione sulla codifica sicura prima di toccare qualsiasi altro codice affidabile. Se questa era una backdoor intenzionale, questa è tutta un'altra storia. Spero sia stato solo un bug, ma dobbiamo davvero migliorare le nostre conoscenze nella creazione di TEE, poiché anche questi funzionano all'interno di sistemi basati su cloud.
Riferimento
[1] Shakevsky, A., Ronen, E. e Wool, A. (2022). La fiducia muore nell'oscurità: far luce sul design TrustZone Keymaster di Samsung. Archivio ePrint di crittografia .