Articulo de referencia

cripta (C)

`crypt` es una función de la biblioteca POSIX de C. Se utiliza normalmente para calcular el hash de las contraseñas de las cuentas de usuario. La función genera una cadena de te...

`crypt` es una función de la biblioteca POSIX de C. Se utiliza normalmente para calcular el hash de las contraseñas de las cuentas de usuario. La función genera una cadena de texto que también codifica el valor aleatorio (generalmente los dos primeros caracteres son el valor aleatorio y el resto es el resultado del hash), e identifica el algoritmo de hash utilizado (por defecto, el algoritmo tradicional que se explica más adelante). Esta cadena de salida forma un registro de contraseña, que normalmente se almacena en un archivo de texto.

De forma más formal, crypt proporciona funciones de derivación de claves criptográficas para la validación y el almacenamiento de contraseñas en sistemas Unix.

Relación con la utilidad criptográfica de Unix

En Unix existe una utilidad de cifrado independiente que a menudo se confunde con la función de la biblioteca C. Para distinguirlas, los autores suelen referirse al programa de utilidad como crypt(1) , porque está documentado en la sección 1 de las páginas del manual de Unix , y a la función de la biblioteca C como crypt(3) , porque su documentación se encuentra en la sección 3 del manual. [ 1 ]

Detalles

Esta misma función de cifrado se utiliza tanto para generar un nuevo hash para su almacenamiento como para aplicar un hash a una contraseña proporcionada con un valor de sal registrado para su comparación.

Las implementaciones modernas de Unix de la rutina de la biblioteca crypt admiten una variedad de esquemas hash. El algoritmo hash particular utilizado se puede identificar mediante un prefijo de código único en el texto hash resultante, siguiendo un estándar de facto llamado Formato Criptográfico Modular. [ 2 ] [ 3 ] [ 4 ]

La crypt()función de la biblioteca también está incluida en los lenguajes de programación Perl , [ 5 ] PHP , [ 6 ] Pike , [ 7 ] Python [ 8 ] (aunque ahora está obsoleta desde la versión 3.11) y Ruby [ 9 ] .

Funciones de derivación de clave compatibles con crypt

Con el tiempo se han introducido varios algoritmos. Para permitir la compatibilidad con versiones anteriores , cada esquema comenzó a utilizar alguna convención de serialización de los hashes de contraseñas que más tarde se denominó Formato Criptográfico Modular (MCF). [ 3 ] Los hashes crypt(3) antiguos generados antes del estándar MCF de facto pueden variar de un esquema a otro. Un subconjunto bien definido del Formato Criptográfico Modular se creó durante la Competencia de Hashing de Contraseñas . [ 3 ] El formato se define como: [ 10 ]

$<id>[$<param>=<value>(,<param>=<value>)*][$<salt>[$<hash>]]

dónde

  • id: un identificador que representa el algoritmo de hash (como 1 para MD5 , 5 para SHA-256 , etc.)
  • paramnombre y sus valueparámetros de complejidad hash, como el número de rondas/iteraciones
  • salt: sal siguiendo el alfabeto de base 64 (DES utiliza el valor decodificado)
  • hash: resultado codificado en radix-64 del hash de la contraseña y el salt

La codificación radix-64 en crypt se llama B64 y utiliza un alfabeto ./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzdiferente al más común RFC 4648 base64.

El subconjunto PHC cubre la mayoría de los hashes MCF. Existen varios métodos adicionales definidos por la aplicación. [ 3 ]

Implementación original que utiliza la contraseña como clave.

La implementación original de la función de biblioteca crypt() [ 11 ] en la Tercera Edición de Unix [ 12 ] imitaba la máquina de cifrado M-209 . En lugar de cifrar la contraseña con una clave, lo que habría permitido recuperarla a partir del valor cifrado y la clave, utilizaba la propia contraseña como clave, y la base de datos de contraseñas contenía el resultado de cifrar la contraseña con esta clave.

Esquema tradicional basado en DES

