First 16 bytes of AES-128 CFB-8 decryption are damaged

那年仲夏 提交于 2019-12-31 07:16:08

问题


I've been working on a project recently that should connect to a server with the help of a protocol. So far so good, but when I combed to decrypt the packages, I quickly noticed that something is not working properly.

The first 16 bytes of all packets are decrypted incorrectly. I have tried it with different libraries but that does not work either. I work in the C++ language and have so far used Crypto++ and OpenSSL for decryption, without success.

Under this Link you can find the protocol, here the decryption protocol Link and here is my corresponding code:

OpenSSL:

void init() {

    unsigned char* sharedSecret = new unsigned char[AES_BLOCK_SIZE];

    std::generate(sharedSecret,
        sharedSecret + AES_BLOCK_SIZE,
        std::bind(&RandomGenerator::GetInt, &m_RNG, 0, 255));

    for (int i = 0; i < 16; i++) {
        sharedSecretKey += sharedSecret[i];
    }

    // Initialize AES encryption and decryption
    if (!(m_EncryptCTX = EVP_CIPHER_CTX_new()))
        std::cout << "123" << std::endl;

    if (!(EVP_EncryptInit_ex(m_EncryptCTX, EVP_aes_128_cfb8(), nullptr, (unsigned char*)sharedSecretKey.c_str(), (unsigned char*)sharedSecretKey.c_str())))
        std::cout << "123" << std::endl;

    if (!(m_DecryptCTX = EVP_CIPHER_CTX_new()))
        std::cout << "123" << std::endl;

    if (!(EVP_DecryptInit_ex(m_DecryptCTX, EVP_aes_128_cfb8(), nullptr, (unsigned char*)sharedSecretKey.c_str(), (unsigned char*)sharedSecretKey.c_str())))
        std::cout << "123" << std::endl;

    m_BlockSize = EVP_CIPHER_block_size(EVP_aes_128_cfb8());
}

std::string result;
int size = 0;
result.resize(1000);
EVP_DecryptUpdate(m_DecryptCTX, &((unsigned char*)result.c_str())[0], &size, &sendString[0], data.size());

Crypto++:

CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption AESDecryptor((byte*)sharedSecret.c_str(), (unsigned int)16, sharedSecret.c_str(), 1);

std::string sTarget("");
CryptoPP::StringSource ss(data, true, new CryptoPP::StreamTransformationFilter(AESDecryptor, new CryptoPP::StringSink(sTarget)));

I think important to mention is that I use one and the same shared secret for the key and the iv (initialization vector). In other posts, this was often labeled as a problem. I do not know how to fix it in this case because the protocol want it.

I would be looking forward to a constructive feedback.


回答1:


EVP_EncryptInit_ex(m_EncryptCTX, EVP_aes_128_cfb8(), nullptr,
    (unsigned char*)sharedSecretKey.c_str(), (unsigned char*)sharedSecretKey.c_str()))

And:

CFB_Mode<AES>::Decryption AESDecryptor((byte*)sharedSecret.c_str(),
    (unsigned int)16, sharedSecret.c_str(), 1);

std::string sTarget("");
StringSource ss(data, true, new StreamTransformationFilter(AESDecryptor, new StringSink(sTarget)));

It is not readily apparent, but you need to set feedback size for the mode of operation of the block cipher in Crypto++. The Crypto++ feedback size is 128 by default.

The code to set the feedback size of CFB mode can be found at CFB Mode on the Crypto++ wiki. You want the 3rd or 4th example down the page.

AlgorithmParameters params =
        MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
        (Name::IV(), ConstByteArrayParameter(iv));

That is kind of an awkward way to pass parameters. It is documented in the sources files and on the wiki at NameValuePairs. It allows you to pass arbitrary parameters through consistent interfaces. It is powerful once you acquire a taste for it.

And then use params to key the encryptor and decryptor:

CFB_Mode< AES >::Encryption enc;
enc.SetKey( key, key.size(), params );

// CFB mode must not use padding. Specifying
//  a scheme will result in an exception
StringSource ss1( plain, true, 
   new StreamTransformationFilter( enc,
      new StringSink( cipher )
   ) // StreamTransformationFilter      
); // StringSource

I believe your calls would look something like this (if I am parsing the OpenSSL correctly):

const byte* ptr = reinterpret_cast<const byte*>(sharedSecret.c_str());

AlgorithmParameters params =
        MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
        (Name::IV(), ConstByteArrayParameter(ptr, 16));

CFB_Mode< AES >::Encryption enc;
enc.SetKey( ptr, 16, params );

In your production code you should use unique key and iv. So do something like this using HKDF:

std::string seed(AES_BLOCK_SIZE, '0');
std::generate(seed, seed + AES_BLOCK_SIZE,
    std::bind(&RandomGenerator::GetInt, &m_RNG, 0, 255));

SecByteBlock sharedSecret(32);
const byte usage[] = "Key and IV v1";

HKDF<SHA256> hkdf;
hkdf.DeriveKey(sharedSecret, 32, &seed[0], 16, usage, COUNTOF(usage), nullptr, 0);

AlgorithmParameters params =
        MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/)
        (Name::IV(), ConstByteArrayParameter(sharedSecret+16, 16));

CFB_Mode< AES >::Encryption enc;
enc.SetKey(sharedSecret+0, 0, params);

In the code above, sharedSecret is twice as large as it needs to be. You derive the key and iv from the seed using HDKF. sharedSecret+0 is the 16-byte key, and sharedSecret+16 is the 16-byte iv.




回答2:


I was asked to post a test vector. Here is the vector in base64 format.

e80rrpEZrLQp1bA5wzaYFDlUSrd7YbUu0t2Ykxlck/oKUclq8HuT8WHD7Rbbsw==

I hope you could locate a mistake with it.



来源:https://stackoverflow.com/questions/58916216/first-16-bytes-of-aes-128-cfb-8-decryption-are-damaged

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!