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);
至此完成解密过程。