Ataques de Canal Lateral son técnicas de criptoanálisis que explotan información física obtenida de implementaciones criptográficas, como tiempo de ejecución, consumo de energía, emisiones electromagnéticas o sonido.

¿Qué son los Ataques de Canal Lateral?

Los ataques de canal lateral no atacan directamente los algoritmos criptográficos, sino que explotan información física que se filtra durante la ejecución de implementaciones criptográficas en hardware o software.

Tipos de Ataques de Canal Lateral

Timing Attacks

  • Descripción: Explotan diferencias en tiempo de ejecución
  • Información: Tiempo de operaciones criptográficas
  • Ejemplo: Ataques a RSA, AES
  • Contramedidas: Tiempo constante

Power Analysis Attacks

  • Simple Power Analysis (SPA): Análisis directo de consumo
  • Differential Power Analysis (DPA): Análisis estadístico
  • Correlation Power Analysis (CPA): Análisis de correlación
  • Template Attacks: Ataques basados en plantillas

Electromagnetic Attacks

  • EM Emissions: Emisiones electromagnéticas
  • Near Field: Campo cercano
  • Far Field: Campo lejano
  • Frequency Analysis: Análisis de frecuencias

Acoustic Attacks

  • Sound Analysis: Análisis de sonido
  • Keyboard Eavesdropping: Escucha de teclado
  • Printer Eavesdropping: Escucha de impresora
  • CPU Sound: Sonido del procesador

Timing Attacks

Ataque a RSA

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import time
import random
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

class VulnerableRSA:
    def __init__(self, key_size=1024):
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=key_size
        )
        self.public_key = self.private_key.public_key()
    
    def vulnerable_decrypt(self, ciphertext):
        """Implementación vulnerable a timing attack"""
        start_time = time.time()
        
        # Simular operación que toma más tiempo con bits en 1
        result = 1
        for bit in bin(ciphertext)[2:]:
            if bit == '1':
                time.sleep(0.001)  # Simular operación costosa
            result = (result * result) % self.private_key.private_numbers().private_exponent
        
        end_time = time.time()
        execution_time = end_time - start_time
        
        return result, execution_time

class TimingAttack:
    def __init__(self, target_rsa):
        self.target = target_rsa
    
    def attack(self, ciphertext, num_samples=1000):
        """Realizar timing attack"""
        times = []
        
        for _ in range(num_samples):
            _, exec_time = self.target.vulnerable_decrypt(ciphertext)
            times.append(exec_time)
        
        # Análisis estadístico
        avg_time = sum(times) / len(times)
        variance = sum((t - avg_time) ** 2 for t in times) / len(times)
        
        return {
            'average_time': avg_time,
            'variance': variance,
            'times': times
        }

# Ejemplo de uso
vulnerable_rsa = VulnerableRSA()
attacker = TimingAttack(vulnerable_rsa)

ciphertext = 12345
attack_result = attacker.attack(ciphertext)
print(f"Tiempo promedio: {attack_result['average_time']:.6f}s")
print(f"Varianza: {attack_result['variance']:.6f}")

Contramedidas para Timing Attacks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import time
import secrets

class SecureRSA:
    def __init__(self, key_size=1024):
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=key_size
        )
        self.public_key = self.private_key.public_key()
    
    def constant_time_decrypt(self, ciphertext):
        """Implementación con tiempo constante"""
        # Usar operaciones de tiempo constante
        result = 1
        base = ciphertext
        exponent = self.private_key.private_numbers().private_exponent
        
        # Algoritmo de exponenciación modular con tiempo constante
        while exponent > 0:
            if exponent & 1:
                result = (result * base) % self.private_key.private_numbers().public_numbers.n
            base = (base * base) % self.private_key.private_numbers().public_numbers.n
            exponent >>= 1
        
        # Agregar tiempo aleatorio para enmascarar
        time.sleep(secrets.uniform(0.001, 0.002))
        
        return result

# Ejemplo de uso
secure_rsa = SecureRSA()
result = secure_rsa.constant_time_decrypt(12345)
print(f"Resultado seguro: {result}")

Power Analysis Attacks

Simple Power Analysis (SPA)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
import numpy as np
import matplotlib.pyplot as plt

