CULTIVA IA — Servicio de Seguridad
CryptoVault SL
libcryptvault v2.4.1
Ref: CVA-2026-0031
18 jun 2026 · Confidencial
Auditoría de Timing Side-Channel
Análisis de tiempo constante en implementaciones criptográficas — RSA, HMAC, AES
2 Críticas
1 Alta
3 Funciones auditadas
4 Fases de análisis
14d Plazo
📋 Resumen Ejecutivo

Alcance

Tres funciones criptográficas de libcryptvault v2.4.1: cv_rsa_decrypt(), cv_hmac_verify() y cv_aes_cbc_decrypt(). Plataforma Linux x86-64, GCC 12, flags -O2 -march=native.

Metodología

4-fase: análisis estático con ct-verif → detección estadística con dudect (Welch t-test, 10⁷ mediciones) → trazado dinámico con Timecop/Valgrind → verificación post-remediación.

Resultado

Se detectaron 3 vulnerabilidades activas (2 críticas, 1 alta). cv_aes_cbc_decrypt() no presenta fuga estadística. Se entregan parches y suite CI/CD lista para integrar.

⚠️ Riesgo operativo inmediato: Las fugas detectadas en cv_hmac_verify() permiten un oráculo de autenticación explotable en ≈ 2.000 consultas de red. Se recomienda aplicar el parche de la Fase 1 antes del próximo ciclo de despliegue.
📊 Resultados dudect — Welch T-Test (10⁷ mediciones/función)
Valores |t| por función criptográfica
Umbral de seguridad: |t| < 4,5 · El eje está comprimido; los valores reales se muestran a la derecha
cv_hmac_verify()
|t|=4.5
|t| = 187.4
cv_rsa_decrypt()
|t| = 43.7
cv_aes_cbc_decrypt()
|t| = 2.1
Umbral de seguridad: |t| = 4,5 · Valores superiores indican fuga estadísticamente significativa con p < 0,00001 · Muestras: clases fijo vs. aleatorio (50/50) · CPU aislada: taskset -c 2 · Compilado con -O2 -march=native
cv_aes_cbc_decrypt() utiliza una implementación AES-NI basada en instrucciones de hardware que opera en tiempo estrictamente constante. No requiere acción.
🔍 Hallazgos Detallados
CVA-001 Comparación HMAC con memcmp() variable-time CRÍTICA
Función cv_hmac_verify()
Archivo src/hmac.c:89
CVSS v3.1 9.1 CRÍTICO
Patrón Comparación secreta
La función usa memcmp() estándar de libc para comparar el HMAC recibido con el calculado. memcmp() implementa una comparación en cortocircuito (early-exit): retorna en cuanto detecta el primer byte diferente, revelando el número de bytes correctos a través del tiempo de ejecución. Con 32 bytes (SHA-256) y resolución de ~1 ns, un atacante puede recuperar el HMAC válido byte a byte con ~2.000 consultas de red en LAN.
Evidencia Timecop: Conditional jump or move depends on uninitialised value(s) at 0x401C4A: cv_hmac_verify (hmac.c:89) · |t| dudect = 187,4 (umbral 4,5) · Δt promedio entre 1er y 32º byte correcto: +38 ns
src/hmac.c — VULNERABLE C
int cv_hmac_verify(const uint8_t *msg, size_t msg_len,
                        const uint8_t *key, size_t key_len,
                        const uint8_t *expected_hmac) {
    uint8_t computed[32];
    cv_hmac_sha256(msg, msg_len, key, key_len, computed);

    /* ⚠️ CVA-001: memcmp() variable-time — timing oracle */
    return memcmp(computed, expected_hmac, 32) == 0;
}
Remediación: Reemplazar memcmp() por comparación de tiempo constante usando reducción OR acumulativa.
src/hmac.c — CORREGIDO C
/* Comparación tiempo constante: sin early-exit, sin branch sobre secreto */
static int ct_memcmp(const uint8_t *a, const uint8_t *b, size_t n) {
    uint8_t diff = 0;
    for (size_t i = 0; i < n; i++) diff |= a[i] ^ b[i]; /* sin branch */
    return diff == 0; /* 1 byte acumulado: siempre n iteraciones */
}

