F.26. pgcrypto — funciones criptográficas #

F.26.1. Funciones generales de hashing
F.26.2. Funciones de hash para contraseñas
F.26.3. Funciones de encriptación PGP
F.26.4. Funciones de encriptación en bruto (Raw)
F.26.5. Funciones de datos aleatorios
F.26.6. Funciones de soporte para OpenSSL
F.26.7. Parámetros de configuración
F.26.8. Notas
F.26.9. Autor

El módulo pgcrypto proporciona funciones criptográficas para PostgreSQL.

Este módulo se considera trusted (de confianza), es decir, puede ser instalado por usuarios sin privilegios de superusuario que tengan el privilegio CREATE en la base de datos actual.

pgcrypto requiere OpenSSL y no se instalará si el soporte para OpenSSL no fue seleccionado cuando se compiló PostgreSQL.

F.26.1. Funciones generales de hashing #

F.26.1.1. digest() #

digest(data text, type text) returns bytea
digest(data bytea, type text) returns bytea

Calcula un hash binario de los datos (data) proporcionados. type es el algoritmo a utilizar. Los algoritmos estándar son md5, sha1, sha224, sha256, sha384 y sha512. Además, cualquier algoritmo de hash que soporte OpenSSL se detecta automáticamente.

Si quieres obtener el hash como una cadena hexadecimal, utiliza encode() sobre el resultado. Por ejemplo:

CREATE OR REPLACE FUNCTION sha1(bytea) returns text AS $$
    SELECT encode(digest($1, 'sha1'), 'hex')
$$ LANGUAGE SQL STRICT IMMUTABLE;

F.26.1.2. hmac() #

hmac(data text, key text, type text) returns bytea
hmac(data bytea, key bytea, type text) returns bytea

Calcula el MAC con hash (HMAC) para los datos (data) con la clave (key). type es el mismo que en digest().

Esto es similar a digest(), pero el hash solo se puede recalcular si se conoce la clave. Esto evita que alguien altere los datos y también cambie el hash para que coincida.

Si la clave es mayor que el tamaño de bloque del hash, primero se le aplicará el hash y el resultado se utilizará como clave.

F.26.2. Funciones de hash para contraseñas #

Las funciones crypt() y gen_salt() están diseñadas específicamente para el hashing de contraseñas. crypt() realiza el hashing y gen_salt() prepara los parámetros del algoritmo para este proceso.

Los algoritmos en crypt() difieren de los algoritmos de hash habituales como MD5 o SHA-1 en los siguientes aspectos:

  1. Son lentos. Como la cantidad de datos es muy pequeña, esta es la única forma de hacer que descifrar contraseñas por fuerza bruta sea difícil.

  2. Utilizan un valor aleatorio, llamado salt (sal), de modo que los usuarios que tengan la misma contraseña tengan diferentes contraseñas encriptadas. Esta es también una defensa adicional contra la reversión del algoritmo.

  3. Incluyen el tipo de algoritmo en el resultado, por lo que las contraseñas cifradas con diferentes algoritmos pueden coexistir.

  4. Algunos de ellos son adaptativos, lo que significa que a medida que las computadoras se vuelven más rápidas, puedes ajustar el algoritmo para que sea más lento, sin introducir incompatibilidades con las contraseñas existentes.

La Table F.18 enumera los algoritmos soportados por la función crypt().

Table F.18. Algoritmos soportados para crypt()

AlgoritmoLongitud máxima de contraseña¿Adaptativo?Bits de sal (salt)Longitud de salidaDescripción
bf7212860Basado en Blowfish, variante 2a
md5ilimitadono4834Crypt basado en MD5
xdes82420DES extendido
des8no1213Crypt de UNIX original
sha256cryptilimitadohasta 3280Adaptado de la implementación de referencia disponible públicamente Crypt de Unix usando SHA-256 y SHA-512
sha512cryptilimitadohasta 32123Adaptado de la implementación de referencia disponible públicamente Crypt de Unix usando SHA-256 y SHA-512

F.26.2.1. crypt() #

crypt(password text, salt text) returns text

Calcula un hash al estilo crypt(3) para la contraseña (password). Al guardar una nueva contraseña, debes utilizar gen_salt() para generar un nuevo valor de sal (salt). Para verificar una contraseña, pasa el valor del hash guardado como salt, y comprueba si el resultado coincide con el valor guardado.