class SimplePowerAnalysis:
    def __init__(self):
        self.power_traces = []
        self.operations = []
    
    def simulate_power_consumption(self, operation, data):
        """Simular consumo de energía"""
        power = []
        
        if operation == 'AES_encrypt':
            # Simular consumo de energía durante cifrado AES
            for round_num in range(10):
                # Consumo base
                base_power = 100
                
                # Consumo adicional por operaciones
                if round_num == 0:
                    base_power += 50  # AddRoundKey
                else:
                    base_power += 30  # SubBytes, ShiftRows, MixColumns
                
                # Variación aleatoria
                noise = np.random.normal(0, 5)
                power.append(base_power + noise)
        
        return power
    
    def analyze_trace(self, power_trace):
        """Analizar traza de energía"""
        # Encontrar patrones en el consumo
        peaks = []
        for i in range(1, len(power_trace) - 1):
            if power_trace[i] > power_trace[i-1] and power_trace[i] > power_trace[i+1]:
                peaks.append(i)
        
        return peaks
    
    def visualize_trace(self, power_trace, title="Power Trace"):
        """Visualizar traza de energía"""
        plt.figure(figsize=(12, 6))
        plt.plot(power_trace)
        plt.title(title)
        plt.xlabel("Time")
        plt.ylabel("Power Consumption")
        plt.grid(True)
        plt.show()

# Ejemplo de uso
spa = SimplePowerAnalysis()
power_trace = spa.simulate_power_consumption('AES_encrypt', 'test_data')
peaks = spa.analyze_trace(power_trace)
print(f"Picos detectados: {peaks}")

Differential Power Analysis (DPA)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
class DifferentialPowerAnalysis:
    def __init__(self):
        self.traces = []
        self.inputs = []
    
    def collect_traces(self, num_traces=1000):
        """Recopilar trazas de energía"""
        for _ in range(num_traces):
            # Generar entrada aleatoria
            input_data = np.random.randint(0, 256, 16)
            self.inputs.append(input_data)
            
            # Simular traza de energía
            trace = self.simulate_aes_trace(input_data)
            self.traces.append(trace)
    
    def simulate_aes_trace(self, input_data):
        """Simular traza de energía AES"""
        trace = []
        
        # Simular 10 rondas de AES
        for round_num in range(10):
            # Consumo de energía por byte
            for byte in input_data:
                # Consumo base
                power = 50
                
                # Consumo adicional por valor del byte
                power += byte * 0.5
                
                # Ruido
                noise = np.random.normal(0, 10)
                trace.append(power + noise)
        
        return trace
    
    def dpa_attack(self, target_byte=0):
        """Realizar ataque DPA"""
        if not self.traces:
            self.collect_traces()
        
        # Calcular hipótesis para cada clave posible
        best_key = 0
        best_correlation = 0
        
        for key_guess in range(256):
            # Calcular correlación
            correlation = self.calculate_correlation(key_guess, target_byte)
            
            if abs(correlation) > abs(best_correlation):
                best_correlation = correlation
                best_key = key_guess
        
        return best_key, best_correlation
    
    def calculate_correlation(self, key_guess, target_byte):
        """Calcular correlación para una hipótesis de clave"""
        # Simular consumo de energía basado en hipótesis
        predicted_consumption = []
        
        for i, input_data in enumerate(self.inputs):
            # Calcular valor intermedio
            intermediate = input_data[target_byte] ^ key_guess
            
            # Simular consumo de energía
            power = self.sbox_power_model(intermediate)
            predicted_consumption.append(power)
        
        # Calcular correlación con trazas reales
        correlations = []
        for trace in self.traces:
            correlation = np.corrcoef(predicted_consumption, trace)[0, 1]
            correlations.append(correlation)
        
        return np.mean(correlations)
    
    def sbox_power_model(self, value):
        """Modelo de consumo de energía para S-box"""
        # Contar número de bits en 1 (Hamming weight)
        hamming_weight = bin(value).count('1')
        return hamming_weight * 10  # Factor de escala

# Ejemplo de uso
dpa = DifferentialPowerAnalysis()
dpa.collect_traces(1000)
best_key, correlation = dpa.dpa_attack()
print(f"Mejor clave encontrada: {best_key}")
print(f"Correlación: {correlation:.4f}")

