AES

최근 수정 시각:

파일:나무위키+유도.png   가정용 네오지오 기판에 대해서는 네오지오 문서를 참조하십시오.


1. 개요2. 역사3. 알고리즘
3.1. 레인달 알고리즘
3.1.1. SubBytes3.1.2. InvSubBytes3.1.3. ShiftRows3.1.4. InvShiftRows3.1.5. MixColumns3.1.6. InvMixColumns3.1.7. AddRoundKey
3.2. 그외 필요한 스테이지
3.2.1. BASE643.2.2. PKCS7 / PKCS5 Padding
4. 특징
4.1. 프로그래밍 언어 API4.2. 안전성
5. 기타6. 관련 문서


표준문서 : FIPS-197.

1. 개요[편집]

<Advanced Encryption Standard>의 줄인 말이다. 우리말 번역은 '고급 암호화 표준'이다. 벨기에의 2명의 암호학자, 존 대먼과, 빈센트 라이먼이 만든 암호화 알고리즘이다. NIST가 제정한 알고리즘이며 미국 정부가 채택한 후, 높은 안전성과 속도로 인해 인기를 얻어 전 세계의 랜섬웨어에적으로 많이 사용되고 있다.

컴퓨팅 기술의 급속한 발전에 따라 현재 권장되는 암호화 수준은 192bit 이상이며 따라서 대다수의 금융기관들은 256bit 이상의 암호화 체계로 전환했다.

2. 역사[편집]

NIST(National Institute for Standards and Testing)가 기밀문서를 안전하게 암호화 시켜서 보호하기 위해 DES 암호화 알고리즘을 대체할 새로운 암호화 알고리즘을 찾기 시작했다. 하지만 DES는 몇몇 슈퍼 컴퓨터에 의하여 더 이상 안전하지 않다는 결과가 나왔다. 거의 하루 정도의 시간을 소모하여 DES로 암호화 된 데이터를 얻었고, 이제는 DES암호화를 해킹하는 칩도 나왔다. 물론, 비싸다(...). 그러다 AES라는 암호화 알고리즘이 나온 것이다.

NIST는 1998년 8월 20일에 First AES Candidate를 개최하였고[1], 1999년 3월에 Second ARS Candidate Conference를 개최하였고, 1999년 8월에 5개의 암호화 알고리즘이 후보로 추가되었다. 암호화 알고리즘들은 MARS, RC6, Rijndael(레인달), Serpent, Twofish 였다. 결국, AES를 위한 암호화 알고리즘은 레인달이 뽑혔다. 암호화 알고리즘 후보는 보안성이 좋아야 했었고, 비용도 적게 들고, 유연하면서 간단해야 했다. Rijndael이 뽑힌 이유는 다른 암호화 알고리즘이 안 좋아서가 아니다. 다른 알고리즘도 좋기는 하나, 레인달이 유난히 더 좋아서라고 카더라. 이후 2001년 2월 28일, 기밀문서를 암호화 할 때, DES를 대체하여 많이 사용되기 시작되었다.

3. 알고리즘[편집]

AES암호화에 사용되는 단계들이다.

이 밑에 있는 것들이 알고리즘 이름들이다.

  • SubBytes

  • ShiftRows

  • MixColumns

  • AddRoundKey


키 스케쥴다음, 가장 처음에 AddRoundKey로 CipherText를 암호화 시킨다. 그 다음, 위에 4 알고리즘을 CipherText에 적용한다. 비트크기에 따라 반복하는 수가 다르다. AES-128 같은 경우는 9번, AES-192는 11번, 그리고 AES-256은 13번 반복한다.

4 알고리즘을 적용 후, 마지막으로 S-Box, ShiftRows, 그리고 AddRoundKey를 적용한다.

3.1. 레인달 알고리즘[편집]

3.1.1. SubBytes[편집]

바이트들을 S-Box (Substitution Box)에 있는 바이트들과 바꾸는 부분이다.

