레이블이 c인 게시물을 표시합니다. 모든 게시물 표시
레이블이 c인 게시물을 표시합니다. 모든 게시물 표시

2021년 3월 27일 토요일

[C언어] graph 탐색 BFS 인접 행렬




이전에 작성한 linked list 소스를 이해가 쉽게 인접 행렬로 구현함

인접 행렬

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
86
87
88
89
90
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAX_VERTICES 20
 
int adj_matrix[MAX_VERTICES+1][MAX_VERTICES+1];
int visited[MAX_VERTICES+1];
 
void graph_init()
{
    int vi,vo;
    for (vi = 0; vi<MAX_VERTICES; vi++){
        for (vo = 0; vo<MAX_VERTICES; vo++){
            adj_matrix[vi][vo] = 0;
        }
        visited[vi] = 0;
    }
}
 
void insert_edge(int u, int v)
{
    // 간선 정보 u->v
    adj_matrix[u][v]=1;
}
 
// 간단 queue
typedef int element;
int  front, rear;
element  queue[MAX_VERTICES+2];
 
void init()
{
    front = rear = 0;
}
 
int is_empty()
{
    return (front == rear);
}
 
void enqueue(element item)
{
    rear++;
    queue[rear] = item;
}
 
element dequeue()
{
    front++;
    return queue[front];
}
 
// BFS 이해가 쉽게 인접 행렬로 구현
void bfs_list(int v)
{
    int w;
    init();
    visited[v] = TRUE;
    printf("%d ", v); 
    enqueue(v);
    while (!is_empty()) {
        v = dequeue();
        for (w = 0; w < MAX_VERTICES; w++ ){
            if (adj_matrix[v][w]==1 && !visited[w]) {
                visited[w] = TRUE;
                printf("%d ", w);
                enqueue(w);
            }
        }
    }
}
 
main()
{
    int i;
 
    graph_init();
 
    insert_edge(19);
    insert_edge(15);
    insert_edge(12);
    insert_edge(23);
    insert_edge(34);
    insert_edge(58);
    insert_edge(56);
    insert_edge(67);
    insert_edge(910);
    bfs_list(1);
}
cs

bfs_list(1)에서 1은 출발 정점

결과

1
1 2 5 9 3 6 8 10 4 7
cs


인접 행렬 리스트로 구현함


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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <stdio.h>
#include <stdlib.h>
#define TRUE 1
#define FALSE 0
#define MAX_VERTICES 20
#define MAX_ALIST    20
 
typedef struct{
    int in;
    int out;
}adj_info;
 
adj_info adj_alist[MAX_ALIST+1];
int edge_count = 0;
 
int visited[MAX_VERTICES+1];
 
void graph_init()
{
    int i;
    for (i = 0; i<MAX_ALIST; i++){
        adj_alist[i].in = 0;
        adj_alist[i].out = 0;
    }
    edge_count=0;
}
 
void insert_edge(int u, int v)
{
    // 간선 정보 u->v
    adj_alist[edge_count].in = u;
    adj_alist[edge_count].out = v;
    edge_count++;
}
 
// 간단 queue
typedef int element;
int  front, rear;
element  queue[MAX_VERTICES+2];
 
void init()
{
    front = rear = 0;
}
 
int is_empty()
{
    return (front == rear);
}
 
void enqueue(element item)
{
    rear++;
    queue[rear] = item;
}
 
element dequeue()
{
    front++;
    return queue[front];
}
 
// BFS 이해가 쉽게 인접 행렬로 구현
void bfs_list(int v)
{
    int w;
    init();
    visited[v] = TRUE;
    printf("%d ", v); 
    enqueue(v);
    while (!is_empty()) {
        v = dequeue();
        for (w = 0; w < edge_count; w++ ){
            if (adj_alist[w].in==&& !visited[adj_alist[w].out]) {
                visited[adj_alist[w].out] = TRUE;
                printf("%d ", adj_alist[w].out);
                enqueue(adj_alist[w].out);
            }
        }
    }
}
 
main()
{
    int i;
 
    graph_init();
 
    insert_edge(19);
    insert_edge(15);
    insert_edge(12);
    insert_edge(23);
    insert_edge(34);
    insert_edge(58);
    insert_edge(56);
    insert_edge(67);
    insert_edge(910);
    bfs_list(1);
}
cs


결과


1
1 9 5 2 10 8 6 3 7 4
cs


