Gae Ko's Blog

[암호] aes_256_cbc 암호화 알고리즘 소스 코드 본문

암호

[암호] aes_256_cbc 암호화 알고리즘 소스 코드

Gae Ko 2018. 1. 16. 05:04

다음은 openssl을 사용한 aes_256_cbc 암호화 알고리즘 소스 코드이다. 소스코드를 보고 분석하여 보자.


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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/aes.h>
#include <time.h>
 
void aes_256_cbc(FILE *ifp, FILE *ofp, unsigned char *ckey, unsigned char *ivec)
{
    const unsigned BUFSIZE = 4096;
    unsigned char *read_buf = malloc(BUFSIZE); // 암호화할 메세지를 읽어올 공간
    unsigned char *cipher_buf; // 암호화한 결과 메세지를 저장할 공간 
    unsigned blocksize;
    int out_len;
     EVP_CIPHER_CTX *ctx; // 암호화 수행에 사용할 context
    
    // EVP 암호 초기화
    ctx = EVP_CIPHER_CTX_new();
 
    // EVP 암호화 초기 설정
    // - context, 암호 ㄹ고리즘, 키 값, IV값 설정 
    EVP_CipherInit(ctx, EVP_aes_256_cbc(), ckey, ivec, 0);
    blocksize = EVP_CIPHER_CTX_block_size(ctx);
    cipher_buf = malloc(BUFSIZE + blocksize); // block size보다 추가적인 크기를 가짐 (padding 등의 이유)
 
    while(1)
    {
        // Read in data in blocks until EOF. Update the ciphering with each read.
 
        int numRead = fread(read_buf, sizeof(unsigned char), BUFSIZE, ifp); // 입력파일에서 BUFSIZE만큼 데이터를 read
        EVP_CipherUpdate(ctx, cipher_buf, &out_len, read_buf, numRead); // read된 데이토를 암호화  
        fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp); // 출력 파일에 암호화된 데이터를 write
        if (numRead < BUFSIZE) { // EOF : 블록의 크기보다 작은 데이터부터 더이상 암호화가 진행되지 않는다.
            break;
        }
    }
    
    // Now cipher the final block and write it out.
    EVP_CipherFinal(ctx, cipher_buf, &out_len); // 블록사이즈가 맞지 않아 UPDATE()에서 처리가 안된 데이터를 처리. 
    fwrite(cipher_buf, sizeof(unsigned char), out_len, ofp);
 
    // Free memory
 
    free(cipher_buf);
    free(read_buf);
    EVP_CIPHER_CTX_free(ctx);
 
}   
 
int main(int argc, char *argv[]) 
{   
 
    unsigned char ckey[] = "thiskeyisverybaddontusethisinput"// key 값
    unsigned char ivec[] = "dontusethisinputaatwosdfjjienone"// IV 값
    FILE *fIN, *fOUT; // 입출력 파일의 파일 포인터    
    float gap;
    time_t startTime = 0;
    time_t endTime = 0;
        
 
    // main함수의 매개변수인 inputFile과 outputFile를 쓰지 않는 경우
    if(argc <= 2)
    {
        fprintf(stderr, "Usage: %s <input file> <output file>\n", argv[0]);
        exit(EXIT_FAILURE);
    }
    
    //startTime 셋팅
    startTime = clock();
    
    //암호화 시작
    fIN = fopen(argv[1], "rb"); //File to be encrypted; plain text 암호화할 파일 열기 
    fOUT = fopen(argv[2], "wb"); //File to be written; cipher text 암호화한 결과를 저장할 파일 열기 
    aes_256_cbc(fIN, fOUT, ckey, ivec);
    fclose(fIN);
    fclose(fOUT);
    
    //endTime 저장
    endTime = clock();
    
    //암호화하는 데에 걸린 시간 계산하고 출력하기 
    gap = (float)(endTime-startTime)/(CLOCKS_PER_SEC);
    printf("시간 : %f 초 \n", gap);
 
}
cs


1. EVP

- 수많은 Openssl의 암호 api를 하나의 인터페이스로 구성.

- The EVP interface, which can be accessed by including "openssl/evp.h"


2. CTX

- Context

- EVP로 Encryption, Decryption 등 각 수행에 필요하거나 변경되는 정보들을 유지하는 구조체.

- 암호화 알고리즘, 키(key)값, IV(initializarion vector)값, padding 설정 등등에 관한 정보 

- 대칭키 암호에서는 EVP_CIPHER_CTX 구조체를 사용. 


3. EVP Cipher API

- EVP 사용하여 암호 알고리즘이나 방식 등에 상관없이 여러 암호 알고리즘을 동일한 루틴으로 사용 가능. 

- 암호/복호화의 동작 루틴은 동일하고 사용되는 함수명만 다름.


4. 암호 context의 정의와 초기화

void EVP_CHPHER_CTX_new(EVP_CIPHER_CRT *ctx);

- cipher context를 초기화 

- ctx : cipher context의 주소


5. EVP 암호/복호화 초기 설정

- int EVP_CipherInit(EVP_CIPHER_CRT *ctx, const EVP_CIPHER *type, unsigned char *key, unsigned char *iv, int enc);

- 암호/복호화 하기 위한 초기 설정

- 성공시 1, 실패시 0을 리턴

- ctx : 사용되는 cipher context

- type : 암호화 알고리즘. ex. EVP_des_ecd(), EVP_aes_256_cbc(), ... 등

- key : binary key 값. 암호 알고리즘에 따라 길이가 잘림.

- iv : binary iv 값. 암호 알고리즘에 따라 길이가 잘림. ECB mode에서는 NULL로 설정하는데 값이 있어도 사용되지 않음.

- enc : 암호/복호화 flag. 1이면 암호화, 0이면 복호화.


6. EVP 암호/복호화 수행 

- int EVP_CipherUpdate(EVP_CIPHER_CRT *ctx, unsigned char *out, int *outl, unsigned char *in, int inl);

- 실질적으로 데이터를 암호/복호화 한다.

- 성공시 1, 실패시 0 리턴

- block size가 맞지 않으면, Final( )에서 처리. (ECB/CBC mode처럼 block cipher인 경우)

- ctx : 사용되는 cipher context

- out : 암호/복호화된 데이터가 저장될 버퍼

- outl : out의 길이가 저장될 변수로 암호/복호화된 데이터의 길이 

- in : 입력 데이터 (=암호화시 평문=복호화시 암호문)

- inl : in의 길이 



- EVP_CipherFinal(EVP_CIPHER_CRT *ctx, unsigned char *out, int *outl)

- 패딩 및 필요한 작업을 처리 

- 성공시 1, 실패시 0 리턴 

- block size가 맞지 않아 Update( )에서 처리가 안된 데이터를 처리.  (ECB/CBC mode처럼 block cipher인 경우)

- ctx : 사용되는 cipher context

- out : 암호/복호화된 데이터가 저장될 버퍼

- outl : out의 길이가 저장될 변수


* 참고한 사이트

http://blog.naver.com/PostView.nhn?blogId=seongjeongki7&logNo=220886192615

'암호' 카테고리의 다른 글

[암호] 비트맵 파일 암호화하기  (0) 2018.01.24
[암호] 암호화 알고리즘에 따른 암호화 속도 비교하기  (1) 2018.01.24
[암호] SEED  (0) 2018.01.16
[암호] AES  (0) 2018.01.15
[암호] 블록암호의 운용모드  (0) 2018.01.15