int cv_hmac_verify(const uint8_t *msg, size_t msg_len,
                    const uint8_t *key, size_t key_len,
                    const uint8_t *expected_hmac) {
    uint8_t computed[32];
    cv_hmac_sha256(msg, msg_len, key, key_len, computed);
    return ct_memcmp(computed, expected_hmac, 32); /* ✓ tiempo constante */
}
CVA-002 Exponenciación modular con square-and-multiply variable-time (RSA) CRÍTICA
Función cv_rsa_decrypt()
Archivo src/rsa.c:212–231
CVSS v3.1 8.7 CRÍTICO
Patrón Branch sobre exponente secreto
La implementación usa el algoritmo square-and-multiply clásico que ramifica sobre cada bit del exponente secreto d. Cuando un bit es 1, ejecuta una multiplicación adicional, aumentando el tiempo ~15 ns por bit. Con 4096 bits de exponente y ≈10.000 consultas de texto cifrado elegido, un atacante puede reconstruir el exponente privado completo (ataque tipo Kocher 1996 / Brumley-Boneh 2003 adaptado).
Evidencia dudect: |t| = 43,7 (umbral 4,5) · Distribución bimodal clara en histograma de tiempos · Δt promedio bit=0 vs bit=1: +14.8 ns ± 0.3 ns · Confirmado por Timecop en rsa.c:221
src/rsa.c — VULNERABLE (extracto) C
/* Exponenciación modular: ct^d mod N */
BigInt modular_exp(BigInt base, BigInt exp, BigInt mod) {
    BigInt result = bigint_one();
    for (int i = bigint_bits(exp) - 1; i >= 0; i--) {
        result = bigint_mulmod(result, result, mod);  /* siempre: sq */
        if (bigint_bit(exp, i)) {                      /* ⚠️ branch sobre bit secreto */
            result = bigint_mulmod(result, base, mod); /* solo si d_i==1: fuga */
        }
    }
    return result;
}
Remediación: Aplicar Montgomery ladder (siempre realiza ambas multiplicaciones, selección con operaciones bitwise).
src/rsa.c — CORREGIDO (Montgomery ladder) C
/* Montgomery ladder: ambas ramas en TODOS los bits, sin branch sobre secreto */
BigInt modular_exp_ct(BigInt base, BigInt exp, BigInt mod) {
    BigInt r0 = bigint_one(), r1 = bigint_copy(base);
    for (int i = bigint_bits(exp) - 1; i >= 0; i--) {
        uint8_t bit = bigint_bit(exp, i);
        /* swap condicional con operaciones bitwise — sin branch */
        bigint_cswap(&r0, &r1, bit); /* tiempo constante */
        r1 = bigint_mulmod(r0, r1, mod); /* siempre r0*r1 */
        r0 = bigint_mulmod(r0, r0, mod); /* siempre r0^2  */
        bigint_cswap(&r0, &r1, bit); /* restaurar orden */
    }
    return r0;
}
CVA-003 Reducción Montgomery variable-time bajo condición de carry ALTA
Función bigint_mulmod()
Archivo src/bigint.c:341
CVSS v3.1 7.4 ALTA
Patrón Reducción condicional
El paso de reducción final de la multiplicación Montgomery ejecuta una sustracción condicional (if (T >= N) para normalizar el resultado). Cuando el intermedio supera el módulo, el ciclo adicional de reducción genera una diferencia de ~4 ns observable estadísticamente. En combinación con CVA-002, amplifica el canal lateral.
Evidencia: Timecop detecta branch en bigint.c:341 · Inputs construidos para maximizar frecuencia de reducción (y_sq < N ≤ y_cube) muestran Δt = +4.2 ns consistente
Remediación: Sustituir la resta condicional por sustracción incondicional con selección enmascarada del resultado correcto usando operaciones bitwise sobre el bit de borrow.
📈 Métricas CVSS v3.1
CVA-001 · cv_hmac_verify()
9.1Base
9.1Temporal
AV:N / AC:L / PR:N / UI:N / S:U / C:H / I:H / A:N
CVA-002 · cv_rsa_decrypt()
8.7Base
7.9Temporal
AV:N / AC:H / PR:N / UI:N / S:U / C:H / I:H / A:N
CVA-003 · bigint_mulmod() — Reducción Montgomery
7.4Base
6.5Temporal
AV:N / AC:H / PR:N / UI:N / S:U / C:H / I:L / A:N
🛠️ Plan de Remediación por Fases
1
Fase 1 · Días 1-2 · URGENTE
Parche CVA-001 — Comparación HMAC
Riesgo de explotación remota inmediato. Reemplazar memcmp() por ct_memcmp() en src/hmac.c:89.
  • Implementar ct_memcmp() con reducción OR acumulativa
  • Añadir test unitario de regresión timing (dudect harness, 5 min, CI)
  • Deploy hotfix a producción + comunicado interno