Ejemplo para establecer una nueva contraseña:

UPDATE ... SET pswhash = crypt('nueva contraseña', gen_salt('md5'));

Ejemplo de autenticación:

SELECT (pswhash = crypt('contraseña ingresada', pswhash)) AS pswmatch FROM ... ;

Esto devuelve true si la contraseña ingresada es correcta.

F.26.2.2. gen_salt() #

gen_salt(type text [, iter_count integer ]) returns text

Genera una nueva cadena de sal (salt) aleatoria para usar en crypt(). La cadena de sal también le indica a crypt() qué algoritmo utilizar.

El parámetro type specifies el algoritmo de hash. Los tipos aceptados son: des, xdes, md5, bf, sha256crypt y sha512crypt. Los dos últimos, sha256crypt y sha512crypt, son hashes de contraseña modernos basados en SHA-2.

El parámetro iter_count permite al usuario especificar el número de iteraciones para los algoritmos que lo requieran. Cuanto mayor sea el número, más tiempo tomará cifrar la contraseña y, por lo tanto, más tiempo tomará descifrarla. Aunque con un número demasiado alto, el tiempo para calcular un hash podría ser de varios años — lo cual es poco práctico. Si se omite el parámetro iter_count, se utiliza el número de iteraciones por defecto. Los valores permitidos para iter_count dependen del algoritmo y se muestran en la Table F.19.

Table F.19. Recuentos de iteraciones para crypt()

AlgoritmoPor defectoMínMáx
xdes725116777215
bf6431
sha256crypt, sha512crypt50001000999999999

Para xdes hay una limitación adicional de que el número de iteraciones debe ser un número impar.

Para elegir un número de iteraciones adecuado, ten en cuenta que el crypt de DES original fue diseñado para tener una velocidad de 4 hashes por segundo en el hardware de esa época. Una velocidad menor a 4 hashes por segundo probablemente afectaría la usabilidad. Una velocidad mayor a 100 hashes por segundo es probablemente demasiado rápida.

La Table F.20 muestra una descripción general de la lentitud relativa de los diferentes algoritmos de hash. La tabla muestra cuánto tiempo tomaría probar todas las combinaciones de caracteres en una contraseña de 8 caracteres, asumiendo que la contraseña contiene solo letras minúsculas, o bien letras mayúsculas, minúsculas y números. En las entradas de crypt-bf, el número después de una barra es el parámetro iter_count de gen_salt.

El valor por defecto de iter_count para sha256crypt y sha512crypt de 5000 se considera demasiado bajo para el hardware moderno, pero se puede ajustar para generar hashes de contraseñas más fuertes. Por lo demás, ambos hashes, sha256crypt and sha512crypt, se consideran seguros.

Table F.20. Velocidades de algoritmos de hash

AlgoritmoHashes/segPara [a-z]Para [A-Za-z0-9]Duración relativa al hash md5
crypt-bf/817924 años3927 años100k
crypt-bf/736482 años1929 años50k
crypt-bf/671681 año982 años25k
crypt-bf/513504188 días521 años12.5k
crypt-md517158415 días41 años1k
crypt-des23221568157.5 minutos108 días7
sha13777427290 minutos68 días4
md5 (hash)15008550422.5 minutos17 días1

Notas:

  • La máquina utilizada es una Intel Mobile Core i3.

  • Los números de los algoritmos crypt-des y crypt-md5 se obtienen de la salida de la prueba -test de John the Ripper v1.6.38.

  • Los números de md5 hash provienen de mdcrack 1.2.

  • Los números de sha1 provienen de lcrack-20031130-beta.

  • Los números de crypt-bf se obtienen usando un programa simple que realiza un bucle sobre 1000 contraseñas de 8 caracteres. De esa manera se puede mostrar la velocidad con diferentes números de iteraciones. Como referencia: john -test muestra 13506 bucles/seg para crypt-bf/5. (La pequeña diferencia en los resultados concuerda con el hecho de que la implementación de crypt-bf en pgcrypto es la misma que se utiliza en John the Ripper).

