[include(틀:다른 뜻1, other1=가정용 네오지오 기판, rd1=네오지오, other2=능동 정전기식 펜 입력 기술(Active ElectroStatic), rd2=스타일러스 펜)] [include(틀:이론 컴퓨터 과학)] [목차] == 소개 == >'''fFgx/YKxIRcNIQwkmcWzMw==''' >단어 namu.wiki를 암호 umanle, IV 12345678b0z2345n, AES-256-CBC 방식으로 암호화한 문장이며, 계산시 암호 뒷부분은 0x0 으로 패딩 준문서: [[http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf|FIPS-197]]. AES는 <'''A'''dvanced '''E'''ncryption '''S'''tandard>의 약자로 '고급 암호화 표준'라는 의미이다. AES는 [[NIST|미국 표준 기술 연구소]]에 의해서 연방 정보 처리 표준으로 지정된 암호화 방식이며 [[NSA]]에 의해 1급 비밀에 사용할 수 있도록 승인된 암호화 알고리즘이며, 오픈소스로 공개된 알고리즘이다. [[대칭 열쇠 암호|대칭키]]를 쓰는 블럭 암호이다. 높은 안전성과 속도로 인해 인기를 얻어 전 세계적으로 많이 이용되고 있다. 이러한 이점으로 인해서 [[랜섬웨어]]에 많이 이용되고 있기도 하다. 현재 AES는 [[DES]](데이터 암호화 표준)의 뒤를 이을 AES(고급 암호화 표준)라는 이름을 걸고 미국 표준 기술 연구소가 주최한 공모전에서 채택된 Rijndael(레인달) [[알고리즘]]을 가리킨다. 엄밀하게는 Rijndael 알고리즘의 여러 가능성 중, 암호화 블럭의 크기가 128[[비트]]이며 암호화 키의 길이가 128, 192, 256비트인 세 가지 종류가 AES 표준으로 지정되었다. 각각 AES-128, AES-192, AES-256으로 불린다. == 역사 == AES이전 미국 표준 기술 연구소는 1977년에 [[DES]]를 표준으로 지정하였고 DES는 오랫동안 [[암호화]]의 표준으로 잘 사용되었다. 그러나 1990년대에 기술의 발전으로 56비트 키를 쓰는 [[DES]]가 더 이상 안전하지 않게 되었고[* 90년대 당시의 몇몇 슈퍼 컴퓨터들을 사용하여 하루 정도의 시간을 쓰면 DES 암호를 충분히 풀어낼 수 있었으며 현재의 인텔 9900k 기준으로 대략 반나절이면 풀수있다. 계산법은 당시 싱글 400MHz CPU 128개 병렬연산 기준으로 25.4시간이 걸렸기에 9900K 8코어 16스레드를 10코어로 계산할경우 대략 반나절이 나온다.], DES를 3번 사용하는 3-DES와 같은 방법도 사용되기는 하였으나 여러 문제로 인해 새로운 암호화 표준을 지정할 필요가 있었다. NIST는 1997년 1월에 AES라는 이름의 표준을 제정할 것을 발표하였고, 1997년 9월부터 [[암호화]] [[알고리즘]]의 공모를 받기 시작했다. 조건은 128비트 블록 암호이며, 128, 192, 256비트 길이의 키를 지원할 것이었다. 총 15개의 후보 알고리즘은 1998년 8월 20일의 첫번째 AES [[후보]] [[학술대회]](First Advanced Encryption Standard Candidate Conference)와 1999년 3월의 두번째 학회를 거치며 5개로 추려졌다. MARS, RC6, '''Rijndael''', Serpent, Twofish 알고리즘이 최종 후보에 올랐고, 2000년 4월의 세번째 학회에서 다루어졌다. 결국 나머지 후보군들 중에서 안전성, 유연성, 성능 등을 가장 잘 만족하는 Rijndael 알고리즘이 최종적으로 채택되었고, NIST는 2001년 11월 26일에 Rijndael 알고리즘[* 의 128비트 블록, 128, 192, 256비트 키 버전]을 FIPS 197, AES라는 이름으로 표준으로 발표하였다. == 특징 == 대칭형, 블럭 [[암호화]] [[알고리즘]]이다. 대칭형 암호화 알고리즘 중 가장 유명하다. 암호화 키는 128, 192, 256의 세 가지 중 하나가 될 수 있으며, 각각 AES-128, AES-192, AES-256으로 불린다. 암호화 키의 길이에 따라 실행하는 라운드의 수가 다른데, 각각 10, 12, 14 라운드를 실행한다. S-Box를 간단히 설명하자면 입력 데이터를 지정된 숫자로 바꿔서 암호를 깨기 어렵게 만드는 기법이다. AES는 이걸 창조롭게 재발명하여 암호화 속도를 높이고 싶으면 S-Box를 메모리에 박아놓고, 프로그램 메모리 양을 줄이려면 실행시 S-Box를 연산으로 구해내는 기법을 사용했다. == 알고리즘 == AES의 과정을 쉽게 설명하고 보여주는 [[https://www.youtube.com/watch?v=mlzxpkdXP58|동영상]]. 아래의 내용이 너무 복잡하다면 영상과 같이 보자. Rijndael(레인달)이 AES로 채택되었으므로 아래는 Rjindael [[알고리즘]]에 대한 설명이기도 하다. 아래 설명에서 블럭 크기인 128[[비트]]와, 키 길이인 128, 192, 256비트를 헷갈리지 않도록 주의하자. === 개요 === Rijndael 알고리즘은 크게 보아 네 단계로 이루어진다. * KeyExpansion: key schedule(키 스케줄)이라고도 부른다. 128, 192 또는 256비트 길이인 하나의 주 암호화 키를 받아서 아래 라운드들에서 사용할 여러 개의 128비트 '''라운드 키'''를 생성한다. * 0 라운드: 위의 단계에서 생성한 라운드 키 중 첫번째 키를 사용, AddRoundKey를 한 번 실행한다. * 1~(9, 11, 13) 라운드: SubBytes, ShiftRows, MixColumns, AddRoundKey를 순서대로 실행한다. 이것을 AES-128, 192, 256에 따라 각각 9번, 11번, 13번 반복한다. * 마지막 (10, 12, 14)번째 라운드: SubBytes, ShiftRows, AddRoundKey를 순서대로 실행한다. === KeyExpansion === 위에서 언급한 것처럼 key schedule, 키 스케줄이라고도 부른다. 하나의 주 암호화 키로부터 많은 라운드 키들을 만들어 낸다. 주 키의 길이에 따라 총 라운드 수가 달라지므로, 만들어야 할 라운드 키의 갯수도 다르다. AES-128, 192, 256에 따라 각각 10개, 12개, 14개의 라운드 키를 만든다. Rijndael 알고리즘은 라운드 키를 만들 때 32[[비트]]=4[[바이트]]=[[워드]]씩, 연속적으로 만든다. AES는 세 버전 모두 128[[비트]]의 블록 사이즈를 사용하므로, 하나의 라운드 키는 이 4바이트 [[워드]]를 네 개 뭉쳐서 만든다.[* Rijndael 알고리즘을 쓰지만 블록 사이즈가 128비트가 아닌 경우에는 필요한 워드의 갯수가 다르다.] 그러므로 AES-128, 192, 256 버전은 각각 44, 52, 60개의 4바이트 [[워드]]를 만들어야 한다. ==== 개관 ==== 주 키의 길이를 32비트로 나눈 것을 [math(N)]이라 하자. 즉 주 키가 [math(N)]워드다. 예를 들어 AES-192라면 [math(N = 6)]일 것이다. 그리고 필요한 워드는 [math(4R)]이며 AES-192의 경우 [math(52)]워드다. 각 워드를 [math(W_0, W_1, ..., W_{4R-1})]라 할때 아래 규칙에 따라 생성된다. * i < N: W(i) = N(i) * i ≥ N, i ≡ 0 mod N: W(i) = W(i-N) [[논리 연산|XOR]] RotWord(SubWord(W(i-1))) XOR Rcon(i/N) * i ≥ N, N > 6, i ≡ 4 mod N: W(i) = W(i-N) XOR SubWord(W(i-1)) * 그 외: W(i-N) XOR W(i-1) 즉 첫 N개의 워드는 주 키를 순서대로 그대로 가져다 쓴다. 그 다음부턴 N개 워드마다 순환하는데 첫 워드는 이전 워드에 RotWord, SubWord한 것, N칸 이전의 워드, Rcon(i/N) 3개를 XOR한 값으로 정해진다. 그리고 나머지 N-1개는 단순히 이전 워드와 N칸 이전 워드를 XOR한다. 예외로 i ≥ N, N > 6 and i ≡ 4 mod N인 경우[* AES표준에서 N>6인 경우는 N=8인 AES-256만 존재한다.]에는 W(i) = W(i-N) XOR SubWord(W(i-1))를 적용한다. ==== RotWord & SubWord ==== RotWord는 4바이트 워드를 바이트 단위로 한 칸 민(shift/rotate) 것이다. 즉 RotWord([89 ab cd ef]) = [ab cd ef 89]이다. SubWord는 바이트 단위로 아래에 서술할 SubBytes를 실행하는 함수이다. 위의 예를 사용하면 SubWord([ab cd ef 89]) = [62 bd df a7]이 될 것이다. ==== Rcon, Round Constant ==== 키를 더더욱 알기 어렵게 하기 위해 섞어주는 상수이다. 이름은 round constant이지만, 이 라운드는 AES의 큰 흐름에서 말하는 라운드와 다르다! 그 라운드는 4개의 워드를 만들 때마다(즉 128비트마다) 바뀌지만, 이 round constant는 N개의 워드를 만들 때마다 다음 값으로 바뀐다. 즉 W(i)를 구할 때에는 rcon('''i/N''')을 쓴다. 역시 4바이트 워드이며 값은 다음과 같이 주어진다. * rcon(k) = [rc(k) 00 00 00] * rc(1) = 0x01 * If rc(k-1) < 0x80: rc(k) = rc(k-1) * 2 * If rc(k-1) >= 0x80: rc(k) = (rc(k-1) * 2) XOR 0x11B 즉 아랫쪽 3바이트는 항상 0이며, 첫번째 바이트는 2배 하거나 2배 한 이후 0x11B와 XOR한 것이다. 계산해보면 첫번째 바이트는 0x01, 02, 04, 08, 10, 20, 40, 80, 1B, 36, ... 으로 주어진다. Rcon은 N개의 워드를 만들때마다 바뀌므로, 필요한 라운드 키의 개수와는 다르다. 필요한 워드 수가 각각 44, 52, 60인 AES-128, 192, 256은 각각 4, 6, 8로 나누어보면 10, 8, 7번째까지의 Rcon이 필요함을 알 수 있다. AES-128의 경우 44라운드가 필요한데 10개의 Rcon만 쓰이는 이유는 첫 N개의 워드는 주 키를 그대로 가져다 쓰기 때문이다. === SubBytes === SubBytes 단계에서는 128[[비트]]블럭 안의 16[[바이트]]를 바이트 단위로 쪼개, 각 바이트마다 다른 내용으로 치환한다. 이때 미리 주어진 Rijndael S-Box (Substitution Box)를 사용한다. 아래의 표가 S-Box이다. || || 00 || 01 || 02 || 03 || 04 || 05 || 06 || 07 || 08 || 09 || 0A || 0B || 0C || 0D || 0E || 0F || || 00 || 63 || 7C || 77 || 7B || F2 || 6B || 6F || C5 || 30 || 01 || 67 || 2B || FE || D7 || AB || 76 || || 10 || CA || 82 || C9 || 7D || FA || 59 || 47 || F0 || AD || D4 || A2 || AF || 9C || A4 || 72 || C0 || || 20 || B7 || FD || 93 || 26 || 36 || 3F || F7 || CC || 34 || A5 || E5 || F1 || 71 || D8 || 31 || 15 || || 30 || 04 || C7 || 23 || C3 || 18 || 96 || 05 || 9A || 07 || 12 || 80 || E2 || EB || 27 || B2 || 75 || || 40 || 09 || 83 || 2C || 1A || 1B || 6E || 5A || A0 || 52 || 3B || D6 || B3 || 29 || E3 || 2F || 84 || || 50 || 53 || D1 || 00 || ED || 20 || FC || B1 || 5B || 6A || CB || BE || 39 || 4A || 4C || 58 || CF || || 60 || D0 || EF || AA || FB || 43 || 4D || 33 || 85 || 45 || F9 || 02 || 7F || 50 || 3C || 9F || A8 || || 70 || 51 || A3 || 40 || 8F || 92 || 9D || 38 || F5 || BC || B6 || DA || 21 || 10 || FF || F3 || D2 || || 80 || CD || 0C || 13 || EC || 5F || 97 || 44 || 17 || C4 || A7 || 7E || 3D || 64 || 5D || 19 || 73 || || 90 || 60 || 81 || 4F || DC || 22 || 2A || 90 || 88 || 46 || EE || B8 || 14 || DE || 5E || 0B || DB || || A0 || E0 || 32 || 3A || 0A || 49 || 06 || 24 || 5C || C2 || d3 || AC || 62 || 91 || 95 || E4 || 79 || || B0 || E7 || C8 || 37 || 6D || 8D || D5 || 4E || A9 || 6C || 56 || F4 || EA || 65 || 7A || AE || 08 || || C0 || BA || 78 || 25 || 2E || 1C || A6 || B4 || C6 || E8 || dD || 74 || 1F || 4B || BD || 8B || 8A || || D0 || 70 || 3E || B5 || 66 || 48 || 03 || F6 || 0E || 61 || 35 || 57 || B9 || 86 || C1 || 1D || 9E || || E0 || E1 || F8 || 98 || 11 || 69 || D9 || 8E || 94 || 9B || 1E || 87 || E9 || CE || 55 || 28 || DF || || F0 || 8C || A1 || 89 || 0D || BF || E6 || 42 || 68 || 41 || 99 || 2D || 0F || B0 || 54 || BB || 16 || 맨 왼쪽 열이 높은 4비트, 맨 위쪽 행이 낮은 4비트이다. 예를 들어, 0x4C는 40과 0C가 만나는 칸의 0x29가 된다. ==== InvSubBytes ==== Inverse SubBytes. SubBytes와 같지만 복호화를 할 때의 단계이다. 당연히 S-Box를 뒤집은 Inv S-Box를 쓴다. || || 00 || 01 || 02 || 03 || 04 || 05 || 06 || 07 || 08 || 09 || 0A || 0B || 0C || 0D || 0E || 0F || || 00 || 52 || 09 || 6A || D5 || 30 || 36 || A5 || 38 || BF || 40 || A3 || 9E || 81 || F3 || D7 || FB || || 10 || 7C || E3 || 39 || 82 || 9B || 2F || FF || 87 || 34 || 8E || 43 || 44 || C4 || DE || E9 || CB || || 20 || 54 || 7B || 94 || 32 || A6 || C2 || 23 || 3D || EE || 4C || 95 || 0B || 42 || FA || C3 || 4E || || 30 || 08 || 2E || A1 || 66 || 28 || D9 || 24 || B2 || 76 || 5B || A2 || 49 || 6D || 8B || D1 || 25 || || 40 || 72 || F8 || F6 || 64 || 86 || 68 || 98 || 16 || D4 || A4 || 5C || CC || 5D || 65 || B6 || 92 || || 50 || 6C || 70 || 48 || 50 || FD || ED || B9 || DA || 5E || 15 || 46 || 57 || A7 || 8D || 9D || 84 || || 60 || 90 || D8 || AB || 00 || 8C || BC || D3 || 0A || F7 || E4 || 58 || 05 || B8 || B3 || 45 || 06 || || 70 || D0 || 2C || 1E || 8F || CA || 3F || 0F || 02 || C1 || AF || BD || 03 || 01 || 13 || 8A || 6B || || 80 || 3A || 91 || 11 || 41 || 4F || 67 || DC || EA || 97 || F2 || CF || CE || F0 || B4 || E6 || 73 || || 90 || 96 || AC || 74 || 22 || E7 || AD || 35 || 85 || E2 || F9 || 37 || E8 || 1C || 75 || DF || 6E || || A0 || 47 || F1 || 1A || 71 || 1D || 29 || C5 || 89 || 6F || B7 || 62 || 0E || AA || 18 || BE || 1B || || B0 || FC || 56 || 3E || 4B || C6 || D2 || 79 || 20 || 9A || DB || C0 || FE || 78 || CD || 5A || F4 || || C0 || 1F || DD || A8 || 33 || 88 || 07 || C7 || 31 || B1 || 12 || 10 || 59 || 27 || 80 || EC || 5F || || D0 || 60 || 51 || 7F || A9 || 19 || B5 || 4A || 0D || 2D || E5 || 7A || 9F || 93 || C9 || 9C || EF || || E0 || A0 || E0 || 3B || 4D || AE || 2A || F5 || B0 || C8 || EB || BB || 3C || 83 || 53 || 99 || 61 || || F0 || 17 || 2B || 04 || 7E || BA || 77 || D6 || 26 || E1 || 69 || 14 || 63 || 55 || 21 || 0C || 7D || SubBytes에서와 마찬가지로, 0x29를 복호화 하면 0x4C가 된다. === ShiftRows === ShiftRows 단계에서는 128비트=16바이트 블럭을 4x4 바이트 행렬로 보고 각 행마다 왼쪽으로 민(shift/rotate)다. ShiftRows처럼 열을 서로 섞어주는 단계가 없다면 각각의 열이 서로 따로 따로 암호화되어, 4개의 블럭 암호화를 실행한 것과 마찬가지가 되어 좋지 않다. 16바이트를 행 우선으로 아래의 표처럼 배열한 다음, 두번째 줄은 왼쪽으로 한 칸, 세번째 줄은 두 칸, 네번째 줄은 세 칸 만큼 민다. 첫번째 줄은 변화가 없다. 즉 아래의 128비트 블럭은 || 0x00 || 0x01 || 0x02 || 0x03 || || 0x04 || 0x05 || 0x06 || 0x07 || || 0x08 || 0x09 || 0x0A || 0x0B || || 0x0C || 0x0D || 0x0E || 0x0F || ShiftRows를 실행한 후에는 이렇게 된다. || 0x00 || 0x01 || 0x02 || 0x03 || || 0x05 || 0x06 || 0x07 || 0x04 || || 0x0A || 0x0B || 0x08 || 0x09 || || 0x0F || 0x0C || 0x0D || 0x0E || AES의 경우는 128비트 블럭만을 사용하지만, 더 큰 블럭을 갖는 Rijndael 알고리즘에서는 열의 수가 달라지며 미는 바이트의 수도 달라진다. ==== InvShiftRows ==== Inverse Shift Rows. 역시 복호화 할 때 필요한 단계이다. 4x4 행렬을 만든 후 두 번째 줄은 왼쪽으로 3번, 세 번째 줄은 2번, 네 번째 줄은 1번 민다. === MixColumns === 마찬가지로 4x4 행렬을 만든 뒤, 이번에는 열 단위에서 섞어주는 단계이다. 식은 보기 편하게 다음처럼 [[행렬(수학)|행렬]]로 주어진다. 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). 다만 이때 덧셈은 평범한 [[덧셈]]이 아니며, [[논리 연산|XOR]]을 사용해야 한다. 마찬가지로 [[곱셈]]도 덧셈이 XOR인 것에 맞게 계산해 줄 필요가 있다. 만약 더하다가 OverFlow가 발생하면 0x1b와 [[논리 연산|XOR]]을 해 주면 된다 C언어로 표현하면 이렇게 된다. {{{#!syntax cpp 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방식을 적용한다.[* 이는 당연히 소프트웨어적인 최적화로, 하드웨어에서의 최적화 방식과는 다르다. 대부분의 암호 알고리즘의 최적화에서 입력값에 따라 출력값의 연산을 수행하는 것이 아니라, 테이블에서 불러오는 방식으로 적용가능하다.] 마지막 라운드에서는 MixColumns가 없다는 걸 잊지 말자. ==== InvMixColumns ==== Inverse Mix Columns. 역시 복호화 할때 사용한다. [math(S' = \begin{bmatrix} 14 & 11 & 13 & 9\\ 9 & 14 & 11 & 13\\ 13 & 9 & 14 & 11\\ 11 & 13 & 9 & 14 \end{bmatrix} \times S)] === AddRoundKey === 드디어 KeyExpansion 단계에서 만든 라운드 키를 쓸 때가 되었다. 128비트 블럭에 128비트 라운드 키(네 워드를 이어붙여 만든)를 [[논리 연산|XOR]]한다. XOR의 특성 때문에, AddRoundKey 단계는 복호화하는 데 굳이 별도의 역 공식이 필요하지 않고, 같은 라운드 키로 XOR을 한 번 더 하기만 하면 복호화가 된다. AddRoundKey는 '''0라운드''', 1~(9,11,13), (10,12,14) 라운드에서 실행하므로, 위에서 언급했듯 총 (11, 13, 15)개의 라운드 키가 필요하다. === 이 외 === ==== BASE64 인코딩 ==== [[BASE64]]는 이진 데이터를 플레인 텍스트로 [[인코딩]]하는 하나의 방식일 뿐 본래 AES 암호화 알고리즘과는 관련이 없다. 다만 AES 암호화된 결과 데이터는 이진 데이터이기 때문에 데이터 교환 시 불편한 경우가 많아 대부분 암호화된 결과 데이터를 BASE64로 인코딩해서 나온 플레인 텍스트를 사용한다. 물론 BASE64로 인코딩 했다면 복호화 이전에 BASE64 디코딩이 필요하다. ==== PKCS#7 패딩 ==== AES가 블럭 암호화 알고리즘인 만큼 다른 모든 블럭 암호화 알고리즘처럼 [[패딩]](padding)하여 블럭의 빈 자리를 채울 필요가 있다. 일반적으로 PKCS#5와 PKCS#7에 정의된 패딩 알고리즘이 널리 사용된다. PKCS#7 패딩 알고리즘은 블럭의 크기가 k바이트(k는 1~255)일 때 패딩하고자 하는 데이터의 바이트 단위 길이가 k의 배수가 되는데 필요한 나머지 바이트 개수를 n이라 하면 n이라는 값을 n개 덧붙인다. 단, 바이트 단위 길이가 딱 k의 배수이더라도 k라는 값을 k개 덧붙인다.[* 마지막에 01이나 02 02 등 padding으로 오인될 수 있는 값이 붙는 경우를 예방하기 위함이다.] 코드로 표현하자면 다음과 같다. {{{#!syntax javascript const k = /* 1 ~ 255 */; // blockSize const n = k - baseDataLen % k; // padSize == padValue }}} 예를 들어 원문이 아래와 같고, 블럭의 크기가 128비트(16바이트)라 하면, || 01 02 03 04 05 06 07 08 01 02 04 08 10 20 40 80 00 11 22 33 44 55 66 77 88 99 AA || 총 27바이트이므로 16의 배수인 32바이트가 되려면 5바이트가 부족하다. || 01 02 03 04 05 06 07 08 01 02 04 08 10 20 40 80 || 00 11 22 33 44 55 66 77 88 99 AA || 따라서 바이트 '''0x05'''를 '''5개'''만큼 뒤에 덧붙여서 아래와 같이 두 블럭을 만든다. || 01 02 03 04 05 06 07 08 01 02 04 08 10 20 40 80 || 00 11 22 33 44 55 66 77 88 99 AA '''05 05 05 05 05''' || PKCS#5 패딩은 PKCS#7 패딩과 구현 방식이 같지만 블럭의 크기가 8바이트로 고정된 것이다. AES는 128비트(16바이트) 블럭 알고리즘이기 때문에 사실 PKCS#5 패딩을 쓸 일이 없다. 그러나 PKCS#7 패딩과 구현 방식이 같아 보통 같은 구현을 돌려쓰는데다, Java에서 'AES/CBC/PKCS5Padding' 표기법만 허용하고 'AES/CBC/PKCS7Padding' 표기법은 지원하지 않다보니 오히려 AES에 PKCS#5 패딩을 쓰는 것이 맞는 줄 아는 경우가 많다. == 안전성 == [[미국 정부]]가 기밀문서 암호화 처리에 이것을 채택했다. 미국 정부 표준 암호화 알고리즘이기도 하다. 즉 [[미국 정부]]가 믿고 이 기술을 사용할 정도라는 것이다. 현존 암호화 알고리즘 기술 중 AES가 최강의 암호화 알고리즘이고, 키없이 해독하는 것이 거의 불가능하다고 평가되고 있다. 심지어 다른 최신 cipher와 마찬가지로, known-plaintext 조건에서도 해독이 불가능하다고 한다. [[소수]]를 사용한 암호화, [[ECDLP]](Elliptic Curve Discrete Logarithm Problem)의 특성을 이용한 [[공개키 암호화 방식]] 등이 [[양자컴퓨터]]에 취약할 가능성을 보이지만, SPN(Substitution Permutation Network)을 기반으로 하는 AES의 특성상 [[양자컴퓨터]]에도 안전하다. 컴퓨팅 기술의 급속한 발전에 따라 현재 권장되는 암호화 수준은 192비트 이상이며 대다수의 금융기관이나 웹사이트들은 256비트 이상의 [[암호화]] 체계로 전환했다. 컴퓨터 파일이나 각종 디스크 암호화에도 매우 적절한 암호화 방식이다. 특히, 널리 사용되는 표준 암호화 방식이라 하드웨어 지원이 빵빵해서 요즘 하드웨어 정도되면 암호화 되지 않은 디스크와 성능차가 느껴지지 않을 수준이다. 유명한 암호화 프로그램 [[VeraCrypt]]나 [[마이크로소프트]]의 [[BitLocker]]가 대표적으로 사용된다. 암호나 키 파일이 털리지 않는 이상 [[디지털 포렌식]]을 하든 슈퍼컴퓨터를 가져오든 복호화가 불가능하다. == 프로그래밍 언어 API == [[Java|자바]]와 같은 [[JVM]] 기반 언어는 java.security 패키지와, javax.crypto 패키지를 사용하여 AES 암호화를 사용할 수 있다. [[JSP]] 역시 자바 기반이기때문에 사용 가능. [[http://aesencryption.net/#Java-aes-encryption-example|자바 예제 코드.]] [[C(프로그래밍 언어)|C]]/[[C++]]는 기본 라이브러리에 포함되어 있지 않으나, 다양한 서드파티 라이브러리를 사용할 수 있다. [[PHP]]에서는, 설치된 PHP 런타임이 [[OpenSSL]]이나 mcrypt[* 2007년 이후로 업데이트가 끊긴 라이브러리로, 보안 취약성이 우려되어 PHP 7.2부터는 지원이 삭제되었다] 확장의 지원을 포함하고 있는 경우 openssl_encrypt() 또는 mcrypt_encrypt() 메소드를 불러 AES를 사용할 수 있다. [[https://aesencryption.net/#PHP-aes-encryption-example|예시]] 만약 해당 확장이 설치되어 있지 않다면, [[https://github.com/phpseclib/phpseclib|phpseclib]] 등의 외부 라이브러리를 이용해야 한다. [[C\#|C#]] 등의 [[Microsoft .NET]] 환경은 System.Security.Cryptography 네임스페이스와 System.Security.Cryptography.Aes 클래스를 사용하면 된다. 설명은 [[http://msdn.microsoft.com/en-us/library/system.security.cryptography.aes(v=vs.110).aspx|MSDN]] 참조. [[Python]]은 외부 라이브러리를 통해 지원한다. [[https://pypi.org/project/pycryptodome/|pycryptodome]] 모듈을 사용할 수 있다. 더 이전에 만들어진 [[https://pypi.python.org/pypi/pycrypto|pycrypto]]라는 모듈도 있지만, 업데이트가 안된지 오래되었고 Python 3.X 상위 버젼에서 해당 모듈 설치시 에러를 뿜어내며 설치가 되지 않는다. [[Go(프로그래밍 언어)|Go]] 언어는 표준 라이브러리로 제공된다. "crypto/aes" 및 "crypto/cipher"(모드 구현) 패키지를 이용하면 된다. ECB 모드는 1블록(128비트)씩 cipher.Block의 Encrypt/Decrypt 함수를 직접 호출하여 이용 가능하다. [[JavaScript]]의 경우 Web Crypto API([[https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto|SubtleCrypto]])에서 AES 암호화를 지원한다. 단, 보안성이 떨어지는 ECB 모드를 제외하고 CBC, CTR, GCM 모드만 지원한다. [[Node.js]]에서는 [[https://nodejs.org/api/crypto.html|crypto 모듈]]에서 [[OpenSSL]]을 기반으로 AES 암호화를 지원한다. 또한 Node.js 19부터 [[https://nodejs.org/api/webcrypto.html|Web Crypto API]]를 정식 지원한다. [[Deno]]에서도 1.18 버전부터 Web Crypto API를 완전히 지원한다. 광범위하게 사용되는 암호화 방식이다 보니, 많은 CPU에서 AES 암/복호화의 하드웨어 가속과 이를 위한 명령어를 도입한 상태이다. * x86 어셈블리에는 인텔에서 개발한 AES 암복호화 하드웨어 가속용 확장 명령어셋인 "AES-NI(New Instructions)"가 존재한다. 인텔의 경우 웨스트미어에서 처음 도입하였으나 당시에는 서버용 Xeon과 Core i5 이상 제품군에만 탑재되었다. 그러던 것이 하스웰부터는 Core i3 이상부터, 스카이레이크부터는 모든 프로세서에서 지원한다. AMD의 경우 불도저 이후의 모든 프로세서에서 AES-NI를 지원한다. * Arm에서는 Armv8-A부터 AES 하드웨어 가속 명령어셋을 지원한다(FEAT_AES). * POWER의 경우 POWER7+부터 "Vector Facility"(구 VMX/AltiVec)에서 AES 하드웨어 가속 명령어셋을 정의하고 있다. == 기타 == Rijndael 알고리즘의 이름은 알고리즘을 만든 두 [[벨기에]] 암호학자 빈센트 레이먼(Vincent '''Rij'''men)과 조앤 대먼(Joan '''Dae'''men)의 이름에서 따온 것이다. AES에 대해 설명해주는 [[http://www.moserware.com/2009/09/stick-figure-guide-to-advanced.html|만화(영문)]] == 관련 문서 == * [[TrueCrypt]] * [[OpenSSL]] [[분류:컴퓨터 보안]] [[분류:암호학]] [[분류:알고리즘]]