OpenSSL
라이브러리를 사용하기 위해 libssl-dev를 설치한다.
$ sudo apt -y install libssl-dev
컴파일 시 libcrypto.so, libssl.so을 링킹하여 컴파일한다.
블록 알고리즘
이기 때문에 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;
}
블록 알고리즘
이기 때문에 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;
}