Se descubrió que el esquema original de cifrado de contraseñas era demasiado rápido y, por lo tanto, vulnerable a la enumeración por fuerza bruta de las contraseñas más probables. [ 11 ] En la séptima edición de Unix , [ 13 ] el esquema se modificó a una forma modificada del algoritmo DES . Uno de los objetivos de este cambio era ralentizar el cifrado. Además, el algoritmo incorporó un valor aleatorio (salt) de 12 bits para garantizar que un atacante se viera obligado a descifrar cada contraseña de forma independiente, en lugar de poder atacar toda la base de datos de contraseñas simultáneamente.

En detalle, la contraseña del usuario se trunca a ocho caracteres, y estos se reducen a solo 7 bits cada uno; esto forma la clave DES de 56 bits. Luego, esa clave se usa para cifrar un bloque con todos los bits a cero, y después el texto cifrado se vuelve a cifrar con la misma clave, y así sucesivamente hasta completar 25 cifrados DES. Se usa un valor aleatorio (salt) de 12 bits para perturbar el algoritmo de cifrado, por lo que las implementaciones DES estándar no se pueden usar para implementar crypt(). El valor aleatorio y el texto cifrado final se codifican en una cadena imprimible en formato base64 .

Técnicamente, esto no es cifrado, ya que los datos (todos los bits a cero) no se mantienen en secreto; son de conocimiento público. Sin embargo, una de las características de DES es su diseño para resistir la recuperación de claves, incluso en situaciones con texto plano conocido . Teóricamente, es posible que dos contraseñas diferentes produzcan exactamente el mismo hash. Por lo tanto, la contraseña nunca se "descifra": simplemente se utiliza para calcular un resultado, y se presume que la coincidencia de resultados demuestra que las contraseñas eran "iguales".

Las ventajas de este método radican en que el hash se puede almacenar y copiar entre sistemas Unix sin exponer la contraseña en texto plano a los administradores del sistema ni a otros usuarios. Esta portabilidad ha funcionado durante más de 30 años, abarcando diversas generaciones de arquitecturas informáticas y numerosas versiones de Unix de distintos proveedores.

Debilidades del plan tradicional

El algoritmo criptográfico tradicional basado en DES se eligió originalmente porque DES era resistente a la recuperación de claves incluso ante ataques de "texto plano conocido", y porque era computacionalmente costoso. En las primeras máquinas Unix, tardaba más de un segundo en calcular el hash de una contraseña. Esto también lo hacía razonablemente resistente a los ataques de diccionario en aquella época. En ese entonces, los hashes de contraseñas se almacenaban comúnmente en un archivo de cuenta ( /etc/passwd) que era legible para cualquier usuario del sistema. (Este archivo de cuenta también se usaba para asignar números de identificación de usuario a nombres, nombres de usuario a nombres completos, etc.).

En las tres décadas transcurridas desde entonces, los ordenadores se han vuelto mucho más potentes. La Ley de Moore se ha cumplido en general, por lo que la velocidad y la capacidad de los ordenadores disponibles para una inversión financiera determinada se han duplicado más de 20 veces desde que se escribió Unix por primera vez. Esto ha dejado al algoritmo basado en DES vulnerable a ataques de diccionario, y Unix y los sistemas similares a Unix, como Linux, han utilizado archivos "shadow" durante mucho tiempo, migrando solo los valores hash de las contraseñas del archivo de cuenta ( /etc/passwd) a un archivo (llamado convencionalmente /etc/shadow) que solo puede ser leído por procesos privilegiados.

Para aumentar el coste computacional del descifrado de contraseñas, algunos sitios Unix comenzaron a incrementar de forma privada el número de rondas de cifrado de manera ad hoc. Esto tuvo como efecto secundario la incompatibilidad con el estándar : los hashes tenían el mismo formato textual, pero ahora se calculaban utilizando un algoritmo diferente. Algunos sitios también aprovecharon esta incompatibilidad modificando el bloque inicial del estándar de todos los bits a cero. Esto no aumentó el coste del hash, pero impidió la aplicación de diccionarios de hash precalculados basados ​​en el estándar crypt() .crypt()crypt()

