Dracke
Dracke

Reputation: 651

AES 256-cbc encryption C++ using OpenSSL

I am trying to create a function I can put a string key (I have another algorithm to generate the key) into and a message string. The function should encrypt and decrypt the text using the aes256-cbc from OpenSSL library

#define AES_KEYLENGTH 256
string cipher_AES(string key, string message);

int main(int argc, char* argv[])
{
     cipher_AES("115792089237316195423570985008687907853269984665640564039457583884239776304164", "Hello, how are you, you mad?");
     return 0;
}

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

/* computes the ciphertext from plaintext and key using AES256-CBC algorithm */
string cipher_AES(string key, string message)
{
    size_t inputslength = message.length();
    unsigned char aes_input[inputslength];
    unsigned char aes_key[AES_KEYLENGTH];
    memset(aes_input, 0, inputslength/8);
    memset(aes_key, 0, AES_KEYLENGTH/8);
    strcpy((char*) aes_input, message.c_str());
    strcpy((char*) aes_key, key.c_str());

    /* init vector */
    unsigned char iv[AES_BLOCK_SIZE];
    memset(iv, 0x00, AES_BLOCK_SIZE);

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

    AES_KEY enc_key, dec_key;
    AES_set_encrypt_key(aes_key, AES_KEYLENGTH, &enc_key);
    AES_cbc_encrypt(aes_input, enc_out, inputslength, &enc_key, iv, AES_ENCRYPT);

    AES_set_decrypt_key(aes_key, AES_KEYLENGTH, &dec_key);
    AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, 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));

    stringstream ss;
    for(int i = 0; i < encslength; i++)
    {
        ss << enc_out[i];
    }
    return ss.str(););
}

In the output it seems that something is the same but not all of it:

original:       48 65 6C 6C 6F 2C 20 68 6F 77 20 61 72 65 20 79 6F 75 2C 20 79 6F 75 20 69 64 69 6F 74 3F
encrypt:        25 C3 B4 4B 92 68 2E DA 61 B6 AB 19 97 D3 90 8A 5F 8B 3C 4B 78 13 FC E1 3A AF 2C B5 3F C8 2B D7
decrypt:        17 EE 50 27 17 3F DC 89 55 D8 0C D4 4D AD 0B AE 6F 75 2C 20 79 6F 75 20 69 64 69 6F 74 3F

Upvotes: 2

Views: 25427

Answers (3)

Ali Aziz
Ali Aziz

Reputation: 1

you need to change the size for encoding from inputslength to encslength

AES_cbc_encrypt(aes_input, enc_out, encslength, &enc_key, iv, AES_ENCRYPT);

and you need to make the same iv for decryption so make it clear it as you did for encrypt

memset(iv, 0x00, AES_BLOCK_SIZE);

before decrypt

Upvotes: -2

sometimestios
sometimestios

Reputation: 1

Reading the source code of cbc128.c of openssl, there exists a loop calling the iv or the output of last block. When the loop ends, iv will be renewed.

void CRYPTO_cbc128_encrypt(const unsigned char *in, unsigned char *out,
                           size_t len, const void *key,
                           unsigned char ivec[16], block128_f block)
{
    size_t n;
    const unsigned char *iv = ivec;

    if (len == 0)
        return;

#if !defined(OPENSSL_SMALL_FOOTPRINT)
    if (STRICT_ALIGNMENT &&
        ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) {
        while (len >= 16) {
            for (n = 0; n < 16; ++n)
                out[n] = in[n] ^ iv[n];
            (*block) (out, out, key);
            iv = out;
            len -= 16;
            in += 16;
            out += 16;
        }
    } else {
        while (len >= 16) {
            for (n = 0; n < 16; n += sizeof(size_t))
                *(size_t_aX *)(out + n) =
                    *(size_t_aX *)(in + n) ^ *(size_t_aX *)(iv + n);
            (*block) (out, out, key);
            iv = out;
            len -= 16;
            in += 16;
            out += 16;
        }
    }
#endif
    while (len) {
        for (n = 0; n < 16 && n < len; ++n)
            out[n] = in[n] ^ iv[n];
        for (; n < 16; ++n)
            out[n] = iv[n];
        (*block) (out, out, key);
        iv = out;
        if (len <= 16)
            break;
        len -= 16;
        in += 16;
        out += 16;
    }
    memcpy(ivec, iv, 16);
}

Upvotes: 0

matt
matt

Reputation: 79793

Looking at your data, the first block (16 bytes) is wrong but following blocks are correct. This suggests that the wrong IV is being used when decrypting. A little testing (printing the IV before and after the first call to AES_cbc_encrypt) shows that the IV does indeed change during this call.

A little poking around the OpenSSL source shows that it changes the IV parameter to be the last block of the ciphertext when encrypting.

Resetting the IV before the decryption fixes it though, and you get the correct plaintext regenerated:

memset(iv, 0x00, AES_BLOCK_SIZE);
AES_cbc_encrypt(enc_out, dec_out, encslength, &dec_key, iv, AES_DECRYPT);

Upvotes: 7

Related Questions