it-swarm-es.com

Lecciones aprendidas y conceptos erróneos sobre cifrado y criptología.

La criptología es un tema tan amplio que incluso los codificadores experimentados casi siempre cometerán errores las primeras veces. Sin embargo, el cifrado es un tema tan importante, a menudo no podemos permitirnos tener estos errores.

La intención de esta pregunta es identificar y enumerar qué no hacer con un algoritmo o API dados. De esta manera podemos aprender de las experiencias de otros y evitar la propagación de malas prácticas.

Para mantener esta pregunta constructiva, por favor

  1. Incluir un ejemplo "incorrecto"
  2. Explica lo que está mal con ese ejemplo.
  3. Proporcione una implementación correcta (si corresponde).
  4. A lo mejor de su capacidad, proporcione referencias con respecto a los puntos 2 y 3 anteriores.
68
goodguys_activate

No tires tu propia criptografía.

No invente su propio algoritmo o protocolo de encriptación; eso es extremadamente propenso a errores. Como a Bruce Schneier le gusta decir:

"Cualquiera puede inventar un algoritmo de encriptación que ellos mismos no pueden romper; es mucho más difícil inventar uno que nadie más pueda romper".

Los algoritmos criptográficos son muy complejos y necesitan una investigación exhaustiva para asegurarse de que sean seguros; si inventas el tuyo, no lo obtendrás, y es muy fácil terminar con algo inseguro sin darte cuenta.

En su lugar, use un algoritmo y protocolo criptográfico estándar. Lo más probable es que otra persona haya encontrado su problema anteriormente y haya diseñado un algoritmo apropiado para ese propósito.

Su mejor caso es utilizar un esquema bien examinado de alto nivel: para la seguridad de la comunicación, use TLS (o SSL); para datos en reposo, use GPG (o PGP). Si no puede hacer eso, use una biblioteca criptográfica de alto nivel, como cryptlib , GPGME, Keyczar , o NaCL , en lugar de un uno de bajo nivel, como OpenSSL, CryptoAPI, JCE, etc. Gracias a Nate Lawson por esta sugerencia.

76
D.W.

No use cifrado sin autenticación de mensaje

Es un error muy común encriptar datos sin también autenticarlos.

Ejemplo: el desarrollador desea mantener un mensaje en secreto, por lo que cifra el mensaje con el modo AES-CBC. El error: Esto no es suficiente para la seguridad en presencia de ataques activos, ataques de repetición, ataques de reacción, etc. Existen ataques conocidos en el cifrado sin autenticación de mensajes, y los ataques pueden ser bastante graves. La solución es agregar autenticación de mensaje.

Este error ha provocado serias vulnerabilidades en los sistemas implementados que utilizan cifrado sin autenticación, incluidos ASP.NET , XML cifrado , Amazon EC2 , JavaServer Faces, Ruby on Rails, OWASP ESAPI , IPSEC , WEP , ASP.NET nuevamente , y SSH2 No quieres ser el próximo en esta lista.

Para evitar estos problemas, debe usar la autenticación de mensajes cada vez que aplique el cifrado. Tienes dos opciones para hacerlo:

  • Probablemente la solución más simple es usar un esquema de encriptación que proporcione encriptación autenticada , por ejemplo, GCM, CWC, EAX, CCM, OCB. (Consulte también: 1 .) El esquema de cifrado autenticado maneja esto por usted, por lo que no tiene que pensarlo.

  • Alternativamente, puede aplicar su propia autenticación de mensaje, de la siguiente manera. Primero, cifre el mensaje utilizando un esquema de cifrado de clave simétrica apropiado (por ejemplo, AES-CBC). Luego, tome el texto cifrado completo (incluidos los IV, nonces u otros valores necesarios para el descifrado), aplique un código de autenticación de mensaje (por ejemplo, AES-CMAC, SHA1-HMAC, SHA256-HMAC) y agregue el resumen MAC resultante al texto cifrado antes de la transmisión. En el lado receptor, verifique que el resumen MAC sea válido antes de descifrarlo. Esto se conoce como la construcción cifrar-luego-autenticar. (Consulte también: 1 , 2 .) Esto también funciona bien, pero requiere un poco más de atención por su parte.

47
D.W.

Tenga cuidado al concatenar cadenas múltiples, antes del hash.

