티스토리 뷰

고급 암호화 표준이라고 불리는 AES는 미국 표준기술 연구소에서 제정한 암호화 방식이다.

레인달(Rijndael) 알고리즘에 기반된 암호화 방식으로 128, 192, 256비트 의 키길이로 처리할 수 있고 무료 배포가 가능하여 채택되었다.


AES암호화에 사용되는 알고리즘들은 아래와 같이 4가지가 있다. (이들을 묶어 레인달 알고리즘이라 한다.)

- Substitution Box (일명 s-box) : 바이트들을 s-box에 있는 바이트들과 바꾸는 알고리즘, 이는 입력데이터를 지정된 숫자로 바꿔 암호를 깨기 어렵게 만드는 기법이다.

- ShiftRows : 바이트의 행을 Shift하는 알고리즘

- MixColumns : 특수한 공식으로  바이트값들을 바꾸는 알고리즘

- AddRoundKey : XOR 연산자를 사용하여 바이트를 바꾸는 알고리즘



레인달 알고리즘 순서는

키 스케쥴(AES 알고리즘은 대칭키 암호화 알고리즘 이다.) 다음에,

ADDRoundKey로 CipherText를 암호화 시킨다음, 

Encrypt 된 Text에 위의 4가지 알고리즘을 적용시킨다. 

키의 크기에 따라 반복하는 횟수가  AES128 는 9번, 192는 11번 256은 13번 반복한다. 

따라서 AES128,192,256은 사실 같은 알고리즘을 키의 크기에 따라 얼마나 반복하느냐에 따라 나뉘는 것이다.


이렇게 생성된 cipher text를 base64 인코딩을 통해 바이너리 데이터를 가시화 할 수 있으며,

PKCS7 Padding는 base64 인코딩 후, 디코딩 전에 사용하여 바이트 크기를 맞춰주면 된다.


사실 레인달 알고리즘을 구현 할 필요는 없다. OpenSSL에서 다 제공해주기 때문에 AES암호화가 어떤것이냐 어떻게 동작하느냐만 안다면 사용하는데는 크게 문제가 없을 것이다.

아래는 OpenSSL을 사용하여 C에서 해당 AES-CBC 암호화를 EVP를 사용하여 Encrypt/Decrypt한 예제이다.


int

AESCipher(unsigned char* returnText, unsigned char* plainText, unsigned int plainTextLen, unsigned char* key, unsigned char* iv, int algorithm, int mode){


EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));

int returnTextLength = 0;

unsigned long err = 0;

int retTextLen = 0;

int addLen = 0;

 

EVP_CIPHER_CTX_init(ctx);

/*

 * MODE ENCYPRT

 */

if (mode == ENCRYPT){

if (algorithm == AES_CBC256){

if (EVP_EncryptInit(ctx, EVP_aes_256_cbc(), key, iv) != 1) {

err = ERR_get_error();

printf("ERR : EVP_Encrypt() - %s\n", ERR_error_string(err, NULL));

return -1;

}

}

else if (algorithm == AES_CBC128){

if (EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv) != 1) {

err = ERR_get_error();

printf("ERR : EVP_Encrypt() - %s\n", ERR_error_string(err, NULL));

return -1;

}

}

if (EVP_EncryptUpdate(ctx, returnText, &retTextLen, plainText, plainTextLen) != 1

|| (EVP_EncryptFinal(ctx, returnText + retTextLen, &addLen) != 1)) {

err = ERR_get_error();

printf("ERR :  %s\n", ERR_error_string(err, NULL));

return -1;

}

}

 

/*

 * MODE DECYPRT

 */

else if (mode == DECRYPT){

if (algorithm == AES_CBC256){

if (EVP_DecryptInit(ctx, EVP_aes_256_cbc(), key, iv) != 1){

//|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1) {

err = ERR_get_error();

printf("ERR : EVP_Decrypt() - %s\n", ERR_error_string(err, NULL));

return -1;

}

}

else if (algorithm == AES_CBC128){

if (EVP_DecryptInit(ctx, EVP_aes_128_cbc(), key, iv) != 1){

//|| EVP_CIPHER_CTX_set_padding(ctx, 0) != 1) {

err = ERR_get_error();

printf("ERR : EVP_Decrypt() - %s\n", ERR_error_string(err, NULL));

return -1;

}

}

if (EVP_DecryptUpdate(ctx, returnText, &retTextLen, plainText, plainTextLen) != 1

|| (EVP_DecryptFinal(ctx, returnText + retTextLen, &addLen) != 1)) {

err = ERR_get_error();

printf("ERR :  %s\n", ERR_error_string(err, NULL));

return -1;

}

}

 

returnTextLength = addLen + retTextLen;

EVP_CIPHER_CTX_cleanup(ctx);

return returnTextLength;

}

'programming > 암호화 & 보안' 카테고리의 다른 글

[cipher] 양방향 SSL (2 way SSL)  (0) 2018.05.03
[cipher] 암호화 기본 용어 정리  (0) 2018.05.03
[cipher] 대칭키 암호화 (Symmetric key cipher)  (0) 2018.03.28
[cipher] PKI  (0) 2017.02.01
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함