-1

I have an application that has to Encrypt data.

However, when I run the following it returns me different output within the same execution. When I repeat the execution, the pattern of output is exactly the same, see end of my question.

int Encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) {
    EVP_CIPHER_CTX *ctx;
    int len;
    int ciphertext_len;
    if (!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
    if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cfb(), NULL, key, iv)) {
        handleErrors();
        }
    if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) {
        handleErrors();
        }
    ciphertext_len = len;
    if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
        handleErrors();
        }
    ciphertext_len += len;
    EVP_CIPHER_CTX_free(ctx);
    return ciphertext_len;
    }
string EncryptThis(string Data, string Key, string IV, long long Buffer) {
    unsigned char *key = (unsigned char *)Key.c_str();
    unsigned char *iv = (unsigned char *)IV.c_str();
    unsigned char *plaintext = (unsigned char *)Data.c_str();
    unsigned char* ciphertext = new unsigned char[Buffer];
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();
    //cout << Data << endl; //ALWAYS THE SAME
    //cout << Key << endl; //ALWAYS THE SAME
    //cout << IV << endl; //ALWAYS THE SAME


    int ciphertext_len = Encrypt(plaintext, (int)strlen((char *)plaintext), key, iv, ciphertext);
    string Encrypted = base64_encode(reinterpret_cast<const unsigned char *>(ciphertext), ciphertext_len);
    EVP_cleanup();
    ERR_free_strings();
    return Encrypted;
    }
int main() {
    cout << EncryptThis("ThisisATest", "Test", "Test2", 11) << endl;
    cout << EncryptThis("ThisisATest", "Test", "Test2", 11) << endl;
    cout << EncryptThis("ThisisATest", "Test", "Test2", 11) << endl;
    }

In this test the results where:

mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

However, when I run the same application again, it returns me exact the same output even in the same order. So it seems to be a problem with the repetition within the execution of the script?

To clarify. When this application would be called Test.exe and I execute the application three times, it would output the following:

//execute Test.exe
mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

//Execute Test.exe
mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

//execute Test.exe
mJOjOk2wIe5D4oA=
GTvRQb8IZtFYbLI=
plOJA083gOSfVrs=

How is this possible and where is my error?

TVA van Hesteren
  • 1,031
  • 3
  • 20
  • 47
  • Each run should produce 12 lines of output so your code doesn't match the output you provided. – Richard Critten Nov 14 '17 at 16:43
  • Base64 is for computers, hex is for humans. You are asking humans. – zaph Nov 14 '17 at 16:43
  • @RichardCritten, you are right, I have modified the code to match the output – TVA van Hesteren Nov 14 '17 at 17:06
  • @zaph, what do you mean with this comment? I use Base64? – TVA van Hesteren Nov 14 '17 at 17:06
  • @TVAvanHesteren With Base64 the individual bytes can not be seen and can not be examined. Just looking one can not even tell how many bytes are encoded. With Hex there is a one-to-one correspondence between displayed hex characters and the bytes. Patterns can be seen, one can see if it is ASCII, binary and a good estimate can be made if it is random bytes. Ex1: Base64: `AQID`. hex: `010203`, Ex2: ASCII: "Hex", Base64: `SGV4 `, Hex: `486578`. – zaph Nov 14 '17 at 17:41
  • @zaph, so what is wrong with my code? I have no idea what you mean – TVA van Hesteren Nov 14 '17 at 18:00
  • In the last example: ASCII "Hex" is composed of 3-bytes which can be expressed in hex 486578 where "H" is 48, "e" is "65" and "x" is 58. There is a one-to-one correspondence, one ASCII character for each hex character pair. Those with experience with binary will be able to immediately *see* that. "Hex" expressed in Base64 is "SGV4" and one can not *see* the correspondence. See [Hexadecimal](https://en.wikipedia.org/wiki/Hexadecimal). – zaph Nov 14 '17 at 18:52
  • *"Thanks, however the used key and IV aren’t the ones I use in my application. These are random for each iteration..."* - Seriously? Why would you ask why each is different and then make this statement in the comments on Zaph's answer. – jww Nov 15 '17 at 00:55

1 Answers1

5

The key and IV are to short. The key for EVP_aes_256_cfb needs to be 256-bits (32-bytes) and the IV needs to be the block size, 128-bits (16-bytes) for AES.

Since the key and IV are to short the extra length is made up somehow, there is no standard defined. For one or both what ever bytes follow are used. On call to main the memory is the same each time (possible zeroed) so the same results. On the internal calls the memory has been changed by execution but in the same way each time so the output is repeated.

The buffer is too short. it needs to be the length of the data to be encrypted + the block length: 11 + 16 -> 27. It is best if the encryption function (Encrypt) create the buffer, not the caller. The EVP_EncryptUpdate function will return the final length of the encrypted+padding.

Solution: use full length values for the key and IV and handle the buffer internally with the correct length.


Hint 1: CBC mode is more generally used that CFB mode.

Hint 2: Use a random IV, just prefix the encrypted data with the IV for use in decryption, it does not need to be secret. That way the user need not provide the IV.


Note: If you stil have problems with full length key and IV update the question and supply the valuies at the call to and after EVP_EncryptUpdate.

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
zaph
  • 111,848
  • 21
  • 189
  • 228
  • Thanks, however the used key and IV aren’t the ones I use in my application. These are random for each iteration. So, what’s wrong with the CFB mode looking at CBC? I discovered that CFB produces less long strings than CBC does and that’s why I use CFB... besides that, as stated here: https://stackoverflow.com/questions/1220751/how-to-choose-an-aes-encryption-mode-cbc-ecb-ctr-ocb-cfb the CFB method seems to be better than CBC? curious of your answer on my used cipher-method – TVA van Hesteren Nov 14 '17 at 23:14
  • Could you supply me with an example on how to determine the right buffer size? Because I tried to manage this earlier and I couldn’t succeed. This is a working method (multiply input by 2) but not ideal as you already mentioned – TVA van Hesteren Nov 14 '17 at 23:16
  • 1
    For encryption the output buffer needs to be the size of the data to be encrypted + one block size. The encryption method returns the number of bytes encrypted.For decryption the buffer can be the size of encrypted data. See [PKCS#7 padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7) See [CFB mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Feedback_.28CFB.29), it had the same output size as [CBC mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29). Perhaps you are thinking of another mode. – zaph Nov 14 '17 at 23:32
  • There are modes that do not add padding (or as much) such as CFB8 and CTS but saving part of a block is generally not worth it and makes interoperability more difficult. – zaph Nov 14 '17 at 23:49