云原生数据仓库 AnalyticDB PostgreSQL 版内置加密解密模块pgcryoto并集成国密SM4加密算法,允许数据库用户以加密形式存储数据的某些列,为敏感数据增加了一层额外的保护。无密钥时,任何用户都无法读取以加密形式存储在数据库中的数据。
注意事项
pgcrypto插件在数据库服务器内部运行,所有数据和密码都以明文形式在数据库和客户端应用程序之间传输。为了获得最佳安全性,建议在客户端和云原生数据仓库 AnalyticDB PostgreSQL 版之间使用SSL连接。
安装pgcrypto插件
使用pgcryoto插件之前,请您在云原生数据仓库 AnalyticDB PostgreSQL 版实例插件管理中安装pgcrypto插件。具体操作,请参见安装、升级与卸载插件。
通用哈希函数
digest()
函数可以根据不同的算法生成数据的二进制哈希值。
语法
digest(data text, type text) returns bytea
digest(data bytea, type text) returns bytea
data
:需要计算二进制哈希值的原始数据。type
:加密算法。包括MD5、SHA1、SHA224、SHA256、SHA384和SHA512。
示例
使用digest()
函数对字符串ADBPG
进行sha256加密存储,示例如下。
SELECT digest('ADBPG','sha256');
返回结果如下。
digest
--------------------------------------------------------------------
\x2d0525fa98e83619424dc1303ba107c59aabb389bbe94ceef885c742088560bc
(1 row)
密码哈希函数
crypt()
和gen_salt()
函数专用于哈希密码。crypt()
执行哈希用于加密数据,gen_salt()
用于生成加盐哈希。
crypt()
函数中的算法和普通的MD5或者SHA1哈希算法存在以下不同之处:
crypt()
函数中算法很慢。密码通常长度较小,crypt()
只能用比较复杂的加密算法来增加破解难度。crypt()
函数使用一个随机值(Salt,即盐值),使得具有相同口令的用户将得到不同的密文口令。这也是针对破解算法提供一种额外的安全保护。crypt()
函数的结果中包括了算法类型,因此可以针对不同用户使用不同的算法对密码进行加密。crypt()
函数的一些算法具有自适应性,意味着当计算机性能变得更快时,可以调整该算法使其变得更慢,而不会产生与已有密码的不兼容性。
crypt()
函数支持的算法
算法 | 密码最大长度 | 是否自适应 | Salt 位数 | 输出长度 | 描述 |
BF | 72 | 是 | 128 | 60 | 基于Blowfish的变体2a算法。 |
MD5 | unlimited | 否 | 48 | 34 | 基于MD5的加密算法。 |
XDES | 8 | 是 | 24 | 20 | 扩展DES。 |
DES | 8 | 否 | 12 | 13 | 原生UNIX加密。 |
crypt()
语法
crypt(password text, salt text) returns text
crypt()
函数返回password字符串的哈希值,salt参数由gen_salt()
函数生成。由于gen_salt()
函数每次都会生成不同的salt,因此对于相同的password字符串,crypt()
函数每次也会返回不同的结果。校验密码时可以将之前生成的哈希结果作为salt。
crypt()
示例
示例一:通过
crypt()
函数设置一个新密码。UPDATE ... SET pswhash = crypt('my_password', gen_salt('md5'));
示例二:通过比较存储的密码哈希值验证输入的密码的正确性。
SELECT (pswhash = crypt('entered password', pswhash)) AS pswmatch FROM ... ;
如果输入的口令正确,会返回true。
gen_salt()
语法
gen_salt(type text [, iter_count integer ]) returns text
gen_salt()
函数用来产生随机的参数输入给crypt
,此函数每次都会生成一个随机的盐值(salt)字符串,该字符串同时决定了crypt()
函数使用的算法。
type
:用于指定一个生成字符串的哈希算法,取值包括DES、XDES、MD5及BF。
iter_count
:对于XDES和BF算法,iter_count
指定迭代次数,数字越大加密时间越长,被破解需要的时间也越长。
gen_salt()
示例
SELECT gen_salt('des'), gen_salt('xdes'), gen_salt('md5'), gen_salt('bf');
返回结果如下。
gen_salt | gen_salt | gen_salt | gen_salt
----------+-----------+-------------+-------------------------------
qh | _J9..uEUi | $1$SNgqyKAi | $2a$06$B/Etc3J8zYBV49LrDU97MO
(1 row)
PGP加密函数
云原生数据仓库 AnalyticDB PostgreSQL 版实现了OpenPGP(RFC 4880)标准,支持对称加密和非对称加密。
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_sym_encrypt()
用于对称密钥加密。
data
:需要加密的数据。psw
:PGP对称密钥。options
:用于设置选项。
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_sym_decrypt()
用于解密PGP对称密钥加密后的消息。
msg
:需要解密的消息。psw
:PGP对称密钥。options
:用于设置选项。
为了避免输出无效的字符,不允许使用pgp_sym_decrypt
函数对Bytea数据进行解密,可以使用 pgp_sym_decrypt_bytea
对原始文本数据进行解密。
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_pub_encrypt()
用于公钥密钥加密。
data
:需要加密的数据。key
:PGP公钥,如果传入一个私钥将会返回错误。options:用于设置选项。
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
pgp_pub_decrypt()
用于解密一个公共密钥加密的消息。
msg
:需要解密的消息。key
:必须是用于加密的公钥的私钥。如果私钥是用口令保护的,必须在psw
中给出该口令。如果没有口令,但想要指定选项,需要给出一个空口令。
为了避免输出无效的字符,不允许使用pgp_pub_decrypt
函数对Bytea数据进行解密,可以使用pgp_pub_decrypt_bytea
对原始文本数据进行解密。key
为公共密钥对应的私钥,如果私钥使用了密码保护功能,必须在psw
参数中指定密码;如果没有使用密码保护,想要指定options
参数时必须指定一个空的psw
。
随机数据函数
gen_random_bytes()
gen_random_bytes(count integer) returns bytea
gen_random_bytes()
函数用于生成具有强加密性的随机字节。
count
:返回的字节数,取值为1~1024。
示例:
SELECT gen_random_bytes(16);
返回结果如下。
gen_random_bytes
------------------------------------
\x1f1eddc11153afdde0f9e1229f8f4caf
(1 row)
gen_random_uuid()
gen_random_uuid()
函数用于返回一个Version 4的随机UUID。
示例:
SELECT gen_random_uuid();
返回结果如下。
gen_random_uuid
--------------------------------------
2bd664a2-b760-4859-8af6-8d09ccc5b830
国密SM4加密算法
根据信息安全的相关要求,敏感信息通常需要在数据库中进行加密存储,例如登录密码、信用卡号、身份证号等。pgcrypto插件提供了多种加密算法,总体上分为单向加密和双向加密:
单向加密:属于不可逆加密,无法根据密文解密出明文,适用于数据的验证,例如登录密码验证。
双向加密:属于可逆加密,根据密文和密钥可解密出明文,适用于数据的安全传输,例如电子支付、数字签名等。
云原生数据仓库 AnalyticDB PostgreSQL 版还支持国密算法SM4。SM4属于双向加密,您需要提供密钥,在数据库服务端进行加密。
SM4算法目前只支持Text和Varchar数据类型,应用开发人员需要在业务侧将待加密的数据转成字符串(String)后,再进行加密。
仅支持V6.3.8.9及以上版本,安装或升级插件需要如何查看实例内核版本,请参见查看内核小版本。
安装
使用国密算法SM4之前,您需要在云原生数据仓库 AnalyticDB PostgreSQL 版实例插件管理中安装pgcrypto插件。具体操作,请参见安装、升级与卸载插件。
加密
使用SM4函数加密关键字段语法如下。
-- 加密text格式数据
sm4_encrypt_text(<data text>, <password text>)
-- 加密varchar格式数据
sm4_encrypt_varchar(<data varchar>, <password text>)
参数说明如下。
参数 | 说明 |
| 需要加密的Text格式的数据。 |
| 需要加密的Varchar格式的数据。 |
| 加密密钥,为Text格式。 |
示例一:对文本字段
who am i
进行加密,密钥为key
,示例如下。SELECT sm4_encrypt_text('who am i','key');
加密后的值为Bytea类型,返回信息如下。
sm4_encrypt_text ------------------------------------ \x308b71cc7fa0de7d720b2c394a3a83c2 (1 row)
示例二:使用SM4加密函数将明文数据转成密文数据后,写入密文表。创建表
t_plain
存储明文数据和表t_enc
存储密文数据。-- DROP EXTENSION encdb; CREATE TABLE t_plain( id int, name varchar(20), introduction text ) distributed BY (id); INSERT INTO t_plain VALUES (1, 11, 'aaa'); CREATE TABLE t_enc( id int, name varchar(20), introduction bytea ) distributed by (id); INSERT INTO t_enc SELECT id ,name, sm4_encrypt_text(introduction,'passwd') FROM t_plain; SELECT * FROM t_enc;
introduction字段的值已被加密,返回信息如下。
id | name | introduction ----+------+------------------------------------ 1 | 11 | \x0ca8e6c45a83e98efe99dcde0510930e (1 row)
解密
使用SM4函数查询加密字段语法如下。
-- 解密text格式数据
sm4_decrypt_text(data bytea, password text)
-- 解密varchar格式数据
sm4_decrypt_varchar(data bytea, password text)
参数说明如下。
参数 | 说明 |
| 需要解密的Bytea类型的数据。 |
| 加密密钥,为Text格式。 |
示例一:对上文加密的字段进行解密,示例如下。
SELECT sm4_decrypt_text('\x308b71cc7fa0de7d720b2c394a3a83c2'::bytea, 'key');
解密的内容为
who am i
,返回信息如下。sm4_decrypt_text ------------------ who am i (1 row)
示例二:使用SM4函数解密查询密文表
t_enc
。SELECT id, name, sm4_decrypt_text(introduction,'passwd') FROM t_enc;
introduction字段的值已解密,返回信息如下。
id | name | sm4_decrypt_text ----+------+------------------ 1 | 11 | aaa (1 row)
相关文档
pgcrypto的详细信息,请参见postgresql。