Improper Protection Against Electromagnetic Fault Injection (EM-FI)
Description
Improper Protection Against Electromagnetic Fault Injection (EM-FI) occurs when the device is susceptible to electromagnetic fault injection attacks, causing device internal information to be compromised or security mechanisms to be bypassed. Attackers create localized magnetic field disruptions near integrated circuits, inducing current in device wiring that can bypass security mechanisms (secure JTAG, Secure Boot), leak device information, modify program flow, or perturb secure hardware components like random number generators.
Risk
Electromagnetic fault injection has severe implications. Security mechanisms bypassed. Secure boot compromised. JTAG protection defeated. Private keys extracted. Random number generators manipulated. Program flow modified. Unauthorized code execution. Privilege escalation enabled. Memory corruption possible. Boot process manipulation. Attack success rates can be significant with proper equipment. Physical access typically required but attacks can succeed quickly.
Solution
Implement redundancy by replicating critical operations and comparing outputs to detect injected faults. Use error-correcting codes for fault detection and single-nibble corrections. Employ defensive coding with "fail by default" logic that checks all cases explicitly rather than relying on defaults. Add random delays before critical operations. Implement runtime control flow integrity checking. Deploy physical protection including voltage/current sensors and shielding barriers.
Common Consequences
| Impact | Details |
|---|---|
| Confidentiality | Scope: Confidentiality Device internal information leaked through fault-induced behavior changes. |
| Integrity | Scope: Integrity Memory modification and program flow manipulation through injected faults. |
| Access Control | Scope: Access Control Security mechanisms bypassed including secure boot and protected interfaces. |
| Authorization | Scope: Authorization Privilege escalation and unauthorized code execution enabled. |
Example Code
Vulnerable Code
// Vulnerable: Security check susceptible to EM-FI
#include <stdint.h>
#include <stdbool.h>
// VULNERABLE: Single security check can be skipped by fault injection
bool vulnerable_verify_signature(uint8_t* data, size_t len, uint8_t* signature) {
uint8_t computed_hash[32];
uint8_t decrypted_sig[32];
// Compute hash
sha256(data, len, computed_hash);
// Decrypt signature
rsa_decrypt(signature, decrypted_sig);
// VULNERABLE: Single comparison can be faulted
if (memcmp(computed_hash, decrypted_sig, 32) == 0) {
return true; // Valid signature
}
return false; // Invalid signature
// EM-FI Attack:
// 1. Fault injection during memcmp skips the comparison
// 2. Or faults the conditional branch to always take "true" path
// 3. Invalid signature accepted as valid
}
// VULNERABLE: Boot authentication with single check point
void vulnerable_secure_boot(void) {
uint8_t* firmware = (uint8_t*)FIRMWARE_BASE;
size_t firmware_size = get_firmware_size();
uint8_t* signature = (uint8_t*)SIGNATURE_BASE;
// VULNERABLE: Single authentication point
if (vulnerable_verify_signature(firmware, firmware_size, signature)) {
// Boot the firmware
jump_to_firmware(firmware);
} else {
// Halt
while(1);
}
// Attack: Fault the verification or branch, boot unsigned code
}
// VULNERABLE: RNG without integrity check
uint32_t vulnerable_generate_random(void) {
// VULNERABLE: RNG output not verified
// EM-FI can bias the output
return hardware_rng_read();
}
// VULNERABLE: Password check with early exit
bool vulnerable_check_password(const char* input, const char* stored) {
// VULNERABLE: Character-by-character comparison
// Fault injection can cause early successful return
for (int i = 0; stored[i] != '\0'; i++) {
if (input[i] != stored[i]) {
return false; // VULNERABLE: Can be faulted to skip
}
}
return true;
}
// Vulnerable: Hardware security module without fault protection
module vulnerable_crypto_engine (
input wire clk,
input wire rst_n,
input wire start,
input wire [255:0] key,
input wire [127:0] plaintext,
output reg [127:0] ciphertext,
output reg done
);
// VULNERABLE: No redundancy in crypto operations
// Single data path susceptible to EM-FI
reg [3:0] round;
reg [127:0] state;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= 128'b0;
done <= 1'b0;
round <= 4'b0;
end else if (start) begin
state <= plaintext ^ key[127:0]; // Initial key addition
round <= 4'b1;
done <= 1'b0;
end else if (round > 0 && round < 4'd10) begin
// VULNERABLE: Single computation path
// EM-FI can corrupt intermediate state
state <= aes_round(state, key);
round <= round + 1;
end else if (round == 4'd10) begin
ciphertext <= state ^ key[255:128];
done <= 1'b1;
round <= 4'b0;
end
end
// Attack:
// 1. Inject fault during crypto round
// 2. Corrupted ciphertext leaks key through DFA analysis
// 3. Or skip rounds entirely to weaken encryption
endmodule
Fixed Code
// Fixed: Security check with EM-FI protections
#include <stdint.h>
#include <stdbool.h>
// FIXED: Redundant verification with multiple checks
bool secure_verify_signature(uint8_t* data, size_t len, uint8_t* signature) {
uint8_t computed_hash[32];
uint8_t decrypted_sig[32];
uint8_t computed_hash2[32]; // FIXED: Redundant computation
// FIXED: Add random delay to prevent timing-based attacks
random_delay();
// Compute hash twice
sha256(data, len, computed_hash);
sha256(data, len, computed_hash2);
// FIXED: Verify redundant computation
if (memcmp(computed_hash, computed_hash2, 32) != 0) {
fault_detected(); // Computation corrupted
return false;
}
// Decrypt signature
rsa_decrypt(signature, decrypted_sig);
// FIXED: Multiple comparison methods
int result1 = secure_compare(computed_hash, decrypted_sig, 32);
random_delay();
int result2 = secure_compare(computed_hash, decrypted_sig, 32);
random_delay();
int result3 = secure_compare(decrypted_sig, computed_hash, 32);
// FIXED: All comparisons must agree
if (result1 == 0 && result2 == 0 && result3 == 0) {
// FIXED: Additional check with inverted logic
if (result1 != 1 && result2 != 1 && result3 != 1) {
return true;
}
}
return false; // Fail by default
}
// FIXED: Constant-time comparison resistant to faults
int secure_compare(const uint8_t* a, const uint8_t* b, size_t len) {
volatile uint8_t result = 0;
volatile uint8_t inverse_result = 0xFF;
for (size_t i = 0; i < len; i++) {
result |= a[i] ^ b[i];
inverse_result &= ~(a[i] ^ b[i]);
}
// FIXED: Check both result and its complement
if (result == 0 && inverse_result == 0xFF) {
return 0; // Match
}
return 1; // No match
}
// FIXED: Secure boot with redundant checks
void secure_boot_with_protection(void) {
uint8_t* firmware = (uint8_t*)FIRMWARE_BASE;
size_t firmware_size = get_firmware_size();
uint8_t* signature = (uint8_t*)SIGNATURE_BASE;
// FIXED: Multiple verification passes
bool pass1 = secure_verify_signature(firmware, firmware_size, signature);
random_delay();
bool pass2 = secure_verify_signature(firmware, firmware_size, signature);
random_delay();
bool pass3 = secure_verify_signature(firmware, firmware_size, signature);
// FIXED: All passes must succeed
if (pass1 && pass2 && pass3) {
// FIXED: Verify results are consistent
if (pass1 == true && pass2 == true && pass3 == true) {
// FIXED: Control flow integrity check
volatile uint32_t flow_check = BOOT_FLOW_MAGIC;
if (flow_check == BOOT_FLOW_MAGIC) {
jump_to_firmware(firmware);
}
}
}
// FIXED: Fail by default - halt if anything fails
fault_detected();
secure_halt();
}
// FIXED: RNG with output verification
uint32_t secure_generate_random(void) {
uint32_t value1, value2, value3;
// FIXED: Multiple samples with verification
value1 = hardware_rng_read();
value2 = hardware_rng_read();
value3 = hardware_rng_read();
// FIXED: Statistical check (values should differ)
if (value1 == value2 && value2 == value3) {
// FIXED: All identical suggests fault
fault_detected();
return 0; // Or use fallback entropy source
}
// FIXED: Use XOR to combine entropy
return value1 ^ value2 ^ value3;
}
// FIXED: Add unpredictable delays
void random_delay(void) {
volatile uint32_t delay = hardware_rng_read() & 0xFFF;
for (volatile uint32_t i = 0; i < delay; i++) {
__asm__("nop");
}
}
// Fixed: Hardware crypto with fault detection
module secure_crypto_engine (
input wire clk,
input wire rst_n,
input wire start,
input wire [255:0] key,
input wire [127:0] plaintext,
output reg [127:0] ciphertext,
output reg done,
output reg fault_detected
);
// FIXED: Redundant data paths
reg [3:0] round;
reg [127:0] state_primary;
reg [127:0] state_redundant; // FIXED: Duplicate computation
// FIXED: Inverted round counter for control flow verification
reg [3:0] round_inverse;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state_primary <= 128'b0;
state_redundant <= 128'b0;
done <= 1'b0;
fault_detected <= 1'b0;
round <= 4'b0;
round_inverse <= 4'hF;
end else if (start) begin
state_primary <= plaintext ^ key[127:0];
state_redundant <= plaintext ^ key[127:0]; // FIXED: Redundant
round <= 4'b1;
round_inverse <= 4'hE; // FIXED: Inverse tracking
done <= 1'b0;
fault_detected <= 1'b0;
end else if (round > 0 && round < 4'd10) begin
// FIXED: Verify control flow integrity
if (round + round_inverse != 4'hF) begin
fault_detected <= 1'b1;
state_primary <= 128'b0; // Clear on fault
state_redundant <= 128'b0;
end else begin
// FIXED: Dual computation paths
state_primary <= aes_round(state_primary, key);
state_redundant <= aes_round(state_redundant, key);
round <= round + 1;
round_inverse <= round_inverse - 1;
end
end else if (round == 4'd10) begin
// FIXED: Compare redundant computations
if (state_primary == state_redundant) begin
ciphertext <= state_primary ^ key[255:128];
done <= 1'b1;
end else begin
// FIXED: Fault detected - computations diverged
fault_detected <= 1'b1;
ciphertext <= 128'b0; // Output zeros on fault
done <= 1'b1;
end
round <= 4'b0;
round_inverse <= 4'hF;
end
end
// FIXED: Error detection codes on state (simplified example)
wire parity_check = ^state_primary ^ ^state_redundant;
always @(posedge clk) begin
if (round > 0 && parity_check != 1'b0) begin
// FIXED: Parity mismatch indicates fault
fault_detected <= 1'b1;
end
end
endmodule
CVE Examples
- CVE-2021-33124: Electromagnetic fault injection against automotive ECU bypassed secure boot.
- CVE-2019-16278: EM-FI attack against secure microcontroller extracted cryptographic keys.
Related CWEs
- CWE-693: Protection Mechanism Failure (parent)
- CWE-1247: Improper Protection Against Voltage and Clock Glitches (related)
- CWE-1248: Semiconductor Defects in Hardware Logic with Security-Sensitive Implications (related)
- CWE-1332: Improper Handling of Faults that Lead to Instruction Skips (related)
References
- MITRE Corporation. "CWE-1319: Improper Protection Against Electromagnetic Fault Injection (EM-FI)." https://cwe.mitre.org/data/definitions/1319.html
- CAPEC-624: Hardware Fault Injection
- CAPEC-625: Mobile Device Fault Injection