그 S-Box는 이렇게 생겼다.

---

00

01

02

03

04

05

06

07

08

09

0A

0B

0C

0D

0E

0F

00

0x63

0x7C

0x77

0x7B

0xF2

0x6B

0x6F

0xC5

0x30

0x01

0x67

0x2B

0xFE

0xD7

0xAB

0x76

10

0xCA

0x82

0xC9

0x7D

0xFA

0x59

0x47

0xF0

0xAD

0xD4

0xA2

0xAF

0x9C

0xA4

0x72

0xC0

20

0xB7

0xFD

0x93

0x26

0x36

0x3F

0xF7

0xCC

0x34

0xA5

0xE5

0xF1

0x71

0xD8

0x31

0x15

30

0x04

0xC7

0x23

0xC3

0x18

0x96

0x05

0x9A

0x07

0x12

0x80

0xE2

0xEB

0x27

0xB2

0x75

40

0x09

0x83

0x2C

0x1A

0x1B

0x6E

0x5A

0xA0

0x52

0x3B

0xD6

0xB3

0x29

0xE3

0x2F

0x84

50

0x53

0xD1

0x00

0xED

0x20

0xFC

0xB1

0x5B

0x6A

0xCB

0xBE

0x39

0x4A

0x4C

0x58

0xCF

60

0xD0

0xEF

0xAA

0xFB

0x43

0x4D

0x33

0x85

0x45

0xF9

0x02

0x7F

0x50

0x3C

0x9F

0xA8

70

0x51

0xA3

0x40

0x8F

0x92

0x9D

0x38

0xF5

0xBC

0xB6

0xDA

0x21

0x10

0xFF

0xF3

0xD2

80

0xCD

0x0C

0x13

0xEC

0x5F

0x97

0x44

0x17

0xC4

0xA7

0x7E

0x3D

0x64

0x5D

0x19

0x73

90

0x60

0x81

0x4F

0xDC

0x22

0x2A

0x90

0x88

0x46

0xEE

0xB8

0x14

0xDE

0x5E

0x0B

0xDB

A0

0xE0

0x32

0x3A

0x0A

0x49

0x06

0x24

0x5C

0xC2

0xd3

0xAC

0x62

0x91

0x95

0xE4

0x79

B0

0xE7

0xC8

0x37

0x6D

0x8D

0xD5

0x4E

0xA9

0x6C

0x56

0xF4

0xEA

0x65

0x7A

0xAE

0x08

C0

0xBA

0x78

0x25

0x2E

0x1C

0xA6

0xB4

0xC6

0xE8

0xdD

0x74

0x1F

0x4B

0xBD

0x8B

0x8A

D0

0x70

0x3E

0xB5

0x66

0x48

0x03

0xF6

0x0E

0x61

0x35

0x57

0xB9

0x86

0xC1

0x1D

0x9E

E0

0xE1

0xF8

0x98

0x11

0x69

0xD9

0x8E

0x94

0x9B

0x1E

0x87

0xE9

0xCE

0x55

0x28

0xDF

F0

0x8C

0xA1

0x89

0x0D

0xBF

0xE6

0x42

0x68

0x41

0x99

0x2D

0x0F

0xB0

0x54

0xBB

0x16


맨 윗쪽 행과, 첫 번째 열은 단순히 쉽게 읽게 하기 위해 있는 숫자들이므로, 헷갈리지 말자.

예를 들어, 0x4C를 S-Box에서 바꾸면, 0x29가 되겠다.

3.1.2. InvSubBytes[편집]

이 부분은, 위에 SubBytes 와 같지만, 이 알고리즘은 복호화를 할때 사용된다.

Inv S-Box는 이렇게 생겼다.

---

00

01

02

03

04

05

06

07

08

09

0A

0B

0C

0D

0E

0F

00

0x52

0x09

0x6A

0xD5

0x30

0x36

0xA5

0x38

0xBF

0x40

0xA3

0x9E

0x81

0xF3

0xD7