A veces veo un error: la gente quiere un hash de las cadenas S y T. Los concatenan para obtener una sola cadena S || T, luego la combinan para obtener H (S || T). Esto es defectuoso.

El problema: la concatenación deja el límite entre las dos cadenas ambiguas. Ejemplo: builtin || securely = built || insecurely. Dicho de otra manera, el hash H (S || T) no identifica de forma exclusiva la cadena S y T. Por lo tanto, el atacante puede cambiar el límite entre las dos cadenas, sin cambiar el hash. Por ejemplo, si Alice quería enviar las dos cadenas builtin y securely, el atacante podría cambiarlas a las dos cadenas built y insecurely sin invalidar el picadillo.

Se aplican problemas similares al aplicar una firma digital o un código de autenticación de mensaje a una concatenación de cadenas.

La solución: en lugar de una concatenación simple, use una codificación que sea decodificable sin ambigüedades. Por ejemplo, en lugar de calcular H (S || T), podría calcular H (longitud (S) || S || T), donde la longitud (S) es un valor de 32 bits que indica la longitud de S en bytes. O, otra posibilidad es usar H (H (S) || H (T)), o incluso H (H (S) || T).

Para ver un ejemplo del mundo real de esta falla, consulte esta falla en Amazon Web Services o esta falla en Flickr [pdf].

36
D.W.

No reutilice nonces o IVs

Muchos modos de operación requieren un IV (Vector de inicialización). Nunca debe reutilizar el mismo valor para un IV dos veces; hacerlo puede cancelar todas las garantías de seguridad y causar una violación catastrófica de seguridad.

  • Para los modos de operación de cifrado de flujo, como el modo CTR o el modo OFB, la reutilización de un IV es un desastre de seguridad. Puede hacer que los mensajes cifrados sean trivialmente recuperables.

  • Para otros modos de operación, como el modo CBC, la reutilización de un IV también puede facilitar los ataques de recuperación de texto sin formato en algunos casos.

No importa qué modo de operación utilice, no debe reutilizar el IV. Si se pregunta cómo hacerlo correctamente, especificación NIST proporciona documentación detallada sobre cómo usar los modos de operación de cifrado de bloque correctamente.

El proyecto Tarsnap proporciona un buen ejemplo de esta trampa. Tarsnap cifra los datos de la copia de seguridad dividiéndolos en fragmentos y luego cifra cada fragmento con AES en modo CTR. En las versiones 1.0.22 a 1.0.27 de Tarsnap, el mismo IV fue reutilizado inadvertidamente, permitiendo la recuperación de texto sin formato.

¿Cómo pasó esto? Para simplificar el código Tarsnap, y con la esperanza de reducir la posibilidad de errores, Colin Percival aprovechó la oportunidad para "refactorizar" el código AES-CTR en un nuevo archivo (lib/crypto/crypto_aesctr.c en el código fuente de Tarsnap ) y modificó los lugares existentes donde se utilizó AES-CTR para aprovechar estas rutinas. El nuevo código se ve así:

/* Cifrar los datos. */
 - aes_ctr (& encr_aes-> key, encr_aes-> nonce ++, buf, len, 
 - filebuf + CRYPTO_FILE_HLEN); 
 + if ((stream = 
 + crypto_aesctr_init (& encr_aes-> key, encr_aes-> nonce)) == NULL) 
 + goto err0; 
 + crypto_aesctr_stream (stream, buf, filebuf + CRYPTO_FILE_HLEN, len); 
 + crypto_aesctr_free (transmisión); 

Durante la refactorización, el encr_aes->nonce++ sin darse cuenta se convirtió en encr_aes->nonce, y como resultado el mismo valor nonce se usó repetidamente . En particular, el valor nonce CTR no se incrementa después de que cada fragmento se cifra. (El contador CTR se incrementa correctamente después de que se procesaron cada 16 bytes de datos, pero este contador se restablece a cero para cada fragmento nuevo). Colin Percival describe los detalles completos en: http: //www.daemonology. net/blog/2011-01-18-tarsnap-critical-security-bug.html

29
Alex Holst

Asegúrese de sembrar generadores de números aleatorios con suficiente entropía.

Asegúrese de usar generadores de números pseudoaleatorios de fuerza criptográfica para cosas como generar claves, elegir IVs/nonces, etc. No use Rand(), random(), drand48() etc.

