cifrado

Función de derivación de clave basada en contraseña
cifrado
General
DiseñadoresNiels Provos , David Mazières
Primera publicación1999
Derivado dePez globo (cifrado)
Detalle
Tamaños de resúmenes184 bits
Rondasvariable a través del parámetro de costo

bcrypt es una función de hash de contraseñas diseñada por Niels Provos y David Mazières, basada en el cifrado Blowfish y presentada en USENIX en 1999. [1] Además de incorporar una sal para proteger contra ataques de tabla arco iris , bcrypt es una función adaptativa: con el tiempo, el recuento de iteraciones se puede aumentar para hacerlo más lento, por lo que sigue siendo resistente a ataques de búsqueda de fuerza bruta incluso con un aumento en el poder de cálculo.

La función bcrypt es el algoritmo de hash de contraseña predeterminado para OpenBSD , [2] [ se necesita una fuente no primaria ] y era el predeterminado para algunas distribuciones de Linux como SUSE Linux . [3]

Hay implementaciones de bcrypt en C , C++ , C# , Embarcadero Delphi , Elixir , [4] Go , [5] Java , [6] [7] JavaScript , [8] Perl , PHP , Ruby , Python y otros lenguajes.

Fondo

Blowfish es conocido entre los cifrados de bloques por su costosa fase de configuración de claves. Comienza con subclaves en un estado estándar, luego utiliza este estado para realizar un cifrado de bloque utilizando parte de la clave y utiliza el resultado de ese cifrado (que es más preciso en el hash) para reemplazar algunas de las subclaves. Luego utiliza este estado modificado para cifrar otra parte de la clave y utiliza el resultado para reemplazar más subclaves. Procede de esta manera, utilizando un estado modificado progresivamente para hacer un hash de la clave y reemplazar fragmentos de estado, hasta que se hayan establecido todas las subclaves.

Provos y Mazières aprovecharon esta situación y la llevaron más lejos. Desarrollaron un nuevo algoritmo de configuración de claves para Blowfish, y llamaron al cifrado resultante "Eksblowfish" ("Blowfish, programa de claves costoso"). La configuración de claves comienza con una forma modificada de la configuración de claves estándar de Blowfish, en la que se utilizan tanto la sal como la contraseña para configurar todas las subclaves. A continuación, hay una serie de rondas en las que se aplica el algoritmo de codificación estándar de Blowfish, utilizando alternativamente la sal y la contraseña como clave, y cada ronda comienza con el estado de la subclave de la ronda anterior. En teoría, esto no es más fuerte que el programa de claves estándar de Blowfish, pero el número de rondas de cambio de clave es configurable; por lo tanto, este proceso se puede hacer arbitrariamente lento, lo que ayuda a disuadir los ataques de fuerza bruta al hash o la sal.

Descripción

La entrada de la función bcrypt es la cadena de contraseña (hasta 72 bytes), un costo numérico y un valor de sal de 16 bytes (128 bits). La sal suele ser un valor aleatorio. La función bcrypt utiliza estas entradas para calcular un hash de 24 bytes (192 bits). La salida final de la función bcrypt es una cadena con el formato:

$2<a/b/x/y>$[costo]$[sal de 22 caracteres][hash de 31 caracteres]

Por ejemplo, con la contraseña de entrada abc123xyz, el costo 12y una sal aleatoria, la salida de bcrypt es la cadena

$2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW\__/\/ \____________________/\_____________________________/Costo de Alg Salt Hash

Dónde:

  • $2a$:El identificador del algoritmo hash (bcrypt)
  • 12:Costo de entrada (2 12 es decir 4096 rondas)
  • R9h/cIPz0gi.URNNX3kh2O:Una codificación base-64 de la sal de entrada
  • PST9/PgBkqquzi.Ss7KIUgO2t0jWMUW:Una codificación base 64 de los primeros 23 bytes del hash de 24 bytes calculado

La codificación base-64 en bcrypt utiliza la tabla ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789[ 9], que difiere de la codificación Base64 RFC  4648 .

Historial de versiones

2$ (1999)

La especificación original de bcrypt definía un prefijo $2$. Esto sigue el formato Modular Crypt Format [10] utilizado al almacenar contraseñas en el archivo de contraseñas de OpenBSD:

  • $1$:Cifrado basado en MD5 ('md5crypt')
  • $2$:Cripto basado en Blowfish ('bcrypt')
  • $sha1$:Cifrado basado en SHA-1 ('sha1crypt')
  • $5$:Cifrado basado en SHA-256 ('sha256crypt')
  • $6$:Cifrado basado en SHA-512 ('sha512crypt')

