1

I'm trying to encrypt a simple string such as "Hello World!" via Crypto++, and decrypt it via Crypto++ succeed. but I got an error when decrypt Crypto++ encrypted result via OpenSSL command.

My C++ code:

#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;
}

Output:

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

OpenSSL command:

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!

Try to use OpenSSL to decrypt Crypto++ result failed:

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:
lidroid
  • 13
  • 3

1 Answers1

5

That's because you're using a different padding (Zero Padding in Crypto++ vs. PKCS#7 padding in OpenSSL) and a completely different key.

In OpenSSL, the key is derived from the password that you provide (it's called -pass after all) using the EVP_BytesToKey function.
If you want to use a proper AES key, you can use the -K commandline option to provide a Hex encoded key (should be 32, 48 or 64 characters long).

In Crypto++ you're directly passing a broken key to ecb_encryptor. AES supports keys of 16, 24 and 32 bytes length and nothing in between. But you're providing a 10 byte key and tell Crypto++ that the key is actually 32 byte long. This probably results in a random key because the remaining bytes in memory probably contain some junk values.
If you want to use the password-based encryption of OpenSSL, Crypto++ provides an implementation of OpenSSL's EVP_BytesToKey function.

Whether you decide to use an valid AES key or a password is up to you. Remember that an AES key is supposed to be randomly generated to be secure and a password must be long enough to provide any good security. I would say the password must be roughly 30% longer than the bit strength that you're going for (for 128 bit security you would need a randomly generated password of 21 characters containing uppercase, lowercase letters and digits).

Security considerations:

You should never use ECB mode. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • 2
    The Crypto++ project implements [`OPENSSL EVP BytesToKey`](https://www.cryptopp.com/wiki/OPENSSL_EVP_BytesToKey) for folks who need it. Its an unofficial add-on, but we maintain it if there are problems. – jww May 14 '17 at 18:40
  • 1
    Note that OpenSSL has a -K option to directly pass a key instead of using a password. That's probably easier than integrating EVP_BytesToKey into Crypto++. Additionally OpenSSL uses PKCS#7 padding. Both things could be integrated into this answer. – Maarten Bodewes May 14 '17 at 19:34
  • @Maarten Thanks, I've added that. I can make the answer Community Wiki if you want to add more. – Artjom B. May 14 '17 at 20:32
  • Fine like this Artjom :) – Maarten Bodewes May 14 '17 at 21:31