1

I want to develop functions for encrypt and decrypt. the key size should be at least 128 bits (16 bytes).

I used the AES* api functions from the OpenSSL. but there is some restriction in the AES* functions: the input data buffers should be multiple of 16!

Here after my functions:

unsigned char encrypt_aes_key[]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};

static inline int enc_array_decrypt(unsigned char *encarray, unsigned char *decarray, int size)
{
    int i;
    AES_KEY dec_key;
    unsigned char apibuf[512] = {0};
    unsigned char iv[AES_BLOCK_SIZE];
    memset(iv, 0x00, AES_BLOCK_SIZE);

    AES_set_decrypt_key(encrypt_aes_key, sizeof(encrypt_aes_key)*8, &dec_key); // Size of key is in bits
    AES_cbc_encrypt(encarray, apibuf, size, &dec_key, iv, AES_DECRYPT);
    memcpy(decarray, apibuf, size);

    return 0;
}

static inline int enc_array_encrypt(unsigned char *array, unsigned char *encarray, int size)
{
    int i;
    AES_KEY enc_key;
    unsigned char apibuf[512] = {0};
    unsigned char iv[AES_BLOCK_SIZE];
    memset(iv, 0x00, AES_BLOCK_SIZE);

    AES_set_encrypt_key(encrypt_aes_key, sizeof(encrypt_aes_key)*8, &enc_key); // Size of key is in bits
    AES_cbc_encrypt((unsigned char *)array, apibuf, size, &enc_key, iv, AES_ENCRYPT);
    memcpy(encarray, apibuf, size);

    return 0;
}

if I call my functions with buffer size 9 for example, the functions will return wron output

example:

int main(int argc, char *argv[] )
{
    char buf[9] = {0}, encbuf[9] = {0}, decbuf[9] = {0};
    strcpy(buf, argv[1]);

    enc_array_encrypt(buf, encbuf, 9);
    enc_array_decrypt(encbuf, decbuf, 9);

    printf("%s  \n%s\n", buf, decbuf);

    return 0;
}

The program returns:

$ ./myprogram any
any  
2�����S�

How I can fix that?

by the way I can not force the buffer to be 16x multiplier size. because I will integrate my functions in a big source code (SDK) in which I will call my functions in many places with different input buffer sizes.

I m open to use any other kind of encryption (other than AES), but should support key of 128 bits length. The input buffer and the encrypted buffer should have the same size