기존 대비 BFS 내부의 연결된 간선 선택하는 부분이 변경되었습니다.


출력 결과는 이전과 다르지만 오른쪽 왼쪽 가운데 순서는 관계없고 level 단위로 처리만 되면 BFS이며 이것도 BFS 결과입니다.






2018년 3월 19일 월요일

stringify


linux 소스를 보던중 stringify 매크로 함수가 나와서 신기하다고 생각되어 정리해 보았습니다.

정의는 아래와 같이 되어있습니다.


/* Indirect stringification.  Doing two levels allows the parameter to be a
 * macro itself.  For example, compile with -DFOO=bar, __stringify(FOO)
 * converts to "bar".
 */

/include/linux/stringify.h
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)

자세한 설명은 아래링크를 참고 하면 됩니다.
https://en.wikipedia.org/wiki/C_preprocessor C 매크로 중 #에 대한 처리입니다. Token stringification 부분을 보면 됩니다.

매크로 내에서 # 기능

# 는 인자로 받은 토큰을 문자열로 만듭니다.

예제)
#include <stdio.h>

#define str(s) #s

main()
{
 printf(str(abc));

}

출력
abc

소스를 치환하여 printf(#abc); 라고 하면 오류가 발생합니다.
----------------------------------------------------

예제)
#include <stdio.h>

#define str(s) #s

main()
{
 printf("Hello\n");
 printf(str(p = "foo\n";)); // outputs "p = \"foo\\n\";"
}

출력
Hello
p = "foo\n";

----------------------------------------------------

__stringify

처음으로 다시 돌아오면
__stringify매크로는 두번의 매크로 구성으로 되어있습니다. 결과는 기본적으로 위의 예와 동일합니다. 하지만 두번을 거치면서 새로운 기능이 생기게 됩니다.
예제)
#include <stdio.h>

#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)

main()
{
 printf(__stringify(abc));

}

결과
abc

----------------------------------------------------

매크로 안의 값의 정의가 한번더 있다면 풀어서 매크로 string으로 변환하는 작업을 합니다.
예제)
#include <stdio.h>

#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)

#define abc 123

main()
{
 printf(__stringify(abc));

}

결과
123


매크로 내에서 ... 기능

추가로 매크로 내의 ... 의 기능적 차이점을 예를 들어 알아보겠습니다.
... 를 사용하게되면 함수 인자로 구별하기위한 "," 또한 문자열로 전달이 됩니다.
예제)
#include <stdio.h>

#define str1(s) #s
#define str2(s...) #s

#define abc 123

main()
{
 printf(str1(abc)"\n");
 printf(str2(abc)"\n");
 printf(str1(a b c)"\n");
 printf(str2(a b c)"\n");
 //printf(str1(a,b,c)"\n"); => 에러발생
 printf(str2(a,b,c)"\n");

}

결과
abc
abc
a b c
a b c
a,b,c

2017년 6월 18일 일요일

AES with openssl


앞에서 aes를 https://github.com/kokke/tiny-AES128-C 여기 소스를 이용해서 만들었습니다. http://swlock.blogspot.com/2017/06/aes-128-example-cbc-mode-with-hash-hmac.html

openssl에도 AES가 구현되어 있습니다. 그래서 소스를 검토해보았습니다.

위치는 아래와 같고,
https://github.com/openssl/openssl/tree/master/crypto/aes

핵심 소스는 core에 있습니다.
https://github.com/openssl/openssl/blob/master/crypto/aes/aes_core.c

그래서 openssl을 함께 빌드할때 예제를 찾아보았습니다.
http://www.firmcodes.com/how-do-aes-128-bit-cbc-mode-encryption-c-programming-code-openssl/

소스를 간단하게 정리해 보자면 아래와 같습니다.

AES 128은 128/8=16byte 키를 가집니다.
/* AES key for Encryption and Decryption */
const static unsigned char aes_key[]={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF};

/* Init vector */ <=CBC 모드에서 사용하는 초기값을 의미합니다.
unsigned char iv[AES_BLOCK_SIZE];
memset(iv, 0x00, AES_BLOCK_SIZE);

AES_KEY enc_key, dec_key; <= 키를 의미합니다.
AES_set_encrypt_key(aes_key, sizeof(aes_key)*8, &enc_key); <=키를 세팅하고
AES_cbc_encrypt(aes_input, enc_out, sizeof(aes_input), &enc_key, iv, AES_ENCRYPT); <= 암호화를 합니다.

