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 los ataques de tablas de 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 los ataques de búsqueda de fuerza bruta incluso con un poder de cálculo creciente.
General | |
---|---|
Diseñadores | Niels Provos , David Mazières |
Publicado por primera vez | 1999 |
Derivado de | Blowfish (cifrado) |
Detalle | |
Tamaños de resumen | 184 bits |
Rondas | variable a través del parámetro de costo |
La función bcrypt es el algoritmo hash de contraseña predeterminado para OpenBSD [2] y era el predeterminado para algunas distribuciones de Linux como SUSE Linux . [3]
Hay implementaciones de bcrypt para C , C ++ , C # , Elixir , [4] Go , [5] Java , [6] [7] JavaScript , [8] Perl , PHP , Python , [9] Ruby y otros lenguajes.
Fondo
Blowfish es notable entre los cifrados de bloque por su costosa fase de configuración de claves. Comienza con subclaves en un estado estándar, luego usa este estado para realizar un cifrado de bloque usando parte de la clave y usa el resultado de ese cifrado (que es más preciso en el hash) para reemplazar algunas de las subclaves. Luego usa este estado modificado para encriptar otra parte de la clave y usa el resultado para reemplazar más subclaves. Procede de esta manera, usando un estado progresivamente modificado para codificar la clave y reemplazar bits de estado, hasta que se hayan establecido todas las subclaves.
Provos y Mazières se aprovecharon de esto y lo llevaron más allá. Desarrollaron un nuevo algoritmo de configuración de claves para Blowfish, y denominaron el cifrado resultante "Eksblowfish" ("programa de claves caro Blowfish"). La configuración de la clave comienza con una forma modificada de la configuración de clave estándar de Blowfish, en la que tanto la sal como la contraseña se utilizan para configurar todas las subclaves. Luego, 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, 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 claves es configurable; por lo tanto, este proceso puede hacerse arbitrariamente lento, lo que ayuda a disuadir los ataques de fuerza bruta sobre el hachís o la sal.
Descripción
Una cadena hash bcrypt tiene la forma:
$ 2b $ [costo] $ [sal de 22 caracteres] [hash de 31 caracteres]
Por ejemplo:
$ 2a $ 10 $ N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy\ __ / \ / \ ____________________ / \ _____________________________ / Alg Cost Salt Hash
Dónde:
$2a$
: El identificador del algoritmo hash (bcrypt)10
: Factor de coste (210
==> 1024 rondas)N9qo8uLOickgx2ZMRZoMye
: Salt de 16 bytes (128 bits), codificado en base64 a 22 caracteresIjZAgcfl7p92ldGxad68LJZdL17lhWy
: Hash de 24 bytes (192 bits), codificado en base64 a 31 caracteres
El prefijo "$ 2a $" o "$ 2b $" (o "$ 2y $") en una cadena hash en un archivo de contraseña oculta indica que la cadena hash es un hash bcrypt en formato de cripta modular. [10] El resto de la cadena hash incluye el parámetro de costo, un salt de 128 bits ( Radix-64 codificado como 22 caracteres) y 192 bits del valor hash resultante ( Radix-64 codificado como 31 caracteres). [11] La codificación Radix-64 utiliza el alfabeto Unix / Crypt, y no es Base-64 "estándar" . [12] [13] El parámetro de costo especifica un recuento de iteraciones de expansión clave como una potencia de dos, que es una entrada para el algoritmo de la cripta.
Por ejemplo, el registro de contraseña oculta $2a$10$N9qo8uLOickgx2ZMRZoMyeIjZAgcfl7p92ldGxad68LJZdL17lhWy
especifica un parámetro de costo de 10, lo que indica 2 rondas de expansión de 10 claves. La sal es N9qo8uLOickgx2ZMRZoMye
y el picadillo resultante es IjZAgcfl7p92ldGxad68LJZdL17lhWy
. Según la práctica estándar, la contraseña del usuario en sí no se almacena.
En la mayoría de los lenguajes de programación , es posible verificar si un texto representa una contraseña bcrypt codificada mediante una expresión regular . Esta función se puede utilizar para validar si una contraseña está codificada correctamente. A continuación, se muestra un ejemplo en Python de una expresión regular que funciona en la mayoría de los lenguajes de programación :
importar re# Versión simplificada de una expresión regular para que coincida con las contraseñas de bcryptexpresión_regular = "^ [$] 2 [abxy]? [$] (?: 0 [4-9] | [12] [0-9] | 3 [01]) [$] [./ 0-9a-zA -Z] {53} $ "# Una contraseña de bcrypt codificada con la versión "2y" y cuesta 12encoded_password = "$ 2y $ 12 $ PEmxrth.vjPDazPWQcLs6u9GRFLJvneUkcf / vcXn8L.bzaBUKeX4W"partidos = re . búsqueda ( expresión_regular , contraseña_codificada )si coincide : print ( "¡SÍ! ¡Tenemos una coincidencia!" )otra cosa : imprimir ( "No coincide" )
Cuando se ejecuta, este programa da la siguiente salida:
¡SÍ! ¡Tenemos un partido!
Además de identificar si el texto dado es una contraseña válida de bcrypt, la expresión regular se puede usar para extraer información de él, como su versión, costo, sal y hash. A continuación, se muestra un ejemplo en Python de una expresión regular más avanzada que extrae información de la contraseña codificada. Se puede modificar para que funcione en la mayoría de los lenguajes de programación :
# Este ejemplo requiere python 3.6+importar re# Versión avanzada de una expresión regular para hacer coincidir las contraseñas de bcrypt y extraer su informaciónexpresión_regular = "^ [$] (? P 2 [abxy]?) [$] (? P (? P (0 [4-9] | [12] [0-9] | 3 [01]))) [$] (? P ((? P [./0-9a-zA-Z] ña> {22} ) (? P [./0- 9a-zA-Z] {31} ))) $ "# A continuación, la misma expresión regular para usar en otros idiomas# Tenga en cuenta que la letra "P" se eliminó de los nombres## ^ [$] (? 2 [abxy]?) [$] (? (? (0 [4-9] | [12] [0-9] | 3 [01] ))) [$] (? ((? [./0-9a-zA-Z]{22}) (? [./0-9a-zA-Z]{31 PS ña> ón>patrón = re . compilar ( expresión_regular )# Una contraseña de bcrypt codificada con la versión "2y" y cuesta 12encoded_password = "$ 2y $ 12 $ PEmxrth.vjPDazPWQcLs6u9GRFLJvneUkcf / vcXn8L.bzaBUKeX4W"partido = patrón . coincidencia ( contraseña_codificada )si coincide : print ( "¡SÍ! ¡Tenemos una coincidencia!" ) imprimir ( "" ) print ( f "Versión: { match . group ( 'version' ) } " ) print ( f "Costo: { match . group ( 'cost' ) } " ) print ( f "Fuerza (otro nombre para el costo): { partido . grupo ( 'fuerza' ) } " ) print ( f "Contraseña: { match . group ( 'contraseña' ) } " ) print ( f "Salt: { match . group ( 'salt' ) } " ) print ( f "Hash: { match . group ( 'hash' ) } " )otra cosa : imprimir ( "No coincide" )
Cuando se ejecuta, este programa da la siguiente salida:
¡SÍ! ¡Tenemos un partido!Versión: 2yCoste: 12Fuerza (otro nombre para el costo): 12Contraseña: PEmxrth.vjPDazPWQcLs6u9GRFLJvneUkcf / vcXn8L.bzaBUKeX4WSal: PEmxrth.vjPDazPWQcLs6uHash: 9GRFLJvneUkcf / vcXn8L.bzaBUKeX4W
Historial de versiones
$ 2 $ (1999)
La especificación bcrypt original definía un prefijo de $2$
. Esto sigue el formato Modular Crypt Format [14] utilizado al almacenar contraseñas en el archivo de contraseñas de OpenBSD:
$1$
: Cripta basada en MD5 ('md5crypt')$2$
: Cripta basada en pez globo ('bcrypt')$sha1$
: Cripta basada en SHA-1 ('sha1crypt')$5$
: Cripta basada en SHA-256 ('sha256crypt')$6$
: Cripta basada 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 se revisó para especificar que al aplicar hash a cadenas:
- la cadena debe estar codificada en UTF-8
- el terminador nulo debe estar incluido
Con este cambio, la versión se cambió a $2a$
[15].
$ 2x $, $ 2y $ (junio de 2011)
En junio de 2011, se descubrió un error en crypt_blowfish , una implementación PHP de bcrypt. Se trataba de un mal manejo de los caracteres con el 8º bit configurado. [16] Sugirieron que los administradores del sistema actualicen su base de datos de contraseñas existente, reemplazándolas $2a$
por $2x$
, para indicar que esos hashes son malos (y necesitan usar el antiguo algoritmo roto). También sugirieron la idea de hacer que crypt_blowfish emita los $2y$
hash generados por el algoritmo fijo.
Nadie más, incluido el canónico OpenBSD, adoptó la idea de 2x / 2y. Este cambio de marcador de versión se limitó a crypt_blowfish .
$ 2b $ (febrero de 2014)
Se descubrió un error en la implementación de OpenBSD de bcrypt. Estaban almacenando la longitud de sus cadenas en un carácter sin firmar ( es decir, 8 bits Byte
). [15] Si una contraseña tenía más de 255 caracteres, se desbordaría y se ajustaría a 255. [17]
bcrypt fue creado para OpenBSD. Cuando tuvieron un error en su biblioteca, decidieron aumentar el número de versión.
Algoritmo
El algoritmo bcrypt es el resultado de encriptar el texto "OrpheanBeholderScryDoubt" 64 veces usando Blowfish . En bcrypt, la función habitual de configuración de teclas de Blowfish se reemplaza con una función costosa de configuración de teclas (EksBlowfishSetup):
Función bcrypt Entrada: costo: Número (4..31) log 2 (iteraciones). por ejemplo, 12 ==> 2 12 = 4096 iteraciones salt: matriz de bytes (16 bytes) contraseña de sal aleatoria : matriz de bytes (1..72 bytes) contraseña codificada en UTF-8 Salida: hash: matriz de bytes (24 bytes) // Inicializar el estado de Blowfish con un costoso algoritmo de configuración de claves // P: matriz de 18 subclaves (UInt32 [18]) // S: Cuatro cajas de sustitución (cajas S), S 0 ... S 3 . Cada S-box tiene 1.024 bytes (UInt32 [256]) P , S ← EksBlowfishSetup ( costo , sal , contraseña ) // Encriptar repetidamente el texto "OrpheanBeholderScryDoubt" 64 veces ctext ← "OrpheanBeholderScryDoubt" // 24 bytes ==> tres bloques de 64 bits repeat (64) ctext ← EncryptECB ( P , S , ctext ) // encriptar usando Blowfish estándar en ECB modo // ctext de 24 bytes es el resultado de la contraseña hash return Concatenate ( cost , salt , ctext )
Configuración de teclas costosa
El algoritmo bcrypt depende en gran medida de su algoritmo de configuración de claves "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 salt: matriz de bytes (16 bytes) costo de sal aleatorio : número (4..31) log 2 (iteraciones). por ejemplo, 12 ==> 2 12 = 4096 iteraciones Salida: P: matriz de matriz UInt32 de 18 subclaves por ronda S 1 ..S 4 : matriz de matriz UInt32 de cuatro SBoxes; cada SBox es 256 UInt32 ( es decir, 1024 KB) // Inicializar P (Subclaves) y S (Cajas de sustitución) con los dígitos hexadecimales de pi P , S ← InitialState () // Permuta P y S según la contraseña y salt P , S ← ExpandKey ( P , S , salt , contraseña ) // Esta es la parte "Costosa" de la "Configuración de teclas costosa". // De lo contrario, la configuración de la clave es idéntica a Blowfish. repetir (2 costo ) P , S ← ExpandKey ( P , S , 0, contraseña) P , S ← ExpandKey ( P , S , 0, salt) volver P , S
InitialState funciona como en el algoritmo Blowfish original, llenando las entradas P-array y S-box con la parte fraccionaria de en hexadecimal.
Expandir clave
La función ExpandKey hace lo siguiente:
Función ExpandKey Entrada: contraseña: matriz de bytes (1..72 bytes) contraseña codificada en UTF-8 salt: Byte [16] salt aleatorio P: matriz de UInt32 matriz de 18 subclaves S 1 ..S 4 : UInt32 [1024] Cuatro Salida de SBoxes de 1 KB : P: matriz de UInt32 Matriz de 18 subclaves por ronda S 1 ..S 4 : UInt32 [1024] Cuatro SBoxes de 1 KB // Mezclar la contraseña en la matriz de subclaves P para n ← 1 a 18 do P n ← P n xor contraseña [32 (n-1) .. 32n-1] // tratar 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 do // xor bloque de 64 bits con un medio bloque salt de 64 bits ← bloque xor saltHalf [(n-1) mod 2] // cada iteración alterna entre saltHalf [0] y saltHalf [1] // bloque cifrar usando el programa de clave actual bloque ← Cifrar ( P , S , bloque ) P 2n ← bloque [0..31] // bloque inferior de 32 bits del bloque P 2n + 1 ← bloque [32..63] // bloque superior de 32 bits // Mezclar el estado encriptado en las cajas S internas del estado para i ← 1 a 4 do for n ← 0 a 127 do block ← Encrypt ( estado , bloque xor salt [64 (n-1) .. 64n-1]) // como arriba S i [2n] ← bloque [0..31] // inferior de 32 bits S i [2n + 1] ← bloque [32..63] // estado de retorno superior de 32 bits
Por lo tanto, es el mismo que el programa de claves de Blowfish normal, ya que todos los XOR con el valor de sal todo cero son ineficaces. es similar, pero usa la sal como 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í requiere inicialización con 18 subclaves de 32 bits (equivalente 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 área del usuario en valores numéricos para el algoritmo. Un breve comentario en el texto menciona, pero no obliga, la posibilidad de usar simplemente el valor codificado en ASCII de una cadena de caracteres: "Por último, 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 de terminación cero 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í hace uso de un valor inicial de 72 bytes. Aunque Provos y Mazières no indican el motivo de la restricción más corta, pueden haber sido motivados por la siguiente declaración de la especificación original de Bruce Schneier de Blowfish: "El límite de 448 [bits] en el tamaño de la clave asegura que el [ sic ] cada bit de cada subclave depende de cada bit de la clave ". [18]
Las implementaciones han variado en su enfoque de convertir las contraseñas en valores numéricos iniciales, lo que a veces incluye la reducción de la fuerza de las contraseñas que contienen caracteres que no son ASCII. [19]
Criticas
Longitud máxima de la 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 ExpandKey que xor's
las 18 subclaves de 4 bytes (P) con la contraseña:
P 1 ..P 18 ← P 1 ..P 18 xo contraseña Bytes
La contraseña (que está codificada en UTF-8) se repite hasta que tiene 72 bytes de longitud. Por ejemplo, una contraseña de:
correct horse battery staple␀
(29 bytes)
Se repite hasta que coincide con los 72 bytes de las subclaves 18 P por ronda:
correct horse battery staple␀correct horse battery staple␀correct horse
(72 bytes)
Esto también significa que si una contraseña tuviera más de 72 bytes codificados en UTF-8: la contraseña se truncaría. Algunos caracteres pueden requerir 4 bytes cuando están codificados en UTF-8. Esto significa que, en el peor de los casos, esto puede limitar una contraseña a 18 caracteres:
𐑜𐑝𐑟𐑥𐑷𐑻𐑽𐑾𐑿𐑿𐑰𐑩𐑛𐑙𐑘𐑙𐑒𐑔
(18 caracteres, 72 bytes)
Este límite de contraseñas de 72 bytes (18 subclaves * 4 bytes cada una) podría haberse abordado de varias formas:
Solución 1: aumentar el número de subclaves
Puede aumentar el número de subclaves P utilizadas y, por lo tanto, aumentar la longitud máxima de contraseña disponible. Bruce Schneier, el autor original de Blowfish, señaló que la gente podría jugar agregando más rondas, [20] lo que requiere más subclaves, lo que para bcrypt aumentaría la longitud máxima de la contraseña. Una desventaja de esto es que todavía hay una longitud máxima de contraseña, en lugar de una longitud máxima.
Solución 2: continúe xo mezcle los bytes de clave en la matriz de subclaves P
La mezcla de contraseñas solo continúa mientras P 1 ... P 18 . Una vez que haya llegado a P 18 y todavía tenga bytes de contraseña sin procesar, continúe con el proceso xor en P 1 . Una desventaja de este enfoque es que el tiempo de cálculo pierde la longitud de la contraseña (filtración de información del canal lateral)
Solución 3: contraseña previa al hash
La contraseña larga se puede pre-hash con otra función de hash criptográfica. Esta función siempre genera un resumen de un tamaño fijo. Siempre que el resumen resultante tenga menos de 72 bytes: se puede introducir en bcrypt sin cortarlo. Este es el enfoque adoptado por Dropbox [21] y otros. Por ejemplo, considere la contraseña:
ਤੇਜ਼ ਭੂਰੇ ਲੂੰਬੜ ਨੇ ਆਲਸੀ ਕੁੱਤੇ ਉੱਤੇ ਛਾਲ ਮਾਰ ਦਿੱਤੀ
(32 caracteres, 126 bytes)
Si aplica hash a esa contraseña con SHA-256, obtiene el resumen de 256 bits (32 bytes):
A7 B2 AA 86 CB 57 D3 08 EA 54 9F 34 E5 91 7E 8C 06 9B D0 0D 34 28 B1 CA 8D 71 B2 2E 84 DA C0 F8
La codificación Base64 del resumen proporciona una cadena que consta de 44 caracteres:
p7KqhstX0wjqVJ805ZF+jAab0A00KLHKjXGyLoTawPg=
(44 caracteres, 44 bytes)
y siempre se ajustará al límite de bcrypt de 72 bytes.
Esto es similar a un enfoque utilizado por Pufferfish2 , una evolución de bcrypt que utiliza HMAC SHA-512 para convertir la contraseña en una clave de longitud fija de 64 bytes (512 bits).
Truncamiento de hash de contraseña
El algoritmo bcrypt implica encriptar 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)
Que luego debería obtener radix-64 codificado a 32 caracteres:
hSCvnwM9s4wIX9JeLapehKK5YdLxKcmk
(32 caracteres)
Pero la implementación canónica de OpenBSD trunca el hash de la contraseña a 23 bytes:
85 20 af 9f 03 3d b3 8c 08 5f d2 5e 2d aa 5e 84 a2 b9 61 d2 f1 29 c9
a4(23 bytes)
y el texto codificado en base 64 resultante, que normalmente sería:
hSCvnwM9s4wIX9JeLapehKK5YdLxKck =
tiene el trailing = eliminado, dejando un hash de:
hSCvnwM9s4wIX9JeLapehKK5YdLxKck
No está claro por qué la implementación canónica elimina 8 bits del hash de contraseña resultante.
Uso de codificación base64 no estándar
La codificación Base64 utilizada por la implementación canónica de OpenBSD utiliza un diccionario de codificación que es diferente de los disponibles en casi todos los idiomas y plataformas. La codificación es compatible con crypt . [22] Esto significa que la codificación no es compatible con RFC 4648 .
Ver también
- bcrypt es también el nombre de una utilidad de cifrado de archivos multiplataforma que implementa Blowfish desarrollada en 2002. [23] [24] [25] [26]
- Argon2 (El algoritmo seleccionado por el Concurso de hash de contraseñas en 2015)
- Crypt (C) # cripta de esquema basado en Blowfish - esquema de almacenamiento y verificación de contraseñas - Blowfish
- Estiramiento clave
- PBKDF2 (Función 2 de derivación de claves basada en contraseña)
- scrypt
- PufferFish es una función de hash de contraseña de caché basada en un diseño mejorado de bcrypt.
Referencias
- ^ a b Provos, Niels; Mazières, David; Talan Jason Sutton 2012 (1999). "Un esquema de contraseña adaptable al futuro" . Actas de la Conferencia Técnica Anual de USENIX de 1999 : 81–92.
- ^ "Compromiso del primer trabajo a repo" . 13 de febrero de 1997.
- ^ "Anuncio de seguridad de SUSE: (SUSE-SA: 2011: 035)" . 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 de blowfish (id $ 2a) y los inicios de sesión del sistema también utilizan este método de forma predeterminada.
- ^ Whitlock, David. "Bcrypt Elixir: algoritmo hash de contraseña bcrypt para Elixir" . GitHub . Riverrun.
- ^ "Paquete bcrypt" . godoc.org .
- ^ "jBCrypt - hash de contraseña segura para Java" . www.mindrot.org . Consultado el 11 de marzo de 2017 .
- ^ "bcrypt: una implementación independiente de Java de la función hash de contraseña de bcrypt" . github.com . Consultado el 19 de julio de 2018 .
- ^ "bcryptjs" . npm .
- ^ Stufft, Donald. "bcrypt: hash de contraseñas moderno para su software y sus servidores" , a través de PyPI.
- ^ passlib. "Formato de cripta modular" .
- ^ passlib. "bcrypt" .
- ^ "Hash de contraseña moderno (-ish) para su software y sus servidores: pyca / bcrypt" . 18 de noviembre de 2019 - a través de GitHub.
- ^ "GitHub - bcgit / bc-java: distribución de Java de castillo hinchable (espejo)" . 18 de noviembre de 2019 - a través de GitHub.
- ^ "Formato de cripta modular - Documentación de Passlib v1.7.1" . passlib.readthedocs.io .
- ^ a b "Errores de hash de contraseña de bcrypt corregidos, cambios de versión y consecuencias" . undeadly.org .
- ^ Diseñador, Solar. "oss-sec: solicitud CVE: manejo incorrecto de caracteres de 8 bits crypt_blowfish" . seclists.org .
- ^ " ' cambios de versión de bcrypt' - MARC" . marc.info .
- ^ Schneier, Bruce (1994). "Cifrado de software rápido, descripción de una nueva clave de longitud variable, cifrado de bloque de 64 bits (Blowfish)" . Actas del taller de seguridad de Cambridge (diciembre de 1993) . Springer-Verlag: 191-204.
- ^ "Aviso de seguridad de jBCrypt" . 1 de febrero de 2010. Y "Cambios en CRYPT_BLOWFISH en PHP 5.3.7" . php.net .
- ^ https://www.schneier.com/academic/blowfish/
- ^ https://dropbox.tech/security/how-dropbox-securely-stores-your-passwords
- ^ https://medium.com/hackernoon/the-bcrypt-protocol-is-kind-of-a-mess-4aace5eb31bd
- ^ http://bcrypt.sourceforge.net página de inicio del programa de cifrado de archivos bcrypt
- ^ "bcrypt APK para Android - descarga gratuita en Droid Informer" . droidinformer.org .
- ^ "Paquete T2 - troncal - bcrypt - Una utilidad para cifrar archivos" . t2sde.org .
- ^ "Oracle GoldenGate の ラ イ セ ン ス" . docs.oracle.com .
enlaces externos
- crypt_blowfish, la implementación mantenida por Openwall