pgcrypto 提供了两类加密算法:单向加密和双向加密。
单向加密属于不可逆加密,无法根据密文解密出明文,适用于数据的验证,例如登录密码验证。常用的单向加密算法有 MD5、SHA、HMAC 等。双向加密属于可逆加密,根据密文和密钥可解密出明文,适用于数据的安全传输,例如电子支付、数字签名等。常用的双向加密算法有 AES、DES、RSA、ECC 等。
本文主要演示使用原始加密函数encrypt和decrypt函数做基于AES算法的双向加密过程。
首先来一波技术概念介绍。部分概念出自:https://blog.csdn.net/horses/article/details/109073000
原始加密函数仅仅会对数据进行一次加密,不支持 PGP 加密的任何高级功能,因此存在以下主要问题:
直接将用户密钥作为加密密钥。
不提供任何完整性检查校验加密后的数据是否被修改。
需要用户自己关联所有的加密参数,包括初始值(IV)。
不支持文本数据。
因此,在引入了 PGP 加密之后,不建议使用这些原始加密函数(后续会发布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
其中,data 是需要加密的数据;type 用于指定加密方法。type 参数的语法如下:
algorithm[- mode][/pad: padding]
其中 algorithm 的可能取值如下:bf,Blowfish 算法,aes,AES 算法(Rijndael-128、-192 或者-256)
mode 的可能取值如下:cbc,下一个块依赖于前一个块(默认值)ecb,每个块独立加密(仅用于测试)
padding 的可能取值如下:pkcs,数据可以是任意长度(默认值);none,数据长度必须是密码块大小的倍数
例如,以下函数的加密结果相同:
encrypt(data,'fooz','bf');encrypt(data,'fooz','bf-cbc/pad:pkcs')
对于函数 encrypt_iv 和 decrypt_iv,参数 iv 表示 CBC模式的初始值,ECB 模式忽略该参数。如果它的长度不是准确的块大小,可能会被截断或者使用 0 进行填充。对于没有该参数的两个函数,默认全部使用 0 填充。
接下来演示使用过程。技术栈springboot mybatis。
1.安装pgcrypto 模块
对于 Windows 和 macOS,默认安装已经包含了扩展模块。我们只需要执行以下语句在当前数据库中安装 pgcrypto 模块:
CREATE EXTENSION pgcrypto;
此后,便可使用encrypt函数和decrypt函数。
2.mybatis的xml文件中insert语句中做字段加密
<insert id="insertUserInfo" keyProperty="userId" parameterType="UserInfo"
useGeneratedKeys="true">
insert into travel_fly.user_info
(username,password,create_time,last_update_time,domain_username)
values(
#{username,jdbcType=VARCHAR},
Here we use domain username as secret key.
Aes is the encryption algorithm. -->
encrypt(#{password,jdbcType=VARCHAR}::bytea,#{domainUsername}::bytea,'aes'),
current_timestamp,
current_timestamp,
#{domainUsername,jdbcType=VARCHAR}
)
</insert>
3. mybatis的xml文件中select语句中做字段解密。
<select id="selectAllUserInfo" resultMap="userInfoModel">
select user_id,
username,
convert_from(decrypt(password::bytea,domain_username::bytea,'aes'),'SQL_ASCII') password,
create_time,
last_update_time,
domain_username
from travel_fly.user_info
</select>
注意:加密解密函数接受的前两个参数要求是bytea二进制类型,所以使用::bytea做了类型转换。这里使用了当前登录用户的domainUsername字段作为密钥
另外对函数convert_from(string bytea, src_encoding name)做简单说明。
官方文档:Convert string to the database encoding. The original encoding is specified by src_encoding. The string must be valid in this encoding. 转换字符串编码,自己要指定源编码,目标编码默认为数据库指定编码,
例子:select convert_from('\316\322\312\307pmars','GBK'); = "我是pmars"
SQL_ASCII是postgre数据库的默认编码格式。
注意:发现以上在select和insert块中的加粗的加密解密语句,在postgre版本13下报错,无法识别为函数,但是版本14就好用了。