aes — AES-128 블록 암호
16 바이트를 키로 뒤섞어 16 바이트를 낸다(FIPS 197). 그게 전부다 — 길이가 변하지 않고, 인증도 없고, 같은 입력은 언제나 같은 출력을 낸다. TLS 1.3 이 TLS_AES_128_GCM_SHA256 을 MUST 로 요구하므로(RFC 8446 §9.1) 있다.
혼자 쓰는 모듈이 아니다
| op | 하는 일 | 요구 |
|---|---|---|
gmul | GF(28) 곱(기약다항식 0x11b) | — |
ginv | GF(28) 역원 — x^254(페르마) | 0 의 역원은 0 |
sbox · inv_sbox | S-box 한 바이트 — 표가 아니라 정의로 계산 · 역 S-box | — |
expand_key | 16 바이트 키 → 라운드 키 176 바이트 | rk ≥ 176 · key ≥ 16 |
encrypt_block | st 16 바이트를 제자리에서 암호화 | rk ≥ 176 · st ≥ 16 · tmp ≥ 16 |
표 50.1 — aes 의 op
복호 블록은 없다. GCM 은 카운터 모드라 암호화만 쓴다 — 복호도 암호화로 한다. inv_sbox 가 있는 것은 언젠가 지을 자리를 비워 둔 것이지 지었다는 뜻이 아니다.
S-box 를 표로 적지 않는다. 256 개 상수를 손으로 옮겨 적는 대신 정의 S(x) = 아핀변환(x⁻¹ in GF(2^8)) 을 그대로 쓴다. 옮겨 적을 표가 없으면 옮겨 적다 틀릴 일도 없다. 시험이 계산한 256 개를 정본 표와 대조한다.
성능 — 재 보니 이랬다. 개발 저장소의 측정에서 sbox 한 번이 180 ns(표를 읽는다면 7.5 ns), encrypt_block 한 블록이 약 31 µs 이고 그중 93 % 가 sbox 160 회였다. AES-128-GCM 전체는 0.46 MB/s, ChaCha20-Poly1305 는 41.8 MB/s. 그중 15 배는 이미 갚았다 — ginv 가 x^254 를 254 번 곱하던 것을 제곱-곱으로 바꿔 곱셈이 254 → 15 가 됐고 시험 벡터는 한 자리도 움직이지 않았다. 표를 쓰면 GCM 이 2.5 MB/s 쯤 되겠지만 여전히 ChaCha20 보다 17 배 느리고, 표는 비밀 색인 캐시 부채널 을 들여온다 — AES 의 고전적인 공격 자리다. 느린 대비책을 위해 부채널을 사지 않는다.
확인하는 것 — FIPS 197 부록 B · C 시험 벡터, RFC 8448 §3 의 레코드 암호문(끝까지 써 본다), VM·네이티브 일치.