暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

AntDB-S用户操作指南(4):加密解密

关耳 2023-09-27
234


本系统使用pgcrypto插件进行字段加密,是客户端加密的一种手段。

pgcrypto 提供了两类加密算法:单向加密和双向加密。

单向加密属于不可逆加密,无法根据密文解密出明文,适用于数据的验证,例如登录密码验证。常用的单向加密算法有 MD5、SHA、HMAC 等。

双向加密属于可逆加密,根据密文和密钥可解密出明文,适用于数据的安全传输,例如电子支付、数字签名等。常用的双向加密算法有 AES、DES、RSA、ECC 等。

注意:数据库的编译选项需要加—with-open-ssl。

安装

CREATE EXTENSION pgcrypto;

单向加密

单向加密又称为不可逆加密,即生成密文无法反解的一种加密方式;

  • 通用哈希函数:相同密码加密结果一样。

digest()函数可以根据不同的算法生成数据的二进制哈希值,语法如下:

digest(data text, type text) returns bytea

digest(data bytea, type text) returns bytea

其中,data 是原始数据;type 是加密算法,包括 md5、sha1、sha224、sha256、sha384 以及 sha512;函数的返回结果为二进制字符串。

举例:

CREATE TABLE users (

id SERIAL PRIMARY KEY,

username varchar(20) NOT NULL UNIQUE,

password text NOT NULL

);

INSERT INTO users(username, password)

VALUES ('tony', encode(digest('123456','md5'), 'hex'));

INSERT INTO users(username, password)

VALUES ('anne', encode(digest('123456','md5'), 'hex'));

SELECT * FROM users;

postgres=# SELECT * FROM users;

id | username | password

----+----------+----------------------------------

1 | tony | e10adc3949ba59abbe56e057f20f883e

2 | anne | e10adc3949ba59abbe56e057f20f883e

(2 rows)

  • 密码哈希函数:

crypt() 和 gen_salt() 函数专用于密码加密,其中 crypt() 用于加密数据,gen_salt() 用于生成 salt(加盐)

它们使用了一个随机值(称为盐值),因此密码的用户加密后的密码不同。这也可以针对破解算法提供一种额外的安全保护

crypt() 函数的语法如下:

crypt(password text, salt text) returns text

该函数返回 password 字符串 crypt(3) 格式的哈希值,salt 参数由 gen_salt() 函数生成。例如:

CREATE TABLE testusers(username varchar(100) PRIMARY KEY, cryptpwd text, md5pwd text);

INSERT INTO testusers(username, cryptpwd, md5pwd)

VALUES ('robby', crypt('test', gen_salt('md5')), md5('test')),

('artoo', crypt('test',gen_salt('md5')), md5('test'));

SELECT username, cryptpwd, md5pwd

FROM testusers;

双向加密

双向加密又称为可逆加密,即生成密文后,在需要的时候可以反解为明文;

2.1原始加密函数

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

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

data 是需要加密的数据;type 用于指定加密方法

举例:

create table user_test(username varchar(20),password varchar(60));

insert into user_test values('miya',encode(encrypt('123','abc','aes'),'hex'));

INSERT 0 1

insert into user_test values('kimi',encode(encrypt('456','abc','aes'),'hex'));

select * from user_test;

postgres=# select * from user_test;

username | password

----------+----------------------------------

miya | a4bf9afce727dbd2805393a86a24096c

kimi | 84279efc7942ca7364abcce78db90b0b

(2 rows)

可以看到解密后,能够看到原始的密码:

postgres=# select convert_from(decrypt(decode(password,'hex'),'abc','aes'),'SQL_ASCII') as real_pw,* from user_test;

real_pw | username | password

---------+----------+----------------------------------

123 | miya | a4bf9afce727dbd2805393a86a24096c

456 | kimi | 84279efc7942ca7364abcce78db90b0b

(2 rows)

2.2PGP加密

PGP 加密函数实现了 OpenPGP(RFC 4880)标准中的加密功能,包括对称密钥加密(私钥加密)和非对称密钥加密(公钥加密)。

  • 对称加密解密:加密及解密都使用相同的密钥,也叫单秘钥加密;
  • 非对称加密解密:用公钥加密,用私钥解密;
2.2.1非对称加密

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

其中,data 是要加密的数据;key 是 PGP 公钥,如果传入一个私钥将会返回错误;options 参数用于设置选项,参考下文。

pgp_pub_decrypt()函数用于解密 PGP 公共密钥加密后的消息:

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 参数中指定密码;如果没有使用密码保护,想要指定 options 参数时必须指定一个空的 psw。

