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

댓글 없음:

댓글 쓰기