0xFB

10

0x7C

0xE3

0x39

0x82

0x9B

0x2F

0xFF

0x87

0x34

0x8E

0x43

0x44

0xC4

0xDE

0xE9

0xCB

20

0x54

0x7B

0x94

0x32

0xA6

0xC2

0x23

0x3D

0xEE

0x4C

0x95

0x0B

0x42

0xFA

0xC3

0x4E

30

0x08

0x2E

0xA1

0x66

0x28

0xD9

0x24

0xB2

0x76

0x5B

0xA2

0x49

0x6D

0x8B

0xD1

0x25

40

0x72

0xF8

0xF6

0x64

0x86

0x68

0x98

0x16

0xD4

0xA4

0x5C

0xCC

0x5D

0x65

0xB6

0x92

50

0x6C

0x70

0x48

0x50

0xFD

0xED

0xB9

0xDA

0x5E

0x15

0x46

0x57

0xA7

0x8D

0x9D

0x84

60

0x90

0xD8

0xAB

0x00

0x8C

0xBC

0xD3

0x0A

0xF7

0xE4

0x58

0x05

0xB8

0xB3

0x45

0x06

70

0xD0

0x2C

0x1E

0x8F

0xCA

0x3F

0x0F

0x02

0xC1

0xAF

0xBD

0x03

0x01

0x13

0x8A

0x6B

80

0x3A

0x91

0x11

0x41

0x4F

0x67

0xDC

0xEA

0x97

0xF2

0xCF

0xCE

0xF0

0xB4

0xE6

0x73

90

0x96

0xAC

0x74

0x22

0xE7

0xAD

0x35

0x85

0xE2

0xF9

0x37

0xE8

0x1C

0x75

0xDF

0x6E

A0

0x47

0xF1

0x1A

0x71

0x1D

0x29

0xC5

0x89

0x6F

0xB7

0x62

0x0E

0xAA

0x18

0xBE

0x1B

B0

0xFC

0x56

0x3E

0x4B

0xC6

0xD2

0x79

0x20

0x9A

0xDB

0xC0

0xFE

0x78

0xCD

0x5A

0xF4

C0

0x1F

0xDD

0xA8

0x33

0x88

0x07

0xC7

0x31

0xB1

0x12

0x10

0x59

0x27

0x80

0xEC

0x5F

D0

0x60

0x51

0x7F

0xA9

0x19

0xB5

0x4A

0x0D

0x2D

0xE5

0x7A

0x9F

0x93

0xC9

0x9C

0xEF

E0

0xA0

0xE0

0x3B

0x4D

0xAE

0x2A

0xF5

0xB0

0xC8

0xEB

0xBB

0x3C

0x83

0x53

0x99

0x61

F0

0x17

0x2B

0x04

0x7E

0xBA

0x77

0xD6

0x26

0xE1

0x69

0x14

0x63

0x55

0x21

0x0C

0x7D


맨 윗쪽 행과, 첫 번째 열은 단순히 쉽게 읽게 하기 위해 있는 숫자들이므로, 헷갈리지 말자.

반대로, 0x29를 복호화 하면, 0x4C가 나온다.

3.1.3. ShiftRows[편집]

바이트의 행을 뒤집는 부분이다.

0x00

0x01

0x02

0x03

0x04

0x05

0x06

0x07

0x08

0x09

0x0A

0x0B

0x0C

0x0D

0x0E

0x0F


이런 식으로, 바이트가 있다면,

0x00

0x01

0x02

0x03

0x05

0x06

0x07

0x04

0x0A

0x0B

0x08

0x09

0x0F

0x0C

0x0D

0x0E


이런 식으로 바뀐다.
먼저, 첫 번째 줄은 아무런 변화가 없다.
두 번째 줄에서는, 왼쪽으로 한 칸이 밀렸다.
세 번째 줄은 왼쪽으로 두 칸이 밀렸다.
네 번째 줄은 왼쪽으로 세 칸이 밀렸다.

