# F.26. pgcrypto
F.26.1. General Hashing FunctionsF.26.2. Password Hashing FunctionsF.26.3. PGP Encryption FunctionsF.26.4. Raw Encryption FunctionsF.26.5. Random-Data FunctionsF.26.6. NotesF.26.7. Author
Thepgcrypto
module provides cryptographic functions for PostgreSQL.
This module is considered “trusted”, that is, it can be installed by non-superusers who haveCREATE
privilege on the current database.
# F.26.1. General Hashing Functions
# F.26.1.1.digest()
digest(data text, type text) returns bytea
digest(data bytea, type text) returns bytea
Computes a binary hash of the given*data
.type
*is the algorithm to use. Standard algorithms aremd5
,sha1
,sha224
,sha256
,sha384
andsha512
. Ifpgcrypto
was built with OpenSSL, more algorithms are available, as detailed inTable F.19.
If you want the digest as a hexadecimal string, useencode()
on the result. For example:
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
Calculates hashed MAC for*data
with keykey
.type
*is the same as indigest()
.
This is similar todigest()
but the hash can only be recalculated knowing the key. This prevents the scenario of someone altering data and also changing the hash to match.
If the key is larger than the hash block size it will first be hashed and the result will be used as key.
# F.26.2. Password Hashing Functions
The functionscrypt()
andgen_salt()
are specifically designed for hashing passwords.crypt()
does the hashing andgen_salt()
prepares algorithm parameters for it.
The algorithms incrypt()
differ from the usual MD5 or SHA1 hashing algorithms in the following respects:
They are slow. As the amount of data is so small, this is the only way to make brute-forcing passwords hard.
They use a random value, called thesalt, so that users having the same password will have different encrypted passwords. This is also an additional defense against reversing the algorithm.
They include the algorithm type in the result, so passwords hashed with different algorithms can co-exist.
Some of them are adaptive — that means when computers get faster, you can tune the algorithm to be slower, without introducing incompatibility with existing passwords.
Table F.16lists the algorithms supported by thecrypt()
function.
Table F.16. Supported Algorithms forcrypt()
Algorithm | Max Password Length | Adaptive? | Salt Bits | Output Length | Description |
---|---|---|---|---|---|
男朋友 | 72 | 是的 | 128 | 60 | 基于河豚,变体 2a |
md5 | 无限 | 不 | 48 | 34 | 基于 MD5 的密码 |
xdes | 8 | 是的 | 24 | 20 | 扩展 DES |
德斯 | 8 | 不 | 12 | 13 | 原始 UNIX 地穴 |
# F.26.2.1.地穴()
crypt(password text, salt text) returns text
计算 crypt(3) 风格的散列*密码
.存储新密码时,需要使用gen_salt()
生成一个新的盐
价值。要检查密码,请将存储的哈希值传递为盐
*,并测试结果是否与存储的值匹配。
设置新密码的示例:
UPDATE ... SET pswhash = crypt('new password', gen_salt('md5'));
认证示例:
SELECT (pswhash = crypt('entered password', pswhash)) AS pswmatch FROM ... ;
这返回真的
如果输入的密码正确。
# F.26.2.2.gen_salt()
gen_salt(type text [, iter_count integer ]) returns text
生成一个新的随机盐字符串以用于地穴()
.盐串也告诉地穴()
使用哪种算法。
这*类型
*参数指定散列算法。接受的类型是:德斯
,xdes
,md5
和男朋友
.
The*iter_count
parameter lets the user specify the iteration count, for algorithms that have one. The higher the count, the more time it takes to hash the password and therefore the more time to break it. Although with too high a count the time to calculate a hash may be several years — which is somewhat impractical. If theiter_count
parameter is omitted, the default iteration count is used. Allowed values foriter_count
*depend on the algorithm and are shown inTable F.17.
Table F.17. Iteration Counts forcrypt()
Algorithm | Default | Min | Max |
---|---|---|---|
xdes | 725 | 1 | 16777215 |
bf | 6 | 4 | 31 |
Forxdes
there is an additional limitation that the iteration count must be an odd number.
To pick an appropriate iteration count, consider that the original DES crypt was designed to have the speed of 4 hashes per second on the hardware of that time. Slower than 4 hashes per second would probably dampen usability. Faster than 100 hashes per second is probably too fast.
Table F.18gives an overview of the relative slowness of different hashing algorithms. The table shows how much time it would take to try all combinations of characters in an 8-character password, assuming that the password contains either only lower case letters, or upper- and lower-case letters and numbers. In thecrypt-bf
entries, the number after a slash is the*iter_count
*parameter ofgen_salt
.
Table F.18. Hash Algorithm Speeds
Algorithm | Hashes/sec | For[a-z] | For[A-Za-z0-9] | Duration relative tomd5 hash |
---|---|---|---|---|
crypt-bf/8 | 1792 | 4 years | 3927 years | 100k |
crypt-bf/7 | 3648 | 2 years | 1929 years | 50k |
crypt-bf/6 | 7168 | 1 year | 982 years | 25k |
crypt-bf/5 | 13504 | 188 天 | 521年 | 12.5k |
crypt-md5 | 171584 | 15天 | 41 岁 | 1k |
crypt-des | 23221568 | 157.5 分钟 | 108 天 | 7 |
沙1 | 37774272 | 90 分钟 | 68天 | 4 |
md5 (哈希) | 150085504 | 22.5 分钟 | 17天 | 1 |
笔记:
使用的机器是 Intel Mobile Core i3.
crypt-des
andcrypt-md5
algorithm numbers are taken from John the Ripper v1.6.38-test
output.md5 hash
numbers are from mdcrack 1.2.sha1
numbers are from lcrack-20031130-beta.crypt-bf
numbers are taken using a simple program that loops over 1000 8-character passwords. That way I can show the speed with different numbers of iterations. For reference:john -test
shows 13506 loops/sec forcrypt-bf/5
. (The very small difference in results is in accordance with the fact that thecrypt-bf
implementation inpgcrypto
is the same one used in John the Ripper.)Note that “try all combinations” is not a realistic exercise. Usually password cracking is done with the help of dictionaries, which contain both regular words and various mutations of them. So, even somewhat word-like passwords could be cracked much faster than the above numbers suggest, while a 6-character non-word-like password may escape cracking. Or not.
# F.26.3. PGP Encryption Functions
The functions here implement the encryption part of the OpenPGP (RFC 4880 (opens new window)) standard. Supported are both symmetric-key and public-key encryption.
An encrypted PGP message consists of 2 parts, orpackets:
Packet containing a session key — either symmetric-key or public-key encrypted.
包含使用会话密钥加密的数据的数据包。
使用对称密钥(即密码)加密时:
给定的密码使用 String2Key (S2K) 算法进行哈希处理。这与
地穴()
算法——故意放慢并使用随机盐——但它会产生一个全长的二进制密钥。如果请求单独的会话密钥,将生成一个新的随机密钥。否则 S2K 密钥将直接用作会话密钥。
如果直接使用 S2K 密钥,那么只有 S2K 设置会被放入会话密钥包中。否则会话密钥将使用 S2K 密钥加密并放入会话密钥包中。
使用公钥加密时:
生成一个新的随机会话密钥。
它使用公钥加密并放入会话密钥包中。
在任何一种情况下,要加密的数据都按如下方式处理:
可选的数据操作:压缩、转换为 UTF-8 和/或行尾转换。
数据以随机字节块为前缀。这相当于使用随机 IV。
附加了随机前缀和数据的 SHA1 哈希。
所有这些都使用会话密钥加密并放入数据包中。
# 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
加密*数据
使用对称 PGP 密钥psw
.这选项
*参数可以包含选项设置,如下所述。
# 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
解密对称密钥加密的 PGP 消息。
解密拜茶
数据与pgp_sym_decrypt
是不允许的。这是为了避免输出无效的字符数据。解密原始文本数据pgp_sym_decrypt_bytea
很好。
这*选项
*参数可以包含选项设置,如下所述。
# 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
加密*数据
使用公共 PGP 密钥钥匙
*.给这个函数一个密钥会产生一个错误。
这*选项
*参数可以包含选项设置,如下所述。
# 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
解密公钥加密的消息。钥匙
必须是与用于加密的公钥对应的密钥。如果密钥受密码保护,您必须在psw
.如果没有密码,但要指定选项,则需要提供一个空密码。
解密拜茶
数据与pgp_pub_decrypt
是不允许的。这是为了避免输出无效的字符数据。解密原始文本数据pgp_pub_decrypt_bytea
很好。
这*选项
*参数可以包含选项设置,如下所述。
# F.26.3.5.pgp_key_id()
pgp_key_id(bytea) returns text
pgp_key_id
提取 PGP 公钥或私钥的密钥 ID。或者,如果给定加密消息,它会给出用于加密数据的密钥 ID。
它可以返回 2 个特殊的密钥 ID:
SYMKEY
消息使用对称密钥加密。
任意键
该消息是公钥加密的,但密钥 ID 已被删除。这意味着您将需要尝试所有密钥,以查看哪个密钥对其进行了解密。
pgcrypto
本身不会产生这样的消息。请注意,不同的密钥可能具有相同的 ID。这是罕见的,但很正常的事件。然后客户端应用程序应该尝试对每一个进行解密,看看哪个适合——比如处理
任意键
.
# F.26.3.6.盔甲()
,亲爱的()
armor(data bytea [ , keys text[], values text[] ]) returns text
dearmor(data text) returns bytea
这些函数将二进制数据包装/解包为 PGP ASCII-armor 格式,该格式基本上是带有 CRC 和附加格式的 Base64.
如果*钥匙
和价值观
arrays are specified, anarmor header*is added to the armored format for each key/value pair. Both arrays must be single-dimensional, and they must be of the same length. The keys and values cannot contain any non-ASCII characters.
# F.26.3.7.pgp_armor_headers
pgp_armor_headers(data text, key out text, value out text) returns setof record
pgp_armor_headers()
extracts the armor headers from*data
*. The return value is a set of rows with two columns, key and value. If the keys or values contain any non-ASCII characters, they are treated as UTF-8.
# F.26.3.8. Options for PGP Functions
Options are named to be similar to GnuPG. An option's value should be given after an equal sign; separate options from each other with commas. For example:
pgp_sym_encrypt(data, psw, 'compress-algo=1, cipher-algo=aes256')
All of the options exceptconvert-crlf
apply only to encrypt functions. Decrypt functions get the parameters from the PGP data.
The most interesting options are probablycompress-algo
andunicode-mode
. The rest should have reasonable defaults.
# F.26.3.8.1. cipher-algo
Which cipher algorithm to use.
Values: bf, aes128, aes192, aes256 (OpenSSL-only:3des
,cast5
)
Default: aes128
Applies to: pgp_sym_encrypt, pgp_pub_encrypt
# F.26.3.8.2. compress-algo
Which compression algorithm to use. Only available if PostgreSQL was built with zlib.
Values:
0 - no compression
1 - ZIP compression
2 - ZLIB compression (= ZIP plus meta-data and block CRCs)
Default: 0
Applies to: pgp_sym_encrypt, pgp_pub_encrypt
# F.26.3.8.3. compress-level
How much to compress. Higher levels compress smaller but are slower. 0 disables compression.
Values: 0, 1-9
Default: 6
Applies to: pgp_sym_encrypt, pgp_pub_encrypt
# F.26.3.8.4. convert-crlf
Whether to convert\n
into\r\n
when encrypting and\r\n
to\n
when decrypting. RFC 4880 specifies that text data should be stored using\r\n
line-feeds. Use this to get fully RFC-compliant behavior.
Values: 0, 1
Default: 0
Applies to: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt
# F.26.3.8.5. disable-mdc
Do not protect data with SHA-1. The only good reason to use this option is to achieve compatibility with ancient PGP products, predating the addition of SHA-1 protected packets to RFC 4880. Recent gnupg.org and pgp.com software supports it fine.
Values: 0, 1
Default: 0
Applies to: pgp_sym_encrypt, pgp_pub_encrypt
# F.26.3.8.6. sess-key
Use separate session key. Public-key encryption always uses a separate session key; this option is for symmetric-key encryption, which by default uses the S2K key directly.
Values: 0, 1
Default: 0
Applies to: pgp_sym_encrypt
# F.26.3.8.7. s2k-mode
Which S2K algorithm to use.
Values:
0 - Without salt. Dangerous!
1 - With salt but with fixed iteration count.
3 - Variable iteration count.
Default: 3
Applies to: pgp_sym_encrypt
# F.26.3.8.8. s2k-count
The number of iterations of the S2K algorithm to use. It must be a value between 1024 and 65011712, inclusive.
Default: A random value between 65536 and 253952
Applies to: pgp_sym_encrypt, only with s2k-mode=3
# F.26.3.8.9. s2k-digest-algo
Which digest algorithm to use in S2K calculation.
Values: md5, sha1
Default: sha1
Applies to: pgp_sym_encrypt
# F.26.3.8.10. s2k-cipher-algo
Which cipher to use for encrypting separate session key.
Values: bf, aes, aes128, aes192, aes256
Default: use cipher-algo
Applies to: pgp_sym_encrypt
# F.26.3.8.11. unicode-mode
Whether to convert textual data from database internal encoding to UTF-8 and back. If your database already is UTF-8, no conversion will be done, but the message will be tagged as UTF-8. Without this option it will not be.
Values: 0, 1
Default: 0
Applies to: pgp_sym_encrypt, pgp_pub_encrypt
# F.26.3.9. Generating PGP Keys with GnuPG
To generate a new key:
gpg --gen-key
The preferred key type is “DSA and Elgamal”.
For RSA encryption you must create either DSA or RSA sign-only key as master and then add an RSA encryption subkey withgpg --edit-key
.
To list keys:
gpg --list-secret-keys
To export a public key in ASCII-armor format:
gpg -a --export KEYID > public.key
To export a secret key in ASCII-armor format:
gpg -a --export-secret-keys KEYID > secret.key
You need to usedearmor()
on these keys before giving them to the PGP functions. Or if you can handle binary data, you can drop-a
from the command.
For more details seeman gpg
,The GNU Privacy Handbook (opens new window)and other documentation onhttps://www.gnupg.org/ (opens new window).
# F.26.3.10. Limitations of PGP Code
No support for signing. That also means that it is not checked whether the encryption subkey belongs to the master key.
No support for encryption key as master key. As such practice is generally discouraged, this should not be a problem.
No support for several subkeys. This may seem like a problem, as this is common practice. On the other hand, you should not use your regular GPG/PGP keys with
pgcrypto
, but create new ones, as the usage scenario is rather different.
# F.26.4. Raw Encryption Functions
These functions only run a cipher over data; they don't have any advanced features of PGP encryption. Therefore they have some major problems:
They use user key directly as cipher key.
They don't provide any integrity checking, to see if the encrypted data was modified.
They expect that users manage all encryption parameters themselves, even IV.
They don't handle text.
So, with the introduction of PGP encryption, usage of raw encryption functions is discouraged.
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
使用指定的密码方法加密/解密数据*类型
.的语法类型
*字符串是:
algorithm [ - mode ] [ /pad: padding ]
在哪里*算法
*是其中之一:
男朋友
— 河豚aes
— AES(Rijndael-128、-192 或 -256)和*
模式
*是其中之一:加拿大广播公司
— 下一个块取决于上一个(默认)欧洲央行
— 每个块都单独加密(仅用于测试)和*
填充
*是其中之一:pkcs
— 数据可以是任意长度(默认)没有任何
— 数据必须是密码块大小的倍数因此,例如,这些是等价的:
encrypt(data, 'fooz', 'bf')
encrypt(data, 'fooz', 'bf-cbc/pad:pkcs')
在加密_iv
anddecrypt_iv
, the*iv
*parameter is the initial value for the CBC mode; it is ignored for ECB. It is clipped or padded with zeroes if not exactly block size. It defaults to all zeroes in the functions without this parameter.
# F.26.5. Random-Data Functions
gen_random_bytes(count integer) returns bytea
Returns*count
*cryptographically strong random bytes. At most 1024 bytes can be extracted at a time. This is to avoid draining the randomness generator pool.
gen_random_uuid() returns uuid
Returns a version 4 (random) UUID. (Obsolete, this function is now also included in core PostgreSQL.)
# F.26.6. Notes
# F.26.6.1. Configuration
pgcrypto
configures itself according to the findings of the main PostgreSQLconfigure
script. The options that affect it are--with-zlib
and--with-ssl=openssl
.
When compiled with zlib, PGP encryption functions are able to compress data before encrypting.
When compiled with OpenSSL, there will be more algorithms available. Also public-key encryption functions will be faster as OpenSSL has more optimized BIGNUM functions.
Table F.19. Summary of Functionality with and without OpenSSL
Functionality | Built-in | With OpenSSL |
---|---|---|
MD5 | yes | yes |
SHA1 | 是的 | 是的 |
SHA224/256/384/512 | 是的 | 是的 |
其他摘要算法 | 不 | 是(注1) |
河豚 | 是的 | 是的 |
AES | 是的 | 是的 |
DES/3DES/CAST5 | 不 | 是的 |
原始加密 | 是的 | 是的 |
PGP 对称加密 | 是的 | 是的 |
PGP 公钥加密 | 是的 | 是的 |
针对 OpenSSL 3.0.0 和更高版本编译时,必须在openssl.cnf
配置文件,以便使用DES或Blowfish等旧密码。
笔记:
- OpenSSL支持的任何摘要算法都会自动获取。对于需要明确支持的密码,这是不可能的。
# F.26.6.2.空处理
按照SQL中的标准,如果任何参数为NULL,则所有函数都返回NULL。这可能会对不小心使用造成安全风险。
# F.26.6.3.安全限制
全部的pgcrypto
函数在数据库服务器内部运行。这意味着所有数据和密码都会在pgcrypto
以及明文形式的客户端应用程序。因此,你必须:
本地连接或使用SSL连接。
信任系统管理员和数据库管理员。
如果不能,那么最好在客户端应用程序内部进行加密。
实施并不抵制侧通道攻击 (opens new window)。例如,一次测试所需的时间
pgcrypto
要完成的解密函数因给定大小的密文而异。
# F.26.6.4.有用的阅读
https://www.gnupg.org/gph/en/manual.html (opens new window)
GNU隐私手册。
https://www.openwall.com/crypt/ (opens new window)
描述了crypt blowfish算法。
https://www.iusmentis.com/security/passphrasefaq/ (opens new window)
如何选择一个好的密码。
http://world.std.com/~莱因霍尔德/骰子器皿。html (opens new window)
Interesting idea for picking passwords.
http://www.interhack.net/people/cmcurtin/snake-oil-faq.html (opens new window)
Describes good and bad cryptography.
# F.26.6.5. Technical References
https://tools.ietf.org/html/rfc4880 (opens new window)
OpenPGP message format.
https://tools.ietf.org/html/rfc1321 (opens new window)
The MD5 Message-Digest Algorithm.
https://tools.ietf.org/html/rfc2104 (opens new window)
HMAC: Keyed-Hashing for Message Authentication.
https://www.usenix.org/legacy/events/usenix99/provos.html (opens new window)
Comparison of crypt-des, crypt-md5 and bcrypt algorithms.
https://en.wikipedia.org/wiki/Fortuna_(PRNG) (opens new window)
Description of Fortuna CSPRNG.
https://jlcooke.ca/random/ (opens new window)
Jean-Luc Cooke Fortuna-based
/dev/random
driver for Linux.
# F.26.7. Author
Marko Kreen<[markokr@gmail.com](mailto:markokr@gmail.com)>
pgcrypto
uses code from the following sources:
Algorithm | Author | Source origin |
---|---|---|
DES crypt | 大卫·布伦等 | FreeBSD libcrypt |
MD5 地穴 | 波尔-亨宁坎普 | FreeBSD libcrypt |
河豚地穴 | 太阳能设计师 | www.openwall.com |
河豚密码 | 西蒙·泰瑟姆 | 油灰 |
Rijndael密码 | 布赖恩格拉德曼 | OpenBSD 系统/加密 |
MD5 哈希和 SHA1 | 宽项目 | KAME kame/sys/crypto |
SHA256/384/512 | 亚伦·D·吉福德 | OpenBSD 系统/加密 |
BIGNUM 数学 | 迈克尔·J·弗罗伯格 | dartmouth.edu/~刺痛/sw/imath |