Güvenli Programlamada Ders 1: IV'lerinizi Tekrar Kullanmayın
Yakın tarihli Samsung güvenlik açığı [ burada ] hakkında bir makale yazdım ve bir yorum şöyle dedi ... "bu eski bir hata, IV'ün (Başlatma Vektörleri) yeniden kullanımı çok basit bir sorun gibi görünüyor". Görünüşte, yorum belki yeterince ayrıntıya girmiyor, bu yüzden "hatayı" açıklamaya çalışacağım ve umarım bunun şok edici derecede kötü bir kodlama olduğunu göstereceğim ... koruma açısından neredeyse ihmalkar ve hatta görülebilir kasıtlı bir arka kapı olarak .
Ve "çok temel bir sorun" için, belki de "son derece kötü kodlama" olmalı ve bu "hata" güvenilir ortamlarda asla ve asla görülmemelidir . Acemi bir güvenlik açığı ile kriptografinin nasıl çalıştığına dair neredeyse tam bir bilgi eksikliği gösteriyor. Kağıt burada [1]:
Aslında, baştan sona WEP gibi ve WEP Wifi yönteminin küçük bir IV'ye (Başlatma Vektörü) sahip olduğu ve kullanıma sunulduğunda, yalnızca XOR şifre akışlarını ve düz metni keşfetmek mümkündü. Uyuyan program, herhangi bir Cisco erişim noktasını bir günden daha kısa sürede kırabilir. Neyse ki artık WPA-2 kullanıyoruz ve IV'ün yeniden kullanımına sahip değil.
Bunun gibi bir kod bir kullanıcının cihazının yanına gelirse endişelenmemiz gerektiğini göstermeyi umuyorum. Aslında, bir cep telefonunda bir arka kapı varsa , bu da olabilir.
"Böcek" hakkında okumak istiyorsanız, burayı deneyin:
Samsung Galaxy Cihazlarında Kripto Hatası: Güvenilir Yürütme Ortamlarını (TEE'ler) BozmaKötü bir "böcek"
Şimdi, bu "böceğin" ne kadar kötü olduğunu açıklayacağım. Siber güvenlikle ilgileniyorsanız, umarım AES GCM'nin bir akış şifresi olduğunu bilmelisiniz. Bununla, bir gizli anahtar değeri ve bir tuz değeri (bir IV — Başlatma Vektörü) alır ve sözde sonsuz bir anahtar akışı oluştururuz. Düz metnimiz daha sonra şifreli metnimizi üretmek için anahtar dizisiyle XOR'lanır:
Sabit bir salt değeri her zaman aynı düz metin için aynı anahtar akışını üreteceğinden ve burada anahtar akışını XOR-ing şifre akışlarıyla ortaya çıkarabileceğimiz ve sonunda düz metni ortaya çıkarabileceğimiz için, salt değeri her zaman rastgele olmalıdır. Anahtar sarma durumunda, düz metin bir şifreleme anahtarıdır ve bu nedenle TEE tarafından kullanılan şifreleme anahtarı ortaya çıkacaktır.
IV'leri yeniden kullanırsak, Eve şifre akışlarını birlikte XOR'layabilir ve anahtar dizisini (K) ortaya çıkarabilir. Oradan her şifre akışının şifresini çözebilir, ancak şifre akışını K ile XOR'laması yeterlidir.
kodlama
AES GCM (Galois Sayaç Modu), AES için bir akış şifreleme modudur. CTR modunu temel alır, ancak bir akış şifresine dönüştürür. Bu, şifreleme/şifre çözme sürecinde düşük gecikme süresi sağlar ve işlenmesi hızlıdır. Bununla birlikte, kimlik doğrulama için AEAD modunu entegre eder. Ancak GCM bir akış şifreleme modu olduğundan , yeniden kullanım IV saldırısına açıktır . Bununla, şifrenin IV'ü (Başlatma Vektörü) iki şifre mesajı için aynıdır. Ardından, şifre akışı anahtarını ( K ) ortaya çıkarmak için iki şifre akışına XOR uygulayabiliriz. Daha sonra herhangi bir şifre akışını K ile XOR'layarak düz metni ortaya çıkarabiliriz .
Öyleyse, bunu yapmak için bazı kodlar deneyelim. Bu durumda, yöntemin temel ilkelerini göstermek için Golang'ı kullanacağım. Bu durumda "0123456789ABCDEF" (16 bayt — 128 bit anahtar) statik bir anahtar (bu, TEE içinde değişmeyeceği için) ve "0123456789AB" (12 bayt — 96 bit) [ burada ]:
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
Çözüm
Bu son derece kötü bir kodlama ve yeni bir mezundan bu düzeyde bir uygulama beklemezdim. Bir TEE içinde kod oluşturan bir geliştirme ekibi yeniden kullanım IV saldırısını anlamıyorsa, daha güvenilir bir koda dokunmadan önce güvenli bir kodlama eğitimi kursuna gitmeleri gerekir. Bu kasıtlı bir arka kapıysa, bu tamamen başka bir hikaye. Umarım bu sadece bir hatadır, ancak TEE'lerin oluşturulması konusundaki bilgimizi gerçekten geliştirmemiz gerekiyor, çünkü bunlar da Bulut tabanlı sistemlerde çalışıyor.
Referans
[1] Shakevsky, A., Ronen, E., & Wool, A. (2022). Güven Karanlıkta Ölür: Samsung'un TrustZone Keymaster Design'ına Işık Tutmak. Kriptoloji ePrint Arşivi .