Asegúrese de sembrar el generador de números pseudoaleatorios con suficiente entropía. No lo siembres con la hora del día; Eso es adivinable.

Ejemplos: srand(time(NULL)) es muy malo. Una buena manera de sembrar su PRNG es tomar 128 bits o números verdaderos al azar, por ejemplo, de /dev/urandom, CryptGenRandom o similar. En Java, use SecureRandom, no Random. En .NET, use System.Security.Cryptography.RandomNumberGenerator, no System.Random. En Python, use random.SystemRandom, no random. Gracias a Nate Lawson por algunos ejemplos.

Ejemplo del mundo real: vea esta falla en las primeras versiones del navegador de Netscape , que permitió que un atacante rompiera SSL.

29
D.W.

No utilice un cifrado de bloque con ECB para el cifrado simétrico

(¡Aplica para AES, 3DES, ...)

Aquí hay un post y un muy similar artículo de Microsoft KB sobre cómo el modo ECB da como resultado un código que no está encriptado.

También vea esta publicación similar de Rook

Mensaje de texto sin formato:

alt text

El mismo mensaje cifrado con el modo ECB (no importa qué cifrado use): alt text

El mismo mensaje EXACT usando el modo CBC (de nuevo, no importa qué cifrado use): alt text

La manera incorrecta

public static string Encrypt(string toEncrypt, string key, bool useHashing)
{

byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

if (useHashing)
    keyArray = new MD5CryptoServiceProvider().ComputeHash(keyArray);

var tdes = new TripleDESCryptoServiceProvider() 
    { Key = keyArray, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };

ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(
    toEncryptArray, 0, toEncryptArray.Length);

return Convert.ToBase64String(resultArray, 0, resultArray.Length);
}

El error está en la siguiente línea.

{Key = keyArray, Mode = CipherMode.ECB , Padding = PaddingMode.PKCS7};


La forma correcta

La buena gente de Microsoft me envió el siguiente código para corregir ese artículo de KB vinculado anteriormente. Esto se hace referencia en el caso # 111021973179005

Este código de muestra está utilizando AES para cifrar datos, y la clave para el cifrado AES es el código hash generado por SHA256. AES es el algoritmo del Estándar de cifrado avanzado (AES). El algoritmo AES se basa en permutaciones y sustituciones. Las permutaciones son reordenamientos de datos, y las sustituciones reemplazan una unidad de datos con otra. AES realiza permutaciones y sustituciones utilizando varias técnicas diferentes. Para obtener más detalles sobre AES, consulte el artículo "Mantenga sus datos seguros con el nuevo estándar de cifrado avanzado" en MSDN Magazine en http://msdn.Microsoft.com/en-us/magazine/cc164055.aspx .

SHA es el algoritmo de hash seguro. Ahora se recomienda SHA-2 (SHA-224, SHA-256, SHA-384, SHA-512). Para obtener información más detallada sobre los valores Hash en .NET Framework, consulte http://msdn.Microsoft.com/en-us/library/92f9ye3s.aspx#hash_values .

El valor predeterminado del modo para la operación del algoritmo simétrico para AesCryptoServiceProvider es CBC. CBC es el modo de encadenamiento de bloques cifrados. Introduce comentarios. Antes de encriptar cada bloque de texto sin formato, se combina con el texto cifrado del bloque anterior mediante una operación OR) exclusiva a nivel de bits. Esto garantiza que incluso si el texto sin formato contiene muchos bloques idénticos, cada encriptación en un bloque de texto cifrado diferente. El vector de inicialización se combina con el primer bloque de texto sin formato mediante una operación exclusiva a nivel de bit OR) antes de que se encripte el bloque. Si un solo bit del bloque de texto cifrado está destrozado, el bloque de texto sin formato correspondiente también será destruido. Además, un bit en el bloque posterior, en la misma posición que el bit destruido original, será destruido. Para obtener información más detallada sobre CipherMode, por favor consulte http://msdn.Microsoft.com/en-us/library/system.security.cryptography.ciphermode.aspx .

Aquí está el código de muestra.

// This function is used for encrypting the data with key and iv.
byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoProvider with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create encryptor from the AESCryptoProvider.
        using (ICryptoTransform encryptor = aesCryptoProvider.CreateEncryptor())
        {
            // Create memory stream to store the encrypted data.
            using (MemoryStream stream = new MemoryStream())
            {
                // Create a CryptoStream to encrypt the data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write))
                    // Encrypt the data.
                    cryptoStream.Write(data, 0, data.Length);

                // return the encrypted data.
                return stream.ToArray();
            }
        }
    }
}

