【问题标题】:Crypto++ aes-256-ecb result is different with opensslCrypto++ aes-256-ecb 结果与 openssl 不同
【发布时间】:2017-05-14 18:14:16
【问题描述】:

我正在尝试加密一个简单的字符串,例如“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;
}

输出:

plain: Hello World!
cipher: bVgt4KsCOTULujusMJvhhw==
plain: Hello World!

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!

尝试使用 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:

【问题讨论】:

    标签: encryption openssl aes crypto++ ecb


    【解决方案1】:

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

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

    在 Crypto++ 中,您直接将损坏的密钥传递给 ecb_encryptor。 AES 支持 16、24 和 32 字节长度的密钥,两者之间不支持。但是您提供了一个 10 字节的密钥并告诉 Crypto++ 该密钥实际上是 32 字节长。这可能会导致随机密钥,因为内存中剩余的字节可能包含一些垃圾值。
    如果要使用 OpenSSL 的基于密码的加密,Crypto++ 提供了OpenSSL's EVP_BytesToKey function 的实现。

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

    安全注意事项:

    你不应该使用ECB mode。它是确定性的,因此在语义上不安全。您至少应该使用像CBCCTR 这样的随机模式。最好对您的密文进行身份验证,以免像padding oracle attack 这样的攻击是不可能的。这可以通过 GCM 或 EAX 等经过身份验证的模式或encrypt-then-MAC 方案来完成。

    【讨论】:

    • Crypto++ 项目为需要它的人实现了OPENSSL EVP BytesToKey。它是一个非官方的插件,但如果有问题我们会维护它。
    • 请注意,OpenSSL 有一个 -K 选项可以直接传递密钥而不是使用密码。这可能比将 EVP_BytesToKey 集成到 Crypto++ 中更容易。此外,OpenSSL 使用 PKCS#7 填充。这两件事都可以整合到这个答案中。
    • @Maarten 谢谢,我已经添加了。如果您想添加更多内容,我可以制作答案社区 Wiki。
    • 像这样的 Artjom 很好 :)
    猜你喜欢
    • 2018-10-04
    • 1970-01-01
    • 2012-06-09
    • 2022-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    相关资源
    最近更新 更多