Esquema BSDi extendido basado en DES

BSDi utilizó una ligera modificación del esquema clásico basado en DES. BSDi extendió el valor de la clave aleatoria (salt) a 24 bits e hizo que el número de rondas fuera variable (hasta 2²⁴ - 1). El número de rondas elegido se codifica en el hash de la contraseña almacenada, evitando la incompatibilidad que se producía cuando los sitios modificaban el número de rondas utilizado por el esquema original. Estos hashes se identifican comenzando con un guion bajo ( __), seguido de 4 caracteres que representan el número de rondas y luego 4 caracteres para la clave aleatoria.

El algoritmo BSDi también admite contraseñas más largas, utilizando DES para reducir la contraseña larga inicial a los ocho bytes de 7 bits que admite el algoritmo original.

Esquema basado en MD5

Poul-Henning Kamp diseñó un algoritmo barroco y (en aquel entonces) computacionalmente costoso basado en el algoritmo de resumen de mensajes MD5 . MD5 en sí mismo proporcionaría una buena seguridad criptográfica para el hash de contraseña, pero está diseñado para ser bastante rápido de calcular en relación con la seguridad que proporciona. El esquema crypt() está diseñado para ser costoso de calcular, para ralentizar los ataques de diccionario. La forma imprimible de los hashes de contraseña MD5 comienza con $1$.

Este sistema permite a los usuarios tener contraseñas de cualquier longitud y utilizar cualquier carácter compatible con su plataforma (no solo ASCII de 7 bits). (En la práctica, muchas implementaciones limitan la longitud de la contraseña, pero generalmente admiten contraseñas mucho más largas de las que cualquier persona estaría dispuesta a escribir). El valor aleatorio (salt) también es una cadena arbitraria, limitada únicamente por las características del conjunto de caracteres.

Primero, la contraseña y la clave de cifrado se combinan mediante una función hash, generando un resumen MD5 del mensaje. A continuación, se construye un nuevo resumen, combinando la contraseña, la clave de cifrado y el primer resumen, todo ello en un formato bastante complejo. Posteriormente, este resumen se procesa mil veces mediante una función que lo vuelve a combinar con la contraseña y la clave de cifrado, variando el resultado entre cada iteración. El resultado de la última iteración es el hash de la contraseña.

El número fijo de iteraciones ha provocado que este esquema pierda la eficiencia computacional que tenía anteriormente, y ahora se prefieren los números variables de rondas. En junio de 2012, Poul-Henning Kamp declaró que el algoritmo era inseguro y animó a los usuarios a migrar a cifradores de contraseñas más robustos. [ 14 ]

Plan basado en el pez globo

Niels Provos y David Mazières diseñaron un esquema crypt() llamado bcrypt basado en Blowfish y lo presentaron en USENIX en 1999. [ 15 ] La forma imprimible de estos hashes comienza con $2$, $2a$, $2b$, $2x$o $2y$dependiendo de la variante del algoritmo que se utilice:

  • $2$ - Obsoleto.
  • $2a$  La clave actual se utiliza para identificar este esquema. Dado que en 2011 se descubrió una importante vulnerabilidad de seguridad en una implementación del algoritmo crypt_blowfish que no era de OpenBSD, [ 16 ] los hashes indicados por esta cadena son ahora ambiguos y podrían haber sido generados por la implementación defectuosa o por una implementación corregida posterior. La vulnerabilidad puede activarse mediante algunas cadenas de contraseñas que contienen caracteres no ASCII (con el octavo bit activado).
  • $2b$  Utilizado por implementaciones recientes de OpenBSD para incluir una mitigación a un problema de desbordamiento. [ 17 ] Las versiones anteriores del algoritmo tienen un problema con contraseñas largas. Por diseño, las contraseñas largas se truncan a 72 caracteres, pero existe un problema de desbordamiento de enteros de bytes con ciertas longitudes de contraseña que resulta en hashes débiles. [ 18 ]
  • $2x$  Se agregó una bandera tras el descubrimiento del error crypt_blowfish . Los hashes antiguos se pueden renombrar para indicar que se generaron con el algoritmo defectuoso. Estos hashes siguen siendo débiles, pero al menos queda claro qué algoritmo se utilizó para generarlos.$2x$
  • $2y$  Una bandera en crypt_blowfish para usar inequívocamente el nuevo algoritmo corregido. En una implementación antigua que sufre el error, simplemente no funcionará. En una implementación más reciente y corregida, producirá el mismo resultado que usar .$2y$$2b$

