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.
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.
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.
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.
taskset -c 2 · Compilado con -O2 -march=native
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.
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
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; }
memcmp() por comparación de tiempo constante usando reducción OR acumulativa.
/* 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 */ }
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).
/* 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; }
/* 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; }
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.
memcmp() por ct_memcmp() en src/hmac.c:89.ct_memcmp() con reducción OR acumulativamodular_exp() a Montgomery ladder con bigint_cswap() de tiempo constante y sustracción incondicional en reducción.modular_exp_ct() con Montgomery ladderbigint_mulmod(): sustracción incondicional + borrow-mask-O0 / -O2 / -O3.objdump -d) para confirmar ausencia de CMOVcc secretosname: 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/
main.
| 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 |