/* AES-128 bit CBC Decryption */
memset(iv, 0x00, AES_BLOCK_SIZE); // don't forget to set iv vector again, else you can't decrypt data properly
<= 벡터를 초기값을 넣습니다. 초기 벡터는 입력과 출력을 같은 값으로 넣어야 합니다.
AES_set_decrypt_key(aes_key, sizeof(aes_key)*8, &dec_key); // Size of key is in bits
AES_cbc_encrypt(enc_out, dec_out, sizeof(aes_input), &dec_key, iv, AES_DECRYPT);

이전에 작업했던 부분과 연결하면되는데, 제가 가진 환경이 pc환경이고 openssl을 사용해 빌드할만한 환경이 아니라서 추가 예제를 작성하지 못하고 여기에서 마무리 하도록하겠습니다.




2017년 6월 10일 토요일

AES 128 example CBC mode with hash hmac sha 512


앞에서 AES를 이용한 예제를 만들었습니다.
http://swlock.blogspot.com/2017/05/aes-128-example-cbc-mode.html

하지만 중요한 문제가 있습니다. 암호화가 되어있기 때문에 최종 암호화된 데이터에서 손상이나 변형이 일어나게되면 전혀 알아챌 수 없다는 문제입니다. 그래서 CRC와 같은 HASH함수를 넣을 수 있는데요. 아무렇게나 넣으면 그것의 헛점을 이용해서 빠른 속도로 암호화 해제를 해볼 수가 있습니다.

따라서 그것에 대한 고민은 아래 링크의 주제로 알아보았습니다.
http://swlock.blogspot.com/2017/06/data.html

그중에서도 Encrypt-and-MAC (E&M) 방법을 이용해서 예제로 만들어 보았습니다.

MAC을 암호화된 문서에 첨부하는것인데요. MAC은 Key와 원본 message의 hash로 부터 만들어지게 됩니다. 해제한 원본 message의 MAC값을 계산해서 저장된 값과 일치하는 방법을 사용하면 됩니다.

iv, key 변수는 변경해서 사용하면 됩니다.
컴파일 환경 gcc ( MinGW )
전체 소스
// From https://github.com/kokke/tiny-AES128-C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#define CBC 1
#define ECB 1
#include "aes.h"
#include "hmac_sha2.h"