Ten en cuenta que probar todas las combinaciones no es un ejercicio realista. Normalmente, el descifrado de contraseñas se realiza con la ayuda de diccionarios, que contienen tanto palabras comunes como diversas mutaciones de las mismas. Por lo tanto, incluso las contraseñas con estructura similar a una palabra podrían descifrarse mucho más rápido de lo que sugieren los números anteriores, mientras que una contraseña de 6 caracteres que no parezca una palabra podría evitar ser descifrada. O no.

F.26.3. Funciones de encriptación PGP #

Las funciones aquí descritas implementan la parte de cifrado del estándar OpenPGP (RFC 4880). Se soporta tanto la encriptación por clave simétrica como por clave pública.

Un mensaje PGP encriptado consta de 2 partes o packets (paquetes):

  • Un paquete que contiene una clave de sesión, ya sea encriptada por clave simétrica o por clave pública.

  • Un paquete que contiene los datos encriptados con la clave de sesión.

Al encriptar con una clave simétrica (es decir, una contraseña):

  1. La contraseña proporcionada se procesa usando un algoritmo String2Key (S2K). Esto es bastante similar a los algoritmos de crypt() — deliberadamente lento y con una sal aleatoria — pero produce una clave binaria de longitud completa.

  2. Si se solicita una clave de sesión separada, se generará una nueva clave aleatoria. De lo contrario, la clave S2K se utilizará directamente como clave de sesión.

  3. Si se va a usar la clave S2K directamente, solo se colocarán los parámetros S2K en el paquete de la clave de sesión. De lo contrario, la clave de sesión se encriptará con la clave S2K y se colocará en el paquete de la clave de sesión.

Al encriptar con una clave pública:

  1. Se genera una nueva clave de sesión aleatoria.

  2. Se encripta usando la clave pública y se coloca en el paquete de la clave de sesión.

En cualquier caso, los datos a encriptar se procesan de la siguiente manera:

  1. Manipulación opcional de datos: compresión, conversión a UTF-8 y/o conversión de los finales de línea.

  2. Los datos se prefijan con un bloque de bytes aleatorios. Esto equivale a usar un IV aleatorio.

  3. Se añade un hash SHA-1 del prefijo aleatorio y los datos.

  4. Todo esto se encripta con la clave de sesión y se coloca en el paquete de datos.

F.26.3.1. pgp_sym_encrypt() #

pgp_sym_encrypt(data text, psw text [, options text ]) returns bytea
pgp_sym_encrypt_bytea(data bytea, psw text [, options text ]) returns bytea

Encripta los datos (data) con una clave PGP simétrica (psw). El parámetro options puede contener configuraciones de opciones, como se describe más abajo.

F.26.3.2. pgp_sym_decrypt() #

pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea

Desencripta un mensaje PGP encriptado con clave simétrica.

No está permitido desencriptar datos de tipo bytea con pgp_sym_decrypt. Esto es para evitar la salida de datos de caracteres no válidos. Desencriptar datos que originalmente eran de texto con pgp_sym_decrypt_bytea no presenta problemas.

El parámetro options puede contener configuraciones de opciones, como se describe más abajo.

F.26.3.3. pgp_pub_encrypt() #

pgp_pub_encrypt(data text, key bytea [, options text ]) returns bytea
pgp_pub_encrypt_bytea(data bytea, key bytea [, options text ]) returns bytea

Encripta los datos (data) con una clave PGP pública (key). Proporcionar una clave secreta a esta función producirá un error.

El parámetro options puede contener configuraciones de opciones, como se describe más abajo.

F.26.3.4. pgp_pub_decrypt() #

pgp_pub_decrypt(msg bytea, key bytea [, psw text [, options text ]]) returns text
pgp_pub_decrypt_bytea(msg bytea, key bytea [, psw text [, options text ]]) returns bytea

Desencripta un mensaje encriptado con clave pública. key debe ser la clave secreta correspondiente a la clave pública que se utilizó para encriptar. Si la clave secreta está protegida por contraseña, debes proporcionar la contraseña en psw. Si no hay contraseña pero quieres especificar opciones, debes proporcionar una contraseña vacía.

No está permitido desencriptar datos de tipo bytea con pgp_pub_decrypt. Esto es para evitar la salida de datos de caracteres no válidos. Desencriptar datos que originalmente eran de texto con pgp_pub_decrypt_bytea no presenta problemas.

El parámetro options puede contener configuraciones de opciones, como se describe más abajo.

F.26.3.5. pgp_key_id() #

