AES 암호화

오늘은 암호화 알고리즘중에 AES라는걸 포스팅해보려고 한다. 당당하게 쓰기는 하지만, 이번에 처음으로 암호알고리즘을 배우고 써보는 것이니 잘못된 점이 있을 수도 있다. 우선 개념을 먼저 몇 개 알아야한다.


대칭 알고리즘 & 공개(비공개) 키 암호

대칭 키 암호는 암호화 알고리즘의 한 종류로, 암호화와 복호화에 같은 암호 키를 쓰는 알고리즘을 의미한다.
AES는 대칭 키의 종류로 암호화와 복호화에 같은 키를 사용한다. 이는 보안상 문제가 있기에 보완한 것이 공개(비공개) 키 알고리즘이다.
공개 키 암호는 암호화 알고리즘의 한 종류로, 공개 키와 비공개 키로 암호화와 복호화에 다른 키를 쓰는 알고리즘을 말한다.
이 공개 키 암호는 어떤 키로 암호화를 하느냐에 따라 방식이 달라진다. 공개 키로 암호화를 하는 경우에, 상대방의 공개 키로 암호화한 데이터를 보내면, 상대방은 자신의 비공개 키로 복호화를 한다.
공개 A 키로 암호화를 하면, 비공개 B 키로 복호화  
비공개 B 키로 암호화를 하면, 공개 A 키로 복호화


AES 알고리즘

AES란

DES를 대체한 암호 알고리즘이며 암호화와 복호화 과정에서 동일한 키를 사용하는 대칭 키 알고리즘이다.

알고리즘 순서

AES는 4개의 알고리즘을 반복적으로 사용하여 데이터를 암호화한다.
  • SubBytes
  • ShiftRows
  • MixColumns
  • AddRoundKey
  • KeySchedule


AES 암호화 알고리즘 순서
AES알고리즘 
 
AES 복호화 알고리즘 순서
AES 복호화 알고리즘


SubBytes

S-BOX

AES 알고리즘을 자세히 알기전에 알아야할 테이블이다.
S-Box(Substitution Box)는 암호키와는 별개로 AES 알고리즘의 편의를 위해 만든 16*16의 테이블이다.
설명하기로는, 모든 입력에 대한 SubBytes 연산을 계산한 테이블이라한다. 사실이든 아니든, AES에서 암호키와 동일할 정도로 중요하다. 테이블의 값은 다음과 같다. AES S_BOX SubBytes에서 치환하는 방법은 간단하다. 예를들어 값이 0X7a라면 7와 a를 분리하고, 7를 행에, a를 렬에 넣고 만나는 곳이 SubBytes 연산의 결과가 된다. 위의 그림으로 예를들면 0xda가 연산의 결과이다. 코드는 다음과 같다.
for (i = 0; i < 4; i++) { 	x = plan_text[i] >> 4;
	y = plan_text[i] - (x << 4);
	plan_text[i] = S_BOX[x][y];
}


shiftRows

행을 왼쪽으로 이동시킨다. i번째 행을 왼쪽으로 i칸만큼 이동시키면 된다. 여기에 이미지 삽입 좀 코드는 다음과 같다.
int tmp;

for (int i = 0; i<4; i++) {
	for (int j = 4 - i; j < 4; j++) {
		tmp = plan_text[i][0];
		for (int k = 0; k < 4 - 1; k++) {
			plan_text[i][k] = plan_text[i][k + 1];
		}
		plan_text[i][3] = tmp;
	}
}


MixColumns

MixColumns은 각 렬을 특정행렬과 곱연산만하면 된다. 문제는 이를 프로그래밍하면, 오버플로우의 문제로 인해 xtime이라는 계산 방법을 사용한다. 코드는 다음과 같다.
unsigned char a[0x04], b[0x04], h;

for (int i = 0; i<4; i++) {
	for (int j = 0; j<4; j++) { 		a[j] = plan_text[j][i]; 		h = (unsigned char)((signed char)plan_text[j][i] >> 7);
		b[j] = plan_text[j][i] << 1;
		b[j] ^= 0x1b & h;
	}
	plan_text[0][i] = b[0] ^ a[3] ^ a[2] ^ b[1] ^ a[1];
	plan_text[1][i] = b[1] ^ a[0] ^ a[3] ^ b[2] ^ a[2];
	plan_text[2][i] = b[2] ^ a[1] ^ a[0] ^ b[3] ^ a[3];
	plan_text[3][i] = b[3] ^ a[2] ^ a[1] ^ b[0] ^ a[0];
}


AddRoundKey

데이터와 Key를 XOR 연산을 한다. 다른 설명이 없을 정도로 AES에서 제일 간단한 알고리즘이다. 다만, 이 Key는 매회 KeySchedule에 의해 바뀐다.


KeySchedule

우선 맨 초기의 키값(CipherKey)이 아래와 같다고 가정하자.

KeySchedule 1


CipherKey

0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
TempKey라는 1*4의 행렬을 만들고 암호키(CipherKey) 행렬에서 적절한 위치의 값을 뽑아내 채워넣을 것이다.
for(i = 0 ; i < 3 ; i ++)
    TempKey[j] = CipherKey[i + 1][3];
TempKey[3] = CipherKey[0][3];
그럼 TempKey는 다음과 같이 된다.

TempKey

  711153

KeySchedule 2


여기는 위의 SubBytes와 동일하다.
for (i = 0; i < 4; i++) { 	x = tmp2[i] >> 4;
	y = tmp2[i] - (x << 4);
	TempKey[i] = S_BOX[x][y];
}

KeySchedule 3


위의 과정을 거쳐서 나온 TempKey 행렬을 R_Con행렬과 XOR연산을 한다.

R_Con

KeySchedule를 위한 행렬이다. R_Con은 다음과 같다
  AES R_Con 

 첫 번째 열을 R_Con, 암호키의 첫 번째 세로열 XOR 연산을 해준다.
for (i = 0; i<4; i++) {
	tmp[i][0] = CipherKey[j][0] ^ tmp2[j] ^ R_Con[j][0];
}
그 다음부터는 이전에 연산한 렬과 XOR 연산을 하면 된다.
for (j = 0; j<4; j++) {
	for (k = 1; k<4; k++) {
		tmp[j][k] = CipherKey[j][k] ^ tmp[j][k - 1];
	}
}
이를 위의 알고리즘 순서도의 것과 같이 적절히 반복시키면 암호화가 완성된다. 복호화는 다음 포스팅에서 쓰겠다. 다만, 순서도에서도 볼 수 있듯이 단순히 역순에 불과하다.




더보기

댓글,

Lowpoly

게임 서버 프로그래머 지망생