pgp_key_id()函数用于提取 PGP 公钥或者私钥的密钥 ID;如果传入一个加密后的消息,将会返回加密该消息使用的密钥 ID:

pgp_key_id(bytea) returns text

该函数可能返回 2 个特殊的密钥 ID:

  • SYMKEY,表明该消息使用对称密钥进行加密。
  • ANYKEY,表明该消息使用公共密钥进行加密,但是密钥 ID 已经被删除。这也意味着你需要尝试所有的私钥,查找可以解密该消息的私钥。pgcrypto 不会产生这种加密消息。

armor()函数用于将二进制数据转换为 PGP ASCII-armor 格式,相当于 Base64 加上 CRC 以及额外的格式化。dearmor()函数用于执行相反的转换:

armor(data bytea [ , keys text[], values text[] ]) returns text

dearmor(data text) returns bytea

其中,data 是需要转换的数据;如果指定了 keys 和 values 数值,每个 key/value 对都会生成一个 armor header 并添加到编码格式中;两个数组都是一维数组,长度相同,并且不能包含非 ASCII 字符。

下面举例说明使用步骤:

  1. 生成一个pgp秘钥对

gpg --gen-key

  1. 然后可以使用 gpg --list-secret-keys 查看创建的密钥:

[mass2@host227 ~]$ gpg --list-secret-keys

/data/mass2/.gnupg/secring.gpg

------------------------------

sec 2048R/FB7A4926 2022-08-16

uid mass2 <mass3@asininfo.com>

ssb 2048R/89A5DEEC 2022-08-16

sec是私钥,ssb是公钥。

  1. 将公钥和私钥转换为 ASCII-armor 格式:

gpg -a --export 4A973FF0 > public.key

gpg -a --export-secret-keys 92A1CA53 > secret.key

其中,-a 表示 armour 格式;默认的密钥是二进制格式,不方便处理。在使用 pgcrypto PGP 加密/解密函数时需要利用 dearmor() 函数将密钥转换为二进制再传入参数;如果可以直接处理二进制数据,也可以去掉 -a 选项。

这里为了方便后面使用,将秘钥放在表中使用。

create table keys(v text);

create table seckeys(v text);

insert into keys values(' public.key中的内容,此处省略');

insert into seckeys values (' secret.key 中的内容,此处省略');

  1. 创建表

CREATE TABLE users (

id SERIAL PRIMARY KEY,

username varchar(20) NOT NULL UNIQUE,

card bytea);

将信用卡号加密存储

insert into users select 1, 'tony', pgp_pub_encrypt('62220001', dearmor(keys.v)) from keys;

解密信用卡卡号:

postgres=# SELECT pgp_pub_decrypt(card, dearmor(v), 'areyouok')

postgres-# FROM users,seckeys;

pgp_pub_decrypt

-----------------

62220001

(1 row)

注意:这里的‘areyouok’是生成gpg秘钥时设置的密码。

2.2.2对称加密

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

其中,data 是要加密的数据;psw 是 PGP 对称密钥;options 参数用于设置选项,参考下文。

pgp_sym_decrypt()函数用于解密 PGP 对称密钥加密后的消息:

pgp_sym_decrypt(msg bytea, psw text [, options text ]) returns text
pgp_sym_decrypt_bytea(msg bytea, psw text [, options text ]) returns bytea

其中,msg 是要解密的消息;psw 是 PGP 对称密钥。

举例:

加密:

postgres=# select pgp_sym_encrypt('20014892392', 'this is password', 'cipher-algo=aes256, compress-algo=2');

pgp_sym_encrypt

------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------

\xc30d04090302020575e08adf55137bd24701926549b6345fd40a0200a835e27133cb9aa959792018158cb6544f6acea5146631314555a3f

e3aa3feefc228e01486289d91a92e32910edaf16b2a4558072af21fff309c71ca

(1 row)

解密:

postgres=# select pgp_sym_decrypt('\xc30d04090302020575e08adf55137bd24701926549b6345fd40a0200a835e27133cb9aa959792018158cb6544f6acea5146631314555a3fe3aa3feefc228e01486289d91a92e32910edaf16b2a4558072af21fff309c71ca', 'this is password');

pgp_sym_decrypt

-----------------

20014892392

(1 row)

关于AntDB数据库

AntDB数据库始于2008年,在运营商的核心系统上,为全国24个省份的10亿多用户提供在线服务,具备高性能、弹性扩展、高可靠等产品特性,峰值每秒可处理百万笔通信核心交易,保障系统持续稳定运行近十年,并在通信、金融、交通、能源、物联网等行业成功商用落地。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论