// This function is used for decrypting the data with key and iv.
byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
    // Create an AESCryptoServiceProvider.
    using (var aesCryptoProvider = new AesCryptoServiceProvider())
    {
        // Initialize the AESCryptoServiceProvier with key and iv.
        aesCryptoProvider.KeySize = key.Length * 8;
        aesCryptoProvider.IV = iv;
        aesCryptoProvider.Key = key;

        // Create decryptor from the AESCryptoServiceProvider.
        using (ICryptoTransform decryptor = aesCryptoProvider.CreateDecryptor())
        {
            // Create a memory stream including the encrypted data.
            using (MemoryStream stream = new MemoryStream(data))
            {
                // Create a CryptoStream to decrypt the encrypted data.
                using (CryptoStream cryptoStream = new CryptoStream(stream, decryptor, CryptoStreamMode.Read))
                {
                    // Create a byte buffer array.
                    byte[] readData = new byte[1024];
                    int readDataCount = 0;

                    // Create a memory stream to store the decrypted data.
                    using (MemoryStream resultStream = new MemoryStream())
                    {
                        do
                        {
                            // Decrypt the data and write the data into readData buffer array.
                           readDataCount = cryptoStream.Read(readData, 0, readData.Length);
                            // Write the decrypted data to resultStream.
                            resultStream.Write(readData, 0, readDataCount);
                        }
                        // Check whether there is any more encrypted data in stream.
                        while (readDataCount > 0);
                        // Return the decrypted data.
                        return resultStream.ToArray();
                    }
                }
            }
        }
    }
}



// This function is used for generating a valid key binary with UTF8 encoding and SHA256 hash algorithm.
byte[] GetKey(string key)
{
    // Create SHA256 hash algorithm class.
    using (SHA256Managed sha256 = new SHA256Managed())

    // Decode the string key to binary and compute the hash binary of the key.
    return sha256.ComputeHash(Encoding.UTF8.GetBytes(key));
}

Para obtener más detalles de las clases en el código de muestra, consulte los siguientes enlaces:

· Clase AesCryptoServiceProvider

· SHA256 Clase administrada

· Clase CryptoStream

Además, hay varios artículos que pueden ayudar a comprender mejor la criptografía en .NET Framework. Consulte los enlaces a continuación:

· Servicios criptográficos

· .NET Framework Cryptography Model

· na guía simple para la criptografía

· Cifrado sin secretos

20
goodguys_activate

No use la misma clave para el cifrado y la autenticación. No use la misma clave tanto para el cifrado como para la firma.

Una clave no debe reutilizarse para múltiples propósitos; eso puede abrir varios ataques sutiles.

Por ejemplo, si tiene un par de claves privadas/públicas RSA, no debe usarlo para el cifrado (cifrar con la clave pública, descifrar con la clave privada) y para firmar (firmar con la clave privada, verificar con la clave pública ): elige un único propósito y úsalo para ese único propósito. Si necesita ambas habilidades, genere dos pares de claves, uno para firmar y otro para cifrado/descifrado.

Del mismo modo, con la criptografía simétrica, debe usar una clave para el cifrado y una clave independiente separada para la autenticación de mensajes. No reutilice la misma clave para ambos propósitos.

20
D.W.

Principio de Kerckhoffs: un criptosistema debe ser seguro incluso si todo lo relacionado con el sistema, excepto la clave, es de conocimiento público

Un ejemplo incorrecto: hash de LANMAN

Los hash de LANMAN serían difíciles de descubrir si nadie conociera el algoritmo, sin embargo, una vez que se conocía el algoritmo, ahora es muy trivial descifrarlo.

El algoritmo es el siguiente ( de wikipedia ):

  1. La contraseña del usuario ASCII) se convierte a mayúscula.
  2. Esta contraseña está rellenada de nulo a 14 bytes
  3. La contraseña de "longitud fija" se divide en dos mitades de siete bytes.
  4. Estos valores se utilizan para crear dos teclas DES), una de cada mitad de 7 bytes
  5. Cada una de las dos claves se utiliza para cifrar DES la constante ASCII cadena "KGS! @ # $%", Lo que da como resultado dos valores de texto cifrado de 8 bytes.
  6. Estos dos valores de texto cifrado se concatenan para formar un valor de 16 bytes, que es el hash LM