pgp_key_id(bytea) returns text

pgp_key_id extrae el ID de clave de una clave PGP pública o secreta. O devuelve el ID de clave que se utilizó para encriptar los datos si se le proporciona un mensaje encriptado.

Puede devolver 2 IDs de clave especiales:

  • SYMKEY

    El mensaje está encriptado con una clave simétrica.

  • ANYKEY

    El mensaje está encriptado con clave pública, pero se ha eliminado el ID de la clave. Esto significa que tendrás que probar todas tus claves secretas en él para ver cuál lo desencripta. pgcrypto por sí mismo no genera tales mensajes.

Ten en cuenta que diferentes claves pueden tener el mismo ID. Esto es raro pero es un evento normal. La aplicación cliente debería intentar desencriptar con cada una de ellas para ver cuál funciona — como al manejar ANYKEY.

F.26.3.6. armor(), dearmor() #

armor(data bytea [ , keys text[], values text[] ]) returns text
dearmor(data text) returns bytea

Estas funciones envuelven/desenvuelven datos binarios en el formato de armadura ASCII de PGP (ASCII-armor), que es básicamente Base64 con CRC y formato adicional.

Si se especifican las matrices keys y values, se añade una cabecera de armadura (armor header) al formato armado para cada par clave/valor. Ambas matrices deben ser unidimensionales y deben ser de la misma longitud. Las claves y los valores no pueden contener caracteres que no sean ASCII.

F.26.3.7. pgp_armor_headers #

pgp_armor_headers(data text, key out text, value out text) returns setof record

pgp_armor_headers() extrae las cabeceras de armadura de data. El valor de retorno es un conjunto de filas con dos columnas, key y value. Si las claves o los valores contienen caracteres que no sean ASCII, se tratan como UTF-8.

F.26.3.8. Opciones para funciones PGP #

Las opciones tienen nombres similares a los de GnuPG. El valor de una opción debe proporcionarse después de un signo de igualdad; separa las opciones entre sí con comas. Por ejemplo:

pgp_sym_encrypt(data, psw, 'compress-algo=1, cipher-algo=aes256')

Todas las opciones excepto convert-crlf se aplican únicamente a las funciones de encriptación. Las funciones de desencriptación obtienen los parámetros de los datos PGP.

Las opciones más interesantes son probablemente compress-algo y unicode-mode. El resto debería tener valores por defecto razonables.

F.26.3.8.1. cipher-algo #

Qué algoritmo de cifrado utilizar.


Valores: bf, aes128, aes192, aes256, 3des, cast5
Por defecto: aes128
Se aplica a: pgp_sym_encrypt, pgp_pub_encrypt

F.26.3.8.2. compress-algo #

Qué algoritmo de compresión utilizar. Solo está disponible si PostgreSQL fue compilado con zlib.


Valores:
  0 - sin compresión
  1 - compresión ZIP
  2 - compresión ZLIB (= ZIP más metadatos y CRCs de bloque)
Por defecto: 0
Se aplica a: pgp_sym_encrypt, pgp_pub_encrypt

F.26.3.8.3. compress-level #

Cuánto comprimir. Los niveles más altos comprimen más pero son más lentos. 0 deshabilita la compresión.


Valores: 0, 1-9
Por defecto: 6
Se aplica a: pgp_sym_encrypt, pgp_pub_encrypt

F.26.3.8.4. convert-crlf #

Indica si se debe convertir \n en \r\n al encriptar y \r\n en \n al desencriptar. El RFC 4880 especifica que los datos de texto deben almacenarse usando saltos de línea \r\n. Utiliza esto para obtener un comportamiento completamente compatible con el RFC.


Valores: 0, 1
Por defecto: 0
Se aplica a: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt

F.26.3.8.5. disable-mdc #

No protege los datos con SHA-1. La única buena razón para usar esta opción es lograr compatibilidad con productos PGP antiguos, anteriores a la incorporación de paquetes protegidos por SHA-1 al RFC 4880. El software reciente de gnupg.org y pgp.com lo soporta perfectamente.


Valores: 0, 1
Por defecto: 0
Se aplica a: pgp_sym_encrypt, pgp_pub_encrypt

F.26.3.8.6. sess-key #

