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








댓글 없음:

댓글 쓰기