AES 암호화에 관해서 정말 간절합니다...

hypnosis의 이미지

#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 대칭키 파일 암호화 에서 막히네요 .. 저와 같은 경험해 보신 분들 어디 없나요 ㅠㅠ... 댓글 좀 남겨주세요 ㅠㅠㅠ

ymir의 이미지

양쪽다 AES 알고리즘에 문제가 없다고 가정하면, 결국은 key 나 iv 가 다르거나 잘못되었다는 결론으로 귀결 될 것 같네요.

알고리즘 검증은 make test 나 openssl 명령으로 가능합니다.

$ openssl enc -aes-128-ctr -in infile -out outf.enc
enter aes-128-ctr encryption password:
Verifying - enter aes-128-ctr encryption password:
$ openssl enc -d -aes-128-ctr -in outf.enc -out outf.dec
enter aes-128-ctr decryption password:
$ sha1sum infile
b0b76db81d8598766e3a2a90149f7f680e905678  infile
$ sha1sum outf.dec
b0b76db81d8598766e3a2a90149f7f680e905678  outf.dec

그리고 암호키를 키생성 함수를 통하지 않고 직접 집어 넣는 것 같은데.. 그건 전혀 좋은 방법이 아닌 것 같네요.
암호 알고리즘에서 제공하는 키생성 함수를 쓰는게 안전합니다. (AES_set_encrypt_key, AES_set_decrypt_key)

그리고 사족입니다만, raw crypto function 을 직접 호출하는 것보다 evp 를 쓰는게 더 유리합니다.
cipher 만 바꾸면 원하는 알고리즘으로 쉽게 변경할 수 있으니까요.

EVP_CIPHER_CTX_init
EVP_CipherInit
EVP_CipherUpdate
EVP_CipherFinal
EVP_CIPHER_CTX_cleanup

되면 한다! / feel no sorrow, feel no pain, feel no hurt, there's nothing gained.. only love will then remain.. 『 Mizz 』

hypnosis의 이미지

일단 key 값은 파일의 해쉬 값으로 밑에 writeAESKey 로 답글달아주신분 말대로 AES_set_encrypt를 사용해서

키생성을 했습니다. iv 값은 현재 하드코딩으로 맞춘상태로 윈도우랑 윈도우 사이에선 가능한데..

역시 리눅스랑 윈도우 사이에서 문제가 아직 발생하고 있네요..

ymir의 이미지

먼저 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 』

hypnosis의 이미지


지금 다른곳도 손 댈 곳이 많아서 일단 말씀하신대로 openssl 명령어로(openssl enc -e -salt -in infile -out outfile -k asd ) 이런식으로 사용해서

윈도우에서 바로 풀수 있게 만들었어요 ^^ 나중에 시간이 더 주어지면, 나머지 것들도 확인해서 문제점 찾겠습니다!!

답변 달아주셔서 감사합니다 ㅠㅠ 정말 많은 도움이 됐어요 ~

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.