Usa una clave de sesión independiente. La encriptación por clave pública siempre usa una clave de sesión independiente; esta opción es para la encriptación por clave simétrica, que por defecto usa la clave S2K directamente.


Valores: 0, 1
Por defecto: 0
Se aplica a: pgp_sym_encrypt

F.26.3.8.7. s2k-mode #

Qué algoritmo S2K utilizar.


Valores:
  0 - Sin sal (salt). ¡Peligroso!
  1 - Con sal pero con número de iteraciones fijo.
  3 - Número de iteraciones variable.
Por defecto: 3
Se aplica a: pgp_sym_encrypt

F.26.3.8.8. s2k-count #

El número de iteraciones del algoritmo S2K a utilizar. Debe ser un valor entre 1024 y 65011712, inclusive.


Por defecto: Un valor aleatorio entre 65536 y 253952
Se aplica a: pgp_sym_encrypt, solo con s2k-mode=3

F.26.3.8.9. s2k-digest-algo #

Qué algoritmo de hash utilizar en el cálculo de S2K.


Valores: md5, sha1
Por defecto: sha1
Se aplica a: pgp_sym_encrypt

F.26.3.8.10. s2k-cipher-algo #

Qué cifrado utilizar para encriptar la clave de sesión independiente.


Valores: bf, aes, aes128, aes192, aes256
Por defecto: usar cipher-algo
Se aplica a: pgp_sym_encrypt

F.26.3.8.11. unicode-mode #

Indica si se deben convertir los datos textuales de la codificación interna de la base de datos a UTF-8 y viceversa. Si tu base de datos ya está en UTF-8, no se realizará ninguna conversión, pero el mensaje se etiquetará como UTF-8. Sin esta opción, no lo estará.


Valores: 0, 1
Por defecto: 0
Se aplica a: pgp_sym_encrypt, pgp_pub_encrypt

F.26.3.9. Generación de claves PGP con GnuPG #

Para generar una clave nueva:

gpg --gen-key

El tipo de clave preferido es DSA y Elgamal.

Para la encriptación RSA debes crear una clave de tipo DSA o RSA solo para firmar como maestra y luego añadir una subclave de encriptación RSA con gpg --edit-key.

Para listar las claves:

gpg --list-secret-keys

Para exportar una clave pública en formato de armadura ASCII:

gpg -a --export KEYID > public.key

Para exportar una clave secreta en formato de armadura ASCII:

gpg -a --export-secret-keys KEYID > secret.key

Debes usar dearmor() en estas claves antes de entregárselas a las funciones PGP. O si puedes manejar datos binarios, puedes omitir -a del comando.

Para más detalles consulta man gpg, The GNU Privacy Handbook y otra documentación en https://www.gnupg.org/.

F.26.3.10. Limitaciones del código PGP #

  • No hay soporte para firmas. Eso también significa que no se comprueba si la subclave de encriptación pertenece a la clave maestra.

  • No hay soporte para usar la clave de encriptación como clave maestra. Dado que esa práctica generally se desaconseja, esto no debería ser un problema.

  • No hay soporte para varias subclaves. Esto puede parecer un problema, ya que es una práctica común. Por otro lado, no deberías usar tus claves GPG/PGP habituales con pgcrypto, sino crear unas nuevas, ya que el escenario de uso es bastante diferente.

F.26.4. Funciones de encriptación en bruto (Raw) #

Estas funciones solo aplican un cifrado sobre los datos; no tienen ninguna de las características avanzadas de la encriptación PGP. Por lo tanto, tienen algunos problemas importantes:

  1. Utilizan la clave del usuario directamente como clave de cifrado.

  2. No proporcionan ninguna comprobación de integridad para ver si los datos encriptados fueron modificados.

  3. Esperan que los usuarios gestionen todos los parámetros de encriptación por sí mismos, incluso el IV.

  4. No manejan texto.

Por lo tanto, con la introducción de la encriptación PGP, se desaconseja el uso de las funciones de encriptación en bruto.

encrypt(data bytea, key bytea, type text) returns bytea
decrypt(data bytea, key bytea, type text) returns bytea

encrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea
decrypt_iv(data bytea, key bytea, iv bytea, type text) returns bytea

Encripta/desencripta los datos usando el método de cifrado especificado por type. La sintaxis de la cadena type es:

algorithm [ - mode ] [ /pad: padding ]

