9.3 9.4 9.5 9.6 10 11 12 13 14 Current(15)
阿里云PostgreSQL 问题报告 纠错本页面
PostgreSQL 9.3.1 中文手册
上一页上一级附录 F. 额外提供的模块下一页

F.25. pgcrypto

pgcrypto模块为PostgreSQL提供cryptographic函数。

F.25.1. 一般散列函数

F.25.1.1. digest()

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

计算给定data的二进制散列。type是要使用的算法。 标准算法是md5, sha1, sha224, sha256, sha384sha512。 如果pgcrypto带有OpenSSL建立,那么更多算法可用,在 表 F-18中详细说明。

如果你希望digest作为一个十六进制字符串,那么在结果上使用encode()。 例如:

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

F.25.1.2. hmac()

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

为带有键keydata计算散列的MAC。type 和在digest()中相同。

类似于digest()但是散列只能在知道键的时候计算。 这样就阻止了某个人更改数据并改变匹配的散列的情况。

如果键比散列块大小要大,那么将首先把键散列然后散列的结果作为键使用。

F.25.2. 口令散列函数

函数crypt()gen_salt()是特别为散列口令设计的。 crypt()做散列法,gen_salt()为其准备算法参数。

crypt()中的算法与普通散列算法(如MD5或SHA1)有以下方面的不同:

  1. 他们的速度很慢。因为数据很少,所以这是唯一的让蛮力破解口令困难些的方法。

  2. 它们使用随机值,称为salt,所以有相同口令的用户将会有不同加密了的口令。 也是也对反向算法的附加防御。

  3. 它们在结果中包括算法类型,所以不同算法的口令散列可以共存。

  4. 它们中的一些是自适应的,这意味着当计算机更快速时,你可以将算法调整的慢一些, 而不会引入与现有口令的不相容。

表 F-15列出了crypt() 函数支持的算法。

表 F-15. crypt()支持的算法

算法最大口令长度自适应?Salt位描述
bf72yes128基于Blowfish,2a的变体
md5unlimitedno48基于MD5加密
xdes8yes24扩展的DES
des8no12原始的UNIX加密

F.25.2.1. crypt()

crypt(password text, salt text) returns text

计算一个password的crypt(3)类型散列。当存储一个新的口令时, 需要使用gen_salt()生成一个新的salt值。 要检查一个口令,作为salt传递存储的散列值, 然后检验结果是否匹配存储的值。

设置一个新的口令的示例:

UPDATE ... SET pswhash = crypt('new password', gen_salt('md5'));

认证的示例:

SELECT pswhash = crypt('entered password', pswhash) FROM ... ;

如果输入的口令是正确的这个就返回true

F.25.2.2. gen_salt()

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

crypt()的使用生成一个新的随机salt字符串。 salt字符串也告诉crypt()使用哪种算法。

type参数指定散列算法。接受的类型有:des, xdes, md5bf

iter_count参数让用户指定重复计数,为这一个算法。计数值越高, 拿它去散列口令的次数越多,因此解开它的次数也越多。尽管太高的计数来计算一个散列可能会用几年的时间, 这有点不切实际。如果省略了iter_count参数,那么使用缺省的重复计数。 iter_count的允许值取决于算法,在表 F-16中显示。

表 F-16. crypt()的重复计数

算法缺省最小最大
xdes725116777215
bf6431

对于xdes,这里有一个附加的限制,那就是重复计数必须是奇数。

要选择一个合适的重复计数,考虑原始的DES加密设计是要在那个时间的硬件上每秒有4个散列的速度。 比4个散列每秒慢的可能会降低可用性。高于100散列每秒的可能太快了。

表 F-17给出了不同散列算法的相对缓慢的概述。 该表显示了在8字符口令里尝试所有字符的组合将会花费多长时间,假设口令只包含小写字母, 或者包含大小写字母和数字。在crypt-bf记录中, 斜线后的数字是gen_saltiter_count参数。

表 F-17. 散列算法速度

算法散列/sec对于 [a-z]对于 [A-Za-z0-9]
crypt-bf/828246 年251322 年
crypt-bf/757121 年123457 年
crypt-bf/611262 年62831 年
crypt-bf/521133 年33351 年
crypt-md526812.6 年2625 年
crypt-des3628377 天19 年
sha15902234 天12 年
md523450861 天3 年

