703 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			703 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/**
 | 
						|
 * Copyright (c) 2021 OceanBase
 | 
						|
 * OceanBase CE is licensed under Mulan PubL v2.
 | 
						|
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 | 
						|
 * You may obtain a copy of Mulan PubL v2 at:
 | 
						|
 *          http://license.coscl.org.cn/MulanPubL-2.0
 | 
						|
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
						|
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
						|
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
						|
 * See the Mulan PubL v2 for more details.
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef OB_BUILD_TDE_SECURITY
 | 
						|
 | 
						|
#define USING_LOG_PREFIX SHARE
 | 
						|
#include "share/ob_encryption_util.h"
 | 
						|
#include <openssl/md4.h>
 | 
						|
#include <openssl/md5.h>
 | 
						|
#include <openssl/sha.h>
 | 
						|
#include "share/ob_encryption_struct.h"
 | 
						|
#include "lib/alloc/alloc_assist.h"
 | 
						|
#include "share/ob_errno.h"
 | 
						|
#include "lib/atomic/atomic128.h"
 | 
						|
#include "lib/string/ob_string.h"
 | 
						|
#include "lib/random/ob_random.h"
 | 
						|
#include "lib/utility/ob_macro_utils.h"
 | 
						|
#include "observer/ob_server_struct.h"
 | 
						|
#include "observer/omt/ob_tenant_config_mgr.h"
 | 
						|
 | 
						|
namespace oceanbase
 | 
						|
{
 | 
						|
using namespace common;
 | 
						|
namespace share
 | 
						|
{
 | 
						|
 | 
						|
int ObKeyGenerator::generate_encrypt_key(char *buf, int64_t len)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (len <= 0) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("the buf of len is invalid", K(ret));
 | 
						|
  } else if (!RAND_bytes((unsigned char*)buf, (int)len)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("failed to get a rand bytes");
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObKeyGenerator::generate_encrypt_key_char(char *buf, int64_t len)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  if (len <= 0) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("the buf of len is invalid", K(ret));
 | 
						|
  } else {
 | 
						|
    int i;
 | 
						|
    for (i = 0; i < len; ++i) {
 | 
						|
      switch (common::ObRandom::rand(0, 2)) {
 | 
						|
        case 1:
 | 
						|
        buf[i] = 'A' + common::ObRandom::rand(0, 25);
 | 
						|
        break;
 | 
						|
        case 2:
 | 
						|
        buf[i] = 'a' + common::ObRandom::rand(0, 25);
 | 
						|
        break;
 | 
						|
        default:
 | 
						|
        buf[i] = '0' + common::ObRandom::rand(0, 9);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
static const EVP_CIPHER *get_evp_cipher(const ObCipherOpMode mode)
 | 
						|
{
 | 
						|
  switch (mode)
 | 
						|
  {
 | 
						|
    case ob_aes_128_ecb:    return EVP_aes_128_ecb();
 | 
						|
    case ob_aes_128_cbc:    return EVP_aes_128_cbc();
 | 
						|
    case ob_aes_128_cfb1:   return EVP_aes_128_cfb1();
 | 
						|
    case ob_aes_128_cfb8:   return EVP_aes_128_cfb8();
 | 
						|
    case ob_aes_128_cfb128: return EVP_aes_128_cfb128();
 | 
						|
    case ob_aes_128_ofb:    return EVP_aes_128_ofb();
 | 
						|
    case ob_aes_192_ecb:    return EVP_aes_192_ecb();
 | 
						|
    case ob_aes_192_cbc:    return EVP_aes_192_cbc();
 | 
						|
    case ob_aes_192_cfb1:   return EVP_aes_192_cfb1();
 | 
						|
    case ob_aes_192_cfb8:   return EVP_aes_192_cfb8();
 | 
						|
    case ob_aes_192_cfb128: return EVP_aes_192_cfb128();
 | 
						|
    case ob_aes_192_ofb:    return EVP_aes_192_ofb();
 | 
						|
    case ob_aes_256_ecb:    return EVP_aes_256_ecb();
 | 
						|
    case ob_aes_256_cbc:    return EVP_aes_256_cbc();
 | 
						|
    case ob_aes_256_cfb1:   return EVP_aes_256_cfb1();
 | 
						|
    case ob_aes_256_cfb8:   return EVP_aes_256_cfb8();
 | 
						|
    case ob_aes_256_cfb128: return EVP_aes_256_cfb128();
 | 
						|
    case ob_aes_256_ofb:    return EVP_aes_256_ofb();
 | 
						|
    case ob_aes_128_gcm:    return EVP_aes_128_gcm();
 | 
						|
    case ob_aes_192_gcm:    return EVP_aes_192_gcm();
 | 
						|
    case ob_aes_256_gcm:    return EVP_aes_256_gcm();
 | 
						|
#ifdef OB_USE_BABASSL
 | 
						|
    case ob_sm4_mode:       return EVP_sm4_ctr();
 | 
						|
    case ob_sm4_cbc_mode:   return EVP_sm4_cbc();
 | 
						|
    case ob_sm4_cbc:        return EVP_sm4_cbc();
 | 
						|
    case ob_sm4_ecb:        return EVP_sm4_ecb();
 | 
						|
    case ob_sm4_ofb:        return EVP_sm4_ofb();
 | 
						|
    case ob_sm4_cfb128:     return EVP_sm4_cfb128();
 | 
						|
    case ob_sm4_ctr:        return EVP_sm4_ctr();
 | 
						|
    case ob_sm4_gcm:        return EVP_sm4_gcm();
 | 
						|
#endif
 | 
						|
    default: return NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int ObBlockCipher::get_key_length(const ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  int length = 0;
 | 
						|
  const EVP_CIPHER *cipher = get_evp_cipher(opmode);
 | 
						|
  if (NULL != cipher) {
 | 
						|
    length = EVP_CIPHER_key_length(cipher);
 | 
						|
  }
 | 
						|
  return length;
 | 
						|
}
 | 
						|
 | 
						|
bool ObBlockCipher::is_need_iv(const ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  bool need_iv = false;
 | 
						|
  const EVP_CIPHER *cipher = get_evp_cipher(opmode);
 | 
						|
  if (NULL != cipher) {
 | 
						|
    int default_iv_length = EVP_CIPHER_iv_length(cipher);
 | 
						|
    need_iv = default_iv_length == 0 ? false : true;
 | 
						|
  }
 | 
						|
  return need_iv;
 | 
						|
}
 | 
						|
 | 
						|
bool ObBlockCipher::is_need_aead(const ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  bool need_aead = false;
 | 
						|
  const EVP_CIPHER *cipher = get_evp_cipher(opmode);
 | 
						|
  if (NULL != cipher) {
 | 
						|
    need_aead = EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE;
 | 
						|
  }
 | 
						|
  return need_aead;
 | 
						|
}
 | 
						|
 | 
						|
bool ObBlockCipher::is_need_padding(const ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  bool need_padding = false;
 | 
						|
  const EVP_CIPHER *cipher = get_evp_cipher(opmode);
 | 
						|
  if (NULL != cipher) {
 | 
						|
    need_padding = EVP_CIPH_ECB_MODE == EVP_CIPHER_mode(cipher) ||
 | 
						|
                   EVP_CIPH_CBC_MODE == EVP_CIPHER_mode(cipher);
 | 
						|
  }
 | 
						|
  return need_padding;
 | 
						|
}
 | 
						|
 | 
						|
int64_t ObBlockCipher::get_iv_length(const ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  int64_t iv_length = 0;
 | 
						|
  const EVP_CIPHER *cipher = get_evp_cipher(opmode);
 | 
						|
  if (NULL != cipher) {
 | 
						|
    iv_length = EVP_CIPHER_iv_length(cipher);
 | 
						|
  }
 | 
						|
  return iv_length;
 | 
						|
}
 | 
						|
 | 
						|
int64_t ObBlockCipher::get_aead_tag_length(const ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  return is_need_aead(opmode) ? OB_DEFAULT_AEAD_TAG_LENGTH : 0;
 | 
						|
}
 | 
						|
 | 
						|
int64_t ObBlockCipher::get_ciphertext_length(const ObCipherOpMode opmode, const int64_t data_len)
 | 
						|
{
 | 
						|
  return is_need_padding(opmode) ?
 | 
						|
         (data_len / OB_CIPHER_BLOCK_LENGTH + 1) * OB_CIPHER_BLOCK_LENGTH : data_len;
 | 
						|
}
 | 
						|
 | 
						|
int64_t ObBlockCipher::get_max_plaintext_length(const ObCipherOpMode opmode,
 | 
						|
                                                const int64_t encrypt_len)
 | 
						|
{
 | 
						|
  return is_need_padding(opmode) ?
 | 
						|
         encrypt_len - 1 - (encrypt_len % OB_CIPHER_BLOCK_LENGTH) : encrypt_len;
 | 
						|
}
 | 
						|
 | 
						|
void ObBlockCipher::create_key(const unsigned char *key, int key_length, char *rkey,
 | 
						|
                               enum ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  const int key_size= get_key_length(opmode);
 | 
						|
  char *rkey_end = NULL;
 | 
						|
  char *ptr = NULL;                                   /* 真正的key的起始位置 */
 | 
						|
  char *sptr = NULL;
 | 
						|
  char *key_end= ((char *)key) + key_length;
 | 
						|
  rkey_end= rkey + key_size;
 | 
						|
  memset(rkey, 0, key_size);          /* 初始化key */
 | 
						|
  for (ptr= rkey, sptr= (char *)key; sptr < key_end; ptr++, sptr++)
 | 
						|
  {
 | 
						|
    if (ptr == rkey_end)
 | 
						|
      ptr= rkey;
 | 
						|
    *ptr^= *sptr;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool ObBlockCipher::is_valid_cipher_opmode(const ObCipherOpMode opmode)
 | 
						|
{
 | 
						|
  return opmode > ObCipherOpMode::ob_invalid_mode && opmode < ObCipherOpMode::ob_max_mode &&
 | 
						|
         opmode != ObCipherOpMode::ob_sm4_mode;
 | 
						|
}
 | 
						|
 | 
						|
int ObBlockCipher::encrypt(const char *key, const int64_t key_len,
 | 
						|
                           const char *data, const int64_t data_len, const int64_t buf_len,
 | 
						|
                           const char *iv, const int64_t iv_len,
 | 
						|
                           const char *aad, const int64_t aad_len, const int64_t tag_len,
 | 
						|
                           enum ObCipherOpMode mode, char *buf, int64_t &out_len, char *tag)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  bool need_iv = is_need_iv(mode);
 | 
						|
  bool need_aead = is_need_aead(mode);
 | 
						|
  bool need_padding = is_need_padding(mode);
 | 
						|
  if (!is_valid_cipher_opmode(mode) ||
 | 
						|
      (OB_ISNULL(key) && key_len != 0) || key_len < 0 ||  // allow NULL key
 | 
						|
      (OB_ISNULL(data) && data_len != 0) ||   data_len < 0 || // allow NULL data
 | 
						|
      OB_ISNULL(buf) || buf_len < get_ciphertext_length(mode, data_len)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), K(data_len), K(key_len), K(buf_len), KP(buf), KP(data),
 | 
						|
             KP(key), K(mode));
 | 
						|
  } else if (need_iv && ((iv_len != 0 && OB_ISNULL(iv)) ||
 | 
						|
                         (iv_len != 0 && iv_len != get_iv_length(mode)))) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid initial vector argument", K(ret), K(iv_len), KP(iv), K(mode));
 | 
						|
  } else if (need_aead && ((aad_len != 0 && OB_ISNULL(aad)) ||
 | 
						|
                           (aad_len != 0 && aad_len != OB_DEFAULT_AEAD_AAD_LENGTH) ||
 | 
						|
                           tag_len != OB_DEFAULT_AEAD_TAG_LENGTH || OB_ISNULL(tag))){
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid aead argument", K(ret), K(aad_len), K(tag_len), KP(aad), K(mode));
 | 
						|
  } else {
 | 
						|
    int u_len=0, f_len=0;
 | 
						|
    unsigned char rkey[OB_MAX_CIPHER_KEY_LENGTH / 8];
 | 
						|
    unsigned char *iv_encrypt = (!need_iv || iv_len == 0) ? NULL : (unsigned char *)iv;
 | 
						|
    unsigned char *add_encrypt = (!need_aead || aad_len == 0) ? NULL : (unsigned char *)aad;
 | 
						|
    ENGINE *engine = ObTdeEncryptEngineLoader::get_instance().get_tde_engine(mode);
 | 
						|
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
 | 
						|
    const EVP_CIPHER *cipher = get_evp_cipher(mode);
 | 
						|
    if (NULL != engine) {
 | 
						|
      if (EXECUTE_COUNT_PER_SEC(10)) {
 | 
						|
        LOG_INFO("tde use engine to encrypt data", K(mode));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (OB_ISNULL(ctx) ||OB_ISNULL(cipher)) {
 | 
						|
      ret = OB_INVALID_ARGUMENT;
 | 
						|
      LOG_WARN("get EVP_ctx or EVP_cipher is NULL", K(ret), KP(ctx), KP(cipher));
 | 
						|
    } else if (FALSE_IT(create_key((const unsigned char *)key, (int)key_len, (char *)rkey, mode))) {
 | 
						|
    } else if (FALSE_IT(EVP_CIPHER_CTX_init(ctx))) {
 | 
						|
    } else if (!EVP_EncryptInit_ex(ctx, cipher, engine, rkey, (unsigned char*)iv_encrypt)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to init evp encrytion cipher and engine in encrypt", K(ret));
 | 
						|
    } else if (need_padding && !EVP_CIPHER_CTX_set_padding(ctx, true)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to set padding in encrypt", K(ret));
 | 
						|
    } else if (need_aead && NULL != add_encrypt && !EVP_EncryptUpdate(ctx, NULL, &u_len, (unsigned char *)add_encrypt, (int)aad_len)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to set AAD in encrypt", K(ret));
 | 
						|
    } else if (!EVP_EncryptUpdate(ctx, (unsigned char *)buf, &u_len, (unsigned char *)data, (int)data_len)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to encrypt data in encrypt", K(ret));
 | 
						|
    } else if (!EVP_EncryptFinal(ctx, (unsigned char*)buf + u_len, &f_len)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to encrypt final frame data in encrypt", K(ret));
 | 
						|
    } else if (need_aead && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, (int)tag_len, (unsigned char*)tag)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to encrypt final frame data in encrypt", K(ret));
 | 
						|
    } else {
 | 
						|
      out_len = u_len + f_len;
 | 
						|
    }
 | 
						|
    if (OB_UNLIKELY(OB_ERR_AES_ENCRYPT == ret)) {
 | 
						|
      common::ObString err_reason = common::ObString::make_string(ERR_reason_error_string(ERR_get_error()));
 | 
						|
      LOG_WARN("encrypt failed", K(err_reason));
 | 
						|
    }
 | 
						|
    if (OB_NOT_NULL(ctx)) {
 | 
						|
      EVP_CIPHER_CTX_free(ctx);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObBlockCipher::decrypt(const char *key, const int64_t key_len,
 | 
						|
                           const char *data, const int64_t data_len, const int64_t buf_len,
 | 
						|
                           const char *iv, const int64_t iv_len, const char *aad,
 | 
						|
                           const int64_t aad_len, const char *tag, const int64_t tag_len,
 | 
						|
                           enum ObCipherOpMode mode, char *buf, int64_t &out_len)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  bool need_iv = is_need_iv(mode);
 | 
						|
  bool need_aead = is_need_aead(mode);
 | 
						|
  bool need_padding = is_need_padding(mode);
 | 
						|
  if (!is_valid_cipher_opmode(mode) ||
 | 
						|
      (OB_ISNULL(key) && key_len != 0) || key_len < 0 ||
 | 
						|
      (OB_ISNULL(data) && data_len != 0) || data_len < 0 ||
 | 
						|
      OB_ISNULL(buf) || buf_len < data_len) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(ret), K(data_len), K(key_len), K(buf_len), KP(buf), KP(data),
 | 
						|
             KP(key), K(mode));
 | 
						|
  } else if (need_iv && ((iv_len != 0 && OB_ISNULL(iv)) ||
 | 
						|
                         (iv_len != 0 && iv_len != get_iv_length(mode)))) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid initial vector argument", K(ret), K(iv_len), KP(iv), K(mode));
 | 
						|
  } else if (need_aead && ((aad_len != 0 && OB_ISNULL(aad)) ||
 | 
						|
                           (aad_len != 0 && aad_len != OB_DEFAULT_AEAD_AAD_LENGTH) ||
 | 
						|
                           tag_len != OB_DEFAULT_AEAD_TAG_LENGTH || OB_ISNULL(tag))) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid aead argument", K(ret), K(aad_len), K(tag_len), KP(aad), KP(tag), K(mode));
 | 
						|
  } else {
 | 
						|
    int u_len=0, f_len=0;
 | 
						|
    unsigned char rkey[OB_MAX_CIPHER_KEY_LENGTH / 8];
 | 
						|
    unsigned char *iv_decrypt = (!need_iv || iv_len == 0) ? NULL : (unsigned char *)iv;
 | 
						|
    unsigned char *add_decrypt = (!need_aead || aad_len == 0) ? NULL : (unsigned char *)aad;
 | 
						|
    ENGINE *engine = ObTdeEncryptEngineLoader::get_instance().get_tde_engine(mode);
 | 
						|
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
 | 
						|
    const EVP_CIPHER *cipher = get_evp_cipher(mode);
 | 
						|
    if (NULL != engine) {
 | 
						|
      if (EXECUTE_COUNT_PER_SEC(10)) {
 | 
						|
        LOG_INFO("use engine to decrypt data", K(mode));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    if (OB_ISNULL(ctx) || OB_ISNULL(cipher)) {
 | 
						|
      ret = OB_INVALID_ARGUMENT;
 | 
						|
      LOG_WARN("fail to to init cipher ctx in decrypt", K(ret), KP(ctx), KP(cipher));
 | 
						|
    } else if (FALSE_IT(create_key((const unsigned char *)key, (int)key_len, (char *)rkey, mode))) {
 | 
						|
    } else if (FALSE_IT(EVP_CIPHER_CTX_init(ctx))) {
 | 
						|
    } else if (!EVP_DecryptInit_ex(ctx, cipher, engine, rkey, (unsigned char*)iv_decrypt)) {
 | 
						|
      ret = OB_ERR_AES_DECRYPT;
 | 
						|
      LOG_WARN("fail to init evp ctx in decrypt", K(ret));
 | 
						|
    } else if (need_padding && !EVP_CIPHER_CTX_set_padding(ctx, true)) {
 | 
						|
      ret = OB_ERR_AES_DECRYPT;
 | 
						|
      LOG_WARN("fail to set padding in decrypt", K(ret));
 | 
						|
    } else if (need_aead && NULL != add_decrypt && !EVP_DecryptUpdate(ctx, NULL, &u_len, (const unsigned char *)add_decrypt, (int)aad_len)) {
 | 
						|
      ret = OB_ERR_AES_DECRYPT;
 | 
						|
      LOG_WARN("fail to set AAD in decrypt", K(ret));
 | 
						|
    } else if (!EVP_DecryptUpdate(ctx, (unsigned char *)buf, &u_len, (const unsigned char *)data, (int)data_len)) {
 | 
						|
      ret = OB_ERR_AES_DECRYPT;
 | 
						|
      LOG_WARN("fail to decrypt data in decrypt", K(ret));
 | 
						|
    } else if (need_aead && !EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, (int)tag_len, (unsigned char *)tag)) {
 | 
						|
      ret = OB_ERR_AES_DECRYPT;
 | 
						|
    } else if (!EVP_DecryptFinal(ctx, (unsigned char*)buf + u_len, &f_len)) {
 | 
						|
      ret = OB_ERR_AES_DECRYPT;
 | 
						|
      LOG_WARN("fail to decrypt final frame data in decrypt", K(ret), K(u_len), K(f_len));
 | 
						|
    } else {
 | 
						|
      out_len = u_len + f_len;
 | 
						|
    }
 | 
						|
    if (OB_UNLIKELY(OB_ERR_AES_DECRYPT == ret)) {
 | 
						|
      common::ObString err_reason = common::ObString::make_string(ERR_reason_error_string(ERR_get_error()));
 | 
						|
      LOG_WARN("decrypt failed", K(err_reason));
 | 
						|
    }
 | 
						|
    if (OB_NOT_NULL(ctx)) {
 | 
						|
      EVP_CIPHER_CTX_free(ctx);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
static void* ob_malloc_openssl(size_t nbyte, const char *, int)
 | 
						|
{
 | 
						|
  ObMemAttr attr;
 | 
						|
  attr.ctx_id_ = ObCtxIds::GLIBC;
 | 
						|
  attr.label_ = ObModIds::OB_BUFFER;
 | 
						|
  return ob_malloc(nbyte, attr);
 | 
						|
}
 | 
						|
 | 
						|
static void* ob_realloc_openssl(void *ptr, size_t nbyte, const char *, int)
 | 
						|
{
 | 
						|
  ObMemAttr attr;
 | 
						|
  attr.ctx_id_ = ObCtxIds::GLIBC;
 | 
						|
  attr.label_ = ObModIds::OB_BUFFER;
 | 
						|
  return ob_realloc(ptr, nbyte, attr);
 | 
						|
}
 | 
						|
 | 
						|
static void ob_free_openssl(void *ptr, const char *, int)
 | 
						|
{
 | 
						|
  ob_free(ptr);
 | 
						|
}
 | 
						|
 | 
						|
int ObEncryptionUtil::init_ssl_malloc()
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int tmp_ret = CRYPTO_set_mem_functions(ob_malloc_openssl, ob_realloc_openssl, ob_free_openssl);
 | 
						|
  if (OB_UNLIKELY(tmp_ret != 1)) {
 | 
						|
    ret = OB_ERR_UNEXPECTED;
 | 
						|
    LOG_WARN("failed to set crypto mem functions", K(tmp_ret), K(ret));
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObEncryptionUtil::parse_encryption_algorithm(const char *str,
 | 
						|
                                                 ObCipherOpMode &encryption_algorithm)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  encryption_algorithm = ObCipherOpMode::ob_invalid_mode;
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObEncryptionUtil::parse_encryption_id(const ObString &str, int64_t &encrypt_id)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  ObCipherOpMode encryption_algorithm = ObCipherOpMode::ob_invalid_mode;
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
bool ObEncryptionUtil::is_aes_encryption(const ObCipherOpMode opmode) {
 | 
						|
  return (opmode >= ObCipherOpMode::ob_aes_128_ecb && opmode <= ObCipherOpMode::ob_aes_256_ofb) ||
 | 
						|
         (opmode >= ObCipherOpMode::ob_aes_128_gcm && opmode <= ObCipherOpMode::ob_aes_256_gcm);
 | 
						|
}
 | 
						|
 | 
						|
bool ObEncryptionUtil::is_sm4_encryption(const ObCipherOpMode opmode) {
 | 
						|
  return (opmode >= ObCipherOpMode::ob_sm4_mode && opmode <= ObCipherOpMode::ob_sm4_cbc_mode) ||
 | 
						|
         (opmode >= ObCipherOpMode::ob_sm4_cbc && opmode <= ObCipherOpMode::ob_sm4_gcm);
 | 
						|
}
 | 
						|
 | 
						|
bool ObBackupEncryptionMode::is_valid(const EncryptionMode &mode)
 | 
						|
{
 | 
						|
  return mode >= NONE && mode < MAX_MODE;
 | 
						|
}
 | 
						|
 | 
						|
//TODO(yaoying.yyy):暂时只支持tde,后续需要更新
 | 
						|
bool ObBackupEncryptionMode::is_valid_for_log_archive(const EncryptionMode &mode)
 | 
						|
{
 | 
						|
  return (NONE == mode || TRANSPARENT_ENCRYPTION == mode);
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
const char *backup_encryption_strs[] =
 | 
						|
{
 | 
						|
  "NONE",
 | 
						|
  "PASSWORD",
 | 
						|
  "PASSWORD_ENCRYPTION",
 | 
						|
  "TRANSPARENT_ENCRYPTION",
 | 
						|
  "DUAL_MODE_ENCRYPTION",
 | 
						|
};
 | 
						|
 | 
						|
const char *ObBackupEncryptionMode::to_str(const EncryptionMode &mode)
 | 
						|
{
 | 
						|
  const char *str = "UNKNOWN";
 | 
						|
 | 
						|
  if (is_valid(mode)) {
 | 
						|
    str = backup_encryption_strs[mode];
 | 
						|
  }
 | 
						|
  return str;
 | 
						|
}
 | 
						|
 | 
						|
ObBackupEncryptionMode::EncryptionMode ObBackupEncryptionMode::parse_str(const char *str)
 | 
						|
{
 | 
						|
  ObString obstr(str);
 | 
						|
  return parse_str(obstr);
 | 
						|
}
 | 
						|
 | 
						|
ObBackupEncryptionMode::EncryptionMode ObBackupEncryptionMode::parse_str(const common::ObString &str)
 | 
						|
{
 | 
						|
  EncryptionMode mode = MAX_MODE;
 | 
						|
  const int64_t count = ARRAYSIZEOF(backup_encryption_strs);
 | 
						|
  STATIC_ASSERT(static_cast<int64_t>(ObBackupEncryptionMode::MAX_MODE) == count,
 | 
						|
      "encryption mode count mismatch");
 | 
						|
 | 
						|
  if (str.empty()) {
 | 
						|
    mode = NONE;
 | 
						|
  } else {
 | 
						|
    for (int64_t i = 0; i < count; ++i) {
 | 
						|
      if (0 == str.case_compare(backup_encryption_strs[i])) {
 | 
						|
        mode = static_cast<EncryptionMode>(i);
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return mode;
 | 
						|
}
 | 
						|
 | 
						|
int ObHashUtil::hash(const enum ObHashAlgorithm algo, const ObString data,
 | 
						|
                     ObIAllocator &allocator, ObString &output)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  char *buf = NULL;
 | 
						|
  const char *data_ptr = NULL != data.ptr() ? data.ptr() : "";
 | 
						|
  int64_t buf_len = 0;
 | 
						|
  int64_t out_len = 0;
 | 
						|
  if (OB_FAIL(get_hash_output_len(algo, buf_len))) {
 | 
						|
    LOG_WARN("fail to get hash output len", K(algo), K(ret));
 | 
						|
  } else if (OB_ISNULL(buf = static_cast<char *>(allocator.alloc(buf_len)))) {
 | 
						|
    ret = OB_ALLOCATE_MEMORY_FAILED;
 | 
						|
    LOG_WARN("fail to allocate memory", K(ret));
 | 
						|
  } else if (OB_FAIL(hash(algo, data_ptr, data.length(), buf, buf_len, out_len))) {
 | 
						|
    LOG_WARN("fail to calc hash output", K(ret));
 | 
						|
  } else {
 | 
						|
    output.assign_ptr(buf, static_cast<int32_t>(out_len));
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObHashUtil::hash(const enum ObHashAlgorithm algo, const char *data, const int64_t data_len,
 | 
						|
                       char *buf, const int64_t &buf_len, int64_t &out_len)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  int64_t expect_out_len = 0;
 | 
						|
  if (ObHashAlgorithm::OB_HASH_INVALID == algo || OB_ISNULL(data) || data_len < 0 ||
 | 
						|
      OB_ISNULL(buf)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(algo), K(data_len), K(buf_len), K(ret));
 | 
						|
  } else if (OB_FAIL(get_hash_output_len(algo, expect_out_len))) {
 | 
						|
    LOG_WARN("fail to get hash output len", K(algo), K(ret));
 | 
						|
  } else if (OB_UNLIKELY(buf_len < expect_out_len)) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("invalid argument", K(algo), K(buf_len), K(expect_out_len), K(ret));
 | 
						|
  } else {
 | 
						|
    unsigned int res_len = 0;
 | 
						|
    const EVP_MD *md = get_hash_evp_md(algo);
 | 
						|
    EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
 | 
						|
    if (OB_ISNULL(mdctx) || OB_ISNULL(md)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to init hash ctx", K(ret));
 | 
						|
    } else if (!EVP_DigestInit_ex(mdctx, md, NULL)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to init hash ctx", K(ret));
 | 
						|
    } else if (!EVP_DigestUpdate(mdctx, (const unsigned char *)data, data_len)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to update hash result", K(ret));
 | 
						|
    } else if (!EVP_DigestFinal_ex(mdctx, (unsigned char *)buf, &res_len)) {
 | 
						|
      ret = OB_ERR_AES_ENCRYPT;
 | 
						|
      LOG_WARN("fail to retrieve hash result", K(ret));
 | 
						|
    } else if (OB_UNLIKELY(expect_out_len != res_len)) {
 | 
						|
      ret = OB_ERR_UNEXPECTED;
 | 
						|
      LOG_WARN("invalid hash result length", K(expect_out_len), K(res_len), K(ret));
 | 
						|
    } else {
 | 
						|
      out_len = res_len;
 | 
						|
    }
 | 
						|
    if (OB_NOT_NULL(mdctx)) {
 | 
						|
      EVP_MD_CTX_destroy(mdctx);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObHashUtil::get_hash_output_len(const ObHashAlgorithm algo, int64_t &output_len)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  switch(algo) {
 | 
						|
    case OB_HASH_MD4:
 | 
						|
      output_len = MD4_DIGEST_LENGTH;
 | 
						|
      break;
 | 
						|
    case OB_HASH_MD5:
 | 
						|
      output_len = MD5_DIGEST_LENGTH;
 | 
						|
      break;
 | 
						|
    case OB_HASH_SH1:
 | 
						|
      output_len = SHA_DIGEST_LENGTH;
 | 
						|
      break;
 | 
						|
    case OB_HASH_SH224:
 | 
						|
      output_len = SHA224_DIGEST_LENGTH;
 | 
						|
      break;
 | 
						|
    case OB_HASH_SH256:
 | 
						|
      output_len = SHA256_DIGEST_LENGTH;
 | 
						|
      break;
 | 
						|
    case OB_HASH_SH384:
 | 
						|
      output_len = SHA384_DIGEST_LENGTH;
 | 
						|
      break;
 | 
						|
    case OB_HASH_SH512:
 | 
						|
      output_len = SHA512_DIGEST_LENGTH;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      ret = OB_NOT_SUPPORTED;
 | 
						|
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "cipher type passed");
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ObHashUtil::get_sha_hash_algorightm(const int64_t bit_length, ObHashAlgorithm &algo)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  const int64_t BIT_PER_BYTE = 8;
 | 
						|
  switch(bit_length) {
 | 
						|
    case SHA_DIGEST_LENGTH * BIT_PER_BYTE:
 | 
						|
      algo = OB_HASH_SH1;
 | 
						|
      break;
 | 
						|
    case SHA224_DIGEST_LENGTH * BIT_PER_BYTE:
 | 
						|
      algo = OB_HASH_SH224;
 | 
						|
      break;
 | 
						|
    case SHA256_DIGEST_LENGTH * BIT_PER_BYTE:
 | 
						|
      algo = OB_HASH_SH256;
 | 
						|
      break;
 | 
						|
    case SHA384_DIGEST_LENGTH * BIT_PER_BYTE:
 | 
						|
      algo = OB_HASH_SH384;
 | 
						|
      break;
 | 
						|
    case SHA512_DIGEST_LENGTH * BIT_PER_BYTE:
 | 
						|
      algo = OB_HASH_SH512;
 | 
						|
      break;
 | 
						|
    default:
 | 
						|
      ret = OB_NOT_SUPPORTED;
 | 
						|
      LOG_USER_ERROR(OB_NOT_SUPPORTED, "sha hash output length");
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
const EVP_MD* ObHashUtil::get_hash_evp_md(const ObHashAlgorithm algo)
 | 
						|
{
 | 
						|
  switch(algo) {
 | 
						|
    case OB_HASH_MD4: return EVP_md4();
 | 
						|
    case OB_HASH_MD5: return EVP_md5();
 | 
						|
    case OB_HASH_SH1: return EVP_sha1();
 | 
						|
    case OB_HASH_SH224: return EVP_sha224();
 | 
						|
    case OB_HASH_SH256: return EVP_sha256();
 | 
						|
    case OB_HASH_SH384: return EVP_sha384();
 | 
						|
    case OB_HASH_SH512: return EVP_sha512();
 | 
						|
    default: return NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ObTdeEncryptEngineLoader::ssl_init()
 | 
						|
{
 | 
						|
    OpenSSL_add_all_digests();
 | 
						|
    OpenSSL_add_all_ciphers();
 | 
						|
    OPENSSL_load_builtin_modules();
 | 
						|
    ENGINE_load_builtin_engines();
 | 
						|
    ERR_load_ERR_strings();
 | 
						|
}
 | 
						|
 | 
						|
int ObTdeEncryptEngineLoader::load(const common::ObString& engine)
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  common::ObString err_reason;
 | 
						|
  ObEncryptEngineType type = get_engine_type(engine);
 | 
						|
  if (OB_NONE_ENGINE == type) {
 | 
						|
  } else if (OB_INVALID_ENGINE == type) {
 | 
						|
    ret = OB_INVALID_ARGUMENT;
 | 
						|
    LOG_WARN("unsupport engine", K(engine));
 | 
						|
  } else {
 | 
						|
    if (NULL == tde_engine_[type]) {
 | 
						|
      ENGINE *e = ENGINE_by_id(engine.ptr());
 | 
						|
      if (NULL == e) {
 | 
						|
        ret = OB_INIT_FAIL;
 | 
						|
        err_reason = common::ObString::make_string(ERR_reason_error_string(ERR_get_error()));
 | 
						|
        LOG_WARN("load engine failed", K(engine), K(err_reason));
 | 
						|
      } else if (!ENGINE_init(e)) {
 | 
						|
        ret = OB_INIT_FAIL;
 | 
						|
        err_reason = common::ObString::make_string(ERR_reason_error_string(ERR_get_error()));
 | 
						|
        LOG_WARN("Failed initialisation engine!", K(engine), K(err_reason));
 | 
						|
        ENGINE_free(e);
 | 
						|
      } else {
 | 
						|
        tde_engine_[type] = e;
 | 
						|
        LOG_INFO("tde install engine success", K(engine));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
void ObTdeEncryptEngineLoader::destroy()
 | 
						|
{
 | 
						|
  for (int i = 0; i < OB_MAX_ENGINE; i++) {
 | 
						|
    if (NULL != tde_engine_[i]) {
 | 
						|
      ENGINE_finish(tde_engine_[i]);
 | 
						|
      ENGINE_free(tde_engine_[i]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
ENGINE* ObTdeEncryptEngineLoader::get_tde_engine(ObCipherOpMode &mode) const
 | 
						|
{
 | 
						|
  ObEncryptEngineType type = OB_INVALID_ENGINE;
 | 
						|
  if (ObEncryptionUtil::is_aes_encryption(mode)) {
 | 
						|
    type = OB_AES_ENGINE;
 | 
						|
  } else if (ObEncryptionUtil::is_sm4_encryption(mode)) {
 | 
						|
    type = OB_SM4_ENGINE;
 | 
						|
  } else {
 | 
						|
    type = OB_INVALID_ENGINE;
 | 
						|
  }
 | 
						|
  return tde_engine_[type];
 | 
						|
}
 | 
						|
 | 
						|
ObTdeEncryptEngineLoader &ObTdeEncryptEngineLoader::get_instance()
 | 
						|
{
 | 
						|
  static ObTdeEncryptEngineLoader instance;
 | 
						|
  return instance;
 | 
						|
}
 | 
						|
 | 
						|
ObTdeEncryptEngineLoader::ObEncryptEngineType ObTdeEncryptEngineLoader::get_engine_type(const common::ObString& engine)
 | 
						|
{
 | 
						|
  ObEncryptEngineType type = OB_INVALID_ENGINE;
 | 
						|
  if (OB_NOT_NULL(strcasestr(engine.ptr(), "sm4"))) {
 | 
						|
    type = OB_SM4_ENGINE;
 | 
						|
  } else if (OB_NOT_NULL(strcasestr(engine.ptr(), "hy")) || OB_NOT_NULL(strcasestr(engine.ptr(), "hct"))) {
 | 
						|
    type = OB_SM4_ENGINE;
 | 
						|
  } else if (OB_NOT_NULL(strcasestr(engine.ptr(), "aes"))) {
 | 
						|
    type = OB_AES_ENGINE;
 | 
						|
  } else if (0 == engine.case_compare("none")) {
 | 
						|
    type = OB_NONE_ENGINE;
 | 
						|
  }
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
int ObTdeEncryptEngineLoader::reload_config()
 | 
						|
{
 | 
						|
  int ret = OB_SUCCESS;
 | 
						|
  common::ObString engine = GCONF._load_tde_encrypt_engine.get_value_string();
 | 
						|
  return load(engine);
 | 
						|
}
 | 
						|
 | 
						|
}//end share
 | 
						|
} //end oceanbase
 | 
						|
 | 
						|
#endif
 |