donde algorithm es uno de los siguientes:

  • bf — Blowfish

  • aes — AES (Rijndael-128, -192 o -256)

y mode es uno de los siguientes:

  • cbc — el siguiente bloque depende del anterior (por defecto)

  • cfb — el siguiente bloque depende del bloque encriptado anterior

  • ecb — cada bloque se encripta por separado (solo para pruebas)

y padding es uno de los siguientes:

  • pkcs — los datos pueden ser de cualquier longitud (por defecto)

  • none — los datos deben ser un múltiplo del tamaño del bloque de cifrado

Por ejemplo, los siguientes comandos son equivalentes:

encrypt(data, 'fooz', 'bf')
encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')

En encrypt_iv and decrypt_iv, el parámetro iv es el valor inicial para los modos CBC y CFB; se ignora para el modo ECB. Se recorta o se rellena con ceros si no tiene exactamente el tamaño del bloque. Por defecto tiene solo ceros en las funciones que no incluyen este parámetro.

F.26.5. Funciones de datos aleatorios #

gen_random_bytes(count integer) returns bytea

Devuelve count bytes aleatorios criptográficamente fuertes. Se pueden extraer como máximo 1024 bytes a la vez. Esto es para evitar el agotamiento del grupo de generación de aleatoriedad.

gen_random_uuid() returns uuid

Devuelve un UUID versión 4 (aleatorio). (Obsoleto; esta función llama internamente a la función principal del mismo nombre).

F.26.6. Funciones de soporte para OpenSSL #

fips_mode() returns boolean

Devuelve true si OpenSSL está funcionando con el modo FIPS activado; de lo contrario, devuelve false.

F.26.7. Parámetros de configuración #

Hay un parámetro de configuración que controla el comportamiento de pgcrypto.

pgcrypto.builtin_crypto_enabled (enum) #

pgcrypto.builtin_crypto_enabled determina si las funciones criptográficas integradas gen_salt() y crypt() están disponibles para su uso. Establecer esto en off desactiva estas funciones. on (por defecto) permite que estas funciones funcionen normalmente. fips desactiva estas funciones si se detecta que OpenSSL funciona en modo FIPS.

En el uso ordinario, este parámetro se establece en postgresql.conf, aunque los superusuarios pueden alterarlo sobre la marcha dentro de sus propias sesiones.

F.26.8. Notas #

F.26.8.1. Configuración #

pgcrypto se configura a sí mismo de acuerdo con los hallazgos del script configure principal de PostgreSQL. Las opciones que le afectan son --with-zlib y --with-ssl=openssl.

Cuando se compila con zlib, las funciones de encriptación PGP pueden comprimir los datos antes de encriptarlos.

pgcrypto requiere OpenSSL. De lo contrario, no se compilará ni se instalará.

Cuando se compila con OpenSSL 3.0.0 y versiones posteriores, se debe activar el proveedor heredado (legacy provider) en el archivo de configuración openssl.cnf para poder utilizar cifrados más antiguos como DES o Blowfish.

F.26.8.2. Manejo de valores NULL #

Como es estándar en SQL, todas las funciones devuelven NULL si alguno de los argumentos es NULL. Esto puede crear riesgos de seguridad si se usa de manera descuidada.

F.26.8.3. Limitaciones de seguridad #

Todas las funciones de pgcrypto se ejecutan dentro del servidor de la base de datos. Esto significa que todos los datos y contraseñas viajan entre pgcrypto y las aplicaciones cliente en texto claro. Por lo tanto, debes:

  1. Conectarte localmente o usar conexiones SSL.

  2. Confiar tanto en el administrador del sistema como en el de la base de datos.

Si no puedes hacerlo, es mejor realizar la criptografía dentro de la aplicación cliente.

La implementación no resiste ataques de canales laterales (side-channel attacks). Por ejemplo, el tiempo requerido para que una función de desencriptación de pgcrypto termine varía según los textos cifrados de un tamaño determinado.

F.26.9. Autor #

Marko Kreen

pgcrypto utiliza código de las siguientes fuentes:

AlgoritmoAutorOrigen
Crypt de DESDavid Burren y otroslibcrypt de FreeBSD
Crypt de MD5Poul-Henning Kamplibcrypt de FreeBSD
Crypt de BlowfishSolar Designerwww.openwall.com