5

Recently I finally (with help of stackoverflow's user, @WhozCraig) got to work AES in CBC mode. Now, I would like to do exact same thing but with AES IGE. I took a look at openssl-1.0.1e/test/igetest.c and tried to build my own test. But once again, I have a problem with inputs and outputs proper sizes. Everything else is good, because I copied it from my previous code: AES (aes-cbc-128, aes-cbc-192, aes-cbc-256) encryption/decryption with openssl C.

Now, when I pass an inputs length which is less than 32, it says:

Give a key length [only 128 or 192 or 256!]:
256
Give an input's length:
3
aes_ige.c(88): OpenSSL internal error, assertion failed: (length%AES_BLOCK_SIZE) == 0
 (core dumped)

But when the lenght is bigger than 32, Im also not so sure if its all ok:

Give a key length [only 128 or 192 or 256!]:
256
Give an input's length:
48
original:       58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 
encrypt:        A4 1F C4 E8 42 5E E5 62 1A B6 C1 47 D2 2F 8D 98 D0 0B 32 77 4E 36 84 25 15 5B BA 60 EA A9 64 D2 53 D1 98 78 83 21 90 90 74 44 C7 AA 3E AD 9B 26 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 
decrypt:        58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 

Heres the code:

    #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>

// a simple hex-print routine. could be modified to print 16 bytes-per-line
static void hex_print(const void* pv, size_t len)
{
    const unsigned char * p = (const unsigned char*)pv;
    if (NULL == pv)
        printf("NULL");
    else
    {
        size_t i = 0;
        for (; i<len;++i)
            printf("%02X ", *p++);
    }
    printf("\n");
}

// main entrypoint
int main(int argc, char **argv)
{
    int keylength;
    printf("Give a key length [only 128 or 192 or 256!]:\n");
    scanf("%d", &keylength);

    /* generate a key with a given length */
    unsigned char aes_key[keylength/8];
    memset(aes_key, 0, keylength/8);
    if (!RAND_bytes(aes_key, keylength/8))
        exit(-1);

    size_t inputslength = 0;
    printf("Give an input's length:\n");
    scanf("%lu", &inputslength);

    /* generate input with a given length */
    unsigned char aes_input[inputslength];
    memset(aes_input, 'X', inputslength);

    const size_t ivsize = AES_BLOCK_SIZE*2;

    /* init vector */
    unsigned char iv_enc[ivsize], iv_dec[ivsize];
    RAND_bytes(iv_enc, ivsize);
    memcpy(iv_dec, iv_enc, ivsize);

    // buffers for encryption and decryption
    const size_t encslength = (inputslength/AES_BLOCK_SIZE + 1) * AES_BLOCK_SIZE;//((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
    unsigned char enc_out[encslength];
    unsigned char dec_out[inputslength];
    memset(enc_out, 0, sizeof(enc_out));
    memset(dec_out, 0, sizeof(dec_out));

    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, keylength, &enc_key);
    AES_set_decrypt_key(aes_key, keylength, &dec_key);

    AES_ige_encrypt(aes_input, enc_out, inputslength, &enc_key, iv_enc, AES_ENCRYPT);

    AES_ige_encrypt(enc_out, dec_out, encslength, &dec_key, iv_dec, AES_DECRYPT);

    printf("original:\t");
    hex_print(aes_input, sizeof(aes_input));

    printf("encrypt:\t");
    hex_print(enc_out, sizeof(enc_out));

    printf("decrypt:\t");
    hex_print(dec_out, sizeof(dec_out));

    return 0;
}

FINALLY! Got it working (hope so).But I would be veeery grateful if someone can say, that this code below is 100% good ;)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>

// a simple hex-print routine. could be modified to print 16 bytes-per-line
static void hex_print(const void* pv, size_t len)
{
    const unsigned char * p = (const unsigned char*)pv;
    if (NULL == pv)
        printf("NULL");
    else
    {
        size_t i = 0;
        for (; i<len;++i)
            printf("%02X ", *p++);
    }
    printf("\n");
}

// main entrypoint
int main(int argc, char **argv)
{
    int keylength = 256;
    //printf("Give a key length [only 128 or 192 or 256!]:\n");
    //scanf("%d", &keylength);

    /* generate a key with a given length */
    unsigned char aes_key[keylength/8];
    memset(aes_key, 0, keylength/8);
    if (!RAND_bytes(aes_key, keylength/8))
        exit(-1);

    size_t inputslength = 0;
    printf("Give an input's length:\n");
    scanf("%lu", &inputslength);

    /* generate input with a given length */
    unsigned char aes_input[inputslength];
    memset(aes_input, 'X', inputslength);

    const size_t ivsize = AES_BLOCK_SIZE*2;
    /* init vector */
    unsigned char iv_enc[ivsize], iv_dec[ivsize];
    RAND_bytes(iv_enc, ivsize);
    memcpy(iv_dec, iv_enc, ivsize);

    // buffers for encryption and decryption
    const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
    unsigned char enc_out[encslength];
    unsigned char dec_out[inputslength];
    memset(enc_out, 0, sizeof(enc_out));
    memset(dec_out, 0, sizeof(dec_out));

    // so i can do with this aes-cbc-128 aes-cbc-192 aes-cbc-256
    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, keylength, &enc_key);
    AES_ige_encrypt(aes_input, enc_out, encslength, &enc_key, iv_enc, AES_ENCRYPT);

    AES_set_decrypt_key(aes_key, keylength, &dec_key);
    AES_ige_encrypt(enc_out, dec_out, encslength, &dec_key, iv_dec, AES_DECRYPT);

    printf("original:\t");
    hex_print(aes_input, sizeof(aes_input));

    printf("encrypt:\t");
    hex_print(enc_out, sizeof(enc_out));

    printf("decrypt:\t");
    hex_print(dec_out, sizeof(dec_out));

    return 0;
}

