Vergleichslogik anfällig für Power-Seitenkanal-Angriffe
Beschreibung
Vergleichslogik anfällig für Power-Seitenkanal-Angriffe tritt auf, wenn der Stromverbrauch eines Geräts während der Auswertung von Sicherheitstoken in Echtzeit überwacht werden kann, um Referenz-Token-Werte zu bestimmen. Echtzeit-Stromüberwachung von Geräten ermöglicht es Angreifern, Schwankungen im Energieverbrauch während der Token-Validierung zu beobachten. Wenn Vergleichsalgorithmen nicht ausreichend robust sind und Wiederholungsmechanismen unbegrenzt sind, werden Stromunterschiede zwischen korrekten und falschen Eingaben ausnutzbar, wodurch Angreifer Referenzwerte inkrementell bestimmen können.
Risiko
Power-Seitenkanal-Schwachstellen haben schwerwiegende Sicherheitsauswirkungen. PINs und Passwörter können durch Stromanalyse wiederhergestellt werden. Kryptografische Schlüssel können extrahiert werden. Authentifizierungsumgehungen werden möglich. Secure-Boot-Schlüssel können kompromittiert werden. Challenge-Response-Systeme können besiegt werden. Token-Werte können ohne Brute Force bestimmt werden. Single Power Analysis (SPA) offenbart Operationen direkt. Differential Power Analysis (DPA) extrahiert Schlüssel statistisch.
Lösung
Dekrementieren Sie den Wiederholungszähler vor der Token-Validierung; entwerfen Sie Prüfungen mit einheitlichem Stromverbrauch. Parallelisieren Sie das Verschieben geheimer Daten unter Verwendung breiterer Busse. Injizieren Sie Zufallsdaten in Krypto-Operationen als Rauschen. Implementieren Sie Hardware-Filter für Stromleitungen. Vermeiden Sie einzelne Geheimnisse über längere Zeiträume durch Schlüsselrotation. Verwenden Sie maskierte Implementierungen für kryptografische Operationen. Implementieren Sie Konstant-Leistung-Vergleichsschaltungen. Fügen Sie Rauschgeneratoren zur Stromversorgung hinzu.
Häufige Auswirkungen
| Auswirkung | Details |
|---|---|
| Vertraulichkeit | Umfang: Vertraulichkeit Unbefugter Zugriff - Stromanalyse offenbart geheime Werte wie PINs, Passwörter und kryptografische Schlüssel. |
| Integrität | Umfang: Integrität Schutzmechanismus umgehen - Authentifizierungs- und Verifizierungsmechanismen können besiegt werden. |
| Zugriffskontrolle | Umfang: Zugriffskontrolle Vollständige Systemkompromittierung - Wiederherstellung von Authentifizierungsgeheimnissen gewährt vollen Zugriff. |
Beispielcode und Lösung
Verwundbarer Code
// VERWUNDBAR: Strom-leakender Passwortvergleich
#include <stdint.h>
#define NUM_PW_DIGITS 4
volatile uint8_t stored_password[NUM_PW_DIGITS] = {1, 2, 3, 4};
volatile int password_tries = 3;
uint8_t GetPasswordByte(void);
bool vulnerable_password_check(void) {
uint8_t password_ok = 0;
// VERWUNDBAR: Unterschiedliche Operationen basierend auf Übereinstimmung/Nichtübereinstimmung
for (int i = 0; i < NUM_PW_DIGITS; i++) {
if (GetPasswordByte() == stored_password[i]) {
password_ok |= 1; // Unterschiedliche Strom-Signatur hier
}
else {
password_ok |= 0; // Als hier (ODER mit 0 ist anders)
}
}
// VERWUNDBAR: Wiederholungszähler NACH Prüfung dekrementiert
// Angreifer kann Stromzyklus durchführen, um Dekrement zu vermeiden
if (password_ok) {
return true;
}
else {
password_tries--;
return false;
}
}
// VERWUNDBAR: Serielles Schieben leakt Bits
void vulnerable_serial_shift(uint8_t* secret, int len) {
// VERWUNDBAR: Serielles Schieben offenbart ein Bit zur Zeit
for (int i = 0; i < len * 8; i++) {
uint8_t bit = (secret[i/8] >> (i%8)) & 1;
// Jeder Bit-Shift hat eindeutige Strom-Signatur
shift_out_bit(bit);
}
}
// VERWUNDBAR: Bedingte Operationen basierend auf Geheimnis
void vulnerable_crypto_operation(uint8_t* key, uint8_t* data, int len) {
for (int i = 0; i < len; i++) {
if (key[i] & 0x80) {
// VERWUNDBAR: Operation nur wenn Schlüssel-Bit 1 ist
data[i] = complex_transform(data[i]);
}
// Stromunterschiede offenbaren Schlüssel-Bits
}
}
// VERWUNDBAR: Strom-leakender Komparator
module vulnerable_pin_check (
input wire clk,
input wire reset_n,
input wire [3:0] digit_in,
input wire digit_valid,
output reg access_granted,
output reg check_complete
);
// Gespeicherte PIN
reg [3:0] stored_pin [0:3];
initial begin
stored_pin[0] = 4'd1;
stored_pin[1] = 4'd2;
stored_pin[2] = 4'd3;
stored_pin[3] = 4'd4;
end
reg [1:0] digit_index;
reg match_status;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
digit_index <= 2'b0;
match_status <= 1'b1;
access_granted <= 1'b0;
check_complete <= 1'b0;
end
else if (digit_valid) begin
// VERWUNDBAR: Bedingte Operation leakt Strom
if (digit_in == stored_pin[digit_index]) begin
// Übereinstimmung: bestimmte Strom-Signatur
match_status <= match_status & 1'b1;
end
else begin
// Nichtübereinstimmung: andere Strom-Signatur
match_status <= 1'b0;
end
if (digit_index == 2'd3) begin
access_granted <= match_status;
check_complete <= 1'b1;
end
else begin
digit_index <= digit_index + 1;
end
end
end
endmodule
// VERWUNDBAR: Seriell-Ein/Seriell-Aus Schieberegister
module vulnerable_siso_shift (
input wire clk,
input wire reset_n,
input wire serial_in,
input wire shift_enable,
output wire serial_out
);
reg [7:0] shift_reg;
// VERWUNDBAR: Einzelne Bit-Verschiebungen leaken Daten über Strom
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
shift_reg <= 8'h0;
end
else if (shift_enable) begin
// Jede Verschiebung hat Strom-Signatur basierend auf Bit-Werten
shift_reg <= {shift_reg[6:0], serial_in};
end
end
assign serial_out = shift_reg[7];
endmodule
Sichere Lösung
// SICHER: Strom-balancierter Passwortvergleich
#include <stdint.h>
#define NUM_PW_DIGITS 4
volatile uint8_t stored_password[NUM_PW_DIGITS] = {1, 2, 3, 4};
volatile int password_tries = 3;
uint8_t GetPasswordByte(void);
bool secure_password_check(void) {
uint8_t password_ok = 0;
// SICHER: Wiederholungszähler VOR Prüfung dekrementieren
// Verhindert Stromzyklus-Angriff zur Vermeidung des Dekrements
password_tries--;
// SICHER: Einheitliche Strom-Operationen unabhängig von Übereinstimmung
for (int i = 0; i < NUM_PW_DIGITS; i++) {
uint8_t input = GetPasswordByte();
uint8_t stored = stored_password[i];
// SICHER: Gleiche Operation für Übereinstimmung und Nichtübereinstimmung
// Verwendet konstanten Strom unabhängig vom Ergebnis
if (input == stored) {
password_ok |= 0x10; // Gleiches Hamming-Gewicht
}
else {
password_ok |= 0x01; // Gleiches Hamming-Gewicht
}
}
// Auf alle Übereinstimmungen prüfen (password_ok sollte 0x40 für 4 Übereinstimmungen sein)
return (password_ok == 0x40);
}
// SICHER: Maskierter Vergleich mit Rauschen
bool secure_masked_compare(const uint8_t* input, const uint8_t* stored, int len) {
// SICHER: Zufällige Maske generieren
uint8_t mask = get_random_byte();
uint8_t result = 0;
uint8_t dummy = 0;
for (int i = 0; i < len; i++) {
// SICHER: Maske anwenden, um Strom-Signatur zu verschleiern
uint8_t masked_input = input[i] ^ mask;
uint8_t masked_stored = stored[i] ^ mask;
// Vergleich auf maskierten Werten
uint8_t diff = masked_input ^ masked_stored;
// SICHER: Dummy-Operationen zum Strom-Ausgleich
dummy ^= mask;
dummy ^= (diff | ~diff); // Immer 0xFF
result |= diff;
}
// Dummy verwenden um Optimierung zu verhindern
volatile uint8_t anti_opt = dummy;
(void)anti_opt;
return result == 0;
}
// SICHER: Paralleles Schieben mit breiterem Bus
void secure_parallel_shift(uint8_t* data, int len) {
// SICHER: Mehrere Bits gleichzeitig schieben
// Strom-Signatur vermischt mehrere Bits
for (int i = 0; i < len; i += 4) {
// 32-Bit paralleles Schieben
uint32_t word = *(uint32_t*)&data[i];
shift_out_word(word); // Alle 32 Bits gleichzeitig
}
}
// SICHER: Konstant-Leistung Krypto-Operation
void secure_crypto_operation(const uint8_t* key, uint8_t* data, int len) {
for (int i = 0; i < len; i++) {
// SICHER: Beide Operationen immer ausführen
uint8_t transform_result = complex_transform(data[i]);
uint8_t no_transform = data[i];
// SICHER: Konstant-Zeit-Auswahl basierend auf Schlüssel verwenden
// Beide Operationen werden immer ausgeführt
uint8_t key_bit = (key[i] >> 7) & 1;
data[i] = (transform_result & (0 - key_bit)) |
(no_transform & (0 - (1 - key_bit)));
}
}
// SICHER: Strom-balancierter PIN-Komparator
module secure_pin_check (
input wire clk,
input wire reset_n,
input wire [3:0] digit_in,
input wire digit_valid,
input wire [7:0] random_mask, // Externer Zufall für Maskierung
output reg access_granted,
output reg check_complete
);
// Gespeicherte PIN (wäre in sicherem Speicher)
reg [3:0] stored_pin [0:3];
initial begin
stored_pin[0] = 4'd1;
stored_pin[1] = 4'd2;
stored_pin[2] = 4'd3;
stored_pin[3] = 4'd4;
end
reg [1:0] digit_index;
reg [3:0] match_accumulator;
reg [3:0] dummy_accumulator;
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
digit_index <= 2'b0;
match_accumulator <= 4'hF;
dummy_accumulator <= 4'h0;
access_granted <= 1'b0;
check_complete <= 1'b0;
end
else if (digit_valid) begin
// SICHER: Maskierter Vergleich
wire [3:0] masked_input = digit_in ^ random_mask[3:0];
wire [3:0] masked_stored = stored_pin[digit_index] ^ random_mask[3:0];
// SICHER: Beide Operationen werden immer ausgeführt
wire match = (masked_input == masked_stored);
wire mismatch = (masked_input != masked_stored);
// SICHER: Einheitliche Operationen unabhängig vom Ergebnis
// Gleiche Anzahl von Bit-Umschaltungen für Übereinstimmung und Nichtübereinstimmung
if (match) begin
match_accumulator <= match_accumulator & 4'hF;
dummy_accumulator <= dummy_accumulator | 4'h1;
end
else begin
match_accumulator <= match_accumulator & 4'hE;
dummy_accumulator <= dummy_accumulator | 4'h0;
end
if (digit_index == 2'd3) begin
// SICHER: Einzelner abschließender Vergleich
access_granted <= (match_accumulator == 4'hF);
check_complete <= 1'b1;
end
else begin
digit_index <= digit_index + 1;
end
end
end
endmodule
// SICHER: Parallel-Ein/Parallel-Aus Schieberegister
module secure_pipo_shift (
input wire clk,
input wire reset_n,
input wire [31:0] parallel_in, // 32-Bit paralleles Laden
input wire load_enable,
input wire shift_enable,
output wire [31:0] parallel_out
);
reg [31:0] shift_reg;
// SICHER: Parallele Operationen vermischen einzelne Bits
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
shift_reg <= 32'h0;
end
else if (load_enable) begin
// Alle 32 Bits gleichzeitig laden
shift_reg <= parallel_in;
end
else if (shift_enable) begin
// Alle Bits zusammen schieben - Strom-Signatur
// vermischt alle 32 Bits
shift_reg <= {shift_reg[30:0], 1'b0};
end
end
assign parallel_out = shift_reg;
endmodule
// SICHER: Dual-Rail-Logik für konstanten Strom
module secure_dual_rail_compare (
input wire clk,
input wire reset_n,
input wire a_true, a_false, // Dual-Rail-Eingang A
input wire b_true, b_false, // Dual-Rail-Eingang B
output reg match_true, match_false
);
// SICHER: Dual-Rail-Kodierung gewährleistet konstanten Strom
// Jeder Vergleich beinhaltet gleiche Anzahl von Übergängen
always @(posedge clk or negedge reset_n) begin
if (!reset_n) begin
match_true <= 1'b0;
match_false <= 1'b1;
end
else begin
// SICHER: Beide Rails werden immer berechnet
match_true <= (a_true & b_true) | (a_false & b_false);
match_false <= (a_true & b_false) | (a_false & b_true);
// Gesamtübergänge konstant unabhängig von Werten
end
end
endmodule
CVE-Beispiele
Power-Seitenkanal-Schwachstellen wurden bei Smartcards, sicheren Mikrocontrollern und kryptografischen Implementierungen demonstriert, bei denen Stromanalyse PINs, Passwörter und kryptografische Schlüssel offenbarte.
Verwandte CWEs
- CWE-1300: Unsachgemäßer Schutz physischer Seitenkanale (übergeordnet)
- CWE-1259: Unsachgemäße Beschränkung der Sicherheitstoken-Zuweisung (verwandt)
- CWE-1254: Fehlerhafte Granularität der Vergleichslogik (verwandt)
Referenzen
- MITRE Corporation. "CWE-1255: Comparison Logic is Vulnerable to Power Side-Channel Attacks." https://cwe.mitre.org/data/definitions/1255.html
- Kocher et al. "Differential Power Analysis"
- Mangard, Oswald, Popp. "Power Analysis Attacks: Revealing the Secrets of Smart Cards"