0

I am using the following function to encrypt my data via the OpenSSL Library in Qt:

QByteArray Crypto::Encrypt(QByteArray source, QString password)
{
  EVP_CIPHER_CTX en;

  unsigned char *key_data;
  int key_data_len;

  QByteArray ba = password.toLatin1();
  key_data = (unsigned char*)ba.data();
  key_data_len = strlen((char*)key_data);

  int nrounds = 28;
  unsigned char key[32], iv[32];

  EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), NULL, key_data, key_data_len, nrounds, key, iv);

QByteArray bkey = reinterpret_cast<const char*>(key) //EDIT: Contains the key afterwards
QByteArray biv = reinterpret_cast<const char*>(iv) //EDIT: Is Null afterwards

  EVP_CIPHER_CTX_init(&en);
  EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, key, iv);

  char *input = source.data();
  char *out;
  int len = source.size();

  int c_len = len + 16, f_len = 0;
  unsigned char *ciphertext = (unsigned char *)malloc(c_len);

  EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL);
  EVP_EncryptUpdate(&en, ciphertext, &c_len, (unsigned char *)input, len);
  EVP_EncryptFinal_ex(&en, ciphertext+c_len, &f_len);

  len = c_len + f_len;

  out = (char*)ciphertext;

  EVP_CIPHER_CTX_cleanup(&en);

  return QByteArray(out, len);
}

"source" is in that case "12345678901234567890123456789012abc".
"password" is "1hA!dh==sJAh48S8Ak!?skiitFi120xX".

So....if I got that right, then EVP_BytesToKey() should generate a key out of the password and supplied data to decrypt the string with later.

To Base64-Encoded that key would be: "aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE="
I don't use a salt, so no IV (should be null).

So QByteArray bkey in Base64 leaves me with "aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE="
QByteArray bvi is giving me Null

The encryptet text is "CiUqILbZo+WJBr19IiovRVc1dqGvrastwo0k67TTrs51HB8AbJe8S4uxvB2D7Dkr".

Now I am using the following PHP function to decrypt the ciphertext with the generated key again:

<?php
function decrypt_data($data, $iv, $key) {
    $cypher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

    //if(is_null($iv)) {
    //    $ivlen = mcrypt_enc_get_iv_size($cypher);
    //    $iv = substr($data, 0, $ivlen);
    //    $data = substr($data, $ivlen);
    //}

    // initialize encryption handle
    if (mcrypt_generic_init($cypher, $key, $iv) != -1) {
            // decrypt
            $decrypted = mdecrypt_generic($cypher, $data);

            // clean up
            mcrypt_generic_deinit($cypher);
            mcrypt_module_close($cypher);

            return $decrypted;
    }

    return false;
}

$ctext = "CiUqILbZo+WJBr19IiovRVc1dqGvrastwo0k67TTrs51HB8AbJe8S4uxvB2D7Dkr";
$key = "aQkrZD/zwMFU0VAqjYSWsrkfJfS28pQJXym20UEYNnE=";

$res = decrypt_data(base64_decode($ctext), null, base64_decode($key));

echo $res;
?>

Now I'd expect a response like "12345678901234567890123456789012abc".
What I get is "7890123456789012abc".

My string seems to be decrypted in the right way, but it's cut in half and only the last 19 characters are displayed. Can someone please help me with that? I'm new to encryption and can't really figure out where exactly I went wrong.

Endauriel
  • 402
  • 5
  • 17
  • [OpenSSL 1.1.0c changed the digest algorithm](http://stackoverflow.com/q/39637388/608639) used in some internal components. Formerly, MD5 was used, and 1.1.0 switched to SHA256. Be careful the change is not affecting you in both `EVP_BytesToKey` and commands like `openssl enc`. – jww Jan 26 '17 at 16:22

2 Answers2

0

This is probably because of a misinterpretation from your part. You say:

I don't use a salt, so no IV (should be null).

But there is no reason at all why that would be the case. The EVP_BytesToKey method provided both a key and an IV. The key is obviously correct, but the IV is not. This will result in random characters in your plain text (the IV only changes the first block). As this block will likely contain control characters and what more, it may not display well.

Remember that a salt and IV may have a few things in common (should not be repeated, can be public etc.) but that they are entirely different concepts in cryptography.

Please try again with your Qt code, and this time print out the IV as well as the key...

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • That assumption I made there was more because of my attempt to get the IV-data failing. The IV is a unsigned char*, as far as I know. The key is also. I tried to make the IV the same way a const char* as I did with the key, so I can put it in a ByteArray. But the conversion from the IV fails and the ByteArray is null afterwards, so I made the assumption, that there is no IV in my case. – Endauriel Aug 21 '13 at 11:29
  • EDIT: The method I used for both in Qt was. QByteArray Bkey = reinterpret_cast(key); QByteArray Biv = reinterpret_cast(iv); Bkey contains the keydata, while Biv is null afterwards. – Endauriel Aug 21 '13 at 11:37
  • OK, I think I see the problem: `$iv = substr($data, 0, $ivlen);`. If you don't put the IV in front of the ciphertext then you certainly should not remove it from there. Just create a zero'ed out IV instead and use all of the data in `mdecrypt_generic`... – Maarten Bodewes Aug 21 '13 at 15:06
  • I removed the substr() and used the whole data now. With an IV of null that'll give me now "1²Œö)’9 Ï4Kt¾æ$‰7890123456789012abc", when I use a zero'ed out IV, I get "1sC@]’ö¿Š4Kt¯æ$‰7890123456789012abc". So it basically put some random characters where there were none before. I also tried openssl_decrypt() now instead of mcrypt() which leaves me with the exact same problem unfortunately. :-/ – Endauriel Aug 22 '13 at 06:42
  • You do know that you have a `EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL);` in the above code, don't you? – Maarten Bodewes Aug 22 '13 at 09:39
  • Yes, but I also have a **EVP_EncryptInit_ex(&en, EVP_aes_256_cbc(), NULL, key, iv);** before. Removing the additional **EVP_EncryptInit_ex(&en, NULL, NULL, NULL, NULL);** line does neither change the outcome of the encrypted text nor the encrypted key or iv, so I let it in the code cause it was shown that way in the example code. That line doesn't seem to change anything when I debug it with or without it. Same ciphertext, same key, iv is empty. – Endauriel Aug 22 '13 at 10:14
0

I solved the problem with the empty initialisation vector by trial and error now, though I have no clue why the following was a problem at all. Maybe someone can explain that to me.

Changing the line: int nrounds = 28; did the trick.

If i put any other number than 28 in there, an IV is generated and when I use it afterwards in mcrypt the ciphertext is decrypted in the correct way. Why was it a problem to generate the key with 28 rounds with the openssl-function EVP_BytesToKey()? I reduced it to 5 rounds now, but I'm curious whether this problem might happen again with a password-rounds-combination that has the possibility to generate such a Null-IV.

I don't realy know how the process of the IV generation is handled in this function.

Endauriel
  • 402
  • 5
  • 17