3

I wrote a program to encrypt a string with PolarSSL AES-CBC

this is my code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <polarssl/aes.h>
#include <polarssl/havege.h>

int main()
{
    char buff[2][64] = {"Who can tell me WHY?", ""};
    havege_state hs;
    int retval;
    unsigned char IV[16];

    aes_context enc_ctx;
    aes_context dec_ctx;

    aes_setkey_enc(&enc_ctx, "password", 256);
    aes_setkey_dec(&dec_ctx, "password", 256);

    havege_init(&hs);
    havege_random(&hs, IV, 16);

    //encrypt
    aes_crypt_cbc(&enc_ctx, AES_ENCRYPT, 64, IV, buff[0], buff[1]);
    havege_random(&hs, IV, 16);

    //decrypt
    aes_crypt_cbc(&dec_ctx, AES_DECRYPT, 64, IV, buff[1],buff[0]);

    printf("After decrypt:%s\n", buff[0]);
    return 0;
}

But when I run it, I just got the wrong text after it decrypt.

I don't understand AES algorithm clearly, because my english is very bad, It's too hard for me to read some articles.

-------------------------Added By midCat--------------------------------------------

I followed you advice, and Change me code now I use the same IV and 256-bit key, this is the new code

int main()
{
    char buff[2][64] = {"ABCDEFGHIJKLMN", ""};
    havege_state hs;
    int retval;
    unsigned char IV[16];
    unsigned char IV2[16];
    unsigned char key[32];

    aes_context enc_ctx;
    aes_context dec_ctx;

    havege_init(&hs);
    havege_random(&hs, IV, 16);
    havege_random(&hs, key, 32);
    strncpy(IV, IV2, 16);           //copy IV

    aes_setkey_enc(&enc_ctx, key, 256);
    aes_setkey_dec(&dec_ctx, key, 256);


    //encrypt
    aes_crypt_cbc(&enc_ctx, AES_ENCRYPT, 64, IV, buff[0], buff[1]);
    printf("Before encrypt:%s\n", buff[0]);

    //decrypt
    aes_crypt_cbc(&dec_ctx, AES_DECRYPT, 64, IV2, buff[1],buff[0]);
    printf("After decrypt:%s\n", buff[0]);
    return 0;
}

I compiler it, and run for many times, got the same output:

Before encrypt:ABCDEFGHIJKLMN
After decrypt:ABCDEFGHYC
                        LMN

How to got IV?

midCat
  • 123
  • 4
  • 13
  • AES works on bytes, not characters.. There is a subtle difference.. You cannot use strncpy() to copy the IV. You'll have to use memcpy() as the IV **CAN** contain the NULL character. For the rest, this code is ok (And works on my machine). – Paul Dec 13 '12 at 09:08
  • You also swapped the source and destination operands, you want to use memcpy(IV2, IV, sizeof(IV)) – dnaq Dec 13 '12 at 15:50

3 Answers3

4

EDIT: As Daniel pointed out in his answer, one big problem is that you are trying to use a random IV to decrypt (which will not give you the results you expect). However, I suggest that you read the rest of this answer as well.

First of all, aes_set_key_enc and aes_set_key_dec do not take passwords as input, they take keys. A key should be a completely random value as long as the key length (a random string of 32 bytes in your case, since you want to use a 256-bit key).

In your case you're calling aes_set_key_enc/aes_set_key_dec with a short password, but telling it that it should expect a 256-bit key, this will lead to these functions using memory outside of your password as part of the key, and will lead to the encryption and decryption keys to be different.

To recap, AES (or any cipher algorithm for that matter) expects random keys, the algorithms themselves have no concept of expanding a password to a key.

If you want to use a password as a key you need some function that expands a non-random password into a pseudo-random key. The only sane way to do this is to use a function that is designed to be cryptographically secure, but also slow, this is to mitigate the risk of brute-force attacks on the password.

Good functions to use are Colin Percivals scrypt, bcrypt or PBKDF2 of which I would recommend scrypt the most.

However, I want to stress that you probably shouldn't be working at this abstraction level at all. The primitives that you are using (block ciphers, CBC-mode) are at a really low abstraction level, and building a cryptosystem using those primitives can be really dangerous. For example you do not use any kind of authentication on your ciphertext, which might open up your implementation to chosen ciphertext attacks.

I think that the best way to if you want to use cryptography in your application is to try to work at a higher abstraction level, for example using Dan Bernsteins excellent NaCl or Googles KeyCzar.

To recap, your specific problem can be solved by using 256-bit keys, but you should think twice about implementing your own cryptosystem at this abstraction level.

dnaq
  • 1,904
  • 12
  • 21
  • This is all very good advice and I agree 100%. However, it very likely (depending on compiler) is not the real source of the problem. – Daniel Roethlisberger Dec 12 '12 at 09:28
  • You're right, I missed that he is using a random IV to decrypt. – dnaq Dec 12 '12 at 09:44
  • PolarSSL includes a module for PBKDF2.. So in combination with this code, that would most likely be best. (Aside from the fact that the IV thing is most likely the cause of the problem) – Paul Dec 12 '12 at 22:15
  • I followed your advice, use a 256-bit keys, use the same IV to encrypt and decrypt. But I still got wrong text.Before encrypt, the text is "ABCDEFGHIJKLMN", after decrypt, the text is "ABCDEFGHYCLMN".. – midCat Dec 13 '12 at 00:21
  • 1
    you need to use memcpy to copy the iv, since strncpy stops as soon as it finds a null byte in the input. – dnaq Dec 13 '12 at 11:45
4

You are using a random IV to decrypt. That is wrong. You need the same IV for decryption as you used for encryption. Simply remove the second call to

havege_random(&hs, IV, 16);

between the encrypt and the decrypt.

Also make sure to use a 32 byte char array as second argument to aes_setkey_enc and aes_setkey_dec because you are reading past the end of the string as it is now. Depending on the compiler it might lead to different keys being used for encryption and decryption (and thus, fail).

(Edit for second half of question)

Change this:

strncpy(IV, IV2, 16);           //copy IV

to this:

memcpy(IV2, IV, 16);           //copy IV

That's memcpy instead of strncpy because the IV is random data which can contain the string terminator '\0', and the first argument to both of these functions is the destination, not the source. You copied a string from IV2 to IV instead of memory from IV to IV2.

And to answer the question on how to get the IV for decryption: Normally, the IV is just sent along with the ciphertext. Each IV must only once be used once and it must not be predictable, but it is not necessary to keep it secret. A common construction is to choose a random IV for every message and simply prepend the IV to the ciphertext or to store it in a file header, depending on the scenario.

That being said, I agree with the advice to not construct your own crypto protocols using crypto primitives unless you know what you are doing.

Daniel Roethlisberger
  • 6,662
  • 1
  • 35
  • 54
-1

I just changed 64 to 14 in

aes_crypt_cbc(&dec_ctx, AES_DECRYPT, 64, IV2, buff[1],buff[0]);

and every thing worked fine!

Hamed
  • 3
  • 2