Electromagnetic Attacks

Análisis de Emisiones EM

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class ElectromagneticAnalysis:
    def __init__(self):
        self.em_traces = []
        self.frequencies = []
    
    def simulate_em_emission(self, operation, frequency_range=(1, 1000)):
        """Simular emisión electromagnética"""
        # Simular emisión EM durante operación criptográfica
        frequencies = np.linspace(frequency_range[0], frequency_range[1], 1000)
        amplitudes = []
        
        for freq in frequencies:
            # Amplitud base
            amplitude = 1.0 / (freq + 1)
            
            # Picos en frecuencias específicas
            if operation == 'AES_encrypt':
                # Picos en frecuencias relacionadas con AES
                for harmonic in [100, 200, 300, 400]:
                    if abs(freq - harmonic) < 10:
                        amplitude += 0.5
            
            # Ruido
            noise = np.random.normal(0, 0.1)
            amplitudes.append(amplitude + noise)
        
        return frequencies, amplitudes
    
    def analyze_em_trace(self, frequencies, amplitudes):
        """Analizar traza EM"""
        # Encontrar picos en el espectro
        peaks = []
        for i in range(1, len(amplitudes) - 1):
            if amplitudes[i] > amplitudes[i-1] and amplitudes[i] > amplitudes[i+1]:
                if amplitudes[i] > np.mean(amplitudes) + 2 * np.std(amplitudes):
                    peaks.append(frequencies[i])
        
        return peaks
    
    def visualize_em_spectrum(self, frequencies, amplitudes, title="EM Spectrum"):
        """Visualizar espectro EM"""
        plt.figure(figsize=(12, 6))
        plt.semilogy(frequencies, amplitudes)
        plt.title(title)
        plt.xlabel("Frequency (MHz)")
        plt.ylabel("Amplitude")
        plt.grid(True)
        plt.show()

# Ejemplo de uso
em_analysis = ElectromagneticAnalysis()
frequencies, amplitudes = em_analysis.simulate_em_emission('AES_encrypt')
peaks = em_analysis.analyze_em_trace(frequencies, amplitudes)
print(f"Picos EM detectados: {peaks}")

Acoustic Attacks

Análisis Acústico

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import numpy as np
from scipy import signal