Blowfish destaca entre los cifradores 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 bloques con parte de la clave y usa el resultado de dicho cifrado (en realidad, una función hash) para reemplazar algunas de las subclaves. A continuación, utiliza este estado modificado para cifrar otra parte de la clave y usa el resultado para reemplazar más subclaves. Procede de esta manera, utilizando un estado progresivamente modificado para aplicar la función hash a la clave y reemplazar bits del estado, hasta que todas las subclaves estén configuradas.

El número de rondas de clave es una potencia de dos, que es una entrada para el algoritmo. El número está codificado en el hash textual, por ejemplo$2y$10...

Esquema hash NT

FreeBSD implementó soporte para el algoritmo hash NT LAN Manager para facilitar la compatibilidad con cuentas NT a través de MS-CHAP . [ 19 ] Se sabe que el algoritmo NT-Hash es débil, ya que utiliza el algoritmo hash md4 obsoleto sin ningún salting. [ 20 ] FreeBSD usó el $3$prefijo para esto. No se recomienda su uso, ya que es fácil de romper. [ 1 ]

Esquema basado en SHA2

El esquema MD5, de uso común, se ha vuelto más fácil de atacar a medida que ha aumentado la potencia informática. Aunque el sistema Blowfish tiene la opción de añadir rondas y, por lo tanto, seguir siendo un algoritmo de contraseña desafiante, no utiliza un algoritmo aprobado por el NIST . En vista de estos hechos, Ulrich Drepper de Red Hat lideró un esfuerzo para crear un esquema basado en las funciones hash SHA-2 (SHA-256 y SHA-512). [ 21 ] La forma imprimible de estos hashes comienza con $5$(para SHA-256) o $6$(para SHA-512) dependiendo de la variante SHA que se utilice. Su diseño es similar al criptograma basado en MD5, con algunas diferencias notables: [ 21 ]

  • Evita agregar datos constantes en pocos pasos.
  • El algoritmo MD5 añadía repetidamente la primera letra de la contraseña; este paso se modificó significativamente.
  • Inspirado en la implementación crypt() de Sun , se agregó la funcionalidad para especificar el número de iteraciones (rondas) que realiza el bucle principal en el algoritmo [ 22 ] [ 23 ].
  • El número de iteraciones es 5000 por defecto, con un mínimo de 1000 y un máximo de 999.999.999. [ 24 ]

La especificación y el código de ejemplo se han publicado en el dominio público; a menudo se le conoce como "SHAcrypt". [ 24 ]

Otros hashes

$y$
yescrypt es una extensión de scrypt ( $7$) y finalista de PHC. Se utiliza en varias distribuciones de Linux como alternativa a los esquemas existentes. [ 25 ] Para usar este hash, el libcryptde glibc se reemplaza por uno compatible con versiones anteriores del proyecto "libxcrypt". [ 26 ]
$argon2d$, $argon2i$,$argon2ds$
Estos son los nombres que PHC ha asignado al algoritmo Argon2 , pero no parecen ser de uso generalizado.

Los formatos adicionales, si los hay, se describen en las páginas de manual de las implementaciones. [ 27 ]

Esquemas arcaicos de Unix

BigCrypt es la versión modificada de DES-Crypt utilizada en HP-UX, Digital Unix y OSF/1. La principal diferencia con DES es que BigCrypt utiliza todos los caracteres de una contraseña, no solo los primeros 8, y tiene un hash de longitud variable. [ 28 ]