注意:

  • 使用的这个机器是1.5GHz Pentium 4。

  • crypt-descrypt-md5计算的数字是从 John the Ripper v1.6.38 -test的输出获得的。

  • md5数字来自mdcrack 1.2。

  • sha1数字来自lcrack-20031130-beta。

  • crypt-bf数字使用一个简单的程序获得,这个程序重复超过1000次8字符口令。 这样可以显示速度和不同数字的迭代。例如:john -test显示了 crypt-bf/5的213次循环/秒。(结果中非常小的不同与事实一致, pgcrypto中的crypt-bf实现和John the Ripper中使用的是同一个。)

请注意,"尝试所有组合"是不现实的。不寻常的密码破解在字典的帮助下完成, 包含普通的单词和它们的各种转变。所以,即使有点类似单词的密码可能比上述建议的数字破解的更快, 而一个6字符不像单词的密码可能避开破解。或者不能。

F.25.3. PGP 加密功能

该功能实现了部分OpenPGP (RFC 4880)标准的加密。支持对称秘钥和公共秘钥的加密。

一条加密的PGP消息包含2个部分,或数据包:

  • 数据包包含一个会话秘钥—加密了的对称秘钥或者是公共秘钥。

  • 数据包包含带有会话秘钥的加密数据。

当带有对称秘钥(如一个口令)加密时:

  1. 给定的口令使用String2Key (S2K)算法散列。这和crypt()算法很相似— 自觉地变慢并且带有随机salt—但是它产生一个全长的二进制秘钥。

  2. 如果需要一个单独的会话秘钥,将会产生一个新的随机秘钥。否则将直接使用S2K秘钥作为会话秘钥。

  3. 如果直接使用S2K秘钥,那么只有S2K设置将被放入到会话秘钥包。 否则会话秘钥将用S2K秘钥加密然后放入会话秘钥包。

当使用公共秘钥加密时:

  1. 将会产生一个新的随机会话秘钥。

  2. 它使用公共密钥加密并放入会话秘钥包中。

两种情况下数据被加密的处理如下:

  1. 可选的数据操作:压缩,转换成UTF-8,和/或行尾的转换。

  2. 数据带有一块随机字节的前缀。这相当于使用一个随机的IV。

  3. 附加上一个随机前缀和数据的SHA1散列。

  4. 所有这些都带有会话秘钥加密,并放入数据包中。

F.25.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加密dataoptions参数可以包含选项设置,就像下面描述的那样。

F.25.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解密bytea数据是不允许的。 这是为了避免输出不合法的字符数据。用pgp_sym_decrypt_bytea 解密原始的文本数据是可以的。

options参数可以包含选项设置,就像下面描述的那样。

F.25.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秘钥key加密data。 给这个函数一个秘密秘钥将产生一个错误。

options参数可以包含选项设置,就像下面描述的那样。

F.25.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

解密一个公共密钥加密的消息。key必须是与用来加密的公共秘钥对应的秘密秘钥。 如果该秘密秘钥是密码保护的,你必须在psw中给出密码。 如果没有密码,但是你希望指定选项,你需要给出一个空的密码。

pgp_pub_decrypt解密bytea数据是不允许的。 这是为了避免输出不合法的字符数据。用pgp_pub_decrypt_bytea 解密原始的文本数据是可以的。

options参数可以包含选项设置,就像下面描述的那样。

F.25.3.5. pgp_key_id()

pgp_key_id(bytea) returns text

pgp_key_id摘取一个PGP公共或秘密秘钥的秘钥 ID。 或如果给出一个加密的消息,它给出用于加密数据的秘钥 ID。

它可以返回两个特殊的秘钥 ID:

  • SYMKEY

    该消息是用对称秘钥加密的。

  • ANYKEY

    该消息是公共秘钥加密的,但是秘钥ID已经删除了。这意味着你将要尝试所有你的秘密秘钥, 看看哪个能解密它。pgcrypto本身并不产生这样的消息。

请注意,不同的秘钥可能有相同的ID。这是稀少的,但是是一个普通事件。 然后客户端应用应该尝试解密每一个,看看哪个合适—类似处理ANYKEY

F.25.3.6. armor(), dearmor()

armor(data bytea) returns text
dearmor(data text) returns bytea