I only changed this:

AES_ige_encrypt(aes_input, enc_out, **inputslength**, &enc_key, iv_enc, AES_ENCRYPT);

into that:

AES_ige_encrypt(aes_input, enc_out, **encslength**, &enc_key, iv_enc, AES_ENCRYPT);

is it correct?

EDIT No.2 ;)

Ok guys, did another example, with your advices added some padding to the input. Hope its ok now?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>

// a simple hex-print routine. could be modified to print 16 bytes-per-line
static void hex_print(const void* pv, size_t len)
{
    const unsigned char * p = (const unsigned char*)pv;
    if (NULL == pv)
        printf("NULL");
    else
    {
        size_t i = 0;
        for (; i<len;++i)
            printf("%02X ", *p++);
    }
    printf("\n");
}

// main entrypoint
int main(int argc, char **argv)
{
    int keylength = 256;
    //printf("Give a key length [only 128 or 192 or 256!]:\n");
    //scanf("%d", &keylength);

    /* generate a key with a given length */
    unsigned char aes_key[keylength/8];
    memset(aes_key, 0, keylength/8);
    if (!RAND_bytes(aes_key, keylength/8))
        exit(-1);

    size_t inputslength = 0;
    printf("Give an input's length:\n");
    scanf("%lu", &inputslength);

    /* generate input with a given length */
    unsigned char aes_input[inputslength];
    memset(aes_input, 'X', inputslength);

    const size_t ivsize = AES_BLOCK_SIZE*2;
    /* init vector */
    unsigned char iv_enc[ivsize], iv_dec[ivsize];
    RAND_bytes(iv_enc, ivsize);
    memcpy(iv_dec, iv_enc, ivsize);

    // buffers for encryption and decryption
    const size_t encslength = ((inputslength + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;

    unsigned char paddedinput[encslength];
    memset(paddedinput, 0, encslength);
    memcpy(paddedinput, aes_input, inputslength);

    unsigned char enc_out[encslength];
    unsigned char dec_out[inputslength];
    memset(enc_out, 0, sizeof(enc_out));
    memset(dec_out, 0, sizeof(dec_out));

    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, keylength, &enc_key);
    AES_ige_encrypt(paddedinput, enc_out, encslength, &enc_key, iv_enc, AES_ENCRYPT);

    AES_set_decrypt_key(aes_key, keylength, &dec_key);
    AES_ige_encrypt(enc_out, dec_out, encslength, &dec_key, iv_dec, AES_DECRYPT);

    printf("original:\t");
    hex_print(aes_input, sizeof(aes_input));

    printf("encrypt:\t");
    hex_print(enc_out, sizeof(enc_out));

    printf("decrypt:\t");
    hex_print(dec_out, sizeof(dec_out));

    return 0;
}
Community
  • 1
  • 1
ivy
  • 1,445
  • 3
  • 15
  • 20
  • 1
    @WhozCraig: may I bother you just a little more for a while? Could you please look at my second code I pasted here and only say if its correct or not? The main issue I have with `AES_ige_encrypt` - when I pass `inputslength` instead of `encslength` I got a strange error: `aes_ige.c(88): OpenSSL internal error, assertion failed: (length%AES_BLOCK_SIZE) == 0` – ivy Aug 13 '13 at 11:35
  • 2
    If you don't perform any padding (zero byte padding or otherwise) then you need your plain text to be precisely N times the block size. What part of this is not clear to you? IGE is the same as CBC in that matter. – Maarten Bodewes Aug 14 '13 at 01:28
  • @owlstead: Thanks for the answer. Yup, I read a lot about it yesterday and I think its clear to me now. But theres just one more thing I cant really understand. In my [previous code](http://stackoverflow.com/questions/18152913/aes-aes-cbc-128-aes-cbc-192-aes-cbc-256-encryption-decryption-with-openssl-c) I didnt do any padding, and it was all good. I mean, I passed to `AES_cbc_encrypt` an input with the lenght given by the user (without a padding!), so why now its not working? – ivy Aug 14 '13 at 08:14
  • 1
    Note that it is better to apply PKCS#7 padding if you want to use binary data (that may end with zero valued bytes). Also note that IGE is *not* a replacement for an authentication tag. Integrity/authenticity may not be preserved - man in the middle attacks may apply. IGE is a very sparsely used mode of encryption that only protects against very specific attacks. – Maarten Bodewes Aug 14 '13 at 10:00

1 Answers1

5

The error message says it all.

aes_ige.c(88): OpenSSL internal error, assertion failed: (length%AES_BLOCK_SIZE) == 0

This is basically a run-time-check (assertion) that fails due to invalid input provided to the function AES_ige_encrypt() present in the source at line 88 of aes_ige.c.

OPENSSL_assert((length%AES_BLOCK_SIZE) == 0);

The assertion basically checks if length (the 3rd parameter passed to the function) is an integral multiple of AES_BLOCK_SIZE. If yes, the execution continues, otherwise the program halts and prints warning about the assertion having failed.

  1. So ensure that the size of the data being passed to AES_ige_encrypt() is a multiple of AES_BLOCK_SIZE.

  2. If size of the data is not an integral multiple, then append NUL bytes to it to make the total size the nearest multiple of AES_BLOCK_SIZE.

  3. Also, always pass the "integral-multiple-of-AES_BLOCK_SIZE" value as the length parameter to AES_ige_encrypt().

TheCodeArtist
  • 21,479
  • 4
  • 69
  • 130
  • Thanks for the explanation. I know where the error came from but I cant understand why. In my [previous code](http://stackoverflow.com/questions/18152913/aes-aes-cbc-128-aes-cbc-192-aes-cbc-256-encryption-decryption-with-openssl-c) I didnt do any padding, and it worked. I passed to `AES_cbc_encrypt` an input with the lenght given by the user (without a padding!), so why now its not working? I did another example code: http://pastie.org/private/yzlkcudvpwwfczvpvo8gw and it seem to be ok now. Any ideas why I cant do the same like before? – ivy Aug 14 '13 at 08:19
  • Another question;) So for every block-size cipher I have to pass an input which is a multiple of CIPHERs_BLOCK_SIZE? Is that true for EVERY block size cipher? Thanks:) – ivy Aug 14 '13 at 08:23
  • 4
    Earlier, when you called [**`AES_cbc_encrypt()`**](http://fossies.org/dox/openssl-1.0.1e/aes__cbc_8c_source.html#l00055), it internally called [**`CRYPTO_cbc128_encrypt()`**](http://fossies.org/dox/openssl-1.0.1e/cbc128_8c.html#a5cbe79f5b3a935a6e49ac72e3f3e4fb2) which had no restriction on the length of the payload data to be encrypted. Hence you did not get any error. – TheCodeArtist Aug 14 '13 at 08:26
  • 4
    Regarding your **query on block-size**, the answer depends upon the implementation of the library/framework. As their name implies, BLOCK ciphers would require standard block sizes. When passed non-standard sizes, whether the ***payload is automatically padded*** or ***an error is raised*** depends upon the code that implements the crypto framework/library. – TheCodeArtist Aug 14 '13 at 08:29
  • interesting! How did you check it? About block sizes: so I guess openssls doesnt do any padding. And how about my last pasted code - did I do the padding correctly? – ivy Aug 14 '13 at 08:43
  • 3
    Initially [**zero-ing a buffer of proper-length**](http://pastie.org/private/yzlkcudvpwwfczvpvo8gw#51) and then copying the payload data into it looks good to me. Modify the calculation of `encslength` as follows: **`encslength = ((inputslength + AES_BLOCK_SIZE -1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;`**. The older logic would unnecessarily use a larger buffer in case the payload was **already** an exact multiple of `AES_BLOCK_SIZE`. – TheCodeArtist Aug 14 '13 at 08:47
  • So `encslength = ((inputslength + AES_BLOCK_SIZE -1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;` will be correct for the length of the ciphertext, padded input and decrypted text? Thanks for all of your answers, you helped me a lot! Cheers:) – ivy Aug 14 '13 at 08:53
  • Just one more question. Your formula of calculating the `encslength` will be true for every block cipher? I mean I can use it for every block cipher, remembering to change only `AES_BLOCK_SIZE` to CIPHERs_BLOCK_SIZE? – ivy Aug 14 '13 at 08:56
  • 1
    Yes and yes. The math is the same. About why a certain library works in a particular way- The answer is almost always available "somewhere" in the Documentation. Also whenever the source code is available, it is the best way to check why something happens the way it does. I have linked all openssl functions that i happened to mention earlier to a online openssl source repository. I would encourage you to click the links and spend a few mins browsing the code to have a better understanding. – TheCodeArtist Aug 14 '13 at 09:01
  • Thanks again for your patience and answers :) I will award your answer, but SO says that I have to wait to do this 3 more hours, so please be patient a little bit more;) Cheers! – ivy Aug 14 '13 at 09:20
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/35414/discussion-between-thecodeartist-and-ivy) – TheCodeArtist Aug 14 '13 at 09:34