Crypt16 es una modificación menor de DES que permite contraseñas de hasta 16 caracteres. Se utiliza en Ultrix y Tru64. [ 29 ]

Soporte en sistemas operativos

Linux

La biblioteca GNU C (glibc), utilizada por casi todas las distribuciones de Linux, proporciona una implementación de la función crypt que admite los algoritmos de hash DES, MD5 y (desde la versión 2.7) SHA-2 mencionados anteriormente. Ulrich Drepper, el mantenedor de glibc, rechazó la compatibilidad con bcrypt (esquema 2) ya que no está aprobado por NIST . [ 32 ] Existe una biblioteca de dominio público , crypt_blowfish, disponible para sistemas sin bcrypt. Se ha integrado en glibc en SUSE Linux . [ 33 ]

En agosto de 2017, glibc anunció planes para eliminar por completo su implementación de crypt. En respuesta, varias distribuciones de Linux (incluidas, entre otras, Fedora y Debian) han cambiado a libxcrypt , una implementación compatible con ABI que además admite nuevos algoritmos, incluidos bcrypt y yescrypt. [ 34 ]

La biblioteca C musl admite los esquemas 1, 2, 5 y 6, además del esquema DES tradicional. El código DES tradicional se basa en BSD FreeSec , con modificaciones para que sea compatible con glibc UFC-Crypt . [ 35 ]

macOS

Darwin crypt()proporciona funcionalidades limitadas, admitiendo solo DES y BSDi. OS X utiliza varios sistemas para sus propios hashes de contraseñas, desde el antiguo NeXTStep netinfo hasta el sistema más reciente de servicios de directorio (ds). [ 36 ] [ 37 ]

Véase también

