openGauss源码解析(206)

openGauss源码解析:安全管理源码解析(17)

2. 数据解密接口

openGauss提供的解密接口函数为:

gs_decrypt_aes128 (decryptstr, keystr)

以keystr为用户加密密钥对decryptstr加密字符串进行解密,返回解密后的字符串。解密使用的keystr必须保证与加密时使用的keystr一致才能正常解密。keystr不得为空。

使用示例如下。

opengauss=# SELECT gs_decrypt_aes128(name,'gaussDB123') FROM student005;

gs_decrypt_aes128

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

zhangsan

(1 row)

解密接口函数是通过函数gs_decrypt_aes128实现的,其代码源文件为:“builtins.h”和“cipherfn.cpp”。

该函数是一个openGauss的存储过程函数,通过用户输入的密文(注明文加密生成的密文)和密钥进行数据的解密操作。

主要流程如图9-30所示。

图9-30 数据解密流程

数据解密的代码如下逐个部分介绍。

通过存储过程的入参解析出需要解密的密文和密钥,并进行脱敏的decode操作。相关代码如下:

decodetext = (GS_UCHAR*)(text_to_cstring(PG_GETARG_TEXT_P(0)));

key = (GS_UCHAR*)(text_to_cstring(PG_GETARG_TEXT_P(1)));

keylen = strlen((const char*)key);

/*为解密操作去做密文解码 */

ciphertext = (GS_UCHAR*)(SEC_decodeBase64((char*)decodetext, &decodetextlen));

if ((ciphertext == NULL) || (decodetextlen <= RANDOM_LEN)) {

if (ciphertext != NULL) {

OPENSSL_free(ciphertext);

ciphertext = NULL;

}

errorno = memset_s(decodetext, decodetextlen, '\0', decodetextlen);

securec_check(errorno, "\0", "\0");

pfree_ext(decodetext);

errorno = memset_s(key, keylen, '\0', keylen);

securec_check(errorno, "\0", "\0");

pfree_ext(key);

ereport(ERROR,

(errcode(ERRCODE_EXTERNAL_ROUTINE_INVOCATION_EXCEPTION),

errmsg("Decode the cipher text failed or the ciphertext is too short!")));

}

errorno = memset_s(decodetext, decodetextlen, '\0', decodetextlen);

securec_check(errorno, "\0", "\0");

pfree_ext(decodetext);

plaintext = (GS_UCHAR*)palloc(decodetextlen);

errorno = memset_s(plaintext, decodetextlen, '\0', decodetextlen);

securec_check(errorno, "\0", "\0");

开始将密文转换为明文过程。相关代码如下:

bool gs_decrypt_aes_speed(

GS_UCHAR* ciphertext, GS_UINT32 cipherlen, GS_UCHAR* key, GS_UCHAR* plaintext, GS_UINT32* plainlen)

……

将密文进行解码操作,分离密文和信息两个部分。相关代码如下:

bool aes128DecryptSpeed(GS_UCHAR* CipherText, GS_UINT32 CipherLen, GS_UCHAR* Key, GS_UCHAR* RandSalt,

GS_UCHAR* PlainText, GS_UINT32* PlainLen)

……

/*将密文分成,密文部分、AES向量部分和mac向量部分进行解密操作*/

GS_UINT32 cipherpartlen = CipherLen - RANDOM_LEN - MAC_LEN;

errorno = memcpy_s(aes_vector, RANDOM_LEN, CipherText + cipherpartlen, RANDOM_LEN);

securec_check_c(errorno, "", "");

errorno = memcpy_s(mac_text_saved, MAC_LEN, CipherText + cipherpartlen + RANDOM_LEN, MAC_LEN);

securec_check_c(errorno, "", "");

static THR_LOCAL GS_UINT32 usage_frequency[NUMBER_OF_SAVED_DERIVEKEYS] = {0};

/* insert_position是用来分隔两个不同的区域的usage_frequency */

static THR_LOCAL GS_UINT32 insert_position = NUMBER_OF_SAVED_DERIVEKEYS / 2;

/* 初始化usage_frequency */

if (usage_frequency[0] == 0 && usage_frequency[NUMBER_OF_SAVED_DERIVEKEYS - 1] == 0) {

for (GS_UINT32 i = 0; i < NUMBER_OF_SAVED_DERIVEKEYS; ++i)

usage_frequency[i] = i;

}

errorno = memcpy_s(user_key, RANDOM_LEN, Key, keylen);

securec_check_c(errorno, "\0", "\0");

if (keylen < RANDOM_LEN) {

errorno = memset_s(user_key + keylen, RANDOM_LEN - keylen, '\0', RANDOM_LEN - keylen);

securec_check_c(errorno, "\0", "\0");

}

/*按照使用频率进行顺序查找对应的派生向量*/

