5

I know that when I use CBC mode with Openssl, I can give as an input which is a multiple of a block size. But how about other modes? ECB, CFB, OFB? I saw a doc but its not all clear to me. Should I call them in a loop?

Lets say, ECB. It encrypts 64 bits at a time. So a pseudocode would look like this (should look like this)?

int len = 512, c = 0;
unsigned char in[len], out[len]; 
while(c < len)
{
  Aes_ecb_encrypt(in+c, out+c, &enckey, AES_ENCRYPT);
  c += 8;
}

But with the above code it doesnt encrpyt good. When I change c += 8; into c += 16; its ok then. Whats is good way of doing this? I mean, we all know that 8x8 = 64 bits so this should be correct, but it isnt, the encryption/decryption is working only when I have c += 16;.

What about other cipher modes?

Sample for ECB mode (notice, that the question is also about other modes too;)):

#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;
    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);

    // 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);

    long c = 0;
    while(c < encslength)
    {
        AES_ecb_encrypt(paddedinput+c, enc_out+c, &enc_key, AES_ENCRYPT);
        c += 8;
    }

    c = 0;
    AES_set_decrypt_key(aes_key, keylength, &dec_key);
    while(c < encslength)
    {
        AES_ecb_encrypt(enc_out+c, dec_out+c, &dec_key, AES_DECRYPT);
        c += 8;
    }

    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;
}
ivy
  • 1,445
  • 3
  • 15
  • 20
  • 1
    All AES modes will encrypt in multiples of the block size. How those blocks are used during the encryption process is the major difference between modes. Padding also comes into play (and your input must be a precise block-size multiple if padding is not used; if it *is* used, up to one full extra block size of output data may be generated, depending on the input size). You said, "But with the above code it doesnt encrpyt good." Well, the "above" code doesn't do *anything* because it isn't real code. Bring a [SSCCE](http://www.sscce.org) and we can work with it. – WhozCraig Aug 17 '13 at 18:41
  • @WhozCraig: Thanks. I gave here AES as an example only, Im asking about pretty all other block ciphers. The `SSCCE` I pasted works only when I change `c+=8;` to `c+=16;`. Should I use *same* loop for other cipher modes too? (I guess I will have to change only part with `c+=...;` and call appropriate function mode, right?) – ivy Aug 17 '13 at 18:51
  • 1
    Heh. I *wrote* that example you cite in [this question](http://stackoverflow.com/questions/18152913/aes-aes-cbc-128-aes-cbc-192-aes-cbc-256-encryption-decryption-with-openssl-c). It was somewhat specific to that OP's question, however. So long as the block of data you're encrypting is contiguous, you shouldn't have to loop *at all*. Just encrypt it. – WhozCraig Aug 17 '13 at 18:55
  • @WhozCraig: but do I understand it right, that with the bigger input size I should use a loop here? Try it with 50 - it doesnt decrypt/encrypt the whole input properly! And why `16`, not `8`? When using other modes and long input, I assume, the loop is needed too? – ivy Aug 17 '13 at 18:58
  • 1
    No, thats the point of the input data size parameter of the api you're calling. It will do the block-by-block encryption *for you* through the last block and, if setup to do so, the padding data as well (if applicable to your requested mode). I.e., unless you're trying to encrypt a variant data in a stream, you shouldn't have to loop at all. Just make sure the output buffer is large enough for the final data. If you want to stream-encryption, you certainly can, but in that case use `AES_BLOCK_SIZE` multiples and make sure your decryption side does the same thing. – WhozCraig Aug 17 '13 at 19:00
  • @WhozCraig: Ok, I modified the code I posted as you suggested: http://pastie.org/private/zrn7mvslpmx2zzxs2j7vxg. So tell me now why it doesnt encrypt/decrypt the whole input? – ivy Aug 17 '13 at 19:06
  • @WhozCraig: I did a little research on Openssl's doc site, and found [this](http://www.openssl.org/docs/crypto/des.html). I know, its about `DES` not `AES` but ther's something like that in this doc: `DES_ecb_encrypt() is the basic DES encryption routine that encrypts or decrypts a single 8-byte DES_cblock in electronic code book (ECB) mode.` So is it possible that I'm right and I need to call it in a loop? – ivy Aug 17 '13 at 20:09
  • 1
    You should *not* use `AES_encrypt` and friends. You should be using `EVP_*` functions. See [EVP Symmetric Encryption and Decryption](https://wiki.openssl.org/index.php/EVP_Symmetric_Encryption_and_Decryption) on the OpenSSL wiki. In fact, you should probably be using authenticated encryption because it provides *both* confidentiality and authenticity. See [EVP Authenticated Encryption and Decryption](https://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption) on the OpenSSL wiki. – jww May 15 '15 at 20:18

1 Answers1

3

Lets say, ECB. It encrypts 64 bits at a time

AES is a 128-bit block cipher. It encrypts/decrypts 128-bit at a time. It is a standard. AES_encrypt/AES_decrypt block expects 128 bits or 16 bytes length of the input and output data.

But with the above code it doesnt encrpyt good. When I change c += 8; into c += 16; its ok then. Whats is good way of doing this? I mean, we all know that 8x8 = 64 bits so this should be correct, but it isnt, the encryption/decryption is working only when I have c += 16;

That is why it is working fine on

c+=16

Apart from this, there are few problems in your code.

unsigned char enc_out[encslength];

Please keep the size of dec_out of encslength since you are decrypting encslength bytes not inputslength in your code.

unsigned char dec_out[encslength];
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);

In this section, increase c by 16 as AES is 128 block cipher.

long c = 0;
while(c < encslength)
{
    AES_ecb_encrypt(paddedinput+c, enc_out+c, &enc_key, AES_ENCRYPT);
    c += 16;
}

Similar change here:

c = 0;
AES_set_decrypt_key(aes_key, keylength, &dec_key);
while(c < encslength)
{
    AES_ecb_encrypt(enc_out+c, dec_out+c, &dec_key, AES_DECRYPT);
    c += 16;
}

About other modes:

  1. CFB mode There is no need to pad the data. Use AES_cfb128_encrypt and initialization vector (IV) along with key.

For encryption:

AES_cfb128_encrypt (paddedinput, enc_out, inputlength, &enc_key, iv, AES_ENCRYPT);

For decryption:

AES_cfb128_decrypt (enc_out, dec_out, inputlength, &enc_key, iv, AES_ENCRYPT);
  1. OFB mode Similarly on OFB mode, there is no need to pad the data. Use AES_ofb128_encrypt and IV along with key.

For encryption:

//Initialize num to 0.
num = 0;
AES_ofb128_encrypt (paddedinput, enc_out, inputlength, &enc_key, iv, &num);

For decryption:

num = 0;
AES_ofb128_encrypt (enc_out, dec_out, inputlength, &enc_key, iv, &num);

You may need to tweak the code some bit as per your need.

Please read more about block cipher mode of operation.

doptimusprime
  • 9,115
  • 6
  • 52
  • 90