【问题标题】:Decrypting using openssl c/c++ API fails使用 openssl c/c++ API 解密失败
【发布时间】:2018-07-23 21:46:00
【问题描述】:

我从命令行使用 openssl 创建一个文件。比方说:

echo 'foobar' | openssl enc -aes-128-cbc -e -pass pass:testing > 样本

我可以这样解密

猫样本 | openssl enc -aes-128-cbc -d -pass pass:testing

效果很好。

现在我想使用 openssl c/c++ API 解密该文件,但我不能完全正确。我正在尝试像这样解密

#include <fstream>
#include <memory>
#include <string>

#include <openssl/err.h>
#include <openssl/evp.h>

using EVP_CIPHER_CTX_free_ptr = std::unique_ptr<EVP_CIPHER_CTX, decltype(&::EVP_CIPHER_CTX_free)>;

int main(int argc, char* argv[])
{

    ERR_load_crypto_strings();

    EVP_add_cipher(EVP_aes_128_cbc());

    std::string l_key{"testing"};
    std::string l_ctext{};

    std::ifstream l_file("sample", std::ios::binary | std::ios::in | std::ios::ate);

    if(l_file.is_open())
    {
      std::streampos l_size = l_file.tellg();
      char * lp_buffer = new char[l_size];

      l_file.seekg(0, std::ios::beg);
      l_file.read(lp_buffer, l_size);
      l_ctext.append(lp_buffer, l_size);  

      delete lp_buffer;
      l_file.close();
    }

    std::string l_rtext;

    EVP_CIPHER_CTX_free_ptr ctx(EVP_CIPHER_CTX_new(), ::EVP_CIPHER_CTX_free);

    if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cbc(), NULL,
                               (const unsigned char*)l_key.c_str(), NULL));
      ERR_print_errors_fp(stdout);

    int l_len;

    if(1 != EVP_DecryptUpdate(ctx.get(), (unsigned char*)&l_rtext[0], &l_len,
                              (const unsigned char*)l_ctext.data(),
                              l_ctext.size()))
      ERR_print_errors_fp(stdout);

    if(1 != EVP_DecryptFinal_ex(ctx.get(), (unsigned char*)&l_rtext[0] + l_len,
                                &l_len))
      ERR_print_errors_fp(stdout);

    ERR_free_strings();

    exit(0);
}

但是,最后一次调用 EVP_DecryptFinal_ex 失败了

140559955420968:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:596:

大部分代码都基于 openssl API 附带的示例。我究竟做错了什么?我在EVP_DecryptInit_ex 中将IV 设置为NULL,因为据我所知,只要我不多次使用该密钥,这是可以接受的。

这一切都在带有 GCC 的 Fedora 机器上完成

【问题讨论】:

  • 我不知道我之前是怎么错过的... “我将 IV 设置为 NULL...” - CBC 模式需要 IV。您不能将其设置为 NULL。另外,您需要sizeresize 您的l_rtext。恢复的文本大小最多为l_size。一旦EVP_DecryptFinal_ex 你应该调用resize 来设置缓冲区的最终大小。
  • 如果我使用 API,我可以在没有 IV 的情况下加密某些东西。上面的代码将很好地解密。正如我在回答中所写 - 我发现的问题是命令行中的“openssl enc”将使用默认盐,并且始终使用 IV。
  • “如果我使用 API,我可以在没有 IV 的情况下加密某些东西......” - 如果这是真的,那么这对我来说听起来像是一个错误。如果没有 IV,OpenSSL 无法在 CBC 模式(以及除 ECB 之外的其他模式)下继续运行。

标签: c++ openssl


【解决方案1】:

我有点明白我做错了什么。

  • 命令行“openssl enc”命令使用默认盐,我上面的代码没有寻找那个。所以(而不是尝试使用“-nosalt”选项)我从加密字符串中删除前 16 个字节,并将最后 8 个字节用作盐。
  • 我将密码作为“密钥”提供给 EVP 方法。似乎 'openssl enc' 并没有这样做,所以需要使用盐和密码来创建密钥和 IV(而不是使用 NULL,这是我所做的)。
  • 上述代码中存在错误,因为 l_rtext 需要 resize() 来反映已添加字符的事实。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-14
    • 2021-01-30
    • 2019-04-22
    • 1970-01-01
    • 2011-10-27
    • 2014-01-08
    • 1970-01-01
    相关资源
    最近更新 更多