[C/C++] AES

Alexandria·2024년 3월 4일
0

C lang

목록 보기
3/14
post-thumbnail

1. 환경

OpenSSL 라이브러리를 사용하기 위해 libssl-dev를 설치한다.

$ sudo apt -y install libssl-dev

컴파일 시 libcrypto.so, libssl.so을 링킹하여 컴파일한다.

2. 암호화

블록 알고리즘이기 때문에 key, iv와 암호화 대상의 크기는 블록 사이즈만큼 나뉘어 떨어져야 한다.

그래서 나뉘어 떨어지지 않는 데이터에 대해서는 PKCS 패딩을 취해주자.

key의 길이가 32byte(256bit)이기 때문에 AES-256-CBC이다.

#include <openssl/aes.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

int main(void)
{
    unsigned char iv[AES_BLOCK_SIZE]    = { 0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84, 0xee, 0xd0, 0x66, 0x84 };
    unsigned char key[32]               = { 0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66, 0x5f, 0x8a, 0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f };
    unsigned char data[]                = "\x3c\x2f\x77\x73\x65\x3a\x52\x65\x6e\x65\x77\x52\x65\x73\x70\x6f" \
                                        "\x6e\x73\x65\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x42" \
                                        "\x6f\x64\x79\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x45" \
                                        "\x6e\x76\x65\x6c\x6f\x70\x65\x3e";
    int data_len        = sizeof(data);
    int padding_len     = 0;
    if (data_len % AES_BLOCK_SIZE != 0) padding_len = (AES_BLOCK_SIZE - (data_len % AES_BLOCK_SIZE));
    unsigned char *padded_data = (unsigned char *)malloc(sizeof(unsigned char *) * (data_len + padding_len));
    memset(padded_data, padding_len, (data_len + padding_len));
    memcpy(padded_data, data, data_len);
    ...
}

데이터를 암호화 해본다.

#include <openssl/aes.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

int main(void)
{
    ...
    AES_KEY enc_key;
    unsigned char enc_data[(data_len + padding_len)] = {0};
    if (AES_set_encrypt_key(key, sizeof(key) * 8, &enc_key) < 0 ) return 0;
    AES_cbc_encrypt(padded_data, enc_data, (data_len + padding_len), &enc_key, iv, AES_ENCRYPT);
    for (int i = 0; i < sizeof(enc_data); i ++) printf("\\x%02X", enc_data[i]);
    return 0;
}

전체 코드는 다음과 같다.

#include <openssl/aes.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

int main(void)
{
    unsigned char iv[AES_BLOCK_SIZE]    = { 0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84, 0xee, 0xd0, 0x66, 0x84 };
    unsigned char key[32]               = { 0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66, 0x5f, 0x8a, 0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f };
    unsigned char data[]                = "\x3c\x2f\x77\x73\x65\x3a\x52\x65\x6e\x65\x77\x52\x65\x73\x70\x6f" \
                                        "\x6e\x73\x65\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x42" \
                                        "\x6f\x64\x79\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x45" \
                                        "\x6e\x76\x65\x6c\x6f\x70\x65\x3e";
    int data_len        = sizeof(data);
    int padding_len     = 0;
    if (data_len % AES_BLOCK_SIZE != 0) padding_len = (AES_BLOCK_SIZE - (data_len % AES_BLOCK_SIZE));
    unsigned char *padded_data = (unsigned char *)malloc(sizeof(unsigned char *) * (data_len + padding_len));
    memset(padded_data, padding_len, (data_len + padding_len));
    memcpy(padded_data, data, data_len);

    AES_KEY enc_key;
    unsigned char enc_data[(data_len + padding_len)] = {0};
    if (AES_set_encrypt_key(key, sizeof(key) * 8, &enc_key) < 0 ) return 0;
    AES_cbc_encrypt(padded_data, enc_data, (data_len + padding_len), &enc_key, iv, AES_ENCRYPT);
    for (int i = 0; i < sizeof(enc_data); i ++) printf("\\x%02X", enc_data[i]);
    return 0;
}

3. 복호화

블록 알고리즘이기 때문에 key, iv와 복호화 대상의 크기는 블록 사이즈만큼 나뉘어 떨어져야 한다.

동시에 대칭키이기 때문에 암호화에 사용된 key와 iv를 그대로 사용해준다.

#include <openssl/aes.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

