Das hat mich dann doch gewurmt. Wie sicher ist die Entropie Generierung der BitBox? Also KI erzähl mal.
----------------------------------
Was kannst du mir zu dem Code sagen, der die Entropie erzeugt zur Schlüssel Generierung:
Ja. Ich habe mir den aktuellen Stand des Repositories und insbesondere den Pfad der Zufalls-/Seed-Erzeugung angesehen. Der interessante Teil ist tatsächlich ziemlich gut aufgebaut.
BitBox02-Firmware auf GitHub
Kurzfassung
Bei der Seed-Erzeugung verlässt sich die BitBox02 nicht auf eine einzige Entropiequelle. Stattdessen werden mindestens drei Quellen miteinander kombiniert:
TRNG des Haupt-Mikrocontrollers
TRNG des Secure Elements
werksseitig eingebrachte Zufallsdaten („factory randomness“)
zusätzlich bei der Seed-Erzeugung:
Host-Entropy von der BitBoxApp
und ein Hash des Benutzerpassworts
Die entscheidende Stelle ist create_and_store_seed() in keystore.rs. Dort wird zunächst ein 32-Byte-Zufallswert erzeugt und anschließend mit Host-Entropy und Passwort-Hash per XOR kombiniert.
1. Die eigentliche Zufallserzeugung
Die zentrale Funktion ist:
bitbox_core_utils::random::random_32_bytes()
Sie macht im Wesentlichen:
MCU TRNG
│
├──── XOR ──── Secure-Element TRNG
│
├──── XOR ──── Factory Randomness
│
▼
SHA-256
│
▼
32 Bytes
Das ist im aktuellen Code sehr klar zu sehen. random_32_bytes() holt zunächst 32 Bytes vom Secure Element und übergibt diese als Mixin an random_32_bytes_with_mixin().
Dort passiert:
mixed = MCU_random
mixed ^= securechip_random
mixed ^= factory_randomness
result = SHA256(mixed)
Der relevante Code macht genau dieses XOR und anschließend SHA-256.
Das finde ich grundsätzlich eine sehr vernünftige Konstruktion.
2. MCU-Entropie
Auf der C-Seite kommt die MCU-Entropie aus:
rand_sync_read_buf8(&RAND_0, random, sizeof(random));
also aus dem Hardware-RNG des ATSAMD51. Der BitBox02 verwendet einen Microchip ATSAMD51J20A als Haupt-Mikrocontroller.
Die Funktion random_32_bytes_mcu() liest 32 Bytes aus diesem RNG und XORt sie in den Ausgabepuffer.
Das bedeutet:
Der MCU-RNG ist eine echte Hardware-Entropiequelle und nicht etwa rand() oder ein PRNG.
rand() wird nur im TESTING-Build verwendet. Im normalen Firmware-Build wird rand_sync_read_buf8() verwendet.
3. Zweite unabhängige Quelle: Secure Element
Das ist meines Erachtens der besonders interessante Teil.
Bei Geräten mit ATECC wird:
bitbox_securechip_sys::atecc_random(...)
aufgerufen. Das Secure Element liefert also seinerseits 32 Random Bytes.
Bei der neueren Optiga-Variante wird explizit:
OPTIGA_RNG_TYPE_TRNG
verwendet.
Die Architektur ist somit:
┌─────────────────┐
│ ATSAMD51 TRNG │
│ 32 Bytes │
└────────┬────────┘
│
XOR
│
┌────────▼────────┐
│ Secure Element │
│ TRNG │
│ 32 Bytes │
└────────┬────────┘
│
XOR
│
┌────────▼────────┐
│ Factory Random │
│ 32 Bytes │
└────────┬────────┘
│
▼
SHA-256
│
▼
256 Bit
Das hat einen wichtigen Vorteil:
Ein einzelner defekter oder kompromittierter RNG muss nicht automatisch die gesamte Sicherheit zerstören.
4. Factory Randomness
Zusätzlich gibt es eine dritte Quelle:
let factory_randomness = hal_random.factory_randomness();
Diese wird ebenfalls per XOR eingemischt.
Im alten C-Code sieht man das ebenfalls sehr schön:
const uint8_t* factory_randomness =
(uint8_t*)(FLASH_BOOT_START + FLASH_BOOT_LEN - 32);
random[i] ^= factory_randomness[i];
Das ist also eine geräteindividuelle, bereits bei der Herstellung vorhandene Zufallsquelle.
Das ist sicherheitstechnisch interessant, weil damit die Entropie nicht ausschließlich davon abhängt, dass der RNG des frisch gestarteten Mikrocontrollers perfekt funktioniert.
5. Danach SHA-256
Nach dem XOR wird nicht einfach das Ergebnis als Seed verwendet.
Es wird:
SHA256(
MCU_TRNG
XOR
SecureElement_TRNG
XOR
FactoryRandomness
)
berechnet.
Das Ergebnis sind 32 Bytes = 256 Bit.
Das ist ein klassischer Entropy-Mixing/Extraction-Ansatz.
Wichtig ist dabei:
SHA-256 erzeugt keine Entropie.
Es macht aus den verschiedenen Eingangswerten einen gleichmäßig verteilten 256-Bit-Wert.
Die Sicherheit hängt deshalb weiterhin davon ab, dass mindestens eine der Entropiequellen tatsächlich genügend unbekannte Entropie enthält.
6. Und dann kommt noch die Host-Entropy
Jetzt wird es für die eigentliche Seed-Erzeugung noch interessanter.
In create_and_store_seed() passiert:
let mut seed_vec =
bitbox_core_utils::random::random_32_bytes_from_hal(hal).await?;
let seed = &mut seed_vec[..seed_len];
Dann:
for (i, &entropy_byte) in host_entropy.iter().enumerate() {
seed[i] ^= entropy_byte;
}
Also:
Hardware-Entropie
XOR
Host-Entropie
↓
Seed
Die Host-Entropy bestimmt dabei auch die Seed-Größe:
16 Bytes → 12 BIP39-Wörter
32 Bytes → 24 BIP39-Wörter
7. Das Passwort wird ebenfalls eingemischt
Danach wird noch das Passwort verarbeitet:
password_salted_hashed =
hash_data(
password,
"keystore_seed_generation"
);
und anschließend ebenfalls per XOR in den Seed eingebracht.
Damit sieht die tatsächliche Erzeugung ungefähr so aus:
┌───────────────┐
│ MCU TRNG │
└───────┬───────┘
│
XOR
│
┌───────▼───────┐
│ Secure Element│
│ TRNG │
└───────┬───────┘
│
XOR
│
┌───────▼───────┐
│ Factory Random │
└───────┬───────┘
│
SHA-256
│
▼
256 Bit
│
XOR
│
┌───────▼───────┐
│ Host Entropy │
└───────┬───────┘
│
XOR
│
┌───────▼───────┐
│ Password Hash │
└───────┬───────┘
│
▼
BIP39 Entropy
│
▼
12 / 24 Wörter
Das ist wesentlich mehrschichtig als bei vielen einfachen Hardware-Wallet-Implementierungen.
8. Ein wichtiger Punkt: XOR ist nicht automatisch „Entropie addieren“
Hier würde ich bei einer Sicherheitsanalyse genauer hinschauen.
Die Aussage
„3 × 256 Bit Zufall = 768 Bit Entropie“
wäre falsch.
Das Ergebnis ist weiterhin nur 256 Bit breit.
Der Vorteil des XOR ist vielmehr:
Wenn beispielsweise
MCU_TRNG = vollständig kompromittiert
ist, aber
SecureElement_TRNG
wirklich geheim und zufällig ist, dann kann der Angreifer den finalen Wert nicht bestimmen.
Formal:
X = A XOR B XOR C
Wenn der Angreifer A und C kennt, aber B nicht kennt und B gleichverteilt ist, ist auch X gleichverteilt.
Das ist eine sehr nützliche Eigenschaft.
9. Besonders interessant finde ich die Tests
Die Entwickler haben sogar einen Test, der die komplette Kombination nachvollzieht.
Dort werden künstliche Werte eingesetzt:
MCU random
Secure-chip random
Factory randomness
und anschließend wird exakt:
mixed = bytes(
m ^ s ^ f
for m, s, f in zip(...)
)
sha256(mixed)
berechnet. Das Ergebnis wird gegen einen bekannten Testwert verglichen.
Das ist zwar kein Test der tatsächlichen physikalischen Entropiequalität, aber ein guter Test dafür, dass die Mixing-Logik korrekt implementiert ist.
10. Ein Punkt, den ich bei einer echten Auditierung noch untersuchen würde
Hier würde ich nicht bei random.c aufhören.
Der wirklich interessante Teil ist die Frage:
Wie gut sind die beiden Hardware-TRNGs tatsächlich?
Denn SHA-256 kann einen schlechten RNG nicht magisch reparieren.
Ich würde deshalb insbesondere untersuchen:
A. ATSAMD51 TRNG
Wie funktioniert der TRNG des ATSAMD51 intern?
Welche physikalische Entropiequelle verwendet er?
Welche Health Tests gibt es?
Gibt es bekannte Schwachstellen?
Was passiert bei einem Hardwarefehler?
Wird auf einen fehlerhaften/stehengebliebenen RNG geprüft?
B. ATECC608B / Secure Element
Welche konkrete ATECC-Variante steckt in welcher BitBox02-Revision?
Welche TRNG-Implementierung verwendet der Chip?
Welche Entropiegarantien gibt Microchip?
Welche Tests führt der Chip selbst durch?
C. Factory Randomness
Hier wäre für mich besonders interessant:
Wie wird diese Zufallszahl in der Fabrik erzeugt und wie wird verhindert, dass sie für BitBox Swiss bzw. einen Angreifer rekonstruierbar ist?
Denn diese 32 Bytes liegen anschließend offenbar im Flash und werden bei der Randomness-Kombination verwendet.
11. Noch ein interessanter Sicherheitsaspekt
Die Firmware beschreibt selbst, dass die BitBox02 den Seed aus mehreren starken Entropiequellen erzeugt.
Und die Implementierung geht sogar noch darüber hinaus, weil die BitBoxApp host_entropy liefert.
Das bedeutet:
Ein hypothetischer Angreifer müsste für eine vollständige Vorhersage des Seeds mehrere Dinge kontrollieren bzw. kennen.
Bei 24 Wörtern ist der eigentliche BIP39-Entropieteil:
256 Bit Entropie + 8 Bit Checksumme → 24 Wörter.
Der Code akzeptiert beim internen Seed zwar 16, 24 oder 32 Byte, aber bei der normalen Generierung sind 16 oder 32 Byte vorgesehen.
Mein vorläufiges Urteil
Die Konstruktion der Entropie-Mischung gefällt mir.
Besonders positiv:
zwei voneinander getrennte Hardware-RNGs
zusätzliche Factory Randomness
XOR-Mixing statt Vertrauen auf nur eine Quelle
SHA-256 als Extractor
zusätzliche Host-Entropy
zusätzliche Passwort-basierte Beimischung
32-Byte-Ausgabepfad
Tests der Mixing-Funktion
Open-Source-Firmware
Aber ich würde bei einer ernsthaften Sicherheitsbewertung einen Schritt tiefer gehen. Die entscheidende Frage ist nicht mehr „mischt der Code die Zufallsquellen richtig?“ – das tut er ziemlich offensichtlich.
Die entscheidende Frage lautet:
Wie viel echte, unabhängige Entropie liefern RAND_0, der Secure-Element-TRNG und die Factory Randomness unter realen und adversarialen Bedingungen?
Wenn du möchtest, kann ich als Nächstes genau diesen Teil forensisch durchgehen: vom ATSAMD51J20A-TRNG und rand_sync_read_buf8() über den ATECC608B/Optiga-TRNG bis zur physikalischen Entropiequelle und den Health-Tests – und anschließend bewerten, ob die BitBox02 theoretisch auch dann noch sichere Seeds erzeugt, wenn einer der beiden RNGs komplett kaputt oder sogar bösartig manipuliert wäre. Direkt zum Randomness-Code.
#Bitcoin #Nostr #Plebs
GitHub
GitHub - BitBoxSwiss/bitbox02-firmware: Firmware code of the BitBox02 hardware wallet
Firmware code of the BitBox02 hardware wallet. Contribute to BitBoxSwiss/bitbox02-firmware development by creating an account on GitHub.

Feuer der Erwärmung? 💩Etatisten 💩
Seit Tagen ist schon kalt.
#Bitcoin #Nostr #Plebs