class AcousticAnalysis:
    def __init__(self):
        self.audio_traces = []
        self.sample_rate = 44100
    
    def simulate_keyboard_sound(self, keystrokes):
        """Simular sonido de teclado"""
        audio = []
        
        for keystroke in keystrokes:
            # Generar sonido de tecla
            frequency = self.get_key_frequency(keystroke)
            duration = 0.1  # 100ms
            
            # Generar onda sinusoidal
            t = np.linspace(0, duration, int(self.sample_rate * duration))
            wave = np.sin(2 * np.pi * frequency * t)
            
            # Añadir envolvente
            envelope = np.exp(-t * 10)
            wave *= envelope
            
            # Añadir ruido
            noise = np.random.normal(0, 0.1, len(wave))
            wave += noise
            
            audio.extend(wave)
        
        return np.array(audio)
    
    def get_key_frequency(self, key):
        """Obtener frecuencia de tecla"""
        # Mapeo simplificado de teclas a frecuencias
        key_frequencies = {
            'a': 440, 'b': 466, 'c': 523, 'd': 587, 'e': 659,
            'f': 698, 'g': 784, 'h': 880, 'i': 988, 'j': 1047,
            'k': 1175, 'l': 1319, 'm': 1397, 'n': 1568, 'o': 1760,
            'p': 1976, 'q': 2093, 'r': 2349, 's': 2637, 't': 2794,
            'u': 3136, 'v': 3520, 'w': 3951, 'x': 4186, 'y': 4699,
            'z': 5274
        }
        
        return key_frequencies.get(key.lower(), 440)
    
    def analyze_audio(self, audio):
        """Analizar audio para extraer información"""
        # Transformada de Fourier
        fft = np.fft.fft(audio)
        frequencies = np.fft.fftfreq(len(audio), 1/self.sample_rate)
        
        # Encontrar picos
        peaks = []
        for i in range(1, len(fft) - 1):
            if abs(fft[i]) > abs(fft[i-1]) and abs(fft[i]) > abs(fft[i+1]):
                if abs(fft[i]) > np.mean(np.abs(fft)) + 2 * np.std(np.abs(fft)):
                    peaks.append(frequencies[i])
        
        return peaks
    
    def visualize_audio_spectrum(self, audio, title="Audio Spectrum"):
        """Visualizar espectro de audio"""
        fft = np.fft.fft(audio)
        frequencies = np.fft.fftfreq(len(audio), 1/self.sample_rate)
        
        plt.figure(figsize=(12, 6))
        plt.plot(frequencies[:len(frequencies)//2], np.abs(fft[:len(fft)//2]))
        plt.title(title)
        plt.xlabel("Frequency (Hz)")
        plt.ylabel("Amplitude")
        plt.grid(True)
        plt.show()

# Ejemplo de uso
acoustic_analysis = AcousticAnalysis()
keystrokes = ['p', 'a', 's', 's', 'w', 'o', 'r', 'd']
audio = acoustic_analysis.simulate_keyboard_sound(keystrokes)
peaks = acoustic_analysis.analyze_audio(audio)
print(f"Picos de audio detectados: {peaks}")

Contramedidas

Protección contra Timing Attacks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class TimingAttackProtection:
    def __init__(self):
        self.dummy_operations = []
    
    def constant_time_compare(self, a, b):
        """Comparación de tiempo constante"""
        if len(a) != len(b):
            return False
        
        result = 0
        for x, y in zip(a, b):
            result |= x ^ y
        
        return result == 0
    
    def constant_time_select(self, condition, true_value, false_value):
        """Selección de tiempo constante"""
        mask = -1 if condition else 0
        return (true_value & mask) | (false_value & ~mask)
    
    def add_dummy_operations(self, operation):
        """Añadir operaciones dummy para enmascarar tiempo"""
        # Añadir operaciones que no afectan el resultado
        dummy = 0
        for i in range(1000):
            dummy += i * i
        return operation

# Ejemplo de uso
protection = TimingAttackProtection()
result = protection.constant_time_compare(b"hello", b"hello")
print(f"Comparación segura: {result}")

Protección contra Power Analysis

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class PowerAnalysisProtection:
    def __init__(self):
        self.masking_enabled = True
    
    def masked_aes_operation(self, data, mask):
        """Operación AES enmascarada"""
        if not self.masking_enabled:
            return data
        
        # Aplicar máscara
        masked_data = data ^ mask
        
        # Realizar operación
        result = self.aes_operation(masked_data)
        
        # Remover máscara
        return result ^ mask
    
    def aes_operation(self, data):
        """Operación AES simplificada"""
        # Implementación simplificada
        return data
    
    def randomize_execution_order(self, operations):
        """Randomizar orden de ejecución"""
        import random
        return random.sample(operations, len(operations))

# Ejemplo de uso
power_protection = PowerAnalysisProtection()
mask = 0xAA
data = 0x55
result = power_protection.masked_aes_operation(data, mask)
print(f"Operación enmascarada: {result}")

Conceptos Relacionados

  • Criptoanálisis - Disciplina que incluye ataques de canal lateral
  • AES - Algoritmo vulnerable a ataques de canal lateral
  • RSA - Algoritmo vulnerable a ataques de canal lateral
  • ECC - Algoritmo vulnerable a ataques de canal lateral
  • HSM - Dispositivo que protege contra ataques de canal lateral
  • CISO - Rol que supervisa ataques de canal lateral
  • Ciberseguridad General - Disciplina que incluye ataques de canal lateral
  • Brechas de seguridad - Incidentes causados por ataques de canal lateral
  • Vectores de ataque - Ataques de canal lateral como vector
  • Incident Response - Proceso que incluye ataques de canal lateral
  • SIEM - Sistema que detecta ataques de canal lateral
  • SOAR - Automatización que responde a ataques de canal lateral
  • EDR - Herramienta que protege contra ataques de canal lateral
  • Firewall - Dispositivo que complementa protección contra ataques de canal lateral
  • VPN - Conexión que puede ser vulnerable a ataques de canal lateral
  • Dashboards - Visualización de métricas ataques de canal lateral
  • Registros - Logs de ataques de canal lateral

Referencias