MOHAMED
  • 41,599
  • 58
  • 163
  • 268
  • 1
    I don't think you can have block sizes other than 16 with AES. Round buffer sizes up to nearest 16 bytes and pad unused bytes with 0 to get consistent results. – user694733 Aug 04 '16 at 10:22
  • @user694733 I m open to use any other kind of encryption (other than AES), but should support key of 128 length. – MOHAMED Aug 04 '16 at 10:27
  • 1
    @user694733 Do not add null padding, it is not secure and can to be used with binary data, use [PKCS#7 padding[(https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7). – zaph Aug 04 '16 at 17:31
  • @MOHAMED AES is the best choice for symmetric encryption. Encryption is data based, not character based. Thus the output of encryption is a string of 8-bit bytes, many of which have no printable representation. That is why if a printable character string is required the output is usually encoded with Base64 or hexadecimal. – zaph Aug 04 '16 at 17:36
  • This is the duplicate, but its on the Crypto.SE: [Why does OpenSSL append extra bytes when encrypting with aes-128-ecb?](http://crypto.stackexchange.com/q/12621). Here are some similar questions from Stack Overflow: [Relation between input and ciphertext length in AES](http://stackoverflow.com/q/3716691) and [Does AES_cbc_encrypt add padding?](http://stackoverflow.com/q/31226594) – jww Aug 04 '16 at 20:44
  • 1
    You should *not* use `AES_encrypt` and friends. That's a software-only implementation, so you will not enjoy hardware support, like AES-NI. You should be using `EVP_*` functions. See [EVP Symmetric Encryption and Decryption](http://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](http://wiki.openssl.org/index.php/EVP_Authenticated_Encryption_and_Decryption) on the OpenSSL wiki. – jww Aug 04 '16 at 20:44

1 Answers1

0

It's generally not recommended to use the AES* function directly in OpenSSL. It's better to use the EVP family of functions. These will allow you to give an input buffer of any length.

void log_ssl_err(const char *mes)
{
    unsigned long err;
    char errstr[1000];

    while ((err = ERR_get_error())) {
        ERR_error_string(err, errstr);
        printf("%s: %s", mes, errstr);
    }
}

int encrypt_block(const unsigned char *IV, const unsigned char *key,
                  const unsigned char *src, unsigned int srclen,
                  unsigned char *dest, unsigned int *destlen)
{
    EVP_CIPHER_CTX ctx;
    const EVP_CIPHER *cipher = EVP_get_cipherbyname("AES-256-CBC");
    int mode, len;

    if (cipher == NULL) {
        printf("Invalid keytype");
        return 0;
    }
    mode = EVP_CIPHER_mode(cipher);
    EVP_CIPHER_CTX_init(&ctx);
    if (!EVP_EncryptInit_ex(&ctx, cipher, NULL, NULL, NULL)) {
        log_ssl_err("EncryptInit for cipher failed");
        return 0;
    }
    if (!EVP_EncryptInit_ex(&ctx, NULL, NULL, key, IV)) {
        log_ssl_err("EncryptInit for key/IV failed");
        return 0;
    }
    len = 0;
    if (!EVP_EncryptUpdate(&ctx, dest, &len, src, srclen)) {
        log_ssl_err("EncryptUpdate for data failed");
        EVP_CIPHER_CTX_cleanup(&ctx);
        return 0;
    }
    *destlen = len;
    if (!EVP_EncryptFinal_ex(&ctx, dest + *destlen, &len)) {
        log_ssl_err("EncryptFinal failed");
        EVP_CIPHER_CTX_cleanup(&ctx);
        return 0;
    }
    *destlen += len;
    EVP_CIPHER_CTX_cleanup(&ctx);

    return 1;
}

int decrypt_block(const unsigned char *IV, const unsigned char *key,
                  unsigned char *src, unsigned int srclen,
                  unsigned char *dest, unsigned int *destlen)
{
    EVP_CIPHER_CTX ctx;
    const EVP_CIPHER *cipher = EVP_get_cipherbyname("AES-256-CBC");
    int mode, len;

    if (cipher == NULL) {
        printf("Invalid keytype");
        return 0;
    }
    mode = EVP_CIPHER_mode(cipher);
    EVP_CIPHER_CTX_init(&ctx);
    if (!EVP_DecryptInit_ex(&ctx, cipher, NULL, NULL, NULL)) {
        log_ssl_err("DecryptInit for cipher failed");
        return 0;
    }
    if (!EVP_DecryptUpdate(&ctx, dest, &len, src, srclen)) {
        log_ssl_err("DecryptUpdate for data failed");
        EVP_CIPHER_CTX_cleanup(&ctx);
        return 0;
    }
    *destlen = len;
    if (!EVP_DecryptFinal_ex(&ctx, dest + *destlen, &len)) {
        log_ssl_err("DecryptFinal failed");
        EVP_CIPHER_CTX_cleanup(&ctx);
        return 0;
    }
    *destlen += len;
    EVP_CIPHER_CTX_cleanup(&ctx);

    return 1;
}
dbush
  • 205,898
  • 23
  • 218
  • 273
  • The reason any arbitrary data size can be encrypted is because it is adding PKCS#7 padding by default. Not all library functions do that. – zaph Aug 04 '16 at 17:33
  • in your `encrypt_block()` function, Does the final value of `*destlen` is the same of `srclen`? Because my input data buffer should have the same size of encrypted buffer. – MOHAMED Aug 05 '16 at 09:07
  • As I understand from the ompenssl wiki the `*destlen = srclen + 1`, so the `EVP_*` functions. will make a padding of 1 byte. The padding byte is added by the function `EVP_EncryptFinal_ex`. Am I right ? – MOHAMED Aug 05 '16 at 09:16
  • @MOHAMED `*destlen` will most likely not be the same as `srclen`. If the former is not a multiple of the block size padding will automatically be added and `*destlen` is a multiple of the block size. Even if `srclen` is a multiple, it will still add padding. When the data is decrypted, the padding is checked to ensure it is correct. This helps detect if the ciphertext was corrupted. And yes, the call to `EVP_EncryptFinal_ex` encrypts any bytes that don't fill a whole block along with any padding. – dbush Aug 05 '16 at 12:54
  • so the `*destlen > srclen` ? – MOHAMED Aug 05 '16 at 16:05
  • so even `EVP_*` will not help me in my case. Because I m looking for a solution to encrypt data in which the input data buffer and the encrypted buffer should have the same size – MOHAMED Aug 05 '16 at 17:13
  • @MOHAMED Then you can't use AES. You would need a much simpler, less secure, encryption algorithm. – dbush Aug 05 '16 at 17:29
  • Examples of other algorithmes with key of st least 128 bits? – MOHAMED Aug 06 '16 at 04:03