여기서, 조심할 것이 있다. 128비트, 192 비트 또는 256 비트에 따라 열의 숫자가 달라진다.

3.1.4. InvShiftRows[편집]

Inverse Shift Rows. 이 스테이지도 복호화 할 때 사용된다.

0x00

0x01

0x02

0x03

0x05

0x06

0x07

0x04

0x0A

0x0B

0x08

0x09

0x0F

0x0C

0x0D

0x0E


이런 식의 바이트들을

0x00

0x01

0x02

0x03

0x04

0x05

0x06

0x07

0x08

0x09

0x0A

0x0B

0x0C

0x0D

0x0E

0x0F


이런 식으로 다시 돌려두는 것이다.

첫 번째 줄은 ShiftRows 스테이지에서 그런 것처럼 아무런 변화가 없다.
두 번째 줄은 왼쪽으로 3번 민다.
세 번째 줄은 왼쪽으로 2번 밀렸다.
네 번째 줄은 왼쪽으로 1번 밀면 된다.

3.1.5. MixColumns[편집]

이 단계에서는, 특수한 공식이 사용된다.

a0 * [2 3 1 1] = r0
a1 * [1 2 3 1] = r1
a2 * [1 1 2 3] = r2
a3 * [3 1 1 2] = r3

여기서 r값들을 구하려면, 이런 식으로 해야한다.

r0 = (a0 * 2) + (a1 * 3) + (a2 * 1) + (a3 * 1).
r1 = (a0 * 1) + (a1 * 2) + (a2 * 3) + (a3 * 1).
r2 = (a0 * 1) + (a1 * 1) + (a2 * 2) + (a3 * 3).
r3 = (a0 * 3) + (a1 * 1) + (a2 * 1) + (a3 * 2).

근데, 여기서 곱하기는 절대로 초등학교 수학에서나 나오던 곱하기가 아니다. Exclusive-OR(XOR)을 특별하게 사용해야 한다.

C언어로 표현하면 이렇게 된다.

typedef unsigned char byte;
void rijndael_mixcolumn (byte * data, size_t data_len) {
	if ((data_len % 4) != 0)
		return;

	for (size_t i = 0 ; i < data_len ; i += 4) {
		byte copy_arr [4], res [4];

		memcpy (copy_arr, data + i, 4);

		res [0] = (data [0 + i] << 1) ^ (0x1B & ((byte) ((signed char) data [0 + i] >> 7)));
		res [1] = (data [1 + i] << 1) ^ (0x1B & ((byte) ((signed char) data [1 + i] >> 7)));
		res [2] = (data [2 + i] << 1) ^ (0x1B & ((byte) ((signed char) data [2 + i] >> 7)));
		res [3] = (data [3 + i] << 1) ^ (0x1B & ((byte) ((signed char) data [3 + i] >> 7)));

		data [0 + i] = res [0] ^ copy_arr [3] ^ copy_arr [2] ^ res [1] ^ copy_arr [1];
		data [1 + i] = res [1] ^ copy_arr [0] ^ copy_arr [3] ^ res [2] ^ copy_arr [2];
		data [2 + i] = res [2] ^ copy_arr [1] ^ copy_arr [0] ^ res [3] ^ copy_arr [3];
		data [3 + i] = res [3] ^ copy_arr [2] ^ copy_arr [1] ^ res [0] ^ copy_arr [0];
	}
}


이 과정을 미리 계산해서 Table-lookup에 저장해 놓고 계산하는 방법도 있으며, 모든 AES 최적화에는 이러한 Table-lookup방식을 적용한다.[2]

3.1.6. InvMixColumns[편집]

Inverse Mix Columns. 이 부분은, MixColumns와 흡사하나, InvMixColumns는 Inverse Substitution Box와 마찬가지로, 복호화 할때 사용된다.

공식:
a0 * [14 11 13 9] = r0
a1 * [9 14 11 13] = r1
a2 * [13 9 14 11] = r2
a3 * [11 13 9 14] = r3

