您的位置:  首页 > 技术 > 数据库 > 正文

openGauss数据库源码解析系列文章—— 密态等值查询技术详解(上)

2022-06-30 15:00 https://my.oschina.net/gaussdb/blog/5547352 Gauss松鼠会 次阅读 条评论

风吹麦浪,当收割机又一次奔跑在广阔的原野上,高考结束了。6月,既是高考季,又是毕业季。有一群人变成了大学生,而又有一群人要初入职场。职场人来分享一点个人经历。作为一名IT人,周围的同事的专业主要是计算机、软件、通信等,还有一些物理、电子、材料等其他专业,大厂招聘的时候对学历有一些要求,专业反而没有考公限定的那么严格。有些公司会有导师机制,比如菊厂,一名好的导师会让你迅速熟悉工作环境、项目内容、公司文化,还会带你上分带你聚餐。而且大厂也会有更完善的培训、学习平台让你在技术领域快速成长。当然,最重要的是自己需要有一个Stay hungry ,Stay Foolish的心。祝愿大家保持初心,乘风破浪。

目录

什么是全密态数据库

密态等值查询有哪些能力

openGauss密态数据库加密步骤和语法


 

什么是全密态数据库

除了传统的数据存储加密和数据脱敏等数据保护技术外,openGauss从1.1.0版本开始支持了一种全新的数据全生命周期保护方案:全密态数据库机制。在这种机制下数据在客户端就被加密,从客户端传输到数据库内核,到在内核中完成查询运算,到返回结果给客户端,数据始终处于加密状态,而数据加解密所需的密钥则由用户持有;从而实现了数据拥有者和数据处理者的数据权属分离,有效规避由内鬼和不可信第三方等威胁造成的数据泄漏风险。

密态等值查询有哪些能力

本小节重点介绍全密态数据库的第一阶段能力——密态等值查询。与非加密数据库相比,密态等值查询主要提供以下能力。
(1) 数据加密:openGauss通过客户端驱动加密敏感数据,保证敏感数据明文不在除客户端驱动外的地方存在。遵循密钥分级原则将密钥分为数据加密密钥和密钥加密密钥,客户端驱动仅需要妥善保管密钥加密密钥即可保证只有自己才拥有解密数据密文的能力。
(2) 数据检索:openGauss支持在用户无感知的情况下,为其提供对数据库密文进行等值检索的能力。在数据加密阶段,openGauss会将与加密相关的元数据存储在系统表中,当处理敏感数据时,客户端会自动检索加密相关元数据并对数据进行加解密。
openGauss新增数据加解密表语法,通过采用驱动层过滤技术,在客户端的加密驱动中集成了SQL语法解析、密钥管理和敏感数据加解密等模块来处理相关语法。加密驱动源码流程如图所示。

用户执行SQL查询语句时,通过Pqexec函数执行SQL语句,SQL语句在发送之前首先进入run_pre_query函数函数,通过前端解析器解析涉及密态的语法。然后在run_pre_statement函数中通过分类器对语法标签进行识别,进入对应语法的处理逻辑。在不同的处理逻辑函数中,查找出要替换的数据参数,并存储在结构体StatementData中,数据结构如图9-38所示。最后通过replace_raw_values函数重构SQL语句,将其发送给服务端。在PqgetResult函数接收到从服务端返回的数据时,若是加密数据类型,则用deprocess_value函数对加密数据进行解密。接收完数据后还需要在run_post_query函数中刷新相应的缓存。

 openGauss密态数据库采用列级加密,用户在创建加密表的时候需要指定加密列的列加密密钥(Column Encryption Key,CEK)和加密类型,以确定该数据列以何种方式进行加密。同时,在创建表前,应该先创建客户端主密钥(client master key,CMK)。

openGauss密态数据库加密步骤和语法

整个加密步骤和语法可简化为如下3个阶段:创建客户端密钥CMK、创建列加密密钥CEK和创建加密表。下面将结合一个具体示例对密态等值查询特性进行详细介绍。密态等值查询示例如下。

(1) 创建CMK客户端主密钥。

CREATE CLIENT MASTER KEY cmk_1 WITH (KEY_STORE = LOCALKMS , KEY_PATH = "kms_1" , ALGORITHM = RSA_2048);

(2) 创建CEK列加密密钥。

CREATE COLUMN ENCRYPTION KEY cek_1 WITH VALUES (CLIENT_MASTER_KEY = cmk_1, ALGORITHM = AEAD_AES_256_CBC_HMAC_SHA256);

(3) 创建加密表。

CREATE TABLE creditcard_info (id_number int, name text encrypted with (column_encryption_key = cek_1, encryption_type = DETERMINISTIC), gender varchar(10) encrypted with (column_encryption_key = cek_1, encryption_type = DETERMINISTIC), salary float4 encrypted with (column_encryption_key = cek_1, encryption_type = DETERMINISTIC),credit_card varchar(19) encrypted with (column_encryption_key = cek_1, encryption_type = DETERMINISTIC));