Debido a que ahora conoce el texto cifrado de estos hechos, ahora puede dividir el texto cifrado en dos textos cifrados que sabe que son mayúsculas, lo que puede dar como resultado un conjunto limitado de caracteres que la contraseña podría ser.

Un ejemplo correcto: cifrado AES

  • Algoritmo conocido
  • Escalas con tecnología. Aumente el tamaño de la clave cuando necesite más empuje criptográfico
17
Chris Dale

Intente evitar el uso de contraseñas como claves de cifrado.

Una debilidad común en muchos sistemas es usar una contraseña o frase de contraseña, o un hash de contraseña o frase de contraseña, como clave de cifrado/descifrado. El problema es que esto tiende a ser altamente susceptible a los ataques de búsqueda de claves fuera de línea. La mayoría de los usuarios eligen contraseñas que no tienen suficiente entropía para resistir tales ataques.

La mejor solución es usar una clave de cifrado/descifrado verdaderamente aleatoria, no una generada determinísticamente a partir de una contraseña/frase de contraseña.

Sin embargo, si debe usar uno basado en una contraseña/frase de contraseña, use un esquema apropiado para ralentizar la búsqueda exhaustiva de claves. Recomiendo PBKDF2 , que usa hashing iterativo (en la línea de H(H(H(....H(password)...)))) ralentizar la búsqueda en el diccionario. Organizar el uso de suficientes iteraciones para hacer que este proceso tome, digamos, 100 ms en la máquina del usuario para generar la clave.

13
D.W.

En un protocolo criptográfico: Haga que todos los mensajes autenticados sean reconocibles: no hay dos mensajes iguales

Una generalización/variante de:

  • Tenga cuidado al concatenar múltiples cadenas, antes de cortar.
  • No reutilices las llaves.
  • No reutilices nonces.

Durante una ejecución de protocolo criptográfico, se pueden intercambiar muchos mensajes que no pueden falsificarse sin un secreto (clave o nonce). El receptor puede verificar estos mensajes porque conoce alguna clave pública (firma), o porque solo él y el remitente conocen alguna clave simétrica, o nonce. Esto asegura que estos mensajes no hayan sido modificados.

Pero esto no asegura que estos mensajes hayan sido emitidos durante la misma ejecución del protocolo: un adversario podría haber capturado estos mensajes previamente, o durante un ejecución concurrente del protocolo. Un adversario puede iniciar muchas ejecuciones simultáneas de un protocolo criptográfico para capturar mensajes válidos y reutilizarlos sin modificaciones.

Al reproducir de manera inteligente los mensajes, es posible atacar un protocolo sin comprometer ninguna clave principal, sin atacar ningún RNG, ningún cifrado, etc.

Al hacer que cada mensaje autenticado del protocolo sea claramente distinto para el receptor, se reducen (no se eliminan) las oportunidades para reproducir mensajes no modificados.

13
curiousguy

No utilice longitudes de clave inseguras.

Asegúrese de utilizar algoritmos con una clave suficientemente larga.

Para la criptografía de clave simétrica, recomendaría al menos una clave de 80 bits y, si es posible, una clave de 128 bits es una buena idea. No use cripto de 40 bits; es inseguro y los aficionados lo rompen fácilmente, simplemente probando exhaustivamente todas las claves posibles. No use DES de 56 bits; no es trivial romper, pero está al alcance de atacantes dedicados para romper DES. Un algoritmo de 128 bits, como AES, no es apreciablemente más lento que la criptografía de 40 bits, por lo que no tiene excusa para usar criptomonedas crummy.

Para la criptografía de clave pública, las recomendaciones de longitud de clave dependen del algoritmo y del nivel de seguridad requerido. Además, aumentar el tamaño de la clave perjudica el rendimiento, por lo que una exageración masiva no es económica; por lo tanto, esto requiere un poco más de reflexión que la selección de tamaños de clave de clave simétrica. Para RSA, El Gamal o Diffie-Hellman, recomendaría que la clave sea de al menos 1024 bits, como mínimo absoluto; sin embargo, las claves de 1024 bits están al borde de lo que podría romperse en el corto plazo y generalmente no se recomiendan para uso moderno, por lo que si es posible, recomendaría claves de 1536 o incluso de 2048 bits. Para la criptografía de curva elíptica, las claves de 160 bits parecen adecuadas y las claves de 224 bits son mejores. También puede consultar las pautas publicadas que establecen equivalencias aproximadas entre tamaños de clave simétrica y clave pública .