这些功能打包/解包二进制数据到PGP ASCII-armor格式, 这些基本上是带有CRC的Base64和额外的格式。

F.25.3.7. PGP功能的选项

选项的命名类似于GnuPG。选项的值应该在等号后面给出;选项之间用逗号隔开。例如:

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

除了convert-crlf之外的所有选项只应用到加密函数。 解密函数从PGP数据中获得参数。

最有趣的选项可能就是compress-algounicode-mode了。 其余的应该有合理的默认值。

F.25.3.7.1. cipher-algo

要使用的密码算法。

值: bf, aes128, aes192, aes256 (OpenSSL-only: 3des, cast5)
缺省: aes128
适用于: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.2. compress-algo

要使用的压缩算法。只有PostgreSQL带有zlib建立时可以使用。

值:
0 - 没有压缩
1 - ZIP 压缩
2 - ZLIB 压缩 (= ZIP 加上元数据和块 CRCs)
缺省: 0
适用于: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.3. 压缩级别

压缩多少。较高层次压缩较小但是较慢。0表示禁用压缩。

值: 0, 1-9
缺省: 6
适用于: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.4. 转换 crlf

在加密时是否将\n转换为\r\n和在解密时是否将 \r\n转换为\n。RFC 4880指定文本数据应该使用 \r\n换行存储。使用这个获得全部的RFC兼容性能。

值: 0, 1
缺省: 0
适用于: pgp_sym_encrypt, pgp_pub_encrypt, pgp_sym_decrypt, pgp_pub_decrypt

F.25.3.7.5. 禁用 mdc

不要用SHA-1保护数据。唯一使用这个选项的理由是为了实现与古老的PGP产品的兼容, 该产品早于SHA-1受保护的包添加到RFC 4880。最近的gnupg.org和pgp.com软件也很好的支持它。

值: 0, 1
缺省: 0
适用于: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.7.6. 启用会话秘钥

使用单独的会话秘钥。公共秘钥加密总是使用一个单独的会话秘钥;这是为了对称秘钥加密, 这在默认情况下是直接使用S2K秘钥的。

值: 0, 1
缺省: 0
适用于: pgp_sym_encrypt

F.25.3.7.7. s2k 模式

使用S2K算法。

值:
0 - 没有salt。 危险的!
1 - 有salt但是带有固定的重复计数。
3 - 变量重复计数。
缺省: 3
适用于: pgp_sym_encrypt

F.25.3.7.8. s2k 摘要算法

在S2K计算中使用哪个摘要算法。

值: md5, sha1
缺省: sha1
适用于: pgp_sym_encrypt

F.25.3.7.9. s2k 密码算法

加密单独的会话秘钥使用哪个密码。

值: bf, aes, aes128, aes192, aes256
缺省: use cipher-algo
适用于: pgp_sym_encrypt

F.25.3.7.10. unicode 模式

是否要转换文本数据从数据库内部编码到UTF-8及以前。如果你的数据库已经是UTF-8, 将不需要转换,但是消息将被标记为UTF-8。没有这个选项将不会这样。

值: 0, 1
缺省: 0
适用于: pgp_sym_encrypt, pgp_pub_encrypt

F.25.3.8. 用 GnuPG 产生 PGP 秘钥

要生成一个新的秘钥:

gpg --gen-key

首选的秘钥类型是"DSA and Elgamal"

对于RSA加密,你必须创建DSA或RSA唯一签署秘钥作为主秘钥,然后用 gpg --edit-key添加一个RSA加密子秘钥。

要列出秘钥:

gpg --list-secret-keys

以ASCII-armor格式导出一个公共秘钥:

gpg -a --export KEYID > public.key

以ASCII-armor格式导出一个秘密秘钥:

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

在将它们送给PGP函数之前需要在这些秘钥上使用dearmor()。 或者如果你可以处理二进制数据,你可以从命令行中删除-a

要获取更多详细信息,请参阅man gpg, The GNU Privacy Handbook和其他http://www.gnupg.org上的文档。

F.25.3.9. PGP 代码的限制

  • 不支持签名。这也意味着不检查加密子秘钥是否属于主秘钥。

  • 不支持加密秘钥作为主秘钥。因为通常不建议这样的做法,这应该不是一个问题。

  • 不支持几个子秘钥。这可能看起来像是一个问题,因为这是习惯的做法。另一方面, 不应该使用带有pgcrypto的定期GPG/PGP秘钥,而是创建一个新的秘钥, 因为使用场景相当不同。

