Verwendung eines vorhersagbaren Algorithmus im Zufallszahlengenerator
Beschreibung
Verwendung eines vorhersagbaren Algorithmus im Zufallszahlengenerator tritt auf, wenn ein Gerät einen Algorithmus verwendet, der Pseudozufallszahlen auf vorhersagbare Weise generiert. Pseudozufallszahlengeneratoren (PRNGs) haben endlich viele mögliche Zustände, was schließlich zu wiederholenden Mustern führt. Diese Vorhersagbarkeit ermöglicht verschiedene Angriffe wie Reverse Engineering oder Manipulation und kann die Zufälligkeit beeinträchtigen oder interne Zustände offenlegen. Sicherheitskritische Anwendungen erfordern echte Zufallszahlengeneratoren (TRNGs), die physikalische Phänomene nutzen.
Risiko
Vorhersagbare Zufallszahlen haben schwerwiegende Sicherheitsauswirkungen. Kryptographische Schlüssel können vorhersagbar sein. Sitzungstoken können erraten werden. Nonces können sich wiederholen, was Verschlüsselung bricht. Authentifizierungsmechanismen können umgehbar sein. Zukünftige Zufallswerte können aus vergangenen Beobachtungen berechnet werden. Verschlüsselung kann effektiv aufgehoben werden. PRNG-Zustand kann aus der Ausgabe wiederhergestellt werden.
Lösung
Verwenden Sie echte Zufallszahlengeneratoren (TRNGs) für sicherheitskritische Anwendungen. TRNGs nutzen physikalische Phänomene wie elektrisches Rauschen als Quellen zur Generierung von Zufallszahlen. Kombinieren Sie mehrere Entropiequellen für Robustheit. Verwenden Sie kryptographisch sichere PRNGs, die von TRNGs gesät werden. Implementieren Sie NIST SP 800-90A/B-konforme Zufallszahlengenerierung. Testen Sie Zufälligkeit mit statistischen Testsuiten. Vermeiden Sie Linear Feedback Shift Register (LFSRs) für Sicherheitszwecke.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Bereich: Vertraulichkeit Anwendungsdaten lesen – Vorhersagbare Zufallszahlen ermöglichen Angreifern die Bestimmung kryptographischer Schlüssel, Token und anderer sicherheitskritischer Werte. Hohe Wahrscheinlichkeit. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Linear Feedback Shift Register (LFSR) zur Zufallszahlengenerierung
module vulnerable_lfsr_rng (
input wire clk,
input wire reset_n,
input wire request_random,
output reg [31:0] random_output,
output reg random_valid
);
// VERWUNDBAR: LFSR ist deterministisch und vorhersagbar
reg [31:0] lfsr_state;
// Polynom: x^32 + x^22 + x^2 + x + 1
wire feedback = lfsr_state[31] ^ lfsr_state[21] ^ lfsr_state[1] ^ lfsr_state[0];
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// VERWUNDBAR: Fester Seed
lfsr_state <= 32'h12345678;
random_valid <= 1'b0;
end
else if (request_random) begin
// VERWUNDBAR: Nächster Zustand vollständig durch aktuellen Zustand bestimmt
lfsr_state <= {lfsr_state[30:0], feedback};
random_output <= lfsr_state;
random_valid <= 1'b1;
end
end
// Angriff: 32 aufeinanderfolgende Ausgaben beobachten, um vollen Zustand wiederherzustellen
// Alle zukünftigen Ausgaben können dann vorhergesagt werden
endmodule
// VERWUNDBAR: Einfacher zählerbasierter "Zufall"
module vulnerable_counter_rng (
input wire clk,
input wire request,
output reg [31:0] random_output
);
reg [31:0] counter;
always @(posedge clk) begin
counter <= counter + 1;
if (request) begin
// VERWUNDBAR: Nur ein Zähler - komplett vorhersagbar!
random_output <= counter;
end
end
endmodule
// VERWUNDBAR: Nur zeitbasierter Seed
module vulnerable_time_seeded_rng (
input wire clk,
input wire reset_n,
input wire [31:0] time_counter,
output reg [31:0] random_output
);
reg [31:0] lfsr;
wire feedback = lfsr[31] ^ lfsr[22] ^ lfsr[2] ^ lfsr[1];
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
// VERWUNDBAR: Seed von Systemzeit - niedrige Entropie
// Angreifer der ungefähre Reset-Zeit kennt, kann Seed erraten
lfsr <= time_counter;
end
else begin
lfsr <= {lfsr[30:0], feedback};
random_output <= lfsr;
end
end
endmodule
// VERWUNDBAR: Standard-rand() für Sicherheitszwecke verwenden
#include <stdlib.h>
#include <time.h>
// VERWUNDBAR: rand() ist nicht kryptographisch sicher
void vulnerable_generate_token(char* token, size_t len) {
srand(time(NULL)); // Vorhersagbarer Seed!
for (size_t i = 0; i < len; i++) {
token[i] = 'A' + (rand() % 26); // Vorhersagbare Sequenz
}
}
// VERWUNDBAR: PHP-artiges mt_rand() ist vorhersagbar
// CVE-2021-3692: PHP-Framework verwendet mt_rand() zur Token-Generierung
void vulnerable_session_id(char* session_id) {
mt_srand(time(NULL));
for (int i = 0; i < 32; i++) {
session_id[i] = "0123456789abcdef"[mt_rand() % 16];
}
}
// VERWUNDBAR: Linearer Kongruenzgenerator
uint32_t lcg_state = 1;
uint32_t vulnerable_lcg_random(void) {
// Klassischer LCG - vollständig vorhersagbar aus jeder Ausgabe
lcg_state = lcg_state * 1103515245 + 12345;
return (lcg_state >> 16) & 0x7FFF;
}
Sichere Lösung
// SICHER: Echter Zufallszahlengenerator mit Ringoszillator
module secure_trng (
input wire clk,
input wire reset_n,
input wire request_random,
output reg [31:0] random_output,
output reg random_valid,
output reg entropy_low
);
// Ringoszillator-Entropiequelle (vereinfacht)
// Echte Implementierung verwendet mehrere Oszillatoren und Abtastung
wire [7:0] ring_osc_outputs;
// Mehrere Ringoszillatoren mit verschiedenen Verzögerungen
ring_oscillator #(.STAGES(3)) ro0 (.out(ring_osc_outputs[0]));
ring_oscillator #(.STAGES(5)) ro1 (.out(ring_osc_outputs[1]));
ring_oscillator #(.STAGES(7)) ro2 (.out(ring_osc_outputs[2]));
ring_oscillator #(.STAGES(9)) ro3 (.out(ring_osc_outputs[3]));
ring_oscillator #(.STAGES(11)) ro4 (.out(ring_osc_outputs[4]));
ring_oscillator #(.STAGES(13)) ro5 (.out(ring_osc_outputs[5]));
ring_oscillator #(.STAGES(15)) ro6 (.out(ring_osc_outputs[6]));
ring_oscillator #(.STAGES(17)) ro7 (.out(ring_osc_outputs[7]));
// Entropie-Akkumulator
reg [255:0] entropy_pool;
reg [4:0] sample_count;
// Gesundheitsprüfung
reg [7:0] last_sample;
reg [7:0] stuck_count;
parameter STUCK_THRESHOLD = 100;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
entropy_pool <= 256'h0;
sample_count <= 5'h0;
random_valid <= 1'b0;
entropy_low <= 1'b0;
stuck_count <= 8'h0;
end
else begin
// Ringoszillatoren abtasten
if (ring_osc_outputs == last_sample) begin
stuck_count <= stuck_count + 1;
if (stuck_count > STUCK_THRESHOLD) begin
entropy_low <= 1'b1; // Gesundheitsprüfung fehlgeschlagen
end
end else begin
stuck_count <= 8'h0;
entropy_low <= 1'b0;
end
last_sample <= ring_osc_outputs;
// Entropie akkumulieren
entropy_pool <= {entropy_pool[247:0], ring_osc_outputs};
sample_count <= sample_count + 1;
if (request_random && sample_count == 5'h1F && !entropy_low) begin
// SICHER: Hardware-Entropie verwenden, korrekt aufbereitet
random_output <= condition_entropy(entropy_pool);
random_valid <= 1'b1;
sample_count <= 5'h0;
end else begin
random_valid <= 1'b0;
end
end
end
// Entropie-Aufbereitung (vereinfacht - in der Praxis SHA-256 verwenden)
function [31:0] condition_entropy;
input [255:0] raw_entropy;
begin
// Kryptographische Aufbereitung zum Entfernen von Verzerrungen
condition_entropy = sha256_compress(raw_entropy)[31:0];
end
endfunction
endmodule
// SICHER: CSPRNG gespeist von TRNG
module secure_csprng (
input wire clk,
input wire reset_n,
input wire [255:0] trng_seed,
input wire seed_valid,
input wire request_random,
output reg [31:0] random_output,
output reg random_valid
);
// AES-CTR oder ChaCha20 als CSPRNG verwenden
reg [255:0] state;
reg [127:0] counter;
reg seeded;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
state <= 256'h0;
counter <= 128'h0;
seeded <= 1'b0;
random_valid <= 1'b0;
end
else if (seed_valid) begin
// Von TRNG seeden
state <= trng_seed;
seeded <= 1'b1;
end
else if (request_random && seeded) begin
// Mit AES-CTR generieren
random_output <= aes_encrypt(counter, state[127:0]) ^
aes_encrypt(counter + 1, state[255:128]);
counter <= counter + 2;
random_valid <= 1'b1;
// Periodisch neu seeden
if (counter[31:0] == 32'hFFFFFFFF) begin
seeded <= 1'b0; // Neuen Seed anfordern
end
end else begin
random_valid <= 1'b0;
end
end
endmodule
// SICHER: Kryptographisch sichere Zufallszahlengenerierung
#include <stdint.h>
#include <stdbool.h>
// Auf Linux/Unix
#include <sys/random.h>
// SICHER: Betriebssystem-bereitgestellten CSPRNG verwenden
int secure_generate_random(uint8_t* buffer, size_t len) {
// getrandom() verwendet Kernel-Entropiepool
ssize_t result = getrandom(buffer, len, 0);
return (result == (ssize_t)len) ? 0 : -1;
}
// SICHER: OpenSSL CSPRNG
#include <openssl/rand.h>
int secure_generate_token(char* token, size_t len) {
uint8_t random_bytes[len];
if (RAND_bytes(random_bytes, len) != 1) {
return -1; // Fehler
}
for (size_t i = 0; i < len; i++) {
token[i] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
[random_bytes[i] % 62];
}
// Sensible Daten löschen
OPENSSL_cleanse(random_bytes, len);
return 0;
}
// SICHER: Kryptographisch sichere Session-ID generieren
int secure_session_id(char* session_id, size_t len) {
uint8_t random_bytes[len / 2];
if (RAND_bytes(random_bytes, sizeof(random_bytes)) != 1) {
return -1;
}
for (size_t i = 0; i < sizeof(random_bytes); i++) {
sprintf(session_id + (i * 2), "%02x", random_bytes[i]);
}
OPENSSL_cleanse(random_bytes, sizeof(random_bytes));
return 0;
}
// SICHER: Hardware-RNG-Zugriff (falls verfügbar)
#ifdef __x86_64__
#include <immintrin.h>
int secure_hardware_random(uint64_t* value) {
int retries = 10;
while (retries--) {
if (_rdrand64_step(value)) {
return 0;
}
}
return -1; // RDRAND fehlgeschlagen
}
#endif
// Windows
#ifdef _WIN32
#include <bcrypt.h>
int secure_generate_random_win(uint8_t* buffer, size_t len) {
NTSTATUS status = BCryptGenRandom(NULL, buffer, len,
BCRYPT_USE_SYSTEM_PREFERRED_RNG);
return BCRYPT_SUCCESS(status) ? 0 : -1;
}
#endif
CVE-Beispiele
- CVE-2021-3692: PHP-Framework verwendet mt_rand() zur Token-Generierung
- Verschiedene Schwachstellen in IoT-Geräten, die LFSRs für Sicherheit verwenden
Verwandte CWEs
- CWE-330: Use of Insufficiently Random Values (übergeordnet)
- CWE-1213: Random Number Issues (Kategoriemitglied)
- CWE-1205: Security Primitives and Cryptography Issues (Kategoriemitglied)
- CWE-338: Use of Cryptographically Weak PRNG (verwandt)
Referenzen
- MITRE Corporation. "CWE-1241: Use of Predictable Algorithm in Random Number Generator." https://cwe.mitre.org/data/definitions/1241.html
- NIST SP 800-90A: Recommendation for Random Number Generation Using Deterministic RBGs
- NIST SP 800-90B: Recommendation for the Entropy Sources Used for Random Bit Generation
- REF-1370: LFSR-Implementierung im OpenPiton SoC (HACK@DAC'21)