3.1.7. AddRoundKey[편집]

이 단계는 다른 단계와는 비해 간단하다. 비트 연산자인, XOR연산자를 사용하면된다. [3]
예를 들어, 0x0A ⊕ 0x03 같은 경우에는, 0x09다.

먼저, 0x0A, 즉 10을 이진수로 바꾸면 1010이고, 0x03를 이진수로 바꾸면 0011 이다.
이 두 숫자에 XOR에 적용할 때, 서로 다른 값일 경우 1이 되고, 같은 값이면 0이 된다.
먼저, 10의 이진수의 첫 번째 숫자는 1이고, 0x03의 첫 번째 숫자는 0이다. 이 둘을 XOR으로 처리하면 1이 나온다.
0x0A의 두 번째 숫자는 0, 0x03의 두 번째 숫자는 0이다. 서로 같기때문에 0 이다.
0x0A의 세 번째 숫자는 1, 0x03의 세 번째는 1이다. 즉, 0이 된다.

그렇게 계산을 하면 1001이 나온다. 이것을 16진수로 바꾸면 0x09가 나온다.

복호화에서도 똑같이 XOR을 사용한다. 기본적으로, XOR만으로도 암호화가 가능하다. 하지만, 쉽게 뚫리기에 XOR만 가지고는 안 하고 이렇게 다른 알고리즘과 섞어서 사용한다.

3.2. 그외 필요한 스테이지[편집]

3.2.1. BASE64[편집]

BASE64와 AES 간에는 하등의 관계가 없다.

BASE64는 인코딩하는 방식의 하나일 뿐 AES는 어떤 인코딩이든 암호화 할 수 있다. 다만 당연하게도 AES 암호화의 결과는 (널 바이트도 포함되는) 이진 데이터이기 때문에, BASE64 라는 인코딩이 존재하는 이유와 같이 C 와 같은 언어에서 널 바이트를 끝으로 보는 문자열로 쉽게 다룰 수 있게 하기 위해 BASE64 인코딩을 하는 경우가 많기는 하다.

3.2.2. PKCS7 / PKCS5 Padding[편집]

이 스테이지는 암호화 , 그리고 복호화 에 사용한다.
좀 더 정확히는 BASE64 엔코딩후, 디코딩 전에 한다. [4]
이 스테이지도 Rijndael Cipher와 관련이 없다.

PKCS7 같은 경우는, BASE64로 엔코딩 후, 또는 디코딩 전에 처리한다.

01 02 03 04 05 06 07 08

01 02 03 04 05

같은 바이트가 있다. 이 바이트 들을

01 02 03 04 05 06 07 08

01 02 03 04 05 03 03 03

같이 수정한다.

위와 같이 블록 크기가 8인 데이터들이 있다. 마지막에는 데이터가 5 밖에 없다. 거기에다가 블록 크기가 8이기에, 뒤에 3바이트가 더 있어야 한다. PKCS7 패딩은 뒤에 필요한 바이트만큼의 크기의 바이트들을 넣는 것이다.

4. 특징[편집]

128-bit, 192-bit, 그리고 256-bit 키 길이로 처리한다.

128 비트일경우, 10 번 (마지막 라운드 함수를 포함하여) 라운드를 돌려 암호화 하고, 192 비트는 12번을 돌고, 256 비트 일경우, 14 번을 돈다.

S-Box를 간단히 설명하자면 입력 데이터를 지정된 숫자로 바꿔서 암호를 깨기 어렵게 만드는 기법이다. AES는 이걸 창조롭게 재발명하여 암호화 속도를 높이고 싶으면 S-Box를 메모리에 박아놓고, 프로그램 메모리 양을 줄이려면 실행시 S-Box를 연산으로 구해내는 기법을 사용했다. 입맛에 따라 고를 수 있게. (..)

4.1. 프로그래밍 언어 API[편집]