static uint8_t key[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
static uint8_t  iv[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
  
#define MAX_SIZE 10*1024*1024
#define PADDING_SIZE 16

#include <stdio.h>
#include <stdlib.h>

#define HMAC_SIZE 512

typedef struct {
 long int encsize;
 long int decsize;
 // HMAC-SHA-512
 unsigned char hmac[HMAC_SIZE];
}data_header;

void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);

long int load_file_with_header(char *filename, char *buf, long int buf_size, char *header, long int header_size)
{
 FILE *fp;
 long int rwsize1 = 0;
 long int rwsize2 = 0;
 fp = fopen(filename,"rb");
 if(fp==NULL) return -1;
 
 rwsize1 = fread(header,1,header_size,fp);
 if(rwsize1<=0){
  fclose(fp);
  return -1;
 }
 
 rwsize2 = fread(buf,1,buf_size,fp);
 if(rwsize2<=0){
  fclose(fp);
  return -1;
 }
 fclose(fp);
 return rwsize1+rwsize2;
}

long int save_file_with_header(char *filename, char *buf, long int buf_size, char *header, long int header_size)
{
 FILE *fp;
 long int rwsize1 = 0;
 long int rwsize2 = 0;
 fp = fopen(filename,"wb");
 if(fp==NULL) return -1;
 
 rwsize1 = fwrite(header,1,header_size,fp);
 if(rwsize1<=0){
  fclose(fp);
  return -1;
 }

 rwsize2 = fwrite(buf,1,buf_size,fp);
 if(rwsize2<=0){
  fclose(fp);
  return -1;
 }
 fclose(fp);
 return rwsize1+rwsize2;
}

// load filedata in buf.
// You should set a filesize in advance.
long int load_file(char *filename, char *buf, long int fsize)
{
 FILE *fp;
 long int rwsize = 0;
 fp = fopen(filename,"rb");
 if(fp==NULL) return -1;
 
 rwsize = fread(buf,1,fsize,fp);
 
 if(rwsize<=0){
  fclose(fp);
  return -1;
 }
 fclose(fp);
 return rwsize;
}

// it returns sizes of file.
// if have an error, it will return the value minus.
long int get_file_length(char *filename)
{
 long int length = 0;
 FILE *fp;
 fp = fopen(filename,"rb");
 if( fp == NULL ) return -1;
 fseek(fp,0,2);
 length = ftell(fp);
 fclose(fp);
 return length;
}

// A size must be PADDING_SIZE times.
void AES128_decrypt_cbc(uint8_t *in, uint8_t *out, uint8_t *key, long int size, uint8_t *iv)
{
 AES128_CBC_decrypt_buffer(out+0, in+0, 16, key, iv);
 if( size > 16 ){
  AES128_CBC_decrypt_buffer(out+16, in+16, size-16, 0, 0);
 }
}

// A size must be PADDING_SIZE times.
long int AES128_encrypt_cbc(uint8_t *in, uint8_t *out, uint8_t *key, long int size, uint8_t *iv)
{
 AES128_CBC_encrypt_buffer(out, in, size, key, iv);
 return size+(PADDING_SIZE-(size%PADDING_SIZE));
}


int aes_encrypt_save_with_header(char *filename, char *encfname)
{
 long int encsize;
 char *buffer = NULL;
 char *encbuffer = NULL;
 data_header header;
 long int filesize = get_file_length(filename);
 if( filesize <= 0 ) return -1;
 
 buffer = malloc(filesize+PADDING_SIZE);
 memset(buffer+filesize,0,PADDING_SIZE); // padding
 load_file(filename, buffer, filesize);

 encbuffer = malloc(filesize+PADDING_SIZE);
 encsize = AES128_encrypt_cbc(buffer, encbuffer, key, filesize+(PADDING_SIZE-(filesize%PADDING_SIZE)), iv);
 header.encsize = encsize;
 header.decsize = filesize;
 
 hmac_sha512(key, sizeof(key), (unsigned char *)buffer, filesize, header.hmac, HMAC_SIZE); 
 
 save_file_with_header(encfname, encbuffer, encsize, (char *)&header, sizeof(header));
 
 free(encbuffer);
 free(buffer);
 return 0;
}

char * aes_decrypt_load_with_header(char *encfname, data_header *header)
{
 char *buffer = NULL;
 char *outbuffer = NULL;
 long int filesize = get_file_length(encfname);
 unsigned char hmac_calc[HMAC_SIZE];
 
 buffer = malloc(filesize+1-sizeof(data_header));
 load_file_with_header(encfname, buffer, filesize-sizeof(data_header), (char *)header, sizeof(data_header));
 outbuffer = malloc(filesize+1-sizeof(data_header));
 AES128_decrypt_cbc(buffer, outbuffer, key, header->decsize, iv);
 
 hmac_sha512(key, sizeof(key), (unsigned char *)outbuffer, header->decsize, hmac_calc, HMAC_SIZE); 
 if( memcmp(header->hmac, hmac_calc, HMAC_SIZE)==0 ){
  free(buffer);
  free(outbuffer);
  return NULL;
 } 
 free(buffer);
 return outbuffer;
}

int main(int argc, char *argv[])
{
 data_header loadheader;
 char nbuf[2048]; 
 char *loadbuf;
 if( argc <= 1){
  printf("input file name\n");
  return -1;
 }
 strcpy(nbuf,argv[1]);
 strcat(nbuf,".enc");
 
 aes_encrypt_save_with_header(argv[1],nbuf);
 
 printf("saved file from %s to %s\nenter\n",argv[1],nbuf);
 getchar();
 printf("load %s file\nenter\n",nbuf);
 getchar();
 loadbuf = aes_decrypt_load_with_header(nbuf,&loadheader);
 if(loadbuf==NULL){
  printf("loading fail\n");
  return -1;
 }else{
  printf("loading sucess\n");
 }

 // compare
 {
 long int filesize = get_file_length(argv[1]);
 char *filebuffer;
 filebuffer = malloc(filesize+1);
 load_file(argv[1], filebuffer, filesize);
 
 if(loadheader.decsize!=filesize){
  printf("file size fail %ld!=%ld\n",loadheader.decsize,filebuffer);
  return -1;
 }
 if(memcmp(filebuffer,loadbuf,filesize)==0){
  printf("success\n");
 }else{
  printf("fail\n");
 }
 free(loadbuf);
 free(filebuffer);
 }

 return 0;
}


실행화면
enter라고 표시된것은 해당시점에 enter키를 눌러서 다음단계로 넘어가게 예제를 만들었습니다. (getchar 표준 함수 이용)
E:\blogdata\3>aes_test3 aes.c
saved file from aes.c to aes.c.enc
enter

load aes.c.enc file
enter

loading sucess
success

hex edit로 aes.c.enc 파일은 변경한 경우
"<=====" 표시된 시점에 aes.c.enc 파일을 조작을 하게되면 fail이 발생합니다.
E:\download\blogdata\3>aes_test3 aes.c
saved file from aes.c to aes.c.enc
enter

load aes.c.enc file
enter <======================== 이 시점에서 값을 조작함

loading sucess
fail

소스 링크 : https://drive.google.com/open?id=0B9vAKDzHthQIeEFveFBGODZ1REU








2017년 5월 29일 월요일

AES 128 example CBC mode


AES 128 example CBC mode


참고 소스 : https://github.com/kokke/tiny-AES128-C

동작되는 예제는 아래와 같습니다.
AES 128bit (16byte) 암호화 입니다.
아래 소스는 AES128 CBC mode로 임의의 파일을 암호화 후 *.enc 파일에 저장한 후 다시 파일을 로딩해서 값이 원본과 같은지 비교하는 예제소스 입니다. cbc mode는 block 단위의 암호화를 할때 현재 결과가 다음 블럭의 초기값으로 사용되어지는 모드입니다. 따라서 중간에 에러가 한번 생기면 에러는 마지막단까지 전파가 됩니다. 그리고 초기 벡터 값을 필요로 합니다. (여기에서는 iv 입니다.)

aes_test2.c 로 파일명을 했으며, 위 참고 소스링크의 aes.c, aes.h 파일이 필요합니다.

빌드시 : gcc aes_test2.c aes.c

아래 2개의 배열은 사용자 맞게 바꾸는 값입니다.
key는 암호화를 위한 키값이 됩니다. 일종의 비밀번호라고 생각하면 되는데 이것이 128bit가 됩니다.
참고 소스 코드에 문제가 있는지 padding이 안된 데이터를 넘기면 메모리쪽에 문제가 발생하여, 패딩을 해서 넣도록 제작하였습니다.

iv는 초기 vector값이 됩니다. 이 값 또한 변경 가능합니다.
static uint8_t key[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
static uint8_t  iv[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};

예제 코드
// From https://github.com/kokke/tiny-AES128-C

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>

#define CBC 1
#define ECB 1
#include "aes.h"

static uint8_t key[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
static uint8_t  iv[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
  
#define MAX_SIZE 10*1024*1024
#define PADDING_SIZE 16

#include <stdio.h>
#include <stdlib.h>

typedef struct {
 long int encsize;
 long int decsize;
}data_header;

void AES128_CBC_encrypt_buffer(uint8_t* output, uint8_t* input, uint32_t length, const uint8_t* key, const uint8_t* iv);

long int load_file_with_header(char *filename, char *buf, long int buf_size, char *header, long int header_size)
{
 FILE *fp;
 long int rwsize1 = 0;
 long int rwsize2 = 0;
 fp = fopen(filename,"rb");
 if(fp==NULL) return -1;
 
 rwsize1 = fread(header,1,header_size,fp);
 if(rwsize1<=0){
  fclose(fp);
  return -1;
 }
 
 rwsize2 = fread(buf,1,buf_size,fp);
 if(rwsize2<=0){
  fclose(fp);
  return -1;
 }
 fclose(fp);
 return rwsize1+rwsize2;
}

long int save_file_with_header(char *filename, char *buf, long int buf_size, char *header, long int header_size)
{
 FILE *fp;
 long int rwsize1 = 0;
 long int rwsize2 = 0;
 fp = fopen(filename,"wb");
 if(fp==NULL) return -1;
 
 rwsize1 = fwrite(header,1,header_size,fp);
 if(rwsize1<=0){
  fclose(fp);
  return -1;
 }

 rwsize2 = fwrite(buf,1,buf_size,fp);
 if(rwsize2<=0){
  fclose(fp);
  return -1;
 }
 fclose(fp);
 return rwsize1+rwsize2;
}

// load filedata in buf.
// You should set a filesize in advance.
long int load_file(char *filename, char *buf, long int fsize)
{
 FILE *fp;
 long int rwsize = 0;
 fp = fopen(filename,"rb");
 if(fp==NULL) return -1;
 
 rwsize = fread(buf,1,fsize,fp);
 
 if(rwsize<=0){
  fclose(fp);
  return -1;
 }
 fclose(fp);
 return rwsize;
}

// it returns sizes of file.
// if have an error, it will return the value minus.
long int get_file_length(char *filename)
{
 long int length = 0;
 FILE *fp;
 fp = fopen(filename,"rb");
 if( fp == NULL ) return -1;
 fseek(fp,0,2);
 length = ftell(fp);
 fclose(fp);
 return length;
}

// A size must be PADDING_SIZE times.
void AES128_decrypt_cbc(uint8_t *in, uint8_t *out, uint8_t *key, long int size, uint8_t *iv)
{
 AES128_CBC_decrypt_buffer(out+0, in+0, 16, key, iv);
 if( size > 16 ){
  AES128_CBC_decrypt_buffer(out+16, in+16, size-16, 0, 0);
 }
}

// A size must be PADDING_SIZE times.
long int AES128_encrypt_cbc(uint8_t *in, uint8_t *out, uint8_t *key, long int size, uint8_t *iv)
{
 AES128_CBC_encrypt_buffer(out, in, size, key, iv);
 return size+(PADDING_SIZE-(size%PADDING_SIZE));
}


int aes_encrypt_save_with_header(char *filename, char *encfname)
{
 long int encsize;
 char *buffer = NULL;
 char *encbuffer = NULL;
 data_header header;
 long int filesize = get_file_length(filename);
 if( filesize <= 0 ) return -1;
 
 buffer = malloc(filesize+PADDING_SIZE);
 memset(buffer+filesize,0,PADDING_SIZE); // padding
 load_file(filename, buffer, filesize);

 encbuffer = malloc(filesize+PADDING_SIZE);
 encsize = AES128_encrypt_cbc(buffer, encbuffer, key, filesize+(PADDING_SIZE-(filesize%PADDING_SIZE)), iv);
 header.encsize = encsize;
 header.decsize = filesize;
 save_file_with_header(encfname, encbuffer, encsize, (char *)&header, sizeof(header));
 
 free(encbuffer);
 free(buffer);
 return 0;
}

char * aes_decrypt_load_with_header(char *encfname, data_header *header)
{
 char *buffer = NULL;
 char *outbuffer = NULL;
 long int filesize = get_file_length(encfname);
 
 buffer = malloc(filesize+1-sizeof(data_header));
 load_file_with_header(encfname, buffer, filesize-sizeof(data_header), (char *)header, sizeof(data_header));
 outbuffer = malloc(filesize+1-sizeof(data_header));
 AES128_decrypt_cbc(buffer, outbuffer, key, header->decsize, iv);
 free(buffer);
 return outbuffer;
}

int main(int argc, char *argv[])
{
 data_header loadheader;
 char nbuf[2048]; 
 char *loadbuf;
 if( argc <= 1){
  printf("input file name\n");
  return -1;
 }
 strcpy(nbuf,argv[1]);
 strcat(nbuf,".enc");
 
 aes_encrypt_save_with_header(argv[1],nbuf);
 
 loadbuf = aes_decrypt_load_with_header(nbuf,&loadheader);

 // compare
 {
 long int filesize = get_file_length(argv[1]);
 char *filebuffer;
 filebuffer = malloc(filesize+1);
 load_file(argv[1], filebuffer, filesize);
 
 if(loadheader.decsize!=filesize){
  printf("file size fail %ld!=%ld\n",loadheader.decsize,filebuffer);
  return -1;
 }
 if(memcmp(filebuffer,loadbuf,filesize)==0){
  printf("success\n");
 }else{
  printf("fail\n");
 }
 free(loadbuf);
 free(filebuffer);
 }

 return 0;
}


실행시 AES 변환을 하고자 하는 이름을 뒤에 인자로 적어주면 됩니다.
여기에서는 tiny-AES128-C-master.zip 파일을 선택하였습니다.
같은 폴더에 tiny-AES128-C-master.zip.enc 파일도 같이 생성됩니다.

실행화면
E:\blogdata>gcc aes_test2.c aes.c -o aes_test2

E:\blogdata>aes_test2 tiny-AES128-C-master.zip
success

E:\blogdata>aes_test2 aes.c
success

E:\blogdata>aes_test2 aes.h
success

소스링크:https://drive.google.com/open?id=0B9vAKDzHthQITmY0bDlfRU1aYjg

HMAC에 포함된 예제 : http://swlock.blogspot.com/2017/06/aes-128-example-cbc-mode-with-hash-hmac.html