int main(void)
{
    unsigned char iv[AES_BLOCK_SIZE]    = { 0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84, 0xee, 0xd0, 0x66, 0x84 };
    unsigned char key[32]               = { 0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66, 0x5f, 0x8a, 0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f };
    unsigned char data[]                = "\x6B\xEC\x6A\x28\x82\x92\xCB\x57\x3D\x4A\xDB\x22\x49\xD5\xB8\xEC\x20\x15\x96\xE6\xB4\x6F\x85\x4D\x4E\x5C\x7E\xB4\x38\x74\x99\x4D\x78\x5A\xBC\xCC\xA1\x07\x24\x90\x70\xD4\xFF\x29\x00\xD6\x06\x4D\x36\x9C\x26\xA4\xC1\xDD\x9D\x61\x34\x96\xC4\x0B\xB0\x9A\x4F\x10";
    int data_len        = sizeof(data);

    AES_KEY dec_key;
    unsigned char dec_data[data_len - 1] = {0};
    if (AES_set_decrypt_key(key, sizeof(key) * 8, &dec_key) < 0 ) return 0;
    AES_cbc_encrypt(data, dec_data, data_len, &dec_key, iv, AES_DECRYPT);
    ...
}

복호화의 결과는 PKCS 패딩이 취해진 상태이기 때문에 역으로 패딩을 없애준다.

#include <openssl/aes.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

int main(void)
{
    ...
    int padding_len = dec_data[sizeof(dec_data) - 1];
    unsigned char unpadded_data[sizeof(dec_data) - padding_len] = {0};
    memset(unpadded_data, 0x00, sizeof(unpadded_data));
    memcpy(unpadded_data, dec_data, sizeof(unpadded_data));
    ...
}

원본 데이터와 비교해본다.

#include <openssl/aes.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

int main(void)
{
    ...
    unsigned char original_data[]   = "\x3c\x2f\x77\x73\x65\x3a\x52\x65\x6e\x65\x77\x52\x65\x73\x70\x6f" \
                                    "\x6e\x73\x65\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x42" \
                                    "\x6f\x64\x79\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x45" \
                                    "\x6e\x76\x65\x6c\x6f\x70\x65\x3e";
    if (memcmp(unpadded_data, original_data, sizeof(original_data)) == 0) printf("Validation Success.\n");
    return 0;
}

전체 코드는 다음과 같다.

#include <openssl/aes.h>
#include <stdlib.h>
#include <memory.h>
#include <stdio.h>

int main(void)
{
    unsigned char iv[AES_BLOCK_SIZE]    = { 0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84, 0xee, 0xd0, 0x66, 0x84 };
    unsigned char key[32]               = { 0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66, 0x5f, 0x8a, 0xe6, 0xd1, 0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f };
    unsigned char data[]                = "\x6B\xEC\x6A\x28\x82\x92\xCB\x57\x3D\x4A\xDB\x22\x49\xD5\xB8\xEC\x20\x15\x96\xE6\xB4\x6F\x85\x4D\x4E\x5C\x7E\xB4\x38\x74\x99\x4D\x78\x5A\xBC\xCC\xA1\x07\x24\x90\x70\xD4\xFF\x29\x00\xD6\x06\x4D\x36\x9C\x26\xA4\xC1\xDD\x9D\x61\x34\x96\xC4\x0B\xB0\x9A\x4F\x10";
    int data_len        = sizeof(data);

    AES_KEY dec_key;
    unsigned char dec_data[data_len - 1] = {0};
    if (AES_set_decrypt_key(key, sizeof(key) * 8, &dec_key) < 0 ) return 0;
    AES_cbc_encrypt(data, dec_data, data_len, &dec_key, iv, AES_DECRYPT);

    int padding_len = dec_data[sizeof(dec_data) - 1];
    unsigned char unpadded_data[sizeof(dec_data) - padding_len] = {0};
    memset(unpadded_data, 0x00, sizeof(unpadded_data));
    memcpy(unpadded_data, dec_data, sizeof(unpadded_data));

    unsigned char original_data[]   = "\x3c\x2f\x77\x73\x65\x3a\x52\x65\x6e\x65\x77\x52\x65\x73\x70\x6f" \
                                    "\x6e\x73\x65\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x42" \
                                    "\x6f\x64\x79\x3e\x3c\x2f\x53\x4f\x41\x50\x2d\x45\x4e\x56\x3a\x45" \
                                    "\x6e\x76\x65\x6c\x6f\x70\x65\x3e";
    if (memcmp(unpadded_data, original_data, sizeof(original_data)) == 0) printf("Validation Success.\n");
    return 0;
}
profile
IT 도서관

0개의 댓글

관련 채용 정보