Referencias

  1. 1 2Manual de funciones de la biblioteca de FreeBSDcrypt(3)  
  2. Simson Garfinkel, Alan Schwartz, Gene Spafford. "Seguridad práctica en Unix e Internet" . 2003. Sección "4.3.2.3 crypt16(), DES Extended y formato de cifrado modular" . "El formato de cifrado modular (MCF) especifica un esquema extensible para formatear contraseñas cifradas. MCF es uno de los formatos más populares para contraseñas cifradas".
  3. 1 2 3 4 "Formato criptográfico modular: documentación de Passlib v1.7.1" . Pythonhosted.org . Consultado el 2 de diciembre de 2018 .
  4. "ademarre/binary-mcf" . GitHub.com . Consultado el 2 de diciembre de 2018 .
  5. "crypt - perldoc.perl.org" . Perldoc.perl.org . Consultado el 2 de diciembre de 2018 .
  6. "PHP: crypt - Manual" . Us.php.net . Consultado el 2 de diciembre de 2018 .
  7. "crypt()" . Archivado del original el 2 de octubre de 2012. Consultado el 9 de febrero de 2013 .
  8. "crypt — Función para comprobar contraseñas de Unix — Documentación de Python 3.7.1" . Docs.python.org . Consultado el 2 de diciembre de 2018 .
  9. "Clase: String (Ruby 2.5.3)" . Ruby-doc.org . Consultado el 2 de diciembre de 2018 .
  10. Concurso de hash de contraseñas. "Formato de cadena PHC" . Github .
  11. 1 2 Morris, Robert; Thompson, Ken (1978-04-03). "Seguridad de contraseñas: un estudio de caso" . Bell Laboratories . Recuperado el 17 de diciembre de 2013 .
  12. "crypt – codificación de contraseñas" . Manual del programador de UNIX, tercera edición . 15 de enero de 1973.
  13. "crypt, setkey, encrypt – Cifrado DES" . Manual del programador de la séptima edición de UNIX . 1979.
  14. "El cifrador de contraseñas Md5crypt ya no se considera seguro por su autor — PHKs Bikeshed" . Phk.freebsd.dk . Archivado del original el 17 de marzo de 2018. Consultado el 2 de diciembre de 2018 .
  15. Provos, Niels; Mazières, David (1999). "Un esquema de contraseña adaptable al futuro" . Actas de la Conferencia Técnica Anual de USENIX de 1999 : 81–92 .
  16. Diseñador, Solar (21-06-2011). "crypt_blowfish 1.1; Actualización de seguridad de Owl glibc" .Véase también CVE - 2011-2483 .
  17. "src/lib/libc/crypt/bcrypt.c – vista – 1.27" . Cvsweb.openbsd.org . Consultado el 14 de mayo de 2016 .
  18. Diseñador, Solar (2012-01-02). "Envoltura de clave bcrypt de 8 bits de OpenBSD" .
  19. "NT MD4 password hash como nuevo método de cifrado de contraseñas para FreeBSD" . Mail-archive.com . Consultado el 2 de diciembre de 2018 .
  20. "Protocolo de autenticación NTLM y proveedor de soporte de seguridad" . Davenport.sourceforge.net . Consultado el 2 de diciembre de 2018 .
  21. 1 2 Drepper, Ulrich (19 de septiembre de 2007). "Criptografía Unix con SHA-256/512" . Recuperado el 21 de noviembre de 2018 .
  22. Sun Microsystems. "Página de manual crypt_sunmd5(5)" . Archivado del original el 16 de abril de 2008. Consultado el 5 de marzo de 2008 .
  23. Muffett, Alec (2005-12-05). "OpenSolaris, Pluggable Crypt y el algoritmo de hash de contraseña SunMD5" . Recuperado el 2012-08-11 .
  24. 1 2 Drepper, Ulrich. "Criptografía Unix usando SHA-256 y SHA-512" .
  25. "FESCo dice "Sí" a Fedora 35 usando Yescrypt para el hash de contraseñas ocultas - Phoronix" . www.phoronix.com .
  26. "Cambios/yescrypt como método de hash predeterminado para shadow - Wiki del proyecto Fedora" . libxcrypt: Ya es capaz de calcular hashes yescrypt desde la versión 4.3 .
    • crypt(5) Manual de formatos de archivo de Linux de ManKier.com Implementación de libxcrypt 
    • crypt(3) Manual de funciones de la biblioteca de FreeBSD 
  27. "passlib.hash.bigcrypt - BigCrypt — Passlib v1.7.1 Documentation" . Pythonhosted.org . Consultado el 2 de diciembre de 2018 .
  28. "passlib.hash.crypt16 - Crypt16 — Passlib v1.7.1 Documentation" . Pythonhosted.org . Consultado el 2 de diciembre de 2018 .
  29. libxcrypt - Biblioteca de cifrado extendida para descrypt, md5crypt, bcrypt y otros.
  30. "Debian manpage crypt" . manpages.debian.org . Consultado el 11 de enero de 2022 . Debian Bullseye utiliza libxcrypt. Consulte https://tracker.debian.org/pkg/libxcrypt .
  31. "Soporte de bcrypt para contraseñas en /etc/shadow - Portal de clientes de Red Hat" . Access.redhat.com . 10 de julio de 2018. Consultado el 2 de diciembre de 2018 .
  32. "bcrypt password hashing ("cifrado de contraseñas") para su software y sus servidores" . www.openwall.com .
  33. "Cambios/Reemplazo de glibc libcrypt por libxcrypt - Wiki del Proyecto Fedora" . fedoraproject.org .
  34. "crypt_r.c\crypt\src - musl - musl - una implementación de la biblioteca estándar para sistemas basados ​​en Linux" . git.musl-libc.org .
  35. "Cómo implementa Mac OS X la autenticación por contraseña" . Dribin.org . 7 de abril de 2006. Consultado el 2 de diciembre de 2018 .
  36. "Cómo descifrar contraseñas de Mac OS X - Online Hash Crack" . Onlinehashcrack.com . Consultado el 2 de diciembre de 2018 .
  • Código fuente de crypt(3) de la Séptima Edición de Unix (implementa el DES propuesto)
  • Ejemplos de cadenas de codificación hash de contraseñas
  • Implementación de cifrado en .NET