historiasde lacripta
Javi Morenotwitter tag: #cripta
2 3
456
7 8
1ESCENARIO
FALLOS QUE DESMONTAN UN SISTEMA COMPLETO
FALLOS EN CIFRADOS
FALLOS EN LA PROTECCIÓN DE LA INTEGRIDAD
FALLOS EN FIRMASFALLOS CON CRIPTOGRAFÍA DE CLAVE PÚBLICA
SIDE CHANNELCONCLUSIÓN
escenarioponiéndonos en situación
1
ESC
ENA
RIO
» Disponible para todo el público
» No es complicado entender lo básico.
» [Ya casi] nadie implementa sus algoritmos.
» Disponemos de muchas librerías de bajo nivel.
Criptografía simple y atractiva
¿128 ó 256 bits?
OpenSSLJava crypto APIMicrosoft CryptoAPI
ESC
ENA
RIO
» Extremadamente frágil. Especialmente la criptografía de clave pública.
» Revisar el código cuesta mucho más que desarrollarlo. (además lo debe revisar otro)
» Cuando falla algo… falla todo.
Pero la realidad es otra
ESC
ENA
RIO
Para no implementar criptografía
No uses directa-mente las de
bajo nivel:
SSL para las comunicacionesGPG para el resto
GPGME, keyzcar, u otras comerciales
OpenSSL, Crypto++, Java crypto, BouncyCastle, .NET System.Security.Cryptography
Solución simple
Si no puedes, usa una librería de
alto nivel:
ESC
ENA
RIO
Piensa mal y acertarás
» Confusiones evidentes uso de MAC para firmar “descifrar” una firma para comprobarla confusión de términos
» Seguridad basada en usar SALTs
» Argumentos que defienden lo no estándar seguridad por oscuridad la clave es muy grande lo leí en un blog
ESC
ENA
RIO
Piensa mal y acertarás
» Cifrado de varios bloques con RSA
» Insistencia en mantener los IVs secretos
» Uso de diagramas que no vienen del estándar
» Y una de las mejores: Criptografía y Javascript ¡no tiene sentido! Dispones SSL en el cliente y en el servidor
ESC
ENA
RIO
Un pequeño detalle que lo
derrumba todo
ESC
ENA
RIO
2fallos que desmontan un sistema completola fortaleza de una cadena es la de su eslabón más débil
FALL
OS
QUE
DES
MO
NTA
N U
N S
ISTE
MA
CO
MPL
ETO
Compatiblidad hacia atrás
» Tenemos un esquema antiguo una cookie, hash SHA1 con un cifrado CBC, sin integridad lo mejoramos: HMAC, integridad
» Lo implantamos no adecuadamente se detecta una cookie antigua se migra al nuevo formato ¡!
» Seguir usando ambos esquemas desgraciadamente demasiado común
FALL
OS
QUE
DES
MO
NTA
N U
N S
ISTE
MA
CO
MPL
ETO
PRNGs no adecuados
no uses: random (python) java.util.Random (java) System.Random (.NET)
usa: random.SystemRandom (python) java.security.SecureRandom (java) System.Security.Cryptography.RandomNumberGenerator (.NET)
nunca: time() ^ getpid() y sus hermanos
el “por defecto” no es suficiente
FALL
OS
QUE
DES
MO
NTA
N U
N S
ISTE
MA
CO
MPL
ETO
PRNGs no adecuados
» Son la fortaleza de los cifrados de flujo creación de claves! IVs, contadores, PIDs, …
» El caso OpenSSL y Debian, ¡return 4! entropía reducida a menos de 15bits claves comprometidas peligro de MITM tablas precalculadas RSA, DSA
indispensables para
un sistemacriptográfico
FALL
OS
QUE
DES
MO
NTA
N U
N S
ISTE
MA
CO
MPL
ETO
PRNGs no adecuados
» Relacionado, mismo concepto: el ataque DNS de Kaminsky acertar un valor con 16 bits de entropía
» Con un servidor recién arrancado poca entropía disponible repetición de IVs, valores de desafios...
FALL
OS
QUE
DES
MO
NTA
N U
N S
ISTE
MA
CO
MPL
ETO
PRNGs no adecuados
» Mifare Classic reconstruyeron el circuito a base de fotografías microscópicas.
» Su RNG Semilla 16 bits, basado en un LFSR. Valor derivado del tiempo de lectura desde el encendido.
FALL
OS
QUE
DES
MO
NTA
N U
N S
ISTE
MA
CO
MPL
ETO
PRNGs no adecuados
crypto1 Vs. crapto1
3fallos en cifrados
cuando no es tu propia implementación
FALL
OS
CIF
RAN
DO
Modos de encadenamiento
» ¿ECB? Sin realimentación
» El típico conocido CBC
» OFB, CFB, CTR convierten de bloque a uno flujo sin integridad, se pueden cambiar bits no reusar: IVs, realimentación, contadores...
» CCM, EAX, GCM, OCB CCM == Counter with CBC-MAC cifrado autenticación tampoco se debe reusar IVs FA
LLO
S C
IFRA
ND
O
4fallos en la pro-tección de la integridad
colega, éste no es mi coche
FALL
OS
EN L
A P
ROTE
CC
IÓN
DE
LA IN
TEG
RID
AD
Hashing
»Mismo ejemplo, una cookie: SHA1(data) => replay attacks
SHA1(key || data) => basado en oscuridad
»Usa HMAC!
» Problema: granularidad, parámetros configurables
FALL
OS
EN L
A P
ROTE
CC
IÓN
DE
LA IN
TEG
RID
AD
FALL
OS
EN L
A P
ROTE
CC
IÓN
DE
LA IN
TEG
RID
AD
Hashing
<SignatureMethod Algorithm=”…xmldsig#hmac-sha1”> <HMACOutputLength> 160 </HMACOutputLength></SignatureMethod>
Estándar XMLDsig.Disponible desde alto nivel.
¿y por qué no existe
únicamente SHA1?
FALL
OS
EN L
A P
ROTE
CC
IÓN
DE
LA IN
TEG
RID
AD
Dar más información de la cuenta
» plaintext -> HMAC -> relleno -> cifrado CBC
» El servidor devuelve diferentes errores padding_incorrect
integrity_failure
» ¿CBC? empezamos por el final bruteforce en el último byte
si es correcto -> integrity_failure
iteramos hacia atrás
por la boca muere el pez
5fallos en firmas
¿no te han dicho que nunca firmes algo sin leerlo primero?
FALL
OS
EN F
RIM
AS
Un ejemplo real con una firma RSA
1º Se calcula una simple exponenciación
2º - caso correcto: verificamos todos los datos (relleno incluído)
- pero Nintendo hace: return (0 == strncmp(userHash, myHash, 20));
¿dónde estáel error?
FALL
OS
EN F
RIM
AS
Un ejemplo real con una firma RSA
FALL
OS
EN F
RIM
AS
Un ejemplo real con una firma RSA
creamos 256 mensajes ligera-mente distintos, seguro que al menos 1 hash empieza por \x00.
return (0 == memcmp(userHash, myHash, 20));
saltarnos la comprobación permite: 1. software, IOS y menu de sistema 2. cambiar gran parte del bootloader
FALL
OS
EN F
RIM
AS
FALL
OS
EN F
RIM
AS
La importancia del relleno
» usando RSA directamente permitimos: sig(a*b) = (siga * sigb) mod n
» ataques de parejas de texto plano/cifrado específicas.
» comprobad cada byte, incluyendo el relleno.
» puede ser usado en tu contra para buscar colisiones en las firmas.
6fallos usando criptografía de clave pública
a veces muchos bits nunca serán suficientes
FALL
OS
USA
ND
O C
RIPT
OG
RAFÍ
A D
E C
LAV
E PÚ
BLIC
A
¿DSA conociendo k?
» ¡Debian! Conociendo la salida del PRNG
» Firma DSA (r, s): r = gk mod p mod q s = k-1 (H(m) + x*r) mod q
» Con k conocido: x = ((s*k) – H(m)) * r-1 mod q
» En realidad sólo con parte de los bits de k sería posible con suficientes firmas
Revelala claveprivada
FALL
OS
USA
ND
O C
RIPT
OG
RAFÍ
A D
E C
LAV
E PÚ
BLIC
A
¿Cifrar usando la clave privada?
» escenario: RSA, verificar actualizaciones mantenemos la clave publica secreta usada para descifrar actualizaciones
» no tiene sentido no podemos mantener secreta la pública
for e in [3, 5, 7, … 65537]: n ~= gcd(sig1e–m1, sig2e–m2) if m1e mod n == sig1: break
dos firmas = clave pública
FALL
OS
USA
ND
O C
RIPT
OG
RAFÍ
A D
E C
LAV
E PÚ
BLIC
A
Uso de valores no adecuados
» Son problemas matemáticos que asumen ciertas condiciones
casos particulares claves débiles cambios en algunos parámetros no permitir que sean cero exponentes pequeños
7side channel
la implementación es el enemigo del diseño
SID
E C
HA
NN
EL
¿Side channel has dicho?
» Hasta ahora hemos pensando en: Servidores remotos Nuestro ordenador
» Eventos que filtran información: estados de la cache de la CPU búfer de predicción de saltos datos en la pila uso de recursos planificación
no operamos en
una caja negra ideal
SID
E C
HA
NN
EL
SID
E C
HA
NN
EL
¿Qué más podemos medir?
» Principalmente temporización consumo de potencias radiación EM
» Incluso temperatura sonidos patrones de acceso a discos
SID
E C
HA
NN
EL
¿Entonces?
» Veamos un par de ejemplos de ataques
» Pensemos en posibles protecciones
necesitamos ser paranoicos
SID
E C
HA
NN
EL
Ataque de temporización a RSA
» Exponenciaciones modulares
s=1;while(y) { if (y&1) s = (s*x) mod n; y>>=1; x = (x*x) mod n; }
» El tiempo de cálculo depende del valor de la clave
t_producto > t_cuadrado
SID
E C
HA
NN
EL
Ej. Ataque de temporización a RSA
Si combinamos la temporizacióncon un análisis de potencia consumida.
SID
E C
HA
NN
EL
Análisis de potencia
» SPA (simple), observar varias medidas ver el path de ejecución conocer de antemano el resultado de una comparación
» DPA (diferencial), muchas medidas ataques estadísticos diferencias de medias correlaciones relación entre potencia y datos
SID
E C
HA
NN
EL
Análisis de potencia
SID
E C
HA
NN
EL
Inyección de fallos
» provocando un fallo temporal usando láser power glitching clock glitching
» podemos: introducir un fallo en un cálculo variación el camino de ejecución
SID
E C
HA
NN
EL
Ej. Inyección de fallos en RSA-CRT
» Implementación eficiente en memoria exponenciaciones modulares de modulos más pequeños recombinación
Con un fallo en la exponenciaciónobtenemos una firma una defectuosa
» RSA firma un mensaje mediante s = md (mod n)
SID
E C
HA
NN
EL
» Sin embargo RSA-CRT hace: s1 = mdq (mod q) s2 = mdp (mod p) s = a*s1 + b*s2 (mod n) = md (mod n) a := 0 (mod p), a := 1 (mod q) b := 1 (mod p), b := 0 (mod q)
» Usando una firma defectuosa: s–s’ = a*s1 – a*s1’ := 0 (mod q) s–s’=b*s2–b*s2’:≠0(modp)
Ej. Inyección de fallos en RSA-CRT
SID
E C
HA
NN
EL
Ej. Inyección de fallos en RSA-CRT
» Teniendo s1, s2 (defectuosa), pub(e, n):
sage: q = gcd(s1-s2,n) sage: p = n / q sage: G1 = IntegerModRing(lcm(q-1,p-1)) sage: private_key = G1(e)^-1 sage: G2 = IntegerModRing(n) sage: message = G2(encrypted)^G2(private_key)
SID
E C
HA
NN
EL
¿Cómo protegernos?
» Muy difícil si programamos en un lenguaje de alto nivel
» Mucho cuidado con optimizaciones de los compiladores
» Necesitamos librerías pensadas para resistir este tipo de ataques
SID
E C
HA
NN
EL
Ejemplo
def cmp(s1, s2): total = 0 for a, b in zip(s1, s2) total += (a != b) return not total
» ¿y si las cadenas no tienen la misma longitud?
» ¿y si la longitud es 0?
SID
E C
HA
NN
EL
Ejemplo
» Analizando la línea total += ( a !=b ) if (a != b) tmp = 1 else tmp = 0 total += tmp
» Fuga según el tiempo de ejecución Una línea de código en alto nivel no tiene por qué ser atómica
SID
E C
HA
NN
EL
Ejemplo
» Podríamos cambiarlo por
if len(userMsg) != len(correctValue) return false result = 0 for x, y in zip(userMsg, correctValue) result |= ord(x)^ord(y) return result
Usamos xor en lugar de !=Fuga por tiempo sobre la longitud correcta
SID
E C
HA
NN
EL
Ejemplo
» Solución: si es un valor criptográfico no importa mucho (teóricamente tiene una longitud conocida) si es un passwd: calcular el hash antes de comparar
» Pero deberíamos seguir dudando de algunos factores: ¿y si x, y negativos? ¿realmente conocemos como funciona internamente zip()? ¿hace previamente una comparación de la longitud?
SID
E C
HA
NN
EL
A otros niveles
» Cache timming attack dependiente de la microarquitectura ver artículo de djb sobre openssl AES-256
» ¿nos puede jugar una mala pasado el compilador? optimizaciones fuera auditar el código compilado
» ¿podríamos aplicar estos conceptos via red? con 1000 medidas podemos detectar 20 ns en LAN 30 ms en WAN
SID
E C
HA
NN
EL
Fugas al acceder a claves
» Usa exclusivamente punteros a la claves
» Evita estar copiando claves de un sitio a otro
SID
E C
HA
NN
EL
Fugas al ejecutar saltos
» Evitar saltos endecisiones importantes.
» Que ambos caminos: tarden lo mismo misma estructura de instrucciones
SID
E C
HA
NN
EL
Fugas al comprobar la integridad
» Cuidado al comprobar la paridad
» Podríamos estar revelando la clave
» El comportamiento de los algoritmos ha de ser invariable con los datos procesados
SID
E C
HA
NN
EL
Fugas al comprobar la integridad
public static boolean checkParity( byte[]key, int offset){ for (int i = 0; i < DES_KEY_LEN; i++){ byte keyByte = key[i + offset]; int count = 0; while (keyByte != 0){ // loop till no ‘1’ bits left if ((keyByte & 0x01) != 0) count++; keyByte >>>= 1; // shift right} if ((count & 1) == 0) return false; // not odd } return true; // all bytes were odd}
SID
E C
HA
NN
EL
Fugas al comprobar la integridad
» Si sabemos que: va de LSB a MSB comprobar que es un “1” tarda más que un “0”
» Podemos obtener la clave bit a bit
SID
E C
HA
NN
EL
Fugas al comprobar la integridad
¿solución? usar una tabla de paridad consultarla en un orden aleatorio
SID
E C
HA
NN
EL
Fugas al comprobar la integridad
static byte odd_parity[]= { // each table entry represents odd parity of index 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, ..., 248, 248, 251, 251, 253, 253, 254, 254};
public static boolean checkParity( byte[]key, int offset){ int r = random.nextInt() & 7; // random number 0..7 for ( int i=0, j = r; i<8; i++, j = (j+1)&7 ){ if (key[j] != odd_parity[key[j+offset]]) return false; // parity incorrect } return true; // all bytes were odd}
SID
E C
HA
NN
EL
Fugas cuando accedemos a datos
» Evitad lecturas secuenciales --> usar offset aleatorio
» Ejemplo negativo: memcpy( pin, buffer, 4 );
» Ejemplo más adecuado: for(int i = 0, j = (rand() & 3); i < 4; i++, j = ((j+1) & 3)) buffer[j] = pin[j];
SID
E C
HA
NN
EL
Fugas al verificar a datos
» Usar strncmp() es un error lógico pero memcmp es secuencial
if ( strcmp( givenPasswd, storedPasswd ) != 0 ) return -1; // combo fail
if ( memcmp( givenPasswd, storedPasswd ) != 0 ) return -1; // time leak fail
» Evitad todo lo secuencial
SID
E C
HA
NN
EL
Fugas al verificar a datos
» Posible implementación: char* c1 = givenPasswd; char* c2 = storedPasswd; char error = 0; for (; *c1 != 0 && *c2 != 0; c1++, c2++ ) error |= *c1 ^ *c2; // collect diff in error if (error | *c1 | *c2) // fail if any not zero return -1; return 0;
» Se podría mejorar usando un offset aleatorio.
SID
E C
HA
NN
EL
Fugas al sobreescribir datos
» No hacerlo secuencialmente
» No borrar datos sobreescribiendo ceros
» CMOS consume en los cambios de estado
» Borrad con un random(), limpiad con ceros después
escribir un 0 ≠ escribir un 1
SID
E C
HA
NN
EL
Defendernos de inyecciones de fallos
» Una inyección de fallos puede hasta revelar una clave.
» Pueden ser medidas imple-mentadas en hardware pero también muchas son lógicas.
SID
E C
HA
NN
EL
SID
E C
HA
NN
EL
El caso por defecto
Mismo concepto: result = no if ( equal ) result = yes
result = yesif ( notequal) result = no
Vs.
switch (state) { case STATE_INIT: processInit(apdu); break; case STATE_PERSO: processPerso(apdu); break; case STATE_ISSUED: processIssued(apdu); break; case STATE_LOCKED: processLocked(apdu); break; default: fail();}
SID
E C
HA
NN
EL
Fallos en el flujo de ejecución
» Verificaciones del flujo shadow stack/PC comprobar el estado después de los saltos
» Uso de valores no triviales los valores booleanos con fácilmente corrompibles escoger valores con distancia hamming máxima enmascaramiento en las medidas de potencia true = 0xc3 false = 0x3c
SID
E C
HA
NN
EL
Fallos en los saltos
» No usar booleanos para comprobar saltos
» Comprobar siempre el valor para acceder a esa zona
if (conditionalValue == (byte)0xA5) // then part else if (conditionalValue == (byte)0xC3) // else part
SID
E C
HA
NN
EL
Fallos en los saltos
» En situaciones decisivas, haced varias veces usan-do una comparación complementaria:
// within then part if (conditionalValue != (byte)0xA5) fail(); if (~conditionalValue != (byte)0x5A) fail();
SID
E C
HA
NN
EL
Respuesta a inyección de fallos
staticfinalbyte[]CONSTANT={0x0F,0x1E,0x2D,0x3C, 0x4B, 0x5A,0x69, 0x78 };
static byte[] copied = new byte[CONSTANT.length];
public void main( Strings[] s ){ System.arraycopy( CONSTANT, 0, copied, 0, CONSTANT.LENGTH );
private void check(){ // call this method repeteadly for (int i = 0; i < CONSTANT.LENGTH; i++) if (CONSTANT [i] != copied[i]) fail();}
SID
E C
HA
NN
EL
Respuesta a inyección de fallos
» En caso de: ataques repetidos datos suficientemente sensibles
» Incluso con el borrado de claves privadas
SID
E C
HA
NN
EL
Necesitamos un límite
» Podríamos ser paranoicos hasta el infinito
» Tenemos que plantearnos ¿hay acceso físico? ¿hay negocio atacando el sistema? ¿hay otras zonas más débiles? ¿necesito esta inversión en seguridad?
8conclusión¿Qué nos llevamos de todo esto?
SID
E C
HA
NN
EL
Resumen
» La criptografía es frágil. Cuando falla, falla del todo.
» No implementes la tuya propia: Remodela tu arquitectura
» Si de verdad no puedes
» Que el código sea revisado por terceros 10x
SSL para comunicaciones GPG para el resto
usa una librería de alto nivel cryptlib, keyzcar
preguntas
Javi Moreno<[email protected]>
http://vierito.es/wordpresshttp://twiiter.com/vierito5
hashtag #cripta
cambio sugus por