$2a$

La especificación original no definía cómo manejar caracteres no ASCII ni cómo manejar un terminador nulo. La especificación fue revisada para especificar que al aplicar hashes a cadenas:

  • La cadena debe estar codificada en UTF-8.
  • El terminador nulo debe estar incluido

Con este cambio la versión pasó a ser $2a$[11]

$2x$, $2y$ (junio de 2011)

En junio de 2011, se descubrió un error en crypt_blowfish , una implementación PHP de bcrypt. Manejaba incorrectamente los caracteres con el 8.º bit establecido. [12] Sugirieron que los administradores de sistemas actualizaran su base de datos de contraseñas existente, reemplazando $2a$con $2x$, para indicar que esos hashes son incorrectos (y necesitan usar el antiguo algoritmo roto). También sugirieron la idea de que crypt_blowfish emita $2y$para los hashes generados por el algoritmo corregido.

Nadie más, ni siquiera Canonical ni OpenBSD, adoptó la idea de 2x/2y. Este cambio de marcador de versión se limitó a crypt_blowfish .

2 mil millones de dólares (febrero de 2014)

Se descubrió un error en la implementación de bcrypt en OpenBSD. Utilizaba un valor de 8 bits sin signo para almacenar la longitud de la contraseña. [11] [13] [14] Para contraseñas de más de 255 bytes, en lugar de truncarse en 72 bytes, la contraseña se truncaría en el menor de 72 o la longitud módulo 256. Por ejemplo, una contraseña de 260 bytes se truncaría en 4 bytes en lugar de 72 bytes.

bcrypt fue creado para OpenBSD. Cuando encontraron un error en su biblioteca, decidieron aumentar el número de versión.

Algoritmo

La función bcrypt que se muestra a continuación cifra el texto "OrpheanBeholderScryDoubt" 64 veces utilizando Blowfish . En bcrypt, la función de configuración de clave habitual de Blowfish se reemplaza por una función de configuración de clave costosa (EksBlowfishSetup):

Función bcrypt  Entrada: cost: Número (4..31)  log 2 (Iteraciones). p.ej. 12 ==> 2 12 = 4,096 iteraciones salt: matriz de bytes (16 bytes)  sal aleatoria password: matriz de bytes (1..72 bytes)  contraseña codificada en UTF-8  Salida:  hash: matriz de bytes (24 bytes) //Inicializa el estado de Blowfish con un algoritmo de configuración de clave costoso  //P: matriz de 18 subclaves (UInt32[18])  //S: Cuatro cuadros de sustitución (S-boxes), S 0 ... S 3 . Cada S-box tiene 1024 bytes (UInt32[256])  P , S ← EksBlowfishSetup( password , salt , cost )  //Cifrar repetidamente el texto "OrpheanBeholderScryDoubt" 64 veces  ctext"OrpheanBeholderScryDoubt"  //24 bytes ==> tres bloques de 64 bits  repeat (64) ctext ← EncryptECB( P , S , ctext ) //cifrar usando Blowfish estándar en modo ECB // ctext de 24 bytes es el hash de contraseña resultante  que devuelve Concatenate( cost , salt , ctext )

Configuración de clave costosa

El algoritmo bcrypt depende en gran medida de su algoritmo de configuración de clave "Eksblowfish", que se ejecuta de la siguiente manera:

Función EksBlowfishSetup  Entrada: contraseña: matriz de bytes (1..72 bytes)  contraseña codificada en UTF-8 sal: matriz de bytes (16 bytes)  sal aleatoria costo: Número (4..31)  log 2 (Iteraciones). p.ej. 12 ==> 2 12 = 4,096 iteraciones  Salida: P: matriz de UInt32  matriz de 18 subclaves por ronda S 1 ..S 4 : matriz de UInt32  matriz de cuatro SBoxes; cada SBox es 256 UInt32 ( es decir, cada SBox es 1 KiB) //Inicializar P (subclaves) y S (cuadros de sustitución) con los dígitos hexadecimales de pi  P , S ← InitialState()  //Permutar P y S en función de la contraseña y la sal  P , S ← ExpandKey( P , S , contraseña , sal ) //Esta es la parte "Costosa" de la "Configuración de claves costosas".  //De lo contrario, la configuración de claves es idéntica a Blowfish.  repeat (2 cost ) P , S ← ExpandKey( P , S , password, 0) P , S ← ExpandKey( P , S , salt, 0) devuelve  P , S

