Crypto ++ aes-256-ecb结果与openssl不同

1 encryption openssl aes ecb crypto++

我正在尝试加密一个简单的字符串,例如"Hello World!" 通过Crypto ++,通过Crypto ++解密成功.但是通过OpenSSL命令解密Crypto ++加密结果时出错了.

我的C++代码:

#include <iostream>
#include <aes.h>
#include <base64.h>
#include <modes.h>

std::string aes_encrypt(std::string key, std::string plain)
{
    std::string result;
    CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption ecb_encryptor((byte *)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
    auto encryptor = new CryptoPP::StreamTransformationFilter(ecb_encryptor,
        new CryptoPP::Base64Encoder(new CryptoPP::StringSink(result), false),
        CryptoPP::StreamTransformationFilter::ZEROS_PADDING);
    CryptoPP::StringSource(plain, true, encryptor);

    return result;
}

std::string aes_decrypt(std::string key, std::string cipher)
{
    std::string result;
    CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption ecb_decryptor((byte *)key.c_str(), CryptoPP::AES::MAX_KEYLENGTH);
    auto decryptor = new CryptoPP::Base64Decoder(new CryptoPP::StreamTransformationFilter(ecb_decryptor,
        new CryptoPP::StringSink(result),
        CryptoPP::StreamTransformationFilter::ZEROS_PADDING));
    CryptoPP::StringSource(cipher, true, decryptor);

    return result;
}

int main(int argc, char **argv)
{
    const char *key = "1234567890";
    const char *plain = "Hello World!";

    std::cout << "plain: " << plain << std::endl;
    std::string cipher = aes_encrypt(key, plain);
    std::cout << "cipher: " << aes_encrypt(key, plain) << std::endl;
    std::cout << "plain: " << aes_decrypt(key, cipher) << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

plain: Hello World!
cipher: bVgt4KsCOTULujusMJvhhw==
plain: Hello World!
Run Code Online (Sandbox Code Playgroud)

OpenSSL命令:

xxx@xxxdeMacBook-Pro ~ $ echo -n 'Hello World!' | openssl enc -e -aes-256-ecb -nosalt -a -A -pass pass:1234567890
7sQWFmxUUQ8DpoXh9DXS8g==
xxx@xxxdeMacBook-Pro ~ $ echo -n '7sQWFmxUUQ8DpoXh9DXS8g==' | openssl enc -d -aes-256-ecb -nosalt -a -A -pass pass:1234567890
Hello World!
Run Code Online (Sandbox Code Playgroud)

尝试使用OpenSSL解密Crypto ++结果失败:

xxx@xxxdeMacBook-Pro ~ $ echo -n 'bVgt4KsCOTULujusMJvhhw==' | openssl enc -d -aes-256-ecb -nosalt -a -A -pass pass:1234567890
bad decrypt
78710:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:/BuildRoot/Library/Caches/com.apple.xbs/Sources/OpenSSL098/OpenSSL098-64.50.6/src/crypto/evp/evp_enc.c:330:
Run Code Online (Sandbox Code Playgroud)

Art*_* B. 5

那是因为你使用了不同的填充(Crypto ++中的零填充与OpenSSL中的PKCS#7填充)和完全不同的密钥.

在OpenSSL中,密钥源自您-pass使用EVP_BytesToKey函数提供的密码(毕竟它被调用).
如果要使用正确的AES密钥,可以使用-K命令行选项提供十六进制编码密钥(长度应为32,48或64个字符).

在Crypto ++中,你直接传递一个破碎的密钥ecb_encryptor.AES支持长度为16,24和32字节的密钥,介于两者之间.但是你提供了一个10字节的密钥,告诉Crypto ++密钥实际上是32字节长.这可能导致随机密钥,因为内存中的剩余字节可能包含一些垃圾值.
如果要使用基于密码的OpenSSL加密,Crypto ++提供了OpenSSL的EVP_BytesToKey函数的实现.

您是否决定使用有效的AES密钥或密码.请记住,AES密钥应该是随机生成的,以确保安全,密码必须足够长,以提供任何良好的安全性.我会说密码必须比你想要的位强度大约30%(对于128位安全性,你需要一个随机生成的21个字符的密码,包含大写,小写字母和数字).

安全考虑:

你永远不应该使用ECB模式.它是确定性的,因此在语义上不安全.您应该至少使用CBCCTR等随机模式.最好对您的密文进行身份验证,以便无法进行填充oracle攻击等攻击.这可以使用经过验证的模式(如GCM或EAX)或加密 - 然后MAC方案来完成.

  • Crypto ++项目为需要它的人实现[`OPENSSL EVP BytesToKey`](https://www.cryptopp.com/wiki/OPENSSL_EVP_BytesToKey).它是一个非官方的附加组件,但如果有问题,我们会保留它. (2认同)