8
D.W.

No use la misma clave en ambas direcciones

En las comunicaciones de red, un error común es usar la misma tecla para la comunicación en la dirección A-> B que para la dirección B-> A. Esta es una mala idea, porque a menudo permite ataques de repetición que reproducen algo que A envió a B, de vuelta a A.

El enfoque más seguro es negociar dos claves independientes, una para cada dirección. Alternativamente, puede negociar una sola tecla K, luego usar K1 = AES (K, 00..0) para una dirección y K2 = AES (K, 11..1) para la otra dirección.

8
D.W.

Un pad de una sola vez no es un pad de una sola vez si la clave se estira mediante un algoritmo

El identificador "una sola vez" (también conocido como cifrado de Vernam) se aplica con frecuencia de forma incorrecta a varias soluciones criptográficas en un intento de reclamar seguridad irrompible. Pero, por definición, un cifrado Vernam es seguro si y solo si se cumplen las tres condiciones:

  • El material clave es verdaderamente impredecible; Y
  • El material clave tiene la misma longitud que el texto sin formato; Y
  • El material clave nunca se reutiliza.

Cualquier violación de esas condiciones significa que ya no se trata de una cifra única.

El error común cometido es que una tecla corta se estira con un algoritmo. Esta acción viola la regla de imprevisibilidad (no importa la regla de longitud de la clave). Una vez hecho esto, el pad de una sola vez se transforma matemáticamente en el algoritmo de estiramiento de la clave. La combinación de la clave corta con bytes aleatorios solo altera el espacio de búsqueda necesario para forzar al algoritmo de estiramiento de clave. Del mismo modo, el uso de bytes "generados aleatoriamente" convierte el algoritmo generador de números aleatorios en el algoritmo de seguridad.

Aquí hay un ejemplo simple. Tengo un mensaje que cifraré usando una "plataforma única" que utiliza una función criptográfica segura como generador de claves. Elegí una clave secreta, luego le agregué un número aleatorio para asegurarme de que no se reutilizaría. Como no estoy reutilizando la clave, no hay forma de atacar el texto cifrado restando un mensaje de otro.

          plaintext : 1234567890123456789012345678901234567890
       key material : 757578fbf23ffa4d748e0800dd7c424a46feb0cc
OTP function (xor)  : ----------
         ciphertext : 67412E83622DCE1B0C1E1A348B04D25872A8C85C

El material clave se generó de forma segura utilizando SHA-1 para descifrar mi contraseña secreta (más aleatoria) para estirarla. Pero cualquier atacante que conozca el algoritmo de estiramiento * utilizado es SHA-1 puede atacarlo probando varias entradas en SHA-1 y haciendo XOR a la salida con el texto cifrado. Adivinar la clave "OTP" ahora no es más difícil que adivinar las entradas combinadas al algoritmo criptográfico. Esta propiedad es válida independientemente de qué algoritmo criptográfico base se elija, qué medidas de complejidad tenga o cómo se implemente o sembre.

Es posible que tenga un muy buen algoritmo de estiramiento de teclas. También puede tener un generador de números aleatorios muy seguro. Sin embargo, su algoritmo no es, por definición, un pad de una sola vez y, por lo tanto, no tiene la propiedad irrompible de un pad de una sola vez.

* Aplicar el principio de Kerckhoff significa que debes asumir que el atacante siempre puede determinar los algoritmos utilizados.

3
John Deters

Usa el modo correcto

De manera equivalente, no confíe en la configuración predeterminada de la biblioteca para estar seguro. Específicamente, muchas bibliotecas que implementan AES implementan el algoritmo descrito en FIPS 197, que se llama modo ECB (Electronic Code Book), que es esencialmente un mapeo directo de:

AES(plaintext [32]byte, key [32]byte) -> ciphertext [32]byte

es muy inseguro. El razonamiento es simple, mientras que el número de claves posibles en el espacio de claves es bastante grande, el enlace débil aquí es la cantidad de entropía en el mensaje. Como siempre, xkcd.com describe es mejor que yo http://xkcd.com/257/