InitialState funciona como en el algoritmo Blowfish original, rellenando las entradas de la matriz P y del cuadro S con la parte fraccionaria en hexadecimal. π {\estilo de visualización \pi}

Tecla de expansión

La función ExpandKey hace lo siguiente:

Función ExpandKey  Entrada: P: matriz de UInt32  Matriz de 18 subclaves S 1 ..S 4 : UInt32[1024]  Cuatro SBoxes de 1 KB contraseña: matriz de Bytes (1..72 bytes)  contraseña codificada en UTF-8 sal: Byte[16]  sal aleatoria  Salida: P: matriz de UInt32  Matriz de 18 subclaves por ronda S 1 ..S 4 : UInt32[1024]  Cuatro SBoxes de 1 KB   //Mezcle la contraseña en la matriz de subclaves P  para  n ← 1 a 18, haga P n ← P n  xor  contraseña [32(n-1)..32n-1] //trate la contraseña como cíclica  //Trate la sal de 128 bits como dos mitades de 64 bits (el tamaño del bloque Blowfish). saltHalf[0] ← salt [0..63] //64 bits inferiores de sal saltHalf[1] ← salt [64..127] //64 bits superiores de sal //Inicializa un búfer de 8 bytes (64 bits) con todos ceros. bloque ← 0 //Mezclar el estado interno en cajas P  para  n ← 1 a 9 //xor bloque de 64 bits con un bloque de medio bloque de sal de 64 bits ← xor saltHalf [(n-1) mod 2] // cada  iteración alterna entre saltHalf [0] y saltHalf [1]  // cifrar bloque usando la programación de claves actual  bloque ← Cifrar( P , S , bloque ) P 2nbloque [0..31] //32 bits inferiores del bloque P 2n+1bloque [32..63] //32 bits superiores del bloque //Mezclar el estado cifrado en las cajas S internas del estado  para  i ← 1 a 4 hacer  para  n ← 0 a 127 hacer  bloque ← Encrypt( estado , bloque  xor  saltHalf [(n-1) mod 2]) //como arriba S i [2n] ← bloque [0..31] //32 bits inferiores S i [2n+1] ← bloque [32..63] //32 bits superiores  devolver  estado

Por lo tanto, es lo mismo que la programación de claves Blowfish normal, ya que todos los XOR con el valor de sal todo cero son ineficaces. es similar, pero utiliza la sal como una clave de 128 bits.ExpandKey(state, 0, key)ExpandKey(state, 0, salt)

Entrada del usuario

Muchas implementaciones de bcrypt truncan la contraseña a los primeros 72 bytes, siguiendo la implementación de OpenBSD.

El algoritmo matemático en sí mismo requiere inicialización con 18 subclaves de 32 bits (equivalentes a 72 octetos/bytes). La especificación original de bcrypt no exige ningún método en particular para mapear contraseñas basadas en texto del espacio de usuario a valores numéricos para el algoritmo. Un breve comentario en el texto menciona, pero no exige, la posibilidad de simplemente usar el valor codificado ASCII de una cadena de caracteres: "Finalmente, el argumento clave es una clave de cifrado secreta, que puede ser una contraseña elegida por el usuario de hasta 56 bytes (incluido un byte cero final cuando la clave es una cadena ASCII)". [1]

Tenga en cuenta que la cita anterior menciona contraseñas "de hasta 56 bytes", aunque el algoritmo en sí mismo utiliza un valor inicial de 72 bytes. Aunque Provos y Mazières no indican el motivo de la restricción más corta, es posible que hayan estado motivados por la siguiente declaración de la especificación original de Blowfish de Bruce Schneier : "El límite de 448 [bit] en el tamaño de la clave garantiza que [ sic ] cada bit de cada subclave dependa de cada bit de la clave". [15]

Las implementaciones han variado en su enfoque de convertir contraseñas en valores numéricos iniciales, incluyendo a veces la reducción de la fortaleza de las contraseñas que contienen caracteres no ASCII. [16]

Comparación con otros algoritmos de hash de contraseñas

Es importante tener en cuenta que bcrypt no es una función de derivación de claves (KDF) . Por ejemplo, bcrypt no se puede utilizar para derivar una clave de 512 bits a partir de una contraseña. Al mismo tiempo, algoritmos como pbkdf2 , scrypt y argon2 son funciones de derivación de claves basadas en contraseñas, donde el resultado se utiliza para el propósito de generar hashes de contraseñas en lugar de solo derivar claves.