如示例所示,首先使用“CREATE CLIENT MASTER KEY”语法创建客户端主密钥,其所涉及的语法结构定义如下:

/*  保存创建客户端主密钥的语法信息  */
typedef struct CreateClientLogicGlobal {
    NodeTag type;
    List *global_key_name;         /*  全密态数据库主密钥名称  */
    List *global_setting_params;  /*  全密态数据库主密钥参数,每一个元素是一个ClientLogicGlobalparam  */
} CreateClientLogicGlobal;

/*  保存客户端主密钥参数信息  */
typedef struct ClientLogicGlobalParam {
    NodeTag type;
    ClientLogicGlobalProperty key;  /*  键  */
    char *value;                       /*  值  */
    unsigned int len;                 /*  值长度  */
    int location;                     /*  位置标记  */
} ClientLogicGlobalParam;

/*  保存客户端主密钥参数的key的枚举类型 */
typedef enum class ClientLogicGlobalProperty {
    CLIENT_GLOBAL_FUNCTION,  /*  默认为encryption  */
    CMK_KEY_STORE,             /*  目前仅支持localkms  */
    CMK_KEY_PATH,              /*  密钥存储路径  */
    CMK_ALGORITHM              /*  指定加密CEK的算法  */
} ClientLogicGlobalProperty;
CREATE CLIENT MASTER KEY cmk_1 WITH (KEY_STORE = LOCALKMS , KEY_PATH = "kms_1" , ALGORITHM = RSA_2048);

上面命令的参数说明为:
(1) KEY_STORE:指定管理CMK的组件或工具;目前仅支持localkms模式。
(2) KEY_PATH:一个KEY_STORE中存储了多个CMK,而KEY_PATH用于唯一标识CMK。
(3) ALGORITHM:CMK被用于加密CEK,该参数指定加密CEK的算法,即指定CMK的密钥类型。
客户端主密钥创建语法本质上是将CMK的元信息解析并保存在CreateClientLogicGlobal结构体中。其中global_key_name是密钥名称,global_setting_params是一个List结构,每个节点是一个ClientLogicGlobalParam结构,以键值的形式保存着密钥的信息。客户端先通过解析器“fe_raw_parser()”解析为CreateClientLogicGlobal结构体,对其参数进行校验并发送查询语句到服务端;服务端解析为CreateClientLogicGlobal结构体并检查用户namespace等权限,CMK元信息保存在系统表中。创建CMK的总体流程如图所示。

 有了主密钥CMK,可以基于此创建CEK,下面将对CREATE COLUMN ENCRYPTION KEY语句所涉及的语法结构定义进行逐一介绍。
CREATE COLUMN ENCRYPTION KEY语法相关数据结构:

/*  保存创建列加密密钥的语法信息  */
typedef struct CreateClientLogicColumn {
    NodeTag type;
    List *column_key_name;        /*  列加密密钥名称  */
    List *column_setting_params; /*  列加密密钥参数  */
} CreateClientLogicColumn;

/*  保存列加密密钥参数,保存在CreateClientLogicColumn的column_setting_params中  */
typedef struct ClientLogicColumnParam {
    NodeTag type;
    ClientLogicColumnProperty key;
    char *value;
    unsigned int len;
    List *qualname;
    int location;
} ClientLogicColumnParam;

/*  保存列加密密钥参数的key的枚举类型  */
typedef enum class ClientLogicColumnProperty {
    CLIENT_GLOBAL_SETTING,    /*  加密CEK的CMK  */
    CEK_ALGORITHM,             /*  加密用户数据的算法  */
    CEK_EXPECTED_VALUE,       /*  CEK密钥明文,可选参数  */
    COLUMN_COLUMN_FUNCTION,  /*  默认为encryption  */
} ClientLogicColumnProperty;
CREATE COLUMN ENCRYPTION KEY cek_1 WITH VALUES (CLIENT_MASTER_KEY = cmk_1, ALGORITHM = AEAD_AES_256_CBC_HMAC_SHA256);

上面命令的参数说明为:
(1) CLIENT_MASTER_KEY:指定用于加密CEK的CMK对象。
(2) ALGORITHM:CEK被用于加密用户数据,该参数指定加密用户数据的算法,即指定CEK的密钥类型。
(3) ENCRYPTED_VALUE:列加密密钥的明文,默认随机生成,也可由用户指定,用户指定时密钥长度范围为28~256位。
后续再继续分享如何创建列加密密钥CEK和创建加密表。

 

活动地址:毕业季·进击的技术er

展开阅读全文
  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接