OpenSSL AES cbc c example 암호·복호화 예제

AES 암호 루틴이 필요해서 OpenSSL을 이용하기로 했습니다. MD5 해시코드 함수 때문에 OpenSSL 사용해 본 적이 있어서 쉽게 끝날 줄 알았습니다. 구글에서 OpenSSL AES example을 검색해 보니 cbc 모드 예제가 보이네요. 그리고 예제대로 코드를 작성했는데 처음에는 잘 되는 줄 알았습니다.

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

typedef unsigned char   U8;

static const U8 cipher_key[]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};

#define KEY_BIT 128

int aes_encrypt( U8 *p_in, U8 *p_out, int size)
{
    AES_KEY aes_key;
    U8 iv_aes[AES_BLOCK_SIZE];

    bzero(iv_aes, sizeof(iv_aes));
    AES_set_encrypt_key( cipher_key, KEY_BIT, &aes_key);
    AES_cbc_encrypt( p_in, p_out, size, &aes_key , iv_aes, AES_ENCRYPT);

    return 0;
}

int aes_decrypt( U8 *p_in, U8 *p_out, int size)
{
    AES_KEY aes_key;
    U8 iv_aes[AES_BLOCK_SIZE];

    bzero(iv_aes, sizeof(iv_aes));
    AES_set_decrypt_key( cipher_key, KEY_BIT, &aes_key);
    AES_cbc_encrypt( p_in, p_out, size, &aes_key , iv_aes, AES_DECRYPT);
    return 0;
}


int main(int argc, char *args[])
{
    U8      p_sour[] = {0x01, 0x02, 0x03, 0x04, 0x05};
    U8      p_encrypt[1024];
    U8      p_decrypt[1024];

    aes_encrypt( p_sour   , p_encrypt, sizeof( p_sour));
    aes_decrypt( p_encrypt, p_decrypt, sizeof( p_sour));

    int     ndx;

    printf( "decrypt aes: ");
    for ( ndx = 0; ndx < sizeof( p_sour); ndx++){
        printf( "0x%02x ", p_decrypt[ndx]);
    }
    printf( "\n");

    return 0;
}

실행해 보면 아래처럼 제대로 복호화된 결과 값이 나오거든요.

]$ a.out
decrypt aes: 0x01 0x02 0x03 0x04 0x05

그러나 아래처럼 암호된 문자열을 다른 변수에 복사해서 암호를 풀면 전혀 엉뚱한 값이 출력됩니다.

int main(int argc, char *args[])
{
    U8      p_sour[] = {0x01, 0x02, 0x03, 0x04, 0x05};
    U8      p_encrypt[1024];
    U8      p_decrypt[1024];
    U8      p_temp[1024];

    aes_encrypt( p_sour   , p_encrypt, sizeof( p_sour));

    memcpy( p_temp, p_encrypt, sizeof( p_sour));

    aes_decrypt( p_temp, p_decrypt, sizeof( p_sour));

    int     ndx;

    printf( "decrypt aes: ");
    for ( ndx = 0; ndx < sizeof( p_sour); ndx++){
        printf( "0x%02x, ", p_decrypt[ndx]);
    }
    printf( "\n");

    return 0;
}

실행하면 아까와는 전혀 다른 값이 출력되지요.

]$ a.out
decrypt aes: 0x63 0x81 0xcd 0xbb 0x6c

복호화가 제대로 되지 않는 것이죠. 왜? 다른 변수로 복사해서 복호화하면 안 될까요?

AES cbc는 패딩을 만들어 내는 암호 알고리즘

결론부터 말씀드리면 암호에 대한 저의 무지가 가장 큰 이유였습니다. AES의 cbc모드는 원래 데이터 길이만큼 결과가 나오지 않습니다. 어떤 길이의 데이터를 넣든 128bit 단위로 데이터를 생성합니다. 1byte를 암호화해도 128bit 즉, 16byte 결과 값으로 나옵니다. 1byte에서 16byte까지는 16byte로, 17byte에서 32byte까지는 32byte로 결과 값이 나오죠.

정리하여 말씀 드리면 AES cbc는 원래 데이터 길이에 모자라는 부분을 패딩처리합니다. 암호에서 패딩(Padding)은 데이터를 특정 크기로 맞추기 위해 부족한 부분을 채우는 것을 말합니다.

원래 데이터 길이가 data_size라고 한다면 결과 데이터 길이는 아래와 같습니다.

결과 데이터 길이 = (data_size+16)/16 *16;

예제에서 p_sour이 5바이트 데이터이지만, 암호 결과는 16byte이므로 p_sour 길이만큼 복사한 memcpy( p_temp, p_encrypt, sizeof( p_sour)); 부분이 잘못된 것입니다.

제대로된 OpenSSL AES cbc 예제

올바르게 수정된 main함수는 아래와 같습니다.

int main(int argc, char *args[]) { U8 p_sour[] = {0x01, 0x02, 0x03, 0x04, 0x05}; U8 p_encrypt[1024]; U8 p_decrypt[1024]; U8 p_temp[1024]; int encrypt_size; aes_encrypt( p_sour , p_encrypt, sizeof( p_sour)); encrypt_size = ( sizeof( p_sour) + AES_BLOCK_SIZE) /16 * 16; memcpy( p_temp, p_encrypt, encrypt_size); // 오류 수정 aes_decrypt( p_temp, p_decrypt, encrypt_size); // 오류 수정 int ndx; printf( "decrypt aes: "); for ( ndx = 0; ndx < sizeof( p_sour); ndx++){ printf( "0x%02x ", p_decrypt[ndx]); } printf( "\n"); return 0; }

실행 결과가 올바르게 나오네요.

decrypt aes: 0x01 0x02 0x03 0x04 0x05

아래 글에 AES cbc 모드의 패딩에 대해 자세히 나와 있습니다. 한글로 설명해 놓아서 이해하기 쉽네요.

 

 

● 바다야크 추천 글
?
신고
| 2017.04.11 16:41 | PERMALINK | EDIT/DEL | REPLY
비밀댓글입니다
Name
Password
Homepage Secret