Por lo general, el hash de contraseñas debe completarse en menos de 1000 ms. En este escenario, bcrypt es más seguro que pbkdf2, scrypt y argon2.

  • PBKDF2 : pbkdf2 es más débil que bcrypt. El algoritmo de hash SHA2, que se utiliza habitualmente, no consume mucha memoria. SHA2 está diseñado para ser extremadamente ligero, de modo que pueda ejecutarse en dispositivos ligeros (por ejemplo, tarjetas inteligentes). [17] Esto significa que PBKDF2 es muy débil para el almacenamiento de contraseñas, ya que es fácil adquirir hardware de hash SHA-2 que puede realizar billones de hashes por segundo. [18] [19]
  • scrypt : scrypt es más débil que bcrypt para requisitos de memoria menores a 4 MB. [20] scrypt requiere aproximadamente 1000 veces la memoria de bcrypt para lograr un nivel comparable de defensa contra ataques basados ​​en GPU (para almacenamiento de contraseñas).
  • argon2 : bcrypt es más ligero que Argon2. Esto puede suponer un problema para algunas aplicaciones web en las que el uso de Argon2 requeriría reducir los parámetros de seguridad a un nivel inaceptable para que sigan siendo eficaces. En concreto, Argon2 es menos seguro que bcrypt para tiempos de ejecución inferiores a 1 segundo (es decir, para la autenticación de contraseñas comunes). Argon2 no iguala ni supera la solidez de bcrypt hasta que supera los ≈1000 ms de tiempos de ejecución. [ cita requerida ] Esto puede no ser adecuado para el hash de contraseñas, pero es perfectamente aceptable para la derivación de claves. [21] En algunos casos, se recomienda Argon2 en lugar de bcrypt, si los parámetros de seguridad son lo suficientemente altos. [22]
  • pufferfish2 es una evolución de bcrypt que utiliza una huella de memoria ajustable (como scrypt y argon2), en lugar de la huella de memoria fija de 4 KB de bcrypt. Similar a scrypt o argon2, pufferfish2 gana su dificultad al usar más memoria. A diferencia de scrypt y argon2, pufferfish2 solo opera en el caché L2 de un núcleo de CPU. Mientras que scrypt y argon2 obtienen su dureza de memoria al acceder aleatoriamente a una gran cantidad de RAM, pufferfish2 se limita solo al caché L2 dedicado disponible para un núcleo de CPU. Esto hace que sea aún más difícil de implementar en hardware personalizado que scrypt y argon2. La huella de memoria ideal de pufferfish2 es el tamaño del caché disponible para un núcleo (por ejemplo, 1,25 MB para Intel Alder Lake [23] ). Esto hace que pufferfish2 sea mucho más resistente a la GPU o ASIC.

Críticas

Longitud máxima de contraseña

bcrypt tiene una longitud máxima de contraseña de 72 bytes. Este máximo proviene de la primera operación de la función ExpandKeyxor's que contiene las 18 subclaves de 4 bytes (P) con la contraseña:

P 1 ..P 18 ← P 1 ..P 18 xor contraseñaBytes

La contraseña (codificada en UTF-8) se repite hasta que alcanza los 72 bytes. Por ejemplo, una contraseña de:

correct horse battery staple␀ (29 bytes)

Se repite hasta que coincida con los 72 bytes de las subclaves de 18 P por ronda:

correct horse battery staple␀correct horse battery staple␀correct horse (72 bytes)

En el peor de los casos, una contraseña está limitada a 18 caracteres, cuando cada carácter requiere 4 bytes de codificación UTF-8. Por ejemplo:

𐑜𐑝𐑟𐑥𐑷𐑻𐑽𐑾𐑿𐑿𐑰𐑩𐑛𐑙𐑘𐑙𐑒𐑔 (18 caracteres, 72 bytes)

Truncamiento del hash de la contraseña

El algoritmo bcrypt implica cifrar repetidamente el texto de 24 bytes:

OrpheanBeholderScryDoubt (24 bytes)

Esto genera 24 bytes de texto cifrado, por ejemplo:

85 20 af 9f 03 3d b3 8c 08 5f d2 5e 2d aa 5e 84 a2 b9 61 d2 f1 29 c9 a4 (24 bytes)

La implementación canónica de OpenBSD trunca esto a 23 bytes [ cita requerida ] :

85 20 af 9f 03 3d b3 8c 08 5f d2 5e 2d aa 5e 84 a2 b9 61 d2 f1 29 c9 (23 bytes)

No está claro por qué la implementación canónica elimina 8 bits del hash de contraseña resultante. [ cita requerida ]

Estos 23 bytes se convierten en 31 caracteres cuando se codifican en radix-64:

