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

ImpactDetails
ConfidentialityScope: Confidentiality

Device internal information leaked through fault-induced behavior changes.
IntegrityScope: Integrity

Memory modification and program flow manipulation through injected faults.
Access ControlScope: Access Control

Security mechanisms bypassed including secure boot and protected interfaces.
AuthorizationScope: 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.

  • 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

  1. MITRE Corporation. "CWE-1319: Improper Protection Against Electromagnetic Fault Injection (EM-FI)." https://cwe.mitre.org/data/definitions/1319.html
  2. CAPEC-624: Hardware Fault Injection
  3. CAPEC-625: Mobile Device Fault Injection