for (GS_UINT32 i = 0; i < NUMBER_OF_SAVED_DERIVEKEYS && !DERIVEKEY_FOUND; ++i) {

if (0 == memcmp(random_salt_used[usage_frequency[i]], RandSalt, RANDOM_LEN)) {

DERIVEKEY_FOUND = 1;

for (GS_UINT32 j = 0; j < RANDOM_LEN; ++j) {

GS_UCHAR mask = (char)random_salt_used[usage_frequency[i]][j];

if (user_key[j] == ((char)user_input_used[usage_frequency[i]][j] ^ (char)mask)) {

decrypt_key[j] = ((char)derive_vector_used[usage_frequency[i]][j] ^ (char)mask);

mac_key[j] = ((char)mac_vector_used[usage_frequency[i]][j] ^ (char)mask);

} else {

DERIVEKEY_FOUND = 0;

}

}

if (i > 0 && i < NUMBER_OF_SAVED_DERIVEKEYS / 2 && DERIVEKEY_FOUND) {

GS_UINT32 temp = usage_frequency[i - 1];

usage_frequency[i - 1] = usage_frequency[i];

usage_frequency[i] = temp;

} else if (i >= NUMBER_OF_SAVED_DERIVEKEYS / 2 && DERIVEKEY_FOUND) {

GS_UINT32 temp = usage_frequency[NUMBER_OF_SAVED_DERIVEKEYS / 2 - 1];

usage_frequency[NUMBER_OF_SAVED_DERIVEKEYS / 2 - 1] = usage_frequency[i];

usage_frequency[i] = temp;

} else {

;

}

}

}

/* 如果没有派生向量存在,就生成新的派生key */

if (!DERIVEKEY_FOUND) {

retval = PKCS5_PBKDF2_HMAC(

(char*)Key, keylen, RandSalt, RANDOM_LEN, ITERATE_TIMES, (EVP_MD*)EVP_sha256(), RANDOM_LEN, decrypt_key);

if (!retval) {

……

return false;

}

retval = PKCS5_PBKDF2_HMAC((char*)user_key,

RANDOM_LEN,

RandSalt,

RANDOM_LEN,

MAC_ITERATE_TIMES,

(EVP_MD*)EVP_sha256(),

RANDOM_LEN,

mac_key);

if (!retval) {

……

return false;

}

errorno = memcpy_s(random_salt_used[usage_frequency[insert_position]], RANDOM_LEN, RandSalt, RANDOM_LEN);

securec_check_c(errorno, "\0", "\0");

for (GS_UINT32 j = 0; j < RANDOM_LEN; ++j) {

GS_UCHAR mask = random_salt_used[usage_frequency[insert_position]][j];

user_input_used[usage_frequency[insert_position]][j] = ((char)user_key[j] ^ (char)mask);

derive_vector_used[usage_frequency[insert_position]][j] = ((char)decrypt_key[j] ^ (char)mask);

mac_vector_used[usage_frequency[insert_position]][j] = ((char)mac_key[j] ^ (char)mask);

}

insert_position = (insert_position + 1) % (NUMBER_OF_SAVED_DERIVEKEYS / 2) + NUMBER_OF_SAVED_DERIVEKEYS / 2;

}

使用派生密钥去解密密文。相关代码如下:

GS_UINT32 CRYPT_decrypt(GS_UINT32 ulAlgId, const GS_UCHAR* pucKey, GS_UINT32 ulKeyLen, const GS_UCHAR* pucIV,

GS_UINT32 ulIVLen, GS_UCHAR* pucCipherText, GS_UINT32 ulCLen, GS_UCHAR* pucPlainText, GS_UINT32* pulPLen)

……

cipher = get_evp_cipher_by_id(ulAlgId);

if (cipher == NULL) {

(void)fprintf(stderr, ("invalid ulAlgType for cipher,please check it!\n"));

return 1;

}

ctx = EVP_CIPHER_CTX_new();

if (ctx == NULL) {

(void)fprintf(stderr, ("ERROR in EVP_CIPHER_CTX_new:\n"));

return 1;

}

EVP_CipherInit_ex(ctx, cipher, NULL, pucKey, pucIV, 0);

EVP_CIPHER_CTX_set_padding(ctx, 0);

if (!EVP_DecryptUpdate(ctx, pucPlainText, &dec_num, pucCipherText, ulCLen)) {

(void)fprintf(stderr, ("ERROR in EVP_DecryptUpdate\n"));

goto err;

}

*pulPLen = dec_num;

if (!EVP_DecryptFinal(ctx, pucPlainText + dec_num, &dec_num)) {

(void)fprintf(stderr, ("ERROR in EVP_DecryptFinal\n"));

goto err;

}

*pulPLen += dec_num;

/* padding bytes of the last block need to be removed */

blocksize = EVP_CIPHER_CTX_block_size(ctx);

至此完成解密过程。

posted @ 2024-05-07 09:25  openGauss-bot  阅读(6)  评论(0编辑  收藏  举报