/* enc.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <getopt.h>
#define PrintfErrorExit(x, ...) { fprintf(stderr, __VA_ARGS__); exit(x); }
int encrypt(FILE *inFp, FILE *outFp, const EVP_CIPHER *cipher,
const unsigned char *key, const unsigned char *iv)
{
int inLen, outLen; // inLen:입력된 데이터의 길이, outLen:출력된 데이터의 길이
char inBuf[BUFSIZ], outBuf[BUFSIZ+EVP_MAX_BLOCK_LENGTH]; // inBuf:입력 데이터 버퍼, outBuf:출력 데이터 버퍼
EVP_CIPHER_CTX ctx; // 암호화 수행에 사용할 context
// 1. context 초기화
EVP_CIPHER_CTX_init(&ctx);
// 2. 암호화 초기 설정.
// - context, 암호 알고리즘, 키 값, IV 값 설정
EVP_EncryptInit_ex(&ctx, cipher, NULL, key, iv);
// 3. 데이터 암호화
while((inLen=fread(inBuf, 1, sizeof(inBuf), inFp))>0) // 입력 파일에서 BUFSIZ만큼 데이터를 read
{
if(!EVP_EncryptUpdate(&ctx, outBuf, &outLen, inBuf, inLen)) // read된 데이터를 암호화
{
printf("EVP_EncryptUpdate() error.\n");
EVP_CIPHER_CTX_cleanup(&ctx);
return -1;
}
fwrite(outBuf, 1, outLen, outFp); // 출력 파일에 암호화된 데이터를 write
}
// 4. 암호화의 마지막 처리, e.g. 패딩 처리
if(!EVP_EncryptFinal_ex(&ctx, outBuf, &outLen))
{
printf("EVP_EncryptFinal_ex() error.\n");
EVP_CIPHER_CTX_cleanup(&ctx);
return -2;
}
fwrite(outBuf, 1, outLen, outFp); // 출력 파일에 마지막으로 암호화된(패딩 처리된) 데이터를 write
EVP_CIPHER_CTX_cleanup(&ctx); // context 초기화
return 0;
}
int decrypt(FILE *inFp, FILE *outFp, const EVP_CIPHER *cipher,
const unsigned char *key, const unsigned char *iv)
{
int inLen, outLen;
char inBuf[BUFSIZ], outBuf[BUFSIZ+EVP_MAX_BLOCK_LENGTH];
EVP_CIPHER_CTX ctx; // 복호화 수행에 사용할 context
// 1. context 초기화
EVP_CIPHER_CTX_init(&ctx);
// 2. 복호화 초기 설정.
// - context, 암호 알고리즘, 키 값, IV 값 설정
EVP_DecryptInit_ex(&ctx, cipher, NULL, key, iv);
// 3. 데이터 복호화
while((inLen=fread(inBuf, 1, sizeof(inBuf), inFp))>0) // 입력 파일에서 BUFSIZ만큼 데이터를 read
{
if(!EVP_DecryptUpdate(&ctx, outBuf, &outLen, inBuf, inLen)) // read된 데이터를 복호화, 실패 시 0 리턴
{
printf("EVP_DecryptUpdate() error.\n");
EVP_CIPHER_CTX_cleanup(&ctx);
return -1;
}
fwrite(outBuf, 1, outLen, outFp); // 출력 파일에 복호화된 데이터를 write
}
// 4. 복호화의 마지막 처리, e.g. 패딩 처리
if(!EVP_DecryptFinal_ex(&ctx, outBuf, &outLen))
{
printf("EVP_DecryptFinal_ex() error.\n");
EVP_CIPHER_CTX_cleanup(&ctx);
return -2;
}
fwrite(outBuf, 1, outLen, outFp); // 출력 파일에 마지막으로 복호화된(패딩 처리된) 데이터를 write
EVP_CIPHER_CTX_cleanup(&ctx);
return 0;
}
void printhex(const char *prefix, const unsigned char *s, const int sLen)
{
int i;
printf("%s[%d]:\n", prefix, sLen);
printf("%02X", s[0]);
for(i=1; i<sLen; i++)
printf(":%02X", s[i]);
printf("\n");
}
int main(int argc, char **argv)
{
FILE *inFp, *outFp; // 입출력 파일의 파일 포인터
int opt; // 옵션 문자
int keyLen, ivLen; // 입력된 key 값, iv 값
unsigned char key[EVP_MAX_KEY_LENGTH]; // key 버퍼
unsigned char iv[EVP_MAX_IV_LENGTH]; // iv 버퍼
const EVP_CIPHER *cipher=EVP_enc_null(); // 암호 알고리즘
int (*crypt)(FILE*, FILE*, const EVP_CIPHER*, // 함수 포인터
const unsigned char*, const unsigned char *);
if(argc!=4 || (opt=getopt(argc, argv, "ed"))==-1)
PrintfErrorExit(2, "Usage: %s -e|d <inFile> <outFile>\n", argv[0]);
switch(opt)
{
case 'e': // encrypt
crypt=encrypt;
break;
case 'd': // decrypt
crypt=decrypt;
break;
case '?':
default:
PrintfErrorExit(3, "Usage: %s -e|d <inFile> <outFile>\n", argv[0]);
}
if((inFp=fopen(argv[2], "rb"))==NULL)
PrintfErrorExit(4, "fopen(\"%s\") error.\n", argv[1]);
if((outFp=fopen(argv[3], "wb"))==NULL)
PrintfErrorExit(5, "fopen(\"%s\") error.\n", argv[2]);
OpenSSL_add_all_ciphers(); // EVP_get_cipherbyname()을 사용하기 위해 호출.
cipher=EVP_get_cipherbyname("aes-128-cbc");
memcpy(key, "password01234567", keyLen=EVP_CIPHER_key_length(cipher));
memcpy(iv, "01234567", ivLen=EVP_CIPHER_iv_length(cipher));
printhex("key", key, keyLen);
printhex("iv", iv, ivLen);
if(crypt(inFp, outFp, cipher, key, iv)<0)
exit(6);
fclose(inFp);
fclose(outFp);
exit(0);
}