Historias de la cripta usos indebidos de la criptografía

Post on 17-Jun-2015

1.418 views 1 download

description

Charla de Javier Moreno impartida durante el III Curso de verano de Seguridad Informatica de la UEM de Valencia.

Transcript of Historias de la cripta usos indebidos de la criptografía

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<vierito5@gmail.com>

http://vierito.es/wordpresshttp://twiiter.com/vierito5

hashtag #cripta

cambio sugus por