blob: bf6777a5c8819c123b9e82367a71c606a1adfdd5 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "util/encryption_util.h"
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/ossl_typ.h>
#include <sys/types.h>
#include <algorithm>
#include <cstring>
#include <string>
#include <unordered_map>
namespace doris {
static const int ENCRYPTION_MAX_KEY_LENGTH = 256;
const EVP_CIPHER* get_evp_type(const EncryptionMode mode) {
switch (mode) {
case EncryptionMode::AES_128_ECB:
return EVP_aes_128_ecb();
case EncryptionMode::AES_128_CBC:
return EVP_aes_128_cbc();
case EncryptionMode::AES_128_CFB:
return EVP_aes_128_cfb();
case EncryptionMode::AES_128_CFB1:
return EVP_aes_128_cfb1();
case EncryptionMode::AES_128_CFB8:
return EVP_aes_128_cfb8();
case EncryptionMode::AES_128_CFB128:
return EVP_aes_128_cfb128();
case EncryptionMode::AES_128_CTR:
return EVP_aes_128_ctr();
case EncryptionMode::AES_128_OFB:
return EVP_aes_128_ofb();
case EncryptionMode::AES_192_ECB:
return EVP_aes_192_ecb();
case EncryptionMode::AES_192_CBC:
return EVP_aes_192_cbc();
case EncryptionMode::AES_192_CFB:
return EVP_aes_192_cfb();
case EncryptionMode::AES_192_CFB1:
return EVP_aes_192_cfb1();
case EncryptionMode::AES_192_CFB8:
return EVP_aes_192_cfb8();
case EncryptionMode::AES_192_CFB128:
return EVP_aes_192_cfb128();
case EncryptionMode::AES_192_CTR:
return EVP_aes_192_ctr();
case EncryptionMode::AES_192_OFB:
return EVP_aes_192_ofb();
case EncryptionMode::AES_256_ECB:
return EVP_aes_256_ecb();
case EncryptionMode::AES_256_CBC:
return EVP_aes_256_cbc();
case EncryptionMode::AES_256_CFB:
return EVP_aes_256_cfb();
case EncryptionMode::AES_256_CFB1:
return EVP_aes_256_cfb1();
case EncryptionMode::AES_256_CFB8:
return EVP_aes_256_cfb8();
case EncryptionMode::AES_256_CFB128:
return EVP_aes_256_cfb128();
case EncryptionMode::AES_256_CTR:
return EVP_aes_256_ctr();
case EncryptionMode::AES_256_OFB:
return EVP_aes_256_ofb();
case EncryptionMode::AES_128_GCM:
return EVP_aes_128_gcm();
case EncryptionMode::AES_192_GCM:
return EVP_aes_192_gcm();
case EncryptionMode::AES_256_GCM:
return EVP_aes_256_gcm();
case EncryptionMode::SM4_128_CBC:
return EVP_sm4_cbc();
case EncryptionMode::SM4_128_ECB:
return EVP_sm4_ecb();
case EncryptionMode::SM4_128_CFB128:
return EVP_sm4_cfb128();
case EncryptionMode::SM4_128_OFB:
return EVP_sm4_ofb();
case EncryptionMode::SM4_128_CTR:
return EVP_sm4_ctr();
default:
return nullptr;
}
}
static std::unordered_map<EncryptionMode, uint> mode_key_sizes = {
{EncryptionMode::AES_128_ECB, 128}, {EncryptionMode::AES_192_ECB, 192},
{EncryptionMode::AES_256_ECB, 256}, {EncryptionMode::AES_128_CBC, 128},
{EncryptionMode::AES_192_CBC, 192}, {EncryptionMode::AES_256_CBC, 256},
{EncryptionMode::AES_128_CFB, 128}, {EncryptionMode::AES_192_CFB, 192},
{EncryptionMode::AES_256_CFB, 256}, {EncryptionMode::AES_128_CFB1, 128},
{EncryptionMode::AES_192_CFB1, 192}, {EncryptionMode::AES_256_CFB1, 256},
{EncryptionMode::AES_128_CFB8, 128}, {EncryptionMode::AES_192_CFB8, 192},
{EncryptionMode::AES_256_CFB8, 256}, {EncryptionMode::AES_128_CFB128, 128},
{EncryptionMode::AES_192_CFB128, 192}, {EncryptionMode::AES_256_CFB128, 256},
{EncryptionMode::AES_128_CTR, 128}, {EncryptionMode::AES_192_CTR, 192},
{EncryptionMode::AES_256_CTR, 256}, {EncryptionMode::AES_128_OFB, 128},
{EncryptionMode::AES_192_OFB, 192}, {EncryptionMode::AES_256_OFB, 256},
{EncryptionMode::AES_128_GCM, 128}, {EncryptionMode::AES_192_GCM, 192},
{EncryptionMode::AES_256_GCM, 256},
{EncryptionMode::SM4_128_ECB, 128}, {EncryptionMode::SM4_128_CBC, 128},
{EncryptionMode::SM4_128_CFB128, 128}, {EncryptionMode::SM4_128_OFB, 128},
{EncryptionMode::SM4_128_CTR, 128}};
static void create_key(const unsigned char* origin_key, uint32_t key_length, uint8_t* encrypt_key,
EncryptionMode mode) {
const uint key_size = mode_key_sizes[mode] / 8;
uint8_t* origin_key_end = ((uint8_t*)origin_key) + key_length; /* origin key boundary*/
uint8_t* encrypt_key_end; /* encrypt key boundary */
encrypt_key_end = encrypt_key + key_size;
std::memset(encrypt_key, 0, key_size); /* initialize key */
uint8_t* ptr; /* Start of the encrypt key*/
uint8_t* origin_ptr; /* Start of the origin key */
for (ptr = encrypt_key, origin_ptr = (uint8_t*)origin_key; origin_ptr < origin_key_end;
ptr++, origin_ptr++) {
if (ptr == encrypt_key_end) {
/* loop over origin key until we used all key */
ptr = encrypt_key;
}
*ptr ^= *origin_ptr;
}
}
static int do_encrypt(EVP_CIPHER_CTX* cipher_ctx, const EVP_CIPHER* cipher,
const unsigned char* source, uint32_t source_length,
const unsigned char* encrypt_key, const unsigned char* iv, bool padding,
unsigned char* encrypt, int* length_ptr) {
int ret = EVP_EncryptInit(cipher_ctx, cipher, encrypt_key, iv);
if (ret == 0) {
return ret;
}
ret = EVP_CIPHER_CTX_set_padding(cipher_ctx, padding);
if (ret == 0) {
return ret;
}
int u_len = 0;
ret = EVP_EncryptUpdate(cipher_ctx, encrypt, &u_len, source, source_length);
if (ret == 0) {
return ret;
}
int f_len = 0;
ret = EVP_EncryptFinal(cipher_ctx, encrypt + u_len, &f_len);
*length_ptr = u_len + f_len;
return ret;
}
static int do_gcm_encrypt(EVP_CIPHER_CTX* cipher_ctx, const EVP_CIPHER* cipher,
const unsigned char* source, uint32_t source_length,
const unsigned char* encrypt_key, const unsigned char* iv, int iv_length,
unsigned char* encrypt, int* length_ptr, const unsigned char* aad,
uint32_t aad_length) {
int ret = EVP_EncryptInit_ex(cipher_ctx, cipher, nullptr, nullptr, nullptr);
if (ret != 1) {
return ret;
}
ret = EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, iv_length, nullptr);
if (ret != 1) {
return ret;
}
ret = EVP_EncryptInit_ex(cipher_ctx, nullptr, nullptr, encrypt_key, iv);
if (ret != 1) {
return ret;
}
if (aad) {
int tmp_len = 0;
ret = EVP_EncryptUpdate(cipher_ctx, nullptr, &tmp_len, aad, aad_length);
if (ret != 1) {
return ret;
}
}
std::memcpy(encrypt, iv, iv_length);
encrypt += iv_length;
int u_len = 0;
ret = EVP_EncryptUpdate(cipher_ctx, encrypt, &u_len, source, source_length);
if (ret != 1) {
return ret;
}
encrypt += u_len;
int f_len = 0;
ret = EVP_EncryptFinal_ex(cipher_ctx, encrypt, &f_len);
if (ret != 1) {
return ret;
}
encrypt += f_len;
ret = EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_GCM_GET_TAG, EncryptionUtil::GCM_TAG_SIZE,
encrypt);
*length_ptr = iv_length + u_len + f_len + EncryptionUtil::GCM_TAG_SIZE;
return ret;
}
int EncryptionUtil::encrypt(EncryptionMode mode, const unsigned char* source,
uint32_t source_length, const unsigned char* key, uint32_t key_length,
const char* iv_str, int iv_input_length, bool padding,
unsigned char* encrypt, const unsigned char* aad, uint32_t aad_length) {
const EVP_CIPHER* cipher = get_evp_type(mode);
/* The encrypt key to be used for encryption */
unsigned char encrypt_key[ENCRYPTION_MAX_KEY_LENGTH / 8];
create_key(key, key_length, encrypt_key, mode);
int iv_length = EVP_CIPHER_iv_length(cipher);
if (cipher == nullptr || (iv_length > 0 && !iv_str)) {
return AES_BAD_DATA;
}
char* init_vec = nullptr;
std::string iv_default("DORISDORISDORIS_");
if (iv_str) {
init_vec = &iv_default[0];
memcpy(init_vec, iv_str, std::min(iv_input_length, EVP_MAX_IV_LENGTH));
init_vec[iv_length] = '\0';
}
EVP_CIPHER_CTX* cipher_ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_reset(cipher_ctx);
int length = 0;
int ret = 0;
if (is_gcm_mode(mode)) {
ret = do_gcm_encrypt(cipher_ctx, cipher, source, source_length, encrypt_key,
reinterpret_cast<unsigned char*>(init_vec), iv_length, encrypt,
&length, aad, aad_length);
} else {
ret = do_encrypt(cipher_ctx, cipher, source, source_length, encrypt_key,
reinterpret_cast<unsigned char*>(init_vec), padding, encrypt, &length);
}
EVP_CIPHER_CTX_free(cipher_ctx);
if (ret == 0) {
ERR_clear_error();
return AES_BAD_DATA;
} else {
return length;
}
}
static int do_decrypt(EVP_CIPHER_CTX* cipher_ctx, const EVP_CIPHER* cipher,
const unsigned char* encrypt, uint32_t encrypt_length,
const unsigned char* encrypt_key, const unsigned char* iv, bool padding,
unsigned char* decrypt_content, int* length_ptr) {
int ret = EVP_DecryptInit(cipher_ctx, cipher, encrypt_key, iv);
if (ret == 0) {
return ret;
}
ret = EVP_CIPHER_CTX_set_padding(cipher_ctx, padding);
if (ret == 0) {
return ret;
}
int u_len = 0;
ret = EVP_DecryptUpdate(cipher_ctx, decrypt_content, &u_len, encrypt, encrypt_length);
if (ret == 0) {
return ret;
}
int f_len = 0;
ret = EVP_DecryptFinal_ex(cipher_ctx, decrypt_content + u_len, &f_len);
*length_ptr = u_len + f_len;
return ret;
}
static int do_gcm_decrypt(EVP_CIPHER_CTX* cipher_ctx, const EVP_CIPHER* cipher,
const unsigned char* encrypt, uint32_t encrypt_length,
const unsigned char* encrypt_key, int iv_length,
unsigned char* decrypt_content, int* length_ptr, const unsigned char* aad,
uint32_t aad_length) {
if (encrypt_length < iv_length + EncryptionUtil::GCM_TAG_SIZE) {
return -1;
}
int ret = EVP_DecryptInit_ex(cipher_ctx, cipher, nullptr, nullptr, nullptr);
if (ret != 1) {
return ret;
}
ret = EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_GCM_SET_IVLEN, iv_length, nullptr);
if (ret != 1) {
return ret;
}
ret = EVP_DecryptInit_ex(cipher_ctx, nullptr, nullptr, encrypt_key, encrypt);
if (ret != 1) {
return ret;
}
encrypt += iv_length;
if (aad) {
int tmp_len = 0;
ret = EVP_DecryptUpdate(cipher_ctx, nullptr, &tmp_len, aad, aad_length);
if (ret != 1) {
return ret;
}
}
uint32_t real_encrypt_length = encrypt_length - iv_length - EncryptionUtil::GCM_TAG_SIZE;
int u_len = 0;
ret = EVP_DecryptUpdate(cipher_ctx, decrypt_content, &u_len, encrypt, real_encrypt_length);
if (ret != 1) {
return ret;
}
encrypt += real_encrypt_length;
decrypt_content += u_len;
void* tag = const_cast<void*>(reinterpret_cast<const void*>(encrypt));
ret = EVP_CIPHER_CTX_ctrl(cipher_ctx, EVP_CTRL_GCM_SET_TAG, EncryptionUtil::GCM_TAG_SIZE, tag);
if (ret != 1) {
return ret;
}
int f_len = 0;
ret = EVP_DecryptFinal_ex(cipher_ctx, decrypt_content, &f_len);
*length_ptr = u_len + f_len;
return ret;
}
int EncryptionUtil::decrypt(EncryptionMode mode, const unsigned char* encrypt,
uint32_t encrypt_length, const unsigned char* key, uint32_t key_length,
const char* iv_str, int iv_input_length, bool padding,
unsigned char* decrypt_content, const unsigned char* aad,
uint32_t aad_length) {
const EVP_CIPHER* cipher = get_evp_type(mode);
/* The encrypt key to be used for decryption */
unsigned char encrypt_key[ENCRYPTION_MAX_KEY_LENGTH / 8];
create_key(key, key_length, encrypt_key, mode);
int iv_length = EVP_CIPHER_iv_length(cipher);
if (cipher == nullptr || (iv_length > 0 && !iv_str)) {
return AES_BAD_DATA;
}
char* init_vec = nullptr;
std::string iv_default("DORISDORISDORIS_");
if (iv_str) {
init_vec = &iv_default[0];
memcpy(init_vec, iv_str, std::min(iv_input_length, EVP_MAX_IV_LENGTH));
init_vec[iv_length] = '\0';
}
EVP_CIPHER_CTX* cipher_ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_reset(cipher_ctx);
int length = 0;
int ret = 0;
if (is_gcm_mode(mode)) {
ret = do_gcm_decrypt(cipher_ctx, cipher, encrypt, encrypt_length, encrypt_key, iv_length,
decrypt_content, &length, aad, aad_length);
} else {
ret = do_decrypt(cipher_ctx, cipher, encrypt, encrypt_length, encrypt_key,
reinterpret_cast<unsigned char*>(init_vec), padding, decrypt_content,
&length);
}
EVP_CIPHER_CTX_free(cipher_ctx);
if (ret > 0) {
return length;
} else {
ERR_clear_error();
return AES_BAD_DATA;
}
}
} // namespace doris