Es muy importante usar algo como CBC (Cipher Block Chaining) que básicamente hace que el texto cifrado [i] sea un mapeo:

ciphertext[i] = SomeFunction(ciphertext[i-1], message[i], key)

Solo para señalar algunas bibliotecas de idiomas donde este tipo de error es fácil de cometer: http://golang.org/pkg/crypto/aes/ proporciona una implementación de AES que, si se usa ingenuamente, dar como resultado el modo BCE.

La biblioteca de cifrado por defecto pasa al modo ECB al crear un nuevo objeto AES.

OpenSSL, hace esto bien. Cada llamada AES es explícita sobre el modo de operación. Realmente lo más seguro de la OMI es tratar de no hacer criptografía de bajo nivel como esta usted mismo. Si se ve obligado a hacerlo, proceda como si estuviera caminando sobre cristales rotos (con cuidado) e intente asegurarse de que sus usuarios estén justificados para confiar en usted para proteger sus datos.

3
Shane Hansen

No reutilice la misma clave en muchos dispositivos.

Cuanto más comparta una clave criptográfica, menos probable será que pueda mantenerla en secreto. Algunos sistemas implementados han reutilizado la misma clave simétrica en todos los dispositivos del sistema. El problema con esto es que, tarde o temprano, alguien extraerá la clave de un solo dispositivo y luego podrá atacar a todos los demás dispositivos. Entonces, no hagas eso.

Consulte también "Cifrado simétrico No # 6: No comparta una sola clave en muchos dispositivos" en este artículo del blog . Créditos a Matthew Green.

3
D.W.

No utilice un OTP o cifrado de flujo en el cifrado de disco

Ejemplo 1

Supongamos que dos archivos se guardan usando un cifrado de flujo/OTP. Si el archivo se vuelve a guardar después de una edición menor, un atacante puede ver que solo se modificaron ciertos bits e inferir información sobre el documento. (Imagine cambiar el saludo "Querido Bob" a "Querida Alice").

Ejemplo 2

No hay integridad en la salida: un atacante puede modificar el texto cifrado y modificar el contenido de los datos simplemente haciendo XOR de los datos.

Eliminar: las modificaciones al texto cifrado no se detectan y tienen un impacto predecible en el texto sin formato.

Solución

Use un cifrado de bloque para estas situaciones que incluye comprobaciones de integridad de mensajes

1
goodguys_activate

No confíes en los estándares

Existen muchos estándares en criptografía, y a veces hay que usarlos. Pero no asuma que las personas que escribieron los estándares entendieron adecuadamente la criptografía que necesitaban. Por ejemplo, EAX fue reelaborado en un estándar de red. EAX tiene una prueba de seguridad. La versión reelaborada no lo hizo.

MD5 es un estándar. Ahora está roto Chip y PIN se ha roto repetidamente muchas veces, gracias a una gran cantidad de características peligrosas. GPG aún admite claves DSA que son demasiado cortas para la comodidad. SSL tiene opciones que no deben usarse, y requiere cuidado para evitarlos.

¿Qué se puede hacer con esto? Tener cuidado, comprender los riesgos conocidos y mantenerse al día con la investigación de otros nuevos.

1
Watson Ladd

Solo use MAC que no sean vulnerables a los ataques de extensión de mensaje

Un MAC es un código hash que garantiza la integridad del mensaje (sin modificaciones, etc.) de un texto plano dado. Muchas implementaciones y estándares publicados no protegen un MAC de un atacante que agrega datos adicionales al MAC.

La solución para esto es que la implementación de MAC use una segunda clave (diferente) y vuelva a cifrar la salida final.

ECBC y NMAC son ejemplos de cifrados que evitan correctamente el ataque de extensión de mensaje.

Solución:

  • Use Encrypted CBC (ECBC) en lugar de raw CBC
  • Use NMAC en lugar de cascade
0
goodguys_activate

Nunca use un One Time Pad (OTP) o una clave de cifrado de flujo más de una vez

Una OTP aplicada dos veces significa que los datos cifrados con "secreto perfecto" serán descifrados y de forma clara. Esto sucede porque los datos son XOR'ed dos veces.

Ejemplo

Suponga que se está reutilizando una OTP/o secuencia con la misma clave.

Un atacante recopila una gran cantidad de datos enviados desde un cliente a un servidor, y XOR junta un conjunto de dos paquetes hasta que los dos paquetes se descifran entre sí (o un subconjunto).