2
Fase 2 · Días 3-7
Parche CVA-002 + CVA-003 — RSA Ladder
Migración de modular_exp() a Montgomery ladder con bigint_cswap() de tiempo constante y sustracción incondicional en reducción.
  • Implementar modular_exp_ct() con Montgomery ladder
  • Refactorizar bigint_mulmod(): sustracción incondicional + borrow-mask
  • Validar con dudect 30 min · Compilar GCC y Clang · Test en AWS EC2 c6i
  • Peer review por segundo ingeniero de seguridad
3
Fase 3 · Días 8-11
Verificación Formal + Cross-compiler
Aplicar ct-verif sobre LLVM IR de las funciones parcheadas para obtener prueba matemática de ausencia de fugas. Testar GCC 12, Clang 17 y flags -O0 / -O2 / -O3.
  • Anotar secretos en IR LLVM · Ejecutar ct-verif · Documentar resultado
  • Matriz de tests: 2 compiladores × 3 optimization levels × 2 arquitecturas
  • Revisar ensamblado (objdump -d) para confirmar ausencia de CMOVcc secretos
4
Fase 4 · Días 12-14
Integración CI/CD + Documentación
Suite de tests de tiempo constante integrada en GitHub Actions. Bloqueo automático de PR si |t| > 4,5. Documentación de propiedades de seguridad para clientes financieros.
  • Workflow GitHub Actions (ver abajo) con dudect 10 min en cada PR
  • Badge de seguridad en README y changelog de versión v2.5.0
  • Informe final para auditoría de clientes bancarios (ISO 27001)
⚙️ Pipeline CI/CD — GitHub Actions
.github/workflows/constant-time-audit.yml
name: Constant-Time Security Tests

on:
  pull_request:
    paths:
      - 'src/hmac.c'
      - 'src/rsa.c'
      - 'src/bigint.c'
  push:
    branches: [ main, release/* ]

jobs:
  timing-analysis:
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: Pin CPU y compilar con flags de producción
        run: |
          # Aislar core 2 para reducir ruido de OS
          sudo taskset -cp 2 $$
          gcc -O2 -march=native -o tests/ct_hmac tests/dudect_hmac.c -I.
          gcc -O2 -march=native -o tests/ct_rsa  tests/dudect_rsa.c  -I.

      - name: Test HMAC (dudect, 10 min timeout)
        run: |
          timeout 600 ./tests/ct_hmac
          # Salida 0 si |t| < 4.5, salida 1 si fuga detectada
        env:
          DUDECT_THRESHOLD: '4.5'

      - name: Test RSA-4096 (dudect, 10 min timeout)
        run: |
          timeout 600 ./tests/ct_rsa

      - name: Timecop dynamic trace (Valgrind)
        run: |
          valgrind --error-exitcode=1 \
                   --track-origins=yes \
                   ./tests/timecop_harness
        if: github.event_name == 'push'

      - name: Publicar artefactos de resultados
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: timing-results-${{ github.sha }}
          path: tests/results/
ℹ️ Nota de CI: Los tests dudect en CI producen más ruido que en hardware dedicado. Se recomienda un umbral más conservador de |t| < 3,5 en entornos virtualizados para compensar el jitter de la VM. La cadencia recomendada es: tests rápidos (5 min) en cada PR + tests exhaustivos (30 min) en push a main.
🗂️ Resumen de Vulnerabilidades
ID Función Patrón de Fuga |t| dudect Herramienta detect. Severidad Estado
CVA-001 cv_hmac_verify() Comparación memcmp() early-exit 187.4 dudect + Timecop CRÍTICA Parche listo
CVA-002 cv_rsa_decrypt() Square-and-multiply branch en bit secreto 43.7 dudect + Timecop CRÍTICA En desarrollo
CVA-003 bigint_mulmod() Reducción Montgomery condicional 11.2 Timecop + dudect ALTA En desarrollo
cv_aes_cbc_decrypt() AES-NI (instrucciones hardware) 2.1 dudect OK Sin acción