加密数据和数据库连接

    • 客户端和Master数据库之间的连接可以用SSL加密。这种方式可以通过设置ssl服务器配置参数为on并且编辑pg_hba.conf文件来启用。有关在Greenplum数据库中启用SSL的信息请见Greenplum数据库管理员指南中的“加密客户端/服务器连接”。
    • Greenplum数据库4.2.1及以上的版本允许在Greenplum的并行文件分发服务器、gpfdist和Segment主机之间传输SSL加密数据。详见加密gpfdist连接
    • Greenplum数据库集群中主机之间的网络通信可以使用IPsec加密。集群中的每一对主机之间会建立一个认证过的加密的VPN。对IPsec的支持请检查操作系统文档,或者考虑等组织提供的第三方解决方案。
    • pgcrypto包中的加密/解密函数保护停留在数据库中的数据。列级的加密可以保护敏感信息,例如口令、社会保险号码或者信用卡号码。例子可以在使用PGP加密表中的数据中找到。
    • 加密确保数据只能被拥有解密数据所需密钥的用户看见。
    • 加密和解密数据有性能代价,只加密需要加密的数据。
    • 在生产系统中实现任何加密解决方案之前先做性能测试。
    • 用于生产的Greenplum数据库系统中的服务器证书应该由一个数字证书认证机构(CA)签发,这样客户端可以认证服务器。如果所有的客户端都在该组织本地,这个CA可以是本地的。
    • 只要到Greenplum数据库的客户端连接会通过一个不安全的链路,就应该使用SSL加密。
    • 对称加密模式(加密和解密使用相同的密钥)比非对称模式具有更好的性能,并且应该在可以安全共享密钥时使用对称模式。
    • 使用来自pgcrypto包的函数来加密磁盘上的数据。数据在数据库进程中被加密和解密,因此有必要用SSL来保护客户端连接以避免传输未加密的数据。
    • 在ETL数据被载入数据库或者被从数据库中卸载时,使用gpfdists协议来保护ETL数据。请见。

    密钥管理

    只要使用对称(单私钥)或者非对称(公钥和私钥)加密,就有必要安全地存储主密钥或者私钥。存储加密密钥有很多选项,例如在文件系统上保存、密钥保管库、加密的USB、可信平台模块(TPM)或者硬件安全模块(HSM)。

    在规划密钥管理时考虑下列问题:

    • 密钥将被存在哪里?
    • 密钥何时过期?
    • 如何保护密钥?
    • 如何访问密钥?
    • 如何恢复和收回密钥?

    开放Web应用安全性项目(OWASP)提供了一套非常全面的。

    Greenplum数据库的pgcrypto包提供了加密数据库中静止数据的函数。管理员可以加密具有敏感信息(例如社会保险号码或信用卡号)的列以提供一个额外的保护层。没有加密密钥的用户无法读取以加密形式存储的数据库数据,并且这些数据也无法从磁盘直接读取。

    pgcrypto允许使用对称和非对称加密的PGP加密。对称加密使用同样的密钥加密和解密数据,并且比非对称加密更快。在交换密钥不成问题的环境中它是首选方法。在非对称加密中,公钥被用来加密数据而私钥被用来解密数据。这种模式比对称加密慢一些并且要求更强的密钥。

    使用pgcrypto总是会带来性能和可维护性的代价。有必要只对需要加密的数据使用加密。还有,要记住用户无法通过索引加密数据来搜索它们。

    在用户实现数据库内加密之前,考虑下列PGP限制。

    • 不支持签名。这还意味着不会检查加密子密钥是否属于主密钥。
    • 不支持将加密密钥作为主密钥。这种做法通常是不被鼓励的,因此这一限制应该不是问题。
    • 不支持多个子密钥。这可能看起来像一个问题,因为这是一种常见的做法。在另一方面,用户不应将其常规GPG/PGP密钥用于pgcrypto,而是要创建新的密钥,因为使用场景不同。

    Greenplum数据库默认用zlib编译,这允许PGP加密函数在加密数据之前先压缩数据。在编译有OpenSSL时,将会有更多算法可用。

    因为pgcrypto函数运行在数据库服务器内部,数据和口令是以明文形式在pgcrypto和客户端应用之间移动。为了最好的安全性,用户应该使用本地连接或者使用SSL连接,并且用户应该信任系统管理员和数据库管理员。

    Greenplum数据库默认没有安装pgcrypto包。用户可以从Pivotal Network下载一个pgcrypto包,并且使用Greenplum包管理器(gppkg)在集群中安装pgcrypto。

    pgcrypto会根据主PostgreSQL配置脚本的发现配置自身。

    当编译有zlib时,pgcrypto加密函数能在加密前压缩数据。

    pgcrypto拥有从基本内建函数到高级内建函数的多个加密级别。下面的表格展示了支持的加密算法。

    创建PGP密钥

    要在Greenplum数据库中使用PGP非对称加密,用户必须首先创建公私钥并且安装它们。

    1. 作为root,执行下列命令并且从菜单选择选项1:

    2. 如下例所示,回应提示并且遵循其指导:

      1. What keysize do you want? (2048) Press enter to accept default key size
      2. Requested keysize is 2048 bits
      3. Please specify how long the key should be valid.
      4. 0 = key does not expire
      5. <n> = key expires in n days
      6. <n>w = key expires in n weeks
      7. <n>m = key expires in n months
      8. <n>y = key expires in n years
      9. Key is valid for? (0) 365
      10. Key expires at Wed 13 Jan 2016 10:35:39 AM PST
      11. Is this correct? (y/N) y
      12. GnuPG needs to construct a user ID to identify your key.
      13. Real name: John Doe
      14. Email address: jdoe@email.com
      15. Comment:
      16. You selected this USER-ID:
      17. "John Doe <jdoe@email.com>"
      18. Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
      19. You need a Passphrase to protect your secret key.
      20. (For this demo the passphrase is blank.)
      21. can't connect to `/root/.gnupg/S.gpg-agent': No such file or directory
      22. You don't want a passphrase - this is probably a *bad* idea!
      23. I will do it anyway. You can change your passphrase at any time,
      24. using this program with the option "--edit-key".
      25. We need to generate a lot of random bytes. It is a good idea to perform
      26. some other action (type on the keyboard, move the mouse, utilize the
      27. disks) during the prime generation; this gives the random number
      28. generator a better chance to gain enough entropy.
      29. We need to generate a lot of random bytes. It is a good idea to perform
      30. some other action (type on the keyboard, move the mouse, utilize the
      31. disks) during the prime generation; this gives the random number
      32. generator a better chance to gain enough entropy.
      33. gpg: /root/.gnupg/trustdb.gpg: trustdb created
      34. gpg: key 2027CC30 marked as ultimately trusted
      35. public and secret key created and signed.
      36. gpg: checking the trustdbgpg:
      37. 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
      38. gpg: next trustdb check due at 2016-01-13
      39. pub 2048R/2027CC30 2015-01-13 [expires: 2016-01-13]
      40. Key fingerprint = 7EDA 6AD0 F5E0 400F 4D45 3259 077D 725E 2027 CC30
      41. uid John Doe <jdoe@email.com>
      42. sub 2048R/4FD2EFBB 2015-01-13 [expires: 2016-01-13]
    3. 通过输入下列命令来列出PGP密钥:

      1. gpg --list-secret-keys
      2. /root/.gnupg/secring.gpg
      3. ------------------------
      4. sec 2048R/2027CC30 2015-01-13 [expires: 2016-01-13]
      5. uid John Doe <jdoe@email.com>
      6. ssb 2048R/4FD2EFBB 2015-01-13

      2027CC30是公钥并且将被用来加密数据库中的数据。4FD2EFBB是私钥并且将被用来解密数据。

    4. 使用下列命令导出密钥:

    更多有关PGP加密函数的信息请见pgcrypto文档。

    这个小节展示如何使用用户产生的PGP密钥加密插入到一列中的数据。

    1. 转储public.key文件的内容,然后把它拷贝的剪贴板:

      1. -----BEGIN PGP PUBLIC KEY BLOCK-----
      2. Version: GnuPG v2.0.14 (GNU/Linux)
      3. mQENBFS1Zf0BCADNw8Qvk1V1C36Kfcwd3Kpm/dijPfRyyEwB6PqKyA05jtWiXZTh
      4. 2His1ojSP6LI0cSkIqMU9LAlncecZhRIhBhuVgKlGSgd9texg2nnSL9Admqik/yX
      5. R5syVKG+qcdWuvyZg9oOOmeyjhc3n+kkbRTEMuM3flbMs8shOwzMvstCUVmuHU/V
      6. vG5rJAe8PuYDSJCJ74I6w7SOH3RiRIc7IfL6xYddV42l3ctd44bl8/i71hq2UyN2
      7. /Hbsjii2ymg7ttw3jsWAx2gP9nssDgoy8QDy/o9nNqC8EGlig96ZFnFnE6Pwbhn+
      8. ic8MD0lK5/GAlR6Hc0ZIHf8KEcavruQlikjnABEBAAG0HHRlc3Qga2V5IDx0ZXN0
      9. a2V5QGVtYWlsLmNvbT6JAT4EEwECACgFAlS1Zf0CGwMFCQHhM4AGCwkIBwMCBhUI
      10. AgkKCwQWAgMBAh4BAheAAAoJEAd9cl4gJ8wwbfwH/3VyVsPkQl1owRJNxvXGt1bY
      11. 7BfrvU52yk+PPZYoes9UpdL3CMRk8gAM9bx5Sk08q2UXSZLC6fFOpEW4uWgmGYf8
      12. JRoC3ooezTkmCBW8I1bU0qGetzVxopdXLuPGCE7hVWQe9HcSntiTLxGov1mJAwO7
      13. TAoccXLbyuZh9Rf5vLoQdKzcCyOHh5IqXaQOT100TeFeEpb9TIiwcntg3WCSU5P0
      14. DGoUAOanjDZ3KE8Qp7V74fhG1EZVzHb8FajR62CXSHFKqpBgiNxnTOk45NbXADn4
      15. eTUXPSnwPi46qoAp9UQogsfGyB1XDOTB2UOqhutAMECaM7VtpePv79i0Z/NfnBe5
      16. AQ0EVLVl/QEIANabFdQ+8QMCADOipM1bF/JrQt3zUoc4BTqICaxdyzAfz0tUSf/7
      17. Zro2us99GlARqLWd8EqJcl/xmfcJiZyUam6ZAzzFXCgnH5Y1sdtMTJZdLp5WeOjw
      18. gCWG/ZLu4wzxOFFzDkiPv9RDw6e5MNLtJrSp4hS5o2apKdbO4Ex83O4mJYnav/rE
      19. iDDCWU4T0lhv3hSKCpke6LcwsX+7liozp+aNmP0Ypwfi4hR3UUMP70+V1beFqW2J
      20. bVLz3lLLouHRgpCzla+PzzbEKs16jq77vG9kqZTCIzXoWaLljuitRlfJkO3vQ9hO
      21. v/8yAnkcAmowZrIBlyFg2KBzhunYmN2YvkUAEQEAAYkBJQQYAQIADwUCVLVl/QIb
      22. DAUJAeEzgAAKCRAHfXJeICfMMOHYCACFhInZA9uAM3TC44l+MrgMUJ3rW9izrO48
      23. WrdTsxR8WkSNbIxJoWnYxYuLyPb/shc9k65huw2SSDkj//0fRrI61FPHQNPSvz62
      24. WH+N2lasoUaoJjb2kQGhLOnFbJuevkyBylRz+hI/+8rJKcZOjQkmmK8Hkk8qb5x/
      25. HMUc55H0g2qQAY0BpnJHgOOQ45Q6pk3G2/7Dbek5WJ6K1wUrFy51sNlGWE8pvgEx
      26. /UUZB+dYqCwtvX0nnBu1KNCmk2AkEcFK3YoliCxomdOxhFOv9AKjjojDyC65KJci
      27. Pv2MikPS2fKOAg1R3LpMa8zDEtl4w3vckPQNrQNnYuUtfj6ZoCxv
      28. =XZ8J
      29. -----END PGP PUBLIC KEY BLOCK-----
    2. 创建一个名为userssn的表并且插入一些敏感数据,这个例子中是Bob和Alice的社会保险号码。在”dearmor(“之后粘贴public.key的内容。

      1. CREATE TABLE userssn( ssn_id SERIAL PRIMARY KEY,
      2. username varchar(100), ssn bytea);
      3. INSERT INTO userssn(username, ssn)
      4. SELECT robotccs.username, pgp_pub_encrypt(robotccs.ssn, keys.pubkey) AS ssn
      5. FROM (
      6. VALUES ('Alice', '123-45-6788'), ('Bob', '123-45-6799'))
      7. AS robotccs(username, ssn)
      8. CROSS JOIN (SELECT dearmor('-----BEGIN PGP PUBLIC KEY BLOCK-----
      9. Version: GnuPG v2.0.14 (GNU/Linux)
      10. mQENBFS1Zf0BCADNw8Qvk1V1C36Kfcwd3Kpm/dijPfRyyEwB6PqKyA05jtWiXZTh
      11. 2His1ojSP6LI0cSkIqMU9LAlncecZhRIhBhuVgKlGSgd9texg2nnSL9Admqik/yX
      12. R5syVKG+qcdWuvyZg9oOOmeyjhc3n+kkbRTEMuM3flbMs8shOwzMvstCUVmuHU/V
      13. vG5rJAe8PuYDSJCJ74I6w7SOH3RiRIc7IfL6xYddV42l3ctd44bl8/i71hq2UyN2
      14. /Hbsjii2ymg7ttw3jsWAx2gP9nssDgoy8QDy/o9nNqC8EGlig96ZFnFnE6Pwbhn+
      15. ic8MD0lK5/GAlR6Hc0ZIHf8KEcavruQlikjnABEBAAG0HHRlc3Qga2V5IDx0ZXN0
      16. a2V5QGVtYWlsLmNvbT6JAT4EEwECACgFAlS1Zf0CGwMFCQHhM4AGCwkIBwMCBhUI
      17. AgkKCwQWAgMBAh4BAheAAAoJEAd9cl4gJ8wwbfwH/3VyVsPkQl1owRJNxvXGt1bY
      18. 7BfrvU52yk+PPZYoes9UpdL3CMRk8gAM9bx5Sk08q2UXSZLC6fFOpEW4uWgmGYf8
      19. JRoC3ooezTkmCBW8I1bU0qGetzVxopdXLuPGCE7hVWQe9HcSntiTLxGov1mJAwO7
      20. TAoccXLbyuZh9Rf5vLoQdKzcCyOHh5IqXaQOT100TeFeEpb9TIiwcntg3WCSU5P0
      21. DGoUAOanjDZ3KE8Qp7V74fhG1EZVzHb8FajR62CXSHFKqpBgiNxnTOk45NbXADn4
      22. eTUXPSnwPi46qoAp9UQogsfGyB1XDOTB2UOqhutAMECaM7VtpePv79i0Z/NfnBe5
      23. gCWG/ZLu4wzxOFFzDkiPv9RDw6e5MNLtJrSp4hS5o2apKdbO4Ex83O4mJYnav/rE
      24. iDDCWU4T0lhv3hSKCpke6LcwsX+7liozp+aNmP0Ypwfi4hR3UUMP70+V1beFqW2J
      25. bVLz3lLLouHRgpCzla+PzzbEKs16jq77vG9kqZTCIzXoWaLljuitRlfJkO3vQ9hO
      26. v/8yAnkcAmowZrIBlyFg2KBzhunYmN2YvkUAEQEAAYkBJQQYAQIADwUCVLVl/QIb
      27. DAUJAeEzgAAKCRAHfXJeICfMMOHYCACFhInZA9uAM3TC44l+MrgMUJ3rW9izrO48
      28. WrdTsxR8WkSNbIxJoWnYxYuLyPb/shc9k65huw2SSDkj//0fRrI61FPHQNPSvz62
      29. WH+N2lasoUaoJjb2kQGhLOnFbJuevkyBylRz+hI/+8rJKcZOjQkmmK8Hkk8qb5x/
      30. HMUc55H0g2qQAY0BpnJHgOOQ45Q6pk3G2/7Dbek5WJ6K1wUrFy51sNlGWE8pvgEx
      31. /UUZB+dYqCwtvX0nnBu1KNCmk2AkEcFK3YoliCxomdOxhFOv9AKjjojDyC65KJci
      32. Pv2MikPS2fKOAg1R3LpMa8zDEtl4w3vckPQNrQNnYuUtfj6ZoCxv
      33. =XZ8J
      34. -----END PGP PUBLIC KEY BLOCK-----' AS pubkey) AS keys;
    3. 验证ssn列被加密。

    4. 从数据库提取public.key ID:

      1. SELECT pgp_key_id(dearmor('-----BEGIN PGP PUBLIC KEY BLOCK-----
      2. Version: GnuPG v2.0.14 (GNU/Linux)
      3. mQENBFS1Zf0BCADNw8Qvk1V1C36Kfcwd3Kpm/dijPfRyyEwB6PqKyA05jtWiXZTh
      4. 2His1ojSP6LI0cSkIqMU9LAlncecZhRIhBhuVgKlGSgd9texg2nnSL9Admqik/yX
      5. R5syVKG+qcdWuvyZg9oOOmeyjhc3n+kkbRTEMuM3flbMs8shOwzMvstCUVmuHU/V
      6. vG5rJAe8PuYDSJCJ74I6w7SOH3RiRIc7IfL6xYddV42l3ctd44bl8/i71hq2UyN2
      7. /Hbsjii2ymg7ttw3jsWAx2gP9nssDgoy8QDy/o9nNqC8EGlig96ZFnFnE6Pwbhn+
      8. ic8MD0lK5/GAlR6Hc0ZIHf8KEcavruQlikjnABEBAAG0HHRlc3Qga2V5IDx0ZXN0
      9. a2V5QGVtYWlsLmNvbT6JAT4EEwECACgFAlS1Zf0CGwMFCQHhM4AGCwkIBwMCBhUI
      10. AgkKCwQWAgMBAh4BAheAAAoJEAd9cl4gJ8wwbfwH/3VyVsPkQl1owRJNxvXGt1bY
      11. 7BfrvU52yk+PPZYoes9UpdL3CMRk8gAM9bx5Sk08q2UXSZLC6fFOpEW4uWgmGYf8
      12. JRoC3ooezTkmCBW8I1bU0qGetzVxopdXLuPGCE7hVWQe9HcSntiTLxGov1mJAwO7
      13. TAoccXLbyuZh9Rf5vLoQdKzcCyOHh5IqXaQOT100TeFeEpb9TIiwcntg3WCSU5P0
      14. DGoUAOanjDZ3KE8Qp7V74fhG1EZVzHb8FajR62CXSHFKqpBgiNxnTOk45NbXADn4
      15. eTUXPSnwPi46qoAp9UQogsfGyB1XDOTB2UOqhutAMECaM7VtpePv79i0Z/NfnBe5
      16. AQ0EVLVl/QEIANabFdQ+8QMCADOipM1bF/JrQt3zUoc4BTqICaxdyzAfz0tUSf/7
      17. Zro2us99GlARqLWd8EqJcl/xmfcJiZyUam6ZAzzFXCgnH5Y1sdtMTJZdLp5WeOjw
      18. gCWG/ZLu4wzxOFFzDkiPv9RDw6e5MNLtJrSp4hS5o2apKdbO4Ex83O4mJYnav/rE
      19. iDDCWU4T0lhv3hSKCpke6LcwsX+7liozp+aNmP0Ypwfi4hR3UUMP70+V1beFqW2J
      20. bVLz3lLLouHRgpCzla+PzzbEKs16jq77vG9kqZTCIzXoWaLljuitRlfJkO3vQ9hO
      21. v/8yAnkcAmowZrIBlyFg2KBzhunYmN2YvkUAEQEAAYkBJQQYAQIADwUCVLVl/QIb
      22. DAUJAeEzgAAKCRAHfXJeICfMMOHYCACFhInZA9uAM3TC44l+MrgMUJ3rW9izrO48
      23. WrdTsxR8WkSNbIxJoWnYxYuLyPb/shc9k65huw2SSDkj//0fRrI61FPHQNPSvz62
      24. WH+N2lasoUaoJjb2kQGhLOnFbJuevkyBylRz+hI/+8rJKcZOjQkmmK8Hkk8qb5x/
      25. HMUc55H0g2qQAY0BpnJHgOOQ45Q6pk3G2/7Dbek5WJ6K1wUrFy51sNlGWE8pvgEx
      26. /UUZB+dYqCwtvX0nnBu1KNCmk2AkEcFK3YoliCxomdOxhFOv9AKjjojDyC65KJci
      27. Pv2MikPS2fKOAg1R3LpMa8zDEtl4w3vckPQNrQNnYuUtfj6ZoCxv
      28. =XZ8J
      29. -----END PGP PUBLIC KEY BLOCK-----'));
      30. pgp_key_id | 9D4D255F4FD2EFBB

      这会显示用来加密ssn列使用的PGP键ID是9D4D255F4FD2EFBB。只要有新密钥被创建,都推荐执行这一步,然后将该ID保存下来用于跟踪。

      用户可以使用这个键来查看哪一个密钥对被用来加密数据:

      1. SELECT username, pgp_key_id(ssn) As key_used FROM userssn; username | Bob
      2. key_used | 9D4D255F4FD2EFBB
      3. ---------+-----------------
      4. username | Alice
      5. key_used | 9D4D255F4FD2EFBB

      注意: 不同的密钥可能具有相同的ID。这很少见,但是一种普通的事件。客户端应用应该尝试用每一个来解密看看哪一个合适——就像处理ANYKEY一样。请见pgcrypto文档中的。

    5. 如果用户使用口令创建一个密钥,用户可能必须在这里输入口令。不过对于这个例子的目的,口令为空。

    加密gpfdist连接

    gpfdists协议是gpfdist协议的一个安全版本,它能安全地标识文件服务器和Greenplum数据库并且加密其间的通信。使用gpfdists可以防止窃听和中间人攻击。

    gpfdists协议利用下列值得注意的特性实现客户端/服务器的SSL安全性:

    • 要求客户端证书。
    • 不支持多语言证书。
    • 不支持证书撤销列表(CRL)。
    • TLSv1协议被用于TLS_RSA_WITH_AES_128_CBC_SHA加密算法。这些SSL参数不能被更改。
    • 不支持SSL再协商。
    • SSL忽略主机失配参数被设置为false。
    • gpfdist服务器(server.key)或Greenplum数据库(client.key)不支持含有口令的私钥。
    • 为使用的操作系统颁发合适的证书是用户的责任。通常,支持将证书转换成所要求的格式,例如可使用的SSL转换器。

    用--ssl选项启动的gpfdist服务器只能用gpfdists协议通信。没有用--ssl选项启动的gpfdist服务器只能用gpfdist协议通信。更多有关gpfdist的细节请参考Greenplum数据库管理员指南

    有两种方式启用gpfdists协议:

    • 用--ssl选项运行gpfdist,然后在CREATE EXTERNAL TABLE语句的LOCATION子句中使用gpfdists协议。
    • 在YAML控制文件中将SSL选项设置为真,然后用它来运行gpload。运行的gpload会用--ssl选项启动gpfdist服务器,然后使用gpfdists协议。

    在使用gpfdists时,下列客户端证书必须位于每个Segment的$PGDATA/gpfdists目录中:

    • 客户端证书文件,client.crt
    • 客户端私钥文件,client.key
    • 受信证书发布机构,root.crt

    重要: 不要用口令保护私钥。服务器不会为私钥提示要求口令,并且数据装载会在要求口令时失败报错。

    在使用带SSL的gpload时,用户要在YAML控制文件中指定服务器证书的位置。在使用带SSL的gpfdist时,用户用—ssl选项指定服务器证书的位置。

    下面的例子展示了如何安全地装载数据到外部表中。这个例子从所有带txt扩展名的文件使用gpfdists协议创建一个可读外部表ext_expenses。这些文件被格式化为用一个竖线(|)作为列定界符,并且用空格表示空。

    1. 在Segment主机上用--ssl选项运行gpfdist。
    2. 登入数据库并执行下列命令:

      1. =# CREATE EXTERNAL TABLE ext_expenses
      2. ( name text, date date, amount float4, category text, desc1 text )
      3. LOCATION ('gpfdists://etlhost-1:8081/*.txt', 'gpfdists://etlhost-2:8082/*.txt')
      4. FORMAT 'TEXT' ( DELIMITER '|' NULL ' ') ;

    上级主题: 最佳实践

    SHA2算法在版本0.9.8时被加入OpenSSL。对于较老的版本,pgcrypto将使用内建代码。

    2 OpenSSL支持的任何摘要算法都会被自动地取用。而加密算法则不能这样,它们需要被明确地支持。

    AES从0.9.7开始被包括在OpenSSL中。对于较老的版本,pgcrypto将使用内建代码。