La codificación ASCII tiene suficiente redundancia, lo que significa que dado suficiente texto cifrado, los mensajes originales podrían decodificarse (junto con la clave secreta OTP).

Ejemplos del mundo real

  • Proyecto Verona (1941-46) para un ejemplo de una OTP utilizada por los rusos y posteriormente descifrada por la agencia de inteligencia de los EE. UU.

  • PPTPv1 de Microsoft, tanto el cliente como el servidor, cifran los datos con la misma clave.

  • WEP reutiliza la misma clave una vez que se envían 2 ^ 24 paquetes, o si se reinicia una tarjeta NIC. El primer problema se debe a que el IV tiene 24 bits de largo, lo que da como resultado que después de 16 millones de tramas transmitido, se crea un parche de dos tiempos. El segundo problema ocurre en implementaciones de hardware donde, después de un ciclo de encendido, el IV se restablece a cero, lo que resulta en un parche de dos tiempos. Este problema es fácil de ver ya que el IV se envía en claro.

Recomendaciones

  • Se debe crear una nueva clave para cada sesión (por ejemplo, TLS).

  • El cliente debe usar una OTP (o cifrado de flujo con PRG) con el servidor, y el servidor debe usar un clave diferente al cifrar datos al cliente

  • En lugar de generar muchas claves, es posible expandir una sola clave en una secuencia larga utilizando un PRG (suponiendo que confía en el PRG) y usar cada segmento de esa expansión como clave.

  • Tenga en cuenta que no todos los PRG están hechos para funcionar en modo incremental, y puede ser necesaria una entrada aleatoria. (RC4 tiene este problema en modo incremental)

0
goodguys_activate

No use RC4

RC4 fue diseñado en 1987 para su uso como cifrado de flujo. Se usa en HTTPS y WEP.

Hay debilidades

  1. Hay sesgo en la salida inicial: Pr [2º byte = 0] = 2/256
  2. La probabilidad de que dieciséis bits equivalgan a cero es 1/256 ^ 2 + 1/256 ^ 3. Esto ocurre después de que varios datos de datos han sido encriptados.
  3. Vulnerable a los ataques clave relacionados, donde solo el IV cambia pero la clave permanece igual.

Eliminar Si debe usar RC4, ignore los primeros 256 bytes ya que están sesgados. Si usa RC4 para Gigs de datos, entonces el sesgo en RC4 permitirá ataques de todos los datos cifrados anteriores.

0
goodguys_activate

Utilice procesadores de flujo modernos que funcionen adecuadamente en hardware o software

No todos los cifrados de flujo están diseñados para implementarse en hardware o software. Registro de desplazamiento de retroalimentación lineal (LFSR) es un ejemplo de un cifrado de hardware ampliamente implementado que se rompe fácilmente.

LFSR se usa en:

  • Cifrado de DVD (también conocido como CSS) 2 LFSR
  • Cifrado GSM (A5/1.2) 3 LSFR
  • Bluetooth (E0): 4 LFSR

El hardware para lo anterior está ampliamente implementado y, por lo tanto, es difícil de actualizar o cumplir con los estándares modernos. Todo lo anterior está muy dañado y no se debe confiar en sus comunicaciones seguras.

Ataque:

Dado que la clave se divide en dos secciones durante el cifrado (17 bits y 25 bits) y esos bits se utilizan para cifrar el mismo texto cifrado, es posible utilizar el conocimiento del formato MPEG y aplicar fuerza bruta a una clave de 17 bits para extrapolar la clave de 25 bits. es.

Esto no es nuevo, pero FOSS es fácil de encontrar y demuestra este problema.

Solución:

El proyecto eStream (en 2008) calificó 5 cifrados de flujo que deberían usarse. Una diferencia notable es que en lugar de usar una Clave con un IV, los cifrados usan una Clave, un nonce y un contador. Salsa20 funciona de esta manera y está diseñado para usarse fácilmente tanto en hardware como en software. Específicamente, está incluido en el conjunto de instrucciones x86 SSE2.

Aparte

Los cifrados modernos no solo son más seguros, sino que también son más rápidos:

PRG          Speed (MB/sec)
RC4              126         (obsolete)
Salsa20/12       643         (modern)
Sosemaunk        727         (modern)
0
goodguys_activate