fQAtluK7q2uGV7HcJYncfII3WbJvIai (31 caracteres)

alfabeto de codificación base64

La codificación utilizada por la implementación canónica de OpenBSD utiliza el mismo alfabeto Base64 que crypt , que es ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789. [9] Esto significa que la codificación no es compatible con el RFC 4648 más común . [ cita requerida ]

Véase también

Referencias

  1. ^ ab Provos N , Maziéres D (10 de junio de 1999). Un esquema de contraseñas adaptable al futuro (PDF) . Conferencia técnica anual de USENIX de 1999. Vol. Actas del grupo FREENIX. Monterey, California: Asociación USENIX .
  2. ^ "Registro CVS para src/lib/libc/crypt/bcrypt.c". Repositorio CVS . OpenBSD . 23 de marzo de 2014. Revisión 1.32 (primera mención de bcrypt en el registro) . Consultado el 25 de mayo de 2023 . Cambio mínimo en la implementación de bcrypt para no requerir variables globales estáticas
  3. ^ "Anuncio de seguridad de SUSE: (SUSE-SA:2011:035)". Avisos de seguridad . SUSE . 23 de agosto de 2011. Archivado desde el original el 4 de marzo de 2016 . Consultado el 20 de agosto de 2015 . La implementación de crypt() de SUSE admite la función de hash de contraseña Blowfish (id $2a) y los inicios de sesión del sistema de forma predeterminada también utilizan este método.
  4. ^ Whitlock, David (21 de septiembre de 2021). "Bcrypt Elixir: algoritmo de hash de contraseñas bcrypt para Elixir". GitHub . riverrun.
  5. ^ "Paquete bcrypt". godoc.org .
  6. ^ "jBCrypt - algoritmo de hash de contraseñas seguro para Java". www.mindrot.org . Consultado el 11 de marzo de 2017 .
  7. ^ "bcrypt - Una implementación independiente de Java de la función hash de contraseña bcrypt". github.com . Consultado el 19 de julio de 2018 .
  8. ^ "bcryptjs". npm . 7 de febrero de 2017.
  9. ^ ab Provos, Niels (13 de febrero de 1997). «Código fuente de bcrypt.c, líneas 57-58» . Consultado el 29 de enero de 2022 .
  10. ^ "Formato de cripta modular: documentación de Passlib v1.7.1". passlib.readthedocs.io .
  11. ^ ab "Errores en el hash de contraseña bcrypt corregidos, cambios de versión y consecuencias". undeadly.org .
  12. ^ Diseñador, Solar. "oss-sec: solicitud CVE: manejo incorrecto de caracteres de 8 bits en crypt_blowfish". seclists.org .
  13. ^ "'Cambios de versión de bcrypt' - MARC". marc.info .
  14. ^ "Corrección del código bcrypt.c para el error de 2014". 17 de febrero de 2014. Archivado desde el original el 18 de febrero de 2022. Consultado el 17 de febrero de 2022 .
  15. ^ Schneier, Bruce (diciembre de 1993). "Cifrado rápido de software, descripción de una nueva clave de longitud variable, cifrado de bloques de 64 bits (Blowfish)". Actas del taller de seguridad de Cambridge . Springer-Verlag: 191–204.
  16. ^ "Aviso de seguridad de jBCrypt". 1 de febrero de 2010.Y "Cambios en CRYPT_BLOWFISH en PHP 5.3.7". php.net .
  17. ^ Estándar de hash seguro nist.gov
  18. ^ "Rentabilidad de Goldshell KD6 | Valor del minero ASIC". www.asicminervalue.com .
  19. ^ "Rentabilidad del Goldshell KD6".
  20. ^ "Por qué no recomiendo Scrypt". 12 de marzo de 2014.
  21. ^ "Argon2 vs bcrypt vs scrypt: ¿qué algoritmo hash es el adecuado para usted?". Marzo de 2023.
  22. ^ "Hoja de trucos para el almacenamiento de contraseñas de OWASP".
  23. ^ "Especificaciones del producto".
  24. ^ Página de inicio del programa de cifrado de archivos bcrypt
  25. ^ "bcrypt APK para Android - descarga gratuita en Droid Informer". droidinformer.org .
  26. ^ "Paquete T2 - trunk - bcrypt - Una utilidad para cifrar archivos". t2sde.org .
  27. ^ "Oracle GoldenGate の ラ イ セ ン ス". docs.oracle.com .
  • crypt_blowfish, la implementación mantenida por Openwall
Obtenido de "https://es.wikipedia.org/w/index.php?title=Bcrypt&oldid=1250882442"