AES 암호화에 관해서 정말 간절합니다...
글쓴이: hypnosis / 작성시간: 화, 2013/01/29 - 12:03오전
#include "openssl/aes.h" #define IVSIZE 8 typedef struct { unsigned char iVec[AES_BLOCK_SIZE]; unsigned int num; unsigned char ecount[AES_BLOCK_SIZE]; }ctr_state; int AES_InitCTR(ctr_state *state, const unsigned char iv[IVSIZE]); int AES_Encrypt(char *_plainFile, char *_cipherFile, char *_key, char *_iv); int AES_Decrypt(char *_cipherFile, char *_plainFile, char *_iv); void writeAESKey(char* _f_hash); int AES_Encrypt(char *_plainFile, char *_cipherFile, char *_hashValue, char *_iv) { AES_KEY encKey; //AES구조체 FILE *in_File = NULL; //암호화 할 파일에 대한 파일포인터 FILE *out_File = NULL; //암호화 되어 출력 될 파일포인터 int readLen = 0; //파일의 read 길이 int writeLen = 0; //파일의 write 길이 unsigned char readBuf[AES_BLOCK_SIZE]; //read 할 버퍼 unsigned char outBuf[AES_BLOCK_SIZE]; //출력 될 버퍼 ctr_state state; writeAESKey(_hashValue); strcpy(_cipherFile,_plainFile); _cipherFile[strlen(_cipherFile)] = 'a'; _cipherFile[strlen(_cipherFile)+1] = '\0'; FILE *AES_FILE; char uKey[BUFSIZE]={0,}; char *ckey; unsigned int nkey; int i = 1; AES_FILE = fopen("AES_KEY.txt", "rb"); //encKey = Read_AesKey(_hashValue); fread(uKey, sizeof(char), BUFSIZE, AES_FILE); ckey = strtok(uKey, "@"); nkey = strtoul(ckey,NULL,10); //nkey = atoi(ckey); encKey.rd_key[0] = nkey; while(ckey = strtok(NULL, "@")){ if(ckey == NULL){ ckey = NULL; } else{ if(strcmp(ckey, "10")){ nkey = strtoul(ckey,NULL,10); encKey.rd_key[i++] = nkey; } else{ nkey = strtoul(ckey,NULL,10); encKey.rounds = nkey; } } } in_File = fopen(_plainFile, "rb"); if(in_File != NULL) { out_File = fopen (_cipherFile, "wb"); while(1) { AES_InitCTR(&state, (unsigned char*)_iv); readLen = fread(readBuf, sizeof(char), AES_BLOCK_SIZE, in_File); AES_ctr128_encrypt(readBuf, outBuf, readLen, &encKey, state.iVec, state.ecount, &state.num); writeLen = fwrite(outBuf, sizeof(char), readLen, out_File); if(writeLen < AES_BLOCK_SIZE) { break; } } } fclose(AES_FILE); fclose(in_File); fclose(out_File); return 0; } int AES_Decrypt(char *_cipherFile, char *_plainFile, char *_iv) { AES_KEY encKey; //AES구조체 FILE *in_File = NULL; //암호화 할 파일에 대한 파일포인터 FILE *out_File = NULL; //암호화 되어 출력 될 파일포인터 int readLen = 0; //파일의 read 길이 int writeLen = 0; //파일의 write 길이 unsigned char readBuf[AES_BLOCK_SIZE]; //read 할 버퍼 unsigned char outBuf[AES_BLOCK_SIZE]; //출력 될 버퍼 ctr_state state; strcpy(_plainFile,_cipherFile); _plainFile[strlen(_plainFile)-1] = '\0'; printf("확인용1"); FILE *AES_FILE; char uKey[1024] = {0,}; char *ckey; unsigned int nkey; int i = 1; AES_FILE = fopen("AES_KEY.txt", "rb"); //if(AES_FILE == NULL) return 0; printf("확인용1"); fread(uKey, sizeof(char), 1024, AES_FILE); printf("확인용2"); ckey = strtok(uKey, "@"); nkey = ntohl(strtoul(ckey, NULL, 10));//nkey = atoi(ckey);//_atoi64(ckey); encKey.rd_key[0] = nkey; printf("확인용3"); while(ckey = strtok(NULL, "@")){ printf("확인용4"); if(ckey == NULL/* || context == NULL*/){ printf("확인용5"); ckey = NULL; //context = NULL; } else{ if(strcmp(ckey, "10")){ nkey = ntohl(strtoul(ckey, NULL, 10));//nkey = atoi(ckey);// _atoi64(ckey); encKey.rd_key[i++] = nkey; } else{ nkey = strtoul(ckey, NULL, 10);//nkey = atoi(ckey);//_atoi64(ckey); encKey.rounds = nkey; } } } printf("확인용6"); in_File = fopen(_cipherFile, "rb"); if(in_File != NULL) { out_File = fopen(_plainFile, "wb"); while(1) { AES_InitCTR(&state, (unsigned char*)_iv); readLen = fread(readBuf, sizeof(char), AES_BLOCK_SIZE, in_File); AES_ctr128_encrypt(readBuf, outBuf, readLen, &encKey, state.iVec, state.ecount, &state.num); writeLen = fwrite(outBuf, sizeof(char), readLen, out_File); if(writeLen < AES_BLOCK_SIZE) { break; } } } printf("확인용7"); fclose(AES_FILE); fclose(in_File); fclose(out_File); return 0; } int AES_InitCTR(ctr_state *state, const unsigned char iv[IVSIZE]) { state->num = 0; memset(state->ecount, 0, AES_BLOCK_SIZE); memset(state->iVec + IVSIZE, 0, IVSIZE); memcpy(state->iVec, iv, IVSIZE); return 0; } void writeAESKey(char* _f_hash){ AES_KEY encKey; FILE *fp; int i; fp = fopen("AES_KEY.txt", "wb"); AES_set_encrypt_key((unsigned char*)_f_hash, 128, &encKey); for(i = 0; i < 60; i++) { fprintf(fp, "%u%s", encKey.rd_key[i], "@"); } fprintf(fp, "%d", encKey.rounds); fclose(fp); }
위와 같은 코드로 AES암호화 복호화 하고 있습니다. 윈도우는 MFC로 작성하고 암호화 코드는 저 위와 같이 암 복호화 하고
리눅스도 위 와 같은 코드로 암 복호화 를 실행했는데 윈도우 에서 윈도우 로 암복호화를 했을땐 잘 됐는데요.
리눅스에서 암호화 하고, 윈도우에서 복호화를 실행하면 풀리지 않습니다.. (값이 다르게 나옵니다..)
구글링 한 결과 endian 이 달라서 그렇다고 하는데 현재 소켓 통신으로 파일 전송 주고 받고, RSA 메세지 암호화 해서 잘 통신 하고 있는데
AES 대칭키 파일 암호화 에서 막히네요 .. 저와 같은 경험해 보신 분들 어디 없나요 ㅠㅠ... 댓글 좀 남겨주세요 ㅠㅠㅠ
Forums:
음 ..
양쪽다 AES 알고리즘에 문제가 없다고 가정하면, 결국은 key 나 iv 가 다르거나 잘못되었다는 결론으로 귀결 될 것 같네요.
알고리즘 검증은 make test 나 openssl 명령으로 가능합니다.
그리고 암호키를 키생성 함수를 통하지 않고 직접 집어 넣는 것 같은데.. 그건 전혀 좋은 방법이 아닌 것 같네요.
암호 알고리즘에서 제공하는 키생성 함수를 쓰는게 안전합니다. (AES_set_encrypt_key, AES_set_decrypt_key)
그리고 사족입니다만, raw crypto function 을 직접 호출하는 것보다 evp 를 쓰는게 더 유리합니다.
cipher 만 바꾸면 원하는 알고리즘으로 쉽게 변경할 수 있으니까요.
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
음...
일단 key 값은 파일의 해쉬 값으로 밑에 writeAESKey 로 답글달아주신분 말대로 AES_set_encrypt를 사용해서
키생성을 했습니다. iv 값은 현재 하드코딩으로 맞춘상태로 윈도우랑 윈도우 사이에선 가능한데..
역시 리눅스랑 윈도우 사이에서 문제가 아직 발생하고 있네요..
음 ..
먼저 openssl 명령으로 파일 암호화 해서 다른 시스템으로 복사한 후에 openssl 명령으로 풀어 보세요.
그렇다면 알고리즘에 문제가 없다는게 확인 되겠죠. (테스트 벡터 검증도 필요하겠지만, 일단 되었다고 보고..;;)
암호화 된 파일이 두 시스템에 동일한 원본 상태로 있는지 걸 확인해 보세요. (복사중 손상/변경 여부)
그렇다면 파일 전송/저장 기능에는 문제가 없다는 게 확인 될테고..
동일 시스템에서 암/복호화는 문제 없다는 말은 어찌되었든 암복호화 루틴 자체는 (어찌되었든) 동작 한다는 걸로 봐도 될테고 ..
그렇다면 여전히 제일 의심스러운 부분은 key 나 iv 인데..
뭐 AES_set_encrypt_key 와 AES_set_decrypt_key 에 들어가는 userKey 를 hex 로 모두 찍어 보면.. 확인 되겠죠.
AES_set_encrypt_key 와 AES_set_decrypt_key 에 들어가는 userKey 를 타이핑 하기 쉬운 문자열로 바꾸고..
파일을 암호화 한 후에, openssl 명령으로 풀어 보면.. 암복호화 루틴이 제대로 구현되었는지 확인 가능 할 것 같네요.
(반대로도 시험 가능)
끝으로 코드가 눈에 잘 안들어 와서 자세히 보기 힘든데..
파일 읽어 들이는 루프에서 AES_ctr128_encrypt 하기 전에, 매번 AES_InitCTR 를 호출하는게 맞는건지도 궁금..;;
CTR 모드는 안 써봐서 저렇게 하는게 맞는지 잘 모르겠는데..
보통은 init - update - final - free 순으로 가고, init 은 처음에 한 번만 해줍니다.
update 에서는 단순히 key 로 암/복호화 하는 루틴만..
되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』
시간이 너무 없어서..
지금 다른곳도 손 댈 곳이 많아서 일단 말씀하신대로 openssl 명령어로(openssl enc -e -salt -in infile -out outfile -k asd ) 이런식으로 사용해서
윈도우에서 바로 풀수 있게 만들었어요 ^^ 나중에 시간이 더 주어지면, 나머지 것들도 확인해서 문제점 찾겠습니다!!
답변 달아주셔서 감사합니다 ㅠㅠ 정말 많은 도움이 됐어요 ~
댓글 달기