【问题标题】:Encryption using Openssl EVP library and decryption using openssl enc terminal command fails使用 Openssl EVP 库加密和使用 openssl enc 终端命令解密失败
【发布时间】:2019-11-19 06:52:02
【问题描述】:

我正在尝试使用 OpenSSL EVP 库加密字符串,然后使用来自 linux 终端的 openssl 命令解密。 用于解密的 OpenSSL 命令:

openssl enc -aes-256-cbc -base64 -salt -d -md md5 -k <passphrase> -in encrypt.txt -out plain.txt

加密代码:

int CAES::encrypt(const char* msg, unsigned char** encrypted_message, const size_t msg_len, const unsigned char *key, unsigned char *iv, const unsigned char* salt) 
{
    //this buffer will hold the salt and the cipher
    const int buffer_len ( CAES::salt_info_size + std::max((int)(msg_len * 2), EVP_MAX_KEY_LENGTH) );
    unsigned char* buffer = new unsigned char[buffer_len];
    //this will be a pointer to the cipher only
    unsigned char* cipher = CAES::salt_info_size + buffer;
    size_t bytes_encrypted(0);
    bool encryption_error(true);
    EVP_CIPHER_CTX *cipher_ctx( create_cipher_ctx(encryption, key, iv) );
    (void) EVP_CIPHER_CTX_set_key_length(cipher_ctx, EVP_MAX_KEY_LENGTH);
        size_t cipher_len(0);
    int temp_len(0);
    if( EVP_EncryptUpdate(cipher_ctx, cipher, &temp_len, (unsigned char *)msg, strlen(msg)) )
    {
        cipher_len = temp_len;
        if( EVP_EncryptFinal_ex(cipher_ctx, cipher + temp_len, &temp_len) )
        {
            cipher_len += temp_len;
        }
        cipher[cipher_len] = '\0';
        encryption_error = false;
        bytes_encrypted = cipher_len;
    }
    memcpy(buffer + 0 , CAES::salt_tag, CAES::salt_tag_size);
    memcpy(buffer + CAES::salt_tag_size, salt, CAES::salt_size);
    memcpy(*encrypted_message, buffer, CAES::salt_info_size + bytes_encrypted);
    EVP_CIPHER_CTX_free(cipher_ctx);
    delete[] buffer;
    return CAES::salt_info_size + bytes_encrypted;
}

将上面的加密字符串编码为base64的代码:

int CBase64::encode(const unsigned char* msg, const size_t msg_len, char** b64_msg) {
  size_t bytes_encoded = 0;
  bytes_encoded = EVP_EncodeBlock((unsigned char *) *b64_msg, msg, msg_len);
  return bytes_encoded;
}

密钥和 IV 推导

void CAES::init_key_iv(const std::string& pass, const unsigned char* salt, unsigned char* key, unsigned char* iv )
{
  const unsigned char * pass_key = reinterpret_cast<const unsigned char*>( pass.c_str() );
  const size_t pass_key_len ( pass.size() );
  EVP_BytesToKey(CAES::cipher_type, CAES::msg_digest_type, salt, pass_key, pass_key_len, 1, key, iv);
}

以下是密钥大小和盐派生:

unsigned char salt[8] = {};
unsigned char key[32] = {};
unsigned char iv_enc[16] = {};
RAND_bytes(salt, 8);

案例一:

const char* password = "@N";
const char* msg = "neo4j";

在尝试解密时,我得到以下信息:

bad decrypt
140589946300064:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:539:

案例 2:

const char* password = "eemnsis";
const char* msg = "This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.This is long message, repeating 10 times.";

在尝试解密时,我得到以下信息:

error reading input file

【问题讨论】:

    标签: c security encryption openssl


    【解决方案1】:

    我怀疑是 Base64 编码。

    在用于解密的openssl 语句中,使用-base64 选项而不使用-A 选项。因此,需要一个格式化的 Base64 字符串,即在每个 64 字节之后和末尾有换行符,请参阅-A-Option

    但是,当前的encode 函数没有这样做,而是将整个 Base64 字符串写入 单个行。

    问题可以解决

    • -A 选项添加到openssl 语句以进行解密:-base64 -A

    • 或修改encode 方法以包含换行符,例如与EVP_EncodeUpdate 等):

      int CBase64::encode(const unsigned char* msg, const size_t msg_len, char** b64_msg) {
          int len, total = 0;
          EVP_ENCODE_CTX *ectx = EVP_ENCODE_CTX_new();
          EVP_EncodeInit(ectx);
          EVP_EncodeUpdate(ectx, (unsigned char *)*b64_msg, &len, msg, msg_len);
          total += len;
          EVP_EncodeFinal(ectx, (unsigned char *)*b64_msg + len, &len);
          total += len;
          EVP_ENCODE_CTX_free(ectx);
          return total;
      }
      

    【讨论】:

    • 感谢 cmets。我无法使用EVP_ENCODE_CTX_newEVP_ENCODE_CTX_free
    • 温馨提示:使用openssl解密时也可以使用-A-选项!否则,您将需要找到与您的环境兼容的 Base64 编码,并考虑换行符。很难推荐任何东西,因为我不了解您的环境,但是 Internet 上有许多实现,例如gist.github.com/barrysteyn/7308212。这里在Base64Encode 函数中设置了标志BIO_FLAGS_BASE64_NO_NL 以将Base64 字符串写入一行。可能这种方法可以适应换行考虑(虽然我还没有尝试过)。
    猜你喜欢
    • 2019-03-01
    • 2016-09-25
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-11
    • 2021-06-06
    相关资源
    最近更新 更多