F.25.4. 行加密功能

这些功能在数据上只运行一个密码;它们没有任何比PGP加密更先进的特性。 因此它们有一些主要的问题:

  1. 它们使用用户秘钥直接作为加密秘钥。

  2. 它们不提供任何完整性检查,来看看加密的数据是否被修改了。

  3. 它们希望用户自己管理所有加密参数,即使是IV。

  4. 它们不处理文本。

所以,随着PGP加密的引入,不建议使用行加密功能了。

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

加密/解密数据使用type指定的加密方法。 type字符串的语法是:

algorithm [ - mode ] [ /pad: padding ]

algorithm是下列之一:

  • bf — Blowfish

  • aes — AES (Rijndael-128)

mode是下列之一:

  • cbc — 下一个块取决于前一个块(缺省)

  • ecb — 每个块单独加密(只为了测试)

padding是下列之一:

  • pkcs — 数据可以是任意长度(缺省)

  • none — 数据必须是加密块尺寸的几倍

所以,例如,这些是相等的:

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

encrypt_ivdecrypt_iv中,iv 参数是CBC模式的初始值;在ECB中忽略。如果不正好是块的大小则截断或用0补齐。 在没有这个参数的函数里缺省全部为0。

F.25.5. 随机数据函数

gen_random_bytes(count integer) returns bytea

密码强随机字节的返回count。一次最多可以提取1024个字节。 这是为了避免排干随机发生器池。

F.25.6. 注意

F.25.6.1. 配置

pgcrypto根据主PostgreSQL configure脚本的调查结果配置它本身。 影响它的选项是--with-zlib--with-openssl

当用zlib编译时,PGP加密函数可以在加密之前压缩数据。

当用OpenSSL编译时,有更多算法可用。公共秘钥加密函数也会更快, 因为OpenSSL有更多优化了的BIGNUM函数。

表 F-18. 带有和不带有 OpenSSL 的功能性总结

功能性内建带有 OpenSSL
MD5yesyes
SHA1yesyes
SHA224/256/384/512yesyes (注意 1)
其他摘要算法noyes (注意 2)
Blowfishyesyes
AESyesyes (注意 3)
DES/3DES/CAST5noyes
行加密yesyes
PGP 对称加密yesyes
PGP 公共秘钥加密yesyes

注意:

  1. SHA2算法在版本 0.9.8 的时候添加到了OpenSSL。对于更老的版本, pgcrypto使用内建的代码。

  2. 任何OpenSSL支持的摘要算法是自动获得的。这对于密码来说是不可能的,密码需要明确的支持。

  3. AES自版本 0.9.7 以来包含在OpenSSL中了。对于更老的版本, pgcrypto使用内建的代码。

F.25.6.2. NULL 处理

就像SQL中的标准,如果任一参数是NULL,那么所有函数都返回NULL。 这在粗心的使用中可能会造成安全风险。

F.25.6.3. 安全限制

所有pgcrypto函数在数据库服务器内部运行。这意味着pgcrypto 和客户端应用之间的所有数据和口令移动都是以明文的形式。因此必须:

  1. 本地连接或使用SSL连接。

  2. 同时信任系统和数据库管理员。

如果你做不到,那么最好在客户端应用内部做crypto。

F.25.6.4. 有用的阅读

F.25.6.5. 技术参考文献

F.25.7. 作者

Marko Kreen <markokr@gmail.com>

pgcrypto使用来自下列源码的代码:

算法作者起源
DES 加密David Burren 和其他人FreeBSD libcrypt
MD5 加密Poul-Henning KampFreeBSD libcrypt
Blowfish 加密Solar Designerwww.openwall.com
Blowfish 密码Simon TathamPuTTY
Rijndael 密码Brian GladmanOpenBSD sys/crypto
MD5 和 SHA1WIDE ProjectKAME kame/sys/crypto
SHA256/384/512 Aaron D. GiffordOpenBSD sys/crypto
BIGNUM mathMichael J. Frombergerdartmouth.edu/~sting/sw/imath

上一页起始页下一页
pg_buffercache上一级pg_freespacemap
<
/BODY>

AltStyle によって変換されたページ (->オリジナル) /