C++ 使用openssl c/c++;API失败

C++ 使用openssl c/c++;API失败,c++,openssl,C++,Openssl,我从命令行使用openssl创建了一个文件。比如说: echo'foobar'| openssl enc-aes-128-cbc-e-通过:测试> 样品 我可以用这种方法解密 cat样本| openssl enc-aes-128-cbc-d-通过:测试 那很好 现在我想使用openssl c/c++API对该文件进行解密,但我不能完全正确。我正试图这样解密 #include <fstream> #include <memory> #include <string&g

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

echo'foobar'| openssl enc-aes-128-cbc-e-通过:测试> 样品

我可以用这种方法解密

cat样本| openssl enc-aes-128-cbc-d-通过:测试

那很好

现在我想使用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);
}
这段代码大部分基于openssl API附带的示例。我做错了什么?我在
EVP_DecryptInit_ex
中将IV设置为NULL,因为据我所知,只要我不多次使用密钥,这是可以接受的


所有这些都是在一台装有GCC的Fedora机器上完成的,我差不多知道我做错了什么

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

我不确定我之前怎么会错过这个。。。“我将IV设置为空…”-CBC模式需要IV。不能将其设置为空。此外,您需要
调整大小
调整大小
您的
l_rtext
。恢复的文本大小最多为
l\u大小
。一旦
EVP\u DecryptFinal\u ex
你应该调用
resize
来设置缓冲区的最终大小。如果我使用API,我可以在没有IV的情况下加密一些东西。上面的代码将解密该罚款。正如我在回答中所写的——我发现的问题是,命令行中的“openssl enc”将使用默认的salt,并且它将始终使用IV。“如果我使用API,我可以在不使用IV的情况下加密某些内容…”如果这是真的,那么对我来说这听起来像个bug。如果没有IV,OpenSSL无法在CBC模式(以及除ECB以外的其他模式)下进行。
140559955420968:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:596: