안 쓰던 블로그
AES 본문
현재까지 된 코드
아래는 설명
AES는 DES를 대체할 목적으로 개최된 암호 표준 공모에서 채택된 암호 표준이다
확장성을 고려하여 설계되어서 키 길이는 128/192/256 bit를 가지고 키 길이에 상관없이 블록 길이는 128 bit이며 라운드 수는 10/12/14를 가진다.
대략 적인 순서는
1. 라운드키와 xor한다. (AddRoundKey)
2. 바이트를 치환한다. (SubBytes)
3. 행별로 바이트를 옮긴다. (ShiftRows)
4. 열 별로 바이트를 섞는다. (4)
5. 라운키와 xor한다. (AddRoundKey)
6. (라운드 수 - 1) 만큼 2~5를 반복한다.
7. 마지막 라운드는 MixColumns를 제외하고 수행한다.
복호화는 각 단계의 역연산을 거꾸로 수행하면 된다.
1. AddRoundKey
void AddRoundKey(unsigned char state[16], const unsigned char roundKey[16]) //라운드키와 xor
{
unsigned char i; //uint8_t
for (i = 0; i < 16; i++) {
state[i] ^= roundKey[i];
}
}
라운드 키와 xor한다
2. SubBytes
void SubBytes(unsigned char state[16]) //바이트 치환
{
unsigned char i;
for (i = 0; i < 16; i++) {
state[i] = SBox[state[i]];
}
}
이 행렬식을 곱하여 바이트를 치환하는데, 메모리가 부족한 시스템이라면 직접 계산하지만 보통은 미리 다 계산되어 있는 치환표 SBox를 이용한다
예를 들어 만약 37을 바꾼다면 b2가 된다
3. ShiftRows
void ShiftRows(unsigned char state[16])
{
//첫행은 움직이지 않고 둘째행은 1번, 셋째행은 2번, 넷째행은 3번 바이트단위로 왼쪽순환쉬프트
unsigned char tmp = state[1];
state[1] = state[5];
state[5] = state[9];
state[9] = state[13];
state[13] = tmp;
unsigned char tmp1 = state[2], tmp2 = state[6];
state[2] = state[10];
state[6] = state[14];
state[10] = tmp1;
state[14] = tmp2;
unsigned char tmp3 = state[3], tmp4 = state[7], tmp5 = state[11];
state[3] = state[15];
state[7] = tmp3;
state[11] = tmp4;
state[15] = tmp5;
}
첫 행은 움직이지 않고 둘째행은 왼쪽으로 1번, 셋째행은 왼쪽으로 2번, 넷째행은 3번 바이트 단위로 이동하는 왼쪽 순환 쉬프트 과정을 거친다
4. MixColumns
#define xtime(x) ((x<<1) ^ (((x>>7) & 1) * 0x1b))
void MixColumns(unsigned char state[16]) //열 별로 xor
{
int i;
unsigned char Tmp, Tm, t;
for (i = 0; i < 4; i++)
{
t = state[i];
Tmp = state[i] ^ state[i+4] ^ state[i + 8] ^ state[i + 12];
Tm = state[i] ^ state[i + 4];
Tm = xtime(Tm);
state[i] ^= Tm ^ Tmp;
Tm = state[i + 4] ^ state[i + 8];
Tm = xtime(Tm);
state[i + 4] ^= Tm ^ Tmp;
Tm = state[i + 8] ^ state[i + 12];
Tm = xtime(Tm);
state[i + 8] ^= Tm ^ Tmp;
Tm = state[i + 12] ^ t;
Tm = xtime(Tm);
state[i + 12] ^= Tm ^ Tmp;
}
}
이전 라운드에서 나온 값의 각 열에 대해 다음 행렬을 연산한다
그림에서 나온 예시는 d4 * 2 + bf*3 + 5d*1 + 30*1 이다. 곱은 그대로 2, 3, 1 등을 곱하면 된다
근데 한 성분의 비트 수가 8비트밖에 되지 않아서 2나 3을 곱하다 보면 오버플로우가 나게 된다
오버플로우가 발생하면 011b와 XOR연산을 해 준다
각 성분마다 곱셈이 끝나면 더해줘야 하는데, 여기서 하는 덧셈은 실제 덧셈이 아니라 XOR로 더해 주어야 한다
근데 이 코드로 돌리면 제대로 연산 되지 않고 다른 값이 나온다. tiny_aes랑 다른 점이 없어 보이는데..
5. AddRoundKey
암호문과 평문을 XOR한다
여기까지 하면 한 라운드가 종료된다
키 확장
라운드 키는 128비트 기준 총 11개(첫 Addroundkey포함)이고 각 키는 4개의 의 워드로 구성되기때문에 총 44개의 워드가 필요하다.
키 확장 순서
1. 키를 4바이트씩 나누어 4개의 워드로 만든다.
2. 이전 번의 워드와 4번째전 워드를 xor하여 새 워드를 생성한다. ( 4의 배수 번째의 경우 이전 워드를 g함수에 통과시킨다.)
2-1. 입력의 워드를 1바이트만큼 왼쪽 순환시프트를 한다.
2-2. Subbytes에 썼던 치환을 여기서도 사용한다.
2-3. 상수값 R과 xor하여 결과를 반환한다.
3. 워드가 44개 생성될때까지 2를 반복한다.
R상수값
const unsigned char roundConstant[10] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
void KeyExpansion(unsigned char roundKey[11][32], const unsigned char masterKey[16], int r) //키 확장
{
unsigned char i, j, k;
unsigned char temp[4]; //WORD
unsigned char Nk = 4, Nb = 4, Nr = 10; //키 바이트수, 블럭 수, 라운드 수
for (i = 0; i < Nk; i++) { //키를 4바이트씩 나누어 4개 워드로 만든다
roundKey[r][(i * 4) + 0] = masterKey[(i * 4) + 0];
roundKey[r][(i * 4) + 1] = masterKey[(i * 4) + 1];
roundKey[r][(i * 4) + 2] = masterKey[(i * 4) + 2];
roundKey[r][(i * 4) + 3] = masterKey[(i * 4) + 3];
}
for (i = Nk; i < Nb * (Nr + 1); ++i) {
//워드가 44개 나올 때까지 이전 번 워드와 4번째 전 워드를 xor하여 새 워드 생성
k = (i - 1) * 4;
temp[0] = roundKey[k + 0];
temp[1] = roundKey[k + 1];
temp[2] = roundKey[k + 2];
temp[3] = roundKey[k + 3];
if (i % Nk == 0) {
unsigned char u8tmp = temp[0]; //입력 워드 1바이트 왼쪽 순환 시프트
temp[0] = temp[1];
temp[1] = temp[2];
temp[2] = temp[3];
temp[3] = u8tmp;
temp[0] = SBox[temp[0]]; //Subbytes 치환 사용
temp[1] = SBox[temp[1]];
temp[2] = SBox[temp[2]];
temp[3] = SBox[temp[3]];
temp[0] = temp[0] ^ roundConstant[i / Nk]; //상수 r과 xor
}
else if ((i % Nk == 4)) { //4배수면 g통과
temp[0] = SBox[temp[0]];
temp[1] = SBox[temp[1]];
temp[2] = SBox[temp[2]];
temp[3] = SBox[temp[3]];
}
j = i * 4;
k = (i - Nk) * 4;
roundKey[r][j + 0] = roundKey[r][k + 0] ^ temp[0];
roundKey[r][j + 1] = roundKey[r][k + 1] ^ temp[1];
roundKey[r][j + 2] = roundKey[r][k + 2] ^ temp[2];
roundKey[r][j + 3] = roundKey[r][k + 3] ^ temp[3];
}
}
이 부분도 다른 값이 나오는데.. 해결하고 있어요
AES 실행
void AES(unsigned char cipherText[16], const unsigned char plainText[16], const unsigned char key[16])
{
unsigned char state[16] = { 0, };
for (int i = 0; i < 16; i++)
state[i] = plainText[i];
AddRoundKey(state, key);
int Nr = 3;
for (int round = 1; round < Nr; round++)
{
SubBytes(state);
ShiftRows(state);
MixColumns(state);
AddRoundKey(state, key);
}
SubBytes(state);
ShiftRows(state);
AddRoundKey(state, key);
}
'CTF > Crypto' 카테고리의 다른 글
AES란? AES의 암호화와 키 확장 과정 (0) | 2021.03.19 |
---|---|
RSA 공격법: 약간의 평문을 알고, p/q값이 비슷할 때(Fermat Factorization attack) (1) | 2020.09.29 |
크립토 RSA 문제 풀이(낮은 지수 공격, d값 계산) (0) | 2020.09.15 |
파이썬 sage, pycrypto 모듈 (1) | 2020.09.15 |
RSA와 RSA 공격법 (d값 계산, 낮은 지수 공격, 소인수 분해, 하스타드 공격, 위너 공격) (0) | 2020.09.15 |