자바 API에 java.security 패키지와, javax.crypto 패키지를 사용하여 AES 암호화를 사용할 수 있다 뭐, 자바는 API자체 크기가 크고 아름다우니. [5]. 여기를 참고하면 될 듯하다.

C/C++ 같은 경우는, 기본 라이브러리에는 없는 듯 하다 [6]. 3rd Party Software나, 다른 API는 구글에 검색만 해도 다 나오니 필요하면 검색해 보자.

PHP 언어도 지원하는 듯 하다. 자바와 마찬가지로, 여기를 참고하면 될 듯하다.

C#은 지원한다. System.Security.Cryptography 네임스페이스와 System.Security.Cryptography.Aes 클래스를 사용하면 된다. 설명은 이곳을 참고하면 된다.

Python은 외부 라이브러리를 통해 지원한다. Crypto 모듈에서 지원한다. 이 곳을 참고하자.

Go 언어는 지원한다. "crypto/aes" 패키지를 이용하면 된다.

CommonJS 프로젝트를 따르는 JavaScript 언어에서는 crypto 모듈을 지원한다. crypto.createCipher 함수를 사용한다.

Assembly언어는 딱히 라이브러리나, API가 있는것이 아니고, CPU가 인식 할 수 있는 명령어인 기계어를 특정 규칙에 따라서 1:1로 매칭시킨 것이기에 없다.

단, 예외로 Intel x86 계열 CPU 의 경우 데스크탑 제품군은 샌디브릿지부터 AES-NI 라는 확장 명령어셋을 지원한다. AES 연산을 하드웨어 가속시킨 것이다.

4.2. 안전성[편집]

미국 정부가 채택하여 기밀문서를 암호화를 했다. 즉, 정부가 믿을 정도라는 것이다. 그러나, 몇 번은 공격을 받은듯 하다. 솔직히 AES의 알고리즘은 은근히 간단한 수학 공식이다. 암호화하는 게 쉽다고 깨는게 쉬운 건 아니지만 말이다. 물론 절대로 프로그램이나, 암호화를 공격하여 해킹을 막는 방법은 절대로 존재하지 않았고, 존재하지 않고, 앞으로도 존재할 수가 없다. 다만, 공격을 하는 시간을 늘리고, 더 까다롭게 하는 것밖에 못한다. 그러나 아직은 AES가 최강의 암호화이고, 당장은 키없이 해독하는것을 거의 불가능하다고 믿어지고 있다. 심지어, 다른 최신 cipher 와 마찬가지로, known-plaintext 해킹기술로도 해독이 불가능하다고 한다. 물론 NSA가 깼는지 여부는 알 수 없고 한 15년쯤 지나면 밝혀지겠지 싶었지만, 18년이 지난 지금도 NSA가 이미 깨버렸는지에 대한 여부가 알려지진 않았다(...)

5. 기타[편집]

Rijndael은 AES를 만든 두 명의 암호학자 이름에서 따온 것이라고 한다. 벨기에 암호학자 라이먼(Rijmen)과 대먼(Daemon)

AES의 과정을 쉽게 설명하고 보여주는 동영상.

AES에 대해 설명해주는 만화. 물론 영어다.

6. 관련 문서[편집]

[1] 이 행사 때 후보에 들어간 암호화 알고리즘은 15개가 된다.[2] 이는 당연히 소프트웨어적인 최적화로, 하드웨어에서의 최적화 방식과는 다르다. 대부분의 암호 알고리즘의 최적화에서 입력값에 따라 출력값의 연산을 수행하는 것이 아니라, 테이블에서 불러오는 방식으로 적용가능하다.[3] XOR은 CPU가 지원하는 명령어다.[4] 어떤 Cipher를 사용하느냐에 따라 다를 수 있다.[5] JSP는 웹서버 스크립트가 자바이기 때문에 당연히 지원한다.[6] C/C++ 언어의 기본 라이브러리는 기초적인 것만 있다. 절대 그 이상이 있는 건 존재하지 않는다.