테마 선택

📚 지식 노트

AI·하드웨어·주변기기·게임·컴퓨터 시스템·이론 컴퓨터 과학·수학·개발과 운영·보안·응용 분야에 대해 알아 두면 좋은 내용을 정리한 노트다. 위에서 분야를 고르고 아래에서 노트를 고른다.

암호학

암호가 기대는 수학을 장난감 크기의 수로 직접 계산해 본다. 모듈러 거듭제곱과 이산 로그, 역원을 구하는 유클리드 호제법, RSA와 타원 곡선, 해시의 생일 한계, 블록 암호의 뼈대, 난수의 함정, 그리고 양자 컴퓨터 이후를 대비한 격자 암호까지를 순서대로 잇는다.

목차 (12)
  1. 모듈러 산술과 빠른 거듭제곱
  2. 군, 생성원, 이산 로그
  3. 유클리드 호제법과 역원
  4. RSA: 장난감 수로 따라가기
  5. 타원 곡선: 점을 더하는 군
  6. 디피–헬먼과 ECDH
  7. 해시 함수의 성질과 생일 한계
  8. 해시의 두 구조: 메르클–담고르와 스펀지
  9. 블록 암호의 구조: 페이스텔과 SPN
  10. 난수: 암호의 숨은 재료
  11. 양자 컴퓨터와 양자내성 암호
  12. 핵심 문헌

대칭 암호와 AEAD, 해시·MAC, 서명과 인증서를 실제로 어떻게 골라 쓰는지는 보안 › 암호 노트에 정리되어 있다. 이 노트는 그 아래에서 "왜 그게 안전한가"를 받치는 수학을 다룬다. 그림과 본문의 수는 모두 원리를 보이려는 작은 예이고, 실제 암호는 수백~수천 비트 크기의 수를 쓴다. 여기 나온 계산을 실제 보호에 쓰면 안 된다. 검증된 라이브러리를 쓰는 것이 원칙이다.

모듈러 산술과 빠른 거듭제곱

공개키 암호의 계산은 거의 모두 모듈러 산술(나머지 산술)이다. 법(modulus) n을 정하면 수는 0부터 n−1까지만 있고, 넘치면 시계처럼 처음으로 돌아온다. 12시간 시계에서 9시의 5시간 뒤는 (9 + 5) mod 12 = 2시다. 덧셈·뺄셈·곱셈은 계산 중간에 아무 때나 나머지를 취해도 결과가 같아서, 수가 아무리 커져도 n보다 작게 유지할 수 있다. 나눗셈만은 다르다. 'a로 나누기'는 a·x ≡ 1이 되는 역원 x를 곱하는 것이고, 역원은 a와 n이 서로소일 때만 있다(mod 7에서 3의 역원은 5이다).

RSA와 디피–헬먼은 ae mod n 같은 거듭제곱을 수천 비트 지수로 계산한다. a를 e번 곱하면 우주의 나이로도 모자라지만, 지수를 2진수로 보고 제곱-곱하기를 하면 지수의 비트 수에 비례하는 곱셈만으로 끝난다. 2048비트 지수라면 제곱 2047번과 곱셈 최대 2047번이다.

제곱-곱하기 단계 그림: 지수 17의 2진수 10001을 왼쪽부터 한 비트씩 읽으며 65의 거듭제곱 값이 65, 992, 1232, 1547, 2790으로 바뀐다계산할 값: 65¹⁷ mod 3233지수 17의 2진수1¹0²0⁴0⁸1¹⁷읽은 데까지의 지수65¹: 1² ≡ 1, ×65 ≡ 6565¹: 1² ≡ 1, ×65 ≡ 6565²: 65² ≡ 99265²: 65² ≡ 99265⁴: 992² ≡ 123265⁴: 992² ≡ 123265⁸: 1232² ≡ 154765⁸: 1232² ≡ 154765¹⁷: 1547² ≡ 789, ×65 ≡ 2790≡ 는 mod 3233로같다는 뜻이다.결과: 2790곱셈 5번이면 된다
1 / 5

비트 1(1): 제곱해 1, 비트가 1이라 밑 65까지 곱해 65. 지금 값은 65^1 mod 3233 = 65

제곱-곱하기(square-and-multiply). 65¹⁷ mod 3233를 곱셈 16번 대신 지수의 비트 수만큼만 제곱해 구한다. 비트 하나를 읽을 때마다 지금까지 읽은 지수가 두 배(제곱) 또는 두 배 더하기 1(제곱 뒤 곱하기)이 된다. 매 걸음 mod를 취해 수가 커지지 않는다.

이 알고리즘은 비트가 1일 때만 곱셈을 한 번 더 하므로, 그대로 구현하면 걸린 시간이나 전력 소모로 비밀 지수의 비트가 새어 나간다(부채널 공격). 실제 라이브러리는 비트와 상관없이 같은 일을 하는 상수 시간 구현(몽고메리 사다리 등)을 쓴다. 암호를 직접 구현하지 말아야 하는 이유 중 하나다.

군, 생성원, 이산 로그

소수 p를 법으로 하면 1부터 p−1까지의 수는 곱셈에 대해 닫혀 있고 모두 역원이 있다. 이렇게 연산 하나와 그 규칙(결합 법칙, 항등원, 역원)을 갖춘 집합을 군이라 하고, 이 경우를 Zp*라고 쓴다. 원소 g를 거듭 곱해 1로 돌아오기까지의 횟수가 g의 위수이고, 위수가 p−1이라 모든 원소를 한 번씩 지나는 g를 생성원이라 한다. Z23*에서 5는 위수가 22(= p−1)인 생성원이고, 2는 위수가 11뿐이라 절반만 돈다. 위수는 늘 군 크기(p−1 = 22)의 약수다(라그랑주 정리).

5의 거듭제곱을 23으로 나눈 나머지를 k = 1부터 22까지 찍은 산점도. 값이 1부터 22까지 한 번씩 뒤섞여 나온다. 오른쪽에는 2의 거듭제곱이 11개 값만 돌고 1로 돌아오는 순환이 적혀 있다18152216111622k5ᵏ mod 235⁶ ≡ 8생성원 5: 위수 221~22를 모두 한 번씩2는 위수 112→4→8→16→9→18→13→3→6→12→1이산 로그: 5ᵏ ≡ 8인 k는?값이 고르게 흩어져 있어하나씩 대입하는 수밖에 없다
5의 거듭제곱을 23으로 나눈 나머지. 지수 k를 1씩 늘려도 값은 규칙 없이 흩어진다. 앞으로 계산(k → 5^k)은 제곱-곱하기로 빠르지만, 거꾸로(5^k → k)는 마땅한 지름길이 없다.

gk ≡ h를 만족하는 k를 찾는 것이 이산 로그 문제다. 위 그림에서 5k ≡ 8의 답은 k = 6이지만, 이것은 22개를 다 대입해 보고 안 답이다. 알려진 가장 좋은 고전 알고리즘도 큰 p에서는 비현실적으로 느리다. 단, 군의 크기 p−1이 작은 소수들의 곱이면 문제를 쪼개 풀 수 있으므로(폴리그–헬먼) 실제로는 큰 소수 위수의 부분군을 쓴다. 디피–헬먼, DSA, 타원 곡선 암호가 모두 이 '한쪽으로만 쉬운' 성질에 기댄다.

유클리드 호제법과 역원

두 수의 최대공약수(gcd)는 '큰 수를 작은 수로 나눈 나머지'로 바꾸기를 되풀이하면 나온다(유클리드 호제법). 여기에 계수 두 개를 함께 따라가면, gcd(a, b) = s·a + t·b를 만족하는 정수 s, t(베주 계수)도 얻는다. gcd가 1이면 t·b ≡ 1 (mod a)이므로 t가 곧 b의 역원이다. 걸음 수는 작은 수의 자릿수에 비례할 만큼 빨라서 수천 비트 수에도 금방 끝난다.

확장 유클리드 호제법 표: a = 3120, b = 17에서 시작해 몫과 나머지, 계수 s와 t를 한 줄씩 채워 나머지 1에 닿고, 17의 역원 2753을 얻는다a = 3120, b = 17몫 q나머지 rstr = s·a + t·b–3120101·3120 + 0·17–17010·3120 + 1·1718391-1831·3120 − 183·1718-1184-1·3120 + 184·17112-3672·3120 − 367·1780-17312017⁻¹ ≡ -367 ≡ 2753 (mod 3120) — 확인: 17 × 2753 = 46801 = 15 × 3120 + 1
1 / 5

처음 두 줄은 r = 3120, 17이고 각각 1·3120 + 0·17, 0·3120 + 1·17로 쓸 수 있다. 줄마다 r = s·3120 + t·17가 늘 성립하게 표를 채운다.

확장 유클리드 호제법. 나눗셈을 되풀이해 최대공약수를 구하면서, 그 값을 두 수의 정수 조합으로 나타내는 계수 s, t도 함께 얻는다. 최대공약수가 1이면 t가 곧 17의 mod 3120 역원이다. RSA의 비밀 지수 d를 이렇게 구한다.

이 계산은 RSA 키를 만들 때 비밀 지수 d를 구하는 바로 그 단계이고, 타원 곡선에서 점을 더할 때 기울기의 분모를 '나누는' 데도 쓴다. 역원은 페르마의 소정리로 ap−2 mod p를 계산해 구할 수도 있다. 상수 시간 구현에서는 이쪽을 쓰기도 한다.

RSA: 장난감 수로 따라가기

RSA는 큰 소수 두 개 p, q를 곱한 n을 공개한다. φ(n) = (p−1)(q−1)과 서로소인 e를 고르고, e·d ≡ 1 (mod φ(n))인 d를 비밀로 둔다. 암호화는 c = me mod n, 복호화는 m = cd mod n이다. 오일러 정리 때문에 mφ(n) ≡ 1 (mod n)이고(예: 653120 mod 3233 = 1), e·d = 1 + k·φ(n)이므로 (me)d = m · (mφ(n))k ≡ m이 된다. n을 소인수분해할 수 있으면 φ(n)과 d를 바로 계산할 수 있으므로, RSA의 안전성은 큰 수의 소인수분해가 어렵다는 데 기댄다.

장난감 RSA 세 단계: 소수 61과 53으로 n = 3233, d = 2753을 만들고, 메시지 65를 공개키로 암호화해 2790을 얻고, 비밀키나 중국인의 나머지 정리로 다시 65를 얻는다1. 키 만들기p = 61, q = 53n = p·q = 3233φ(n) = 3120e = 17 (공개)d = e⁻¹ mod φ = 2753공개키 (n, e) · 비밀키 d2. 암호화(공개키)m = 65c = m¹⁷ mod n= 2790누구나 할 수 있다3. 복호화(비밀키)m = c²⁷⁵³ mod n = 65또는 c^dp mod p = 4c^dq mod q = 12합치면 m = 65d를 아는 쪽만CRT 복호화는 작은 법 61, 53에서 따로 거듭제곱한 뒤 합친다.dp = d mod (p−1) = 53, dq = d mod (q−1) = 49, q⁻¹ mod p = 38
p = 61, q = 53, e = 17인 장난감 RSA. 메시지 65를 암호화한 값은 2790이고, 비밀 지수 d = 2753으로 복호화하면 다시 65가 된다. φ(n) 대신 λ(n) = lcm(p−1, q−1) = 780을 쓰면 더 작은 d = 413으로도 같은 답이 나온다.
  • CRT로 4배 가까이 빠르게: 비밀키를 가진 쪽은 p, q를 알므로 mod n 대신 절반 크기의 mod p, mod q에서 따로 거듭제곱하고 중국인의 나머지 정리로 합친다. 실제 구현은 거의 다 이 방식이다. 대신 둘 중 한쪽 계산이 오류로 틀리면 그 결과로 n이 인수분해될 수 있어, 서명 뒤에 검증을 한 번 더 하는 방어를 둔다.
  • 교과서 RSA는 결정적이다: 같은 m은 늘 같은 c가 된다. 후보가 몇 개뿐인 메시지('예'/'아니오')는 공격자가 공개키로 하나씩 암호화해 맞춰 볼 수 있다.
  • 교과서 RSA는 곱셈을 보존한다: E(6)·E(7) mod n = 824 × 2369 mod 3233 = 2557이고, 이것을 복호화한 결과는 42 = 6 × 7이다. 평문을 몰라도 암호문을 조작해 관계된 평문을 만들 수 있다는 뜻이다.

그래서 RSA 암호화는 반드시 무작위 패딩과 함께 쓴다. OAEP(RFC 8017)는 메시지에 난수를 섞고 해시 함수 두 번으로 뒤섞어서, 같은 메시지도 매번 다른 암호문이 되고 조작한 암호문은 복호화 때 걸러지게 한다. 옛 PKCS #1 v1.5 패딩은 '패딩이 맞는지'만 알려 줘도 그것을 수십만 번 물어 평문을 되찾는 공격이 있었고(Bleichenbacher 1998), 20년 뒤에도 같은 약점이 주요 제품에서 다시 발견됐다(ROBOT). 오늘날 키 교환에는 RSA 암호화를 거의 쓰지 않고, RSA는 주로 서명(PSS 패딩)에 남아 있다.

타원 곡선: 점을 더하는 군

타원 곡선은 y² = x³ + ax + b를 만족하는 점들이다. 실수 위에서 그리면 매끄러운 곡선이고, 곡선 위의 두 점을 지나는 직선은 곡선과 한 점에서 더 만난다. 그 셋째 점을 x축에 대칭시킨 것을 두 점의 '합'으로 정하면, 무한원점 O를 항등원으로 하는 군이 된다. 같은 점을 두 번 더할 때(두 배)는 접선을 쓴다. 암호에서는 이 규칙을 그대로 mod p 위로 옮겨, 좌표가 0~p−1인 유한한 점들의 군을 쓴다.

  • 덧셈: P ≠ Q이면 기울기 λ = (yQ − yP) / (xQ − xP), 같은 점이면 λ = (3xP² + a) / 2yP. 합은 x = λ² − xP − xQ, y = λ(xP − x) − yP다. 나눗셈은 모두 mod p의 역원 곱하기다.
  • 계산해 보기: y² = x³ + 2x + 2 (mod 17)에서 G = (5, 1)이면 2G의 기울기는 13이고 2G = (6, 3), G + 2G의 기울기는 2이고 3G = (10, 6)다.
  • 위수: 이 곡선의 점은 O를 포함해 19개이고 G를 19번 더하면 O가 된다. 실제 곡선(P-256, Curve25519)은 점이 약 2²⁵⁶개이고 큰 소수 위수의 기준점을 쓴다.
mod 17 타원 곡선의 점 18개를 찍은 그림 위에서 G = (5, 1)에서 시작해 3G, 6G, 13G로 옮겨 가는 스칼라 곱 단계 그림04812160481216xyG1G3G6G13Gk = 13 = 1101₂1··· → 1G = (5, 1)11·· → 3G = (10, 6)110· → 6G = (16, 13)1101 → 13G = (16, 4)비트 0: 두 배만 한다비트 1: 두 배 뒤 G를 더한다G의 위수 19: 19G = O
1 / 4

비트 1(1): 두 배 한 뒤 G를 더한다 → 1G = (5, 1)

유한체 위의 타원 곡선 y² = x³ + 2x + 2 (mod 17). 점은 무한원점 O를 더해 19개이고, G = (5, 1)을 거듭 더하면 19번째에 O로 돌아온다. 13G는 13 = 1101₂의 비트를 왼쪽부터 읽으며 두 배와 더하기만으로 구한다. 실수 곡선과 달리 점들이 흩어져 있어 kG만 보고 k를 되짚기 어렵다.

k·G(G를 k번 더한 점)는 두 배-더하기로 빠르게 구하지만, 점 k·G에서 k를 되찾는 타원 곡선 이산 로그는 어렵다. 유한체의 이산 로그에는 지수 계산법(index calculus) 같은 '약간 빠른' 공격이 있어 큰 법이 필요하지만, 잘 고른 타원 곡선에는 그런 공격이 알려져 있지 않다. 그래서 같은 보안 수준에 훨씬 짧은 키(256비트 대 3072비트)로 충분하다(NIST SP 800-57). 곡선 선택에는 함정이 많아서, 실제로는 Curve25519(RFC 7748)나 NIST P-256처럼 검증된 곡선만 쓴다.

디피–헬먼과 ECDH

디피–헬먼 키 교환은 공개된 g와 p 위에서 앨리스가 ga, 밥이 gb를 보내고, 각자 받은 값을 자기 비밀로 한 번 더 거듭제곱해 같은 gab에 닿는다. p = 23, g = 5, a = 6, b = 15이면 공개값은 8과 19, 공유 비밀은 2이다. 단계별 흐름은 보안 › 암호 노트의 그림에 있다. 엿보는 쪽은 ga와 gb에서 gab를 구해야 하는데(계산 디피–헬먼 문제), 이산 로그를 풀 수 있으면 이것도 풀린다.

유한체 디피–헬먼과 타원 곡선 디피–헬먼을 같은 단계로 나란히 놓은 표. 공개값과 공유 비밀을 장난감 수로 계산했고, 같은 보안 수준에 필요한 크기는 3072비트와 256비트다유한체 DHECDH무대(군)Z₂₃* 곱셈곡선 mod 17의 점 덧셈공개 기준p = 23, g = 5G = (5, 1)앨리스 a = 6 / 3A = 5⁶ = 8A = 3G = (10, 6)밥 b = 15 / 7B = 5¹⁵ = 19B = 7G = (0, 6)공유 비밀B⁶ = A¹⁵ = 23B = 7A = (6, 3)깨려면 풀어야 할 것이산 로그타원 곡선 이산 로그128비트 보안 크기법 p 3072비트곡선 256비트거듭제곱(g^a)이 스칼라 곱(aG)으로 바뀌었을 뿐 교환의 모양은 같다. 유한체 계산은 mod 23이다.
같은 교환을 두 군에서 나란히 계산했다. 거듭제곱 g^a가 타원 곡선에서는 스칼라 곱 aG로 바뀔 뿐 구조는 같다. 128비트 보안 수준의 크기는 NIST SP 800-57의 대응표를 따랐다.
  • 인증이 없으면 중간자에게 진다: 디피–헬먼 자체는 상대가 누구인지 확인하지 않는다. 중간에서 양쪽과 따로 교환하면 그만이다. 그래서 TLS는 교환 값에 서명을 붙이고 인증서로 서명 키를 확인한다.
  • 임시 키와 전방 비밀성: 연결마다 새 a, b를 만들고 버리면(ephemeral), 나중에 서버의 장기 키가 새어도 지난 대화를 풀 수 없다. TLS 1.3은 이 방식만 허용한다.
  • 받은 값 검증: 상대가 보낸 점이 곡선 위에 있는지, 작은 위수의 부분군에 있지 않은지 확인하지 않으면 비밀 키 조각이 새는 공격이 있다. X25519는 이런 실수가 일어나기 어렵게 설계되었다.

해시 함수의 성질과 생일 한계

암호 해시 함수는 아무 길이의 입력을 고정 길이 출력으로 줄이면서 세 가지를 지켜야 한다. 출력만 보고 입력을 찾을 수 없고(원상 저항), 주어진 입력과 같은 출력을 내는 다른 입력을 찾을 수 없고(제2 원상 저항), 같은 출력을 내는 아무 두 입력도 찾을 수 없어야 한다(충돌 저항). 출력이 n비트면 앞의 둘은 대략 2n번 시도가 필요하지만, 충돌은 생일 역설 때문에 2n/2번 근처에서 나온다.

사람 수에 따라 생일이 겹칠 확률이 S자로 오르는 곡선. 23명에서 약 51%, 57명에서 99%를 넘는다0204060800%50%100%사람 수 n (1년 = 365일)23명 → 50.7%57명 → 99.0%겹칠 확률 1 − (365·364·…·(365−n+1)) / 365ⁿ
365일 중에서 n명의 생일이 겹칠 확률. 쌍의 수가 n²/2로 늘기 때문에 365의 제곱근 근처에서 이미 반을 넘는다. 해시의 충돌도 같은 셈이다.

23명만 모여도 생일이 겹칠 확률은 50.7%, 57명이면 99.0%다. 같은 계산을 해시에 하면, 출력의 절반 비트만큼 시도했을 때 충돌 확률이 50%에 닿는다. 64비트 출력은 5.1 × 10^9개, 128비트는 2.2 × 10^19개, 256비트는 4.0 × 10^38개쯤에서다. 64비트 값 수십억 개는 오늘날 컴퓨터로 금방 만들므로 64비트 해시나 블록 크기는 충돌 저항에 쓸 수 없고, SHA-256의 충돌 저항은 128비트 보안으로 센다. MD5와 SHA-1은 이 한계보다도 훨씬 빠르게 충돌을 만드는 공격이 나와 퇴출됐다.

해시의 두 구조: 메르클–담고르와 스펀지

긴 입력을 다루려면 고정 크기를 처리하는 부품을 되풀이해 써야 한다. MD5, SHA-1, SHA-2(FIPS 180-4)는 메르클–담고르 구조로, 압축 함수 f가 '지금까지의 체인 값 + 다음 블록'을 새 체인 값으로 줄이는 일을 반복한다. 압축 함수가 충돌에 강하면 전체도 충돌에 강하다는 증명이 이 구조의 장점이다. SHA-3(FIPS 202)는 스펀지 구조다. 큰 상태를 rate와 capacity로 나눠 rate에만 입력을 섞고 순열 f로 휘저은 뒤, 출력도 rate에서 원하는 만큼 짜낸다(Keccak 팀 설명).

위: 메르클–담고르 구조. 초기값에서 시작해 메시지 블록마다 압축 함수를 거치고 마지막 체인 값이 그대로 해시가 된다. 아래: 스펀지 구조. 상태를 rate와 capacity로 나눠 rate에만 블록을 섞고 순열 f를 돌린 뒤 rate에서 출력을 짜낸다메르클–담고르 (MD5, SHA-1, SHA-2)IVm1fm2fm3f해시마지막 블록은 길이를 덧붙여 채운다(패딩). 출력이 내부 상태 전체라, 해시값을 아는 사람이그 뒤에 블록을 더 이어 붙일 수 있다(길이 확장). 그래서 키를 섞을 때는 HMAC을 쓴다.스펀지 (SHA-3, SHAKE)rate rcapacity cm1⊕m2⊕fff출력흡수(absorb)짜내기(squeeze)capacity는 밖으로 나가지도 들어오지도 않아, 출력만 보고는 상태를 이어 쓸 수 없다.
위는 메르클–담고르, 아래는 스펀지. 메르클–담고르는 마지막 체인 값이 곧 출력이라 길이 확장이 가능하고, 스펀지는 capacity가 늘 숨어 있어 그렇지 않다. 스펀지의 보안 수준은 capacity 크기의 절반이다.

실무에서 중요한 차이는 길이 확장이다. SHA-256(비밀 ‖ 메시지)를 인증 태그로 쓰면, 비밀을 몰라도 해시값에서 이어 계산해 '메시지 ‖ 덧붙인 내용'의 올바른 태그를 만들 수 있다. 그래서 키를 섞은 해시에는 HMAC을 쓴다. SHA-3와 출력 길이를 마음대로 정하는 SHAKE는 이 문제가 없다.

블록 암호의 구조: 페이스텔과 SPN

블록 암호는 키마다 다른 '블록 → 블록' 순열이다. 좋은 블록 암호는 입력의 한 비트만 바꿔도 출력의 절반쯤이 바뀌어야 하고(확산), 키와 출력의 관계가 복잡해야 한다(혼돈). 이것을 간단한 라운드를 여러 번 겹쳐 얻는데, 뼈대는 크게 두 가지다. 페이스텔 구조(DES 등)는 블록을 반으로 나눠 한쪽에 라운드 함수 F의 결과를 XOR하고 자리를 바꾼다. F를 되돌릴 필요가 없어서 F를 마음대로 복잡하게 만들 수 있고, 복호화는 같은 회로에 키 순서만 거꾸로 넣으면 된다.

페이스텔 구조: 왼쪽 반쪽 L과 오른쪽 반쪽 R이 라운드마다 자리를 바꾸고, 새 R은 이전 L에 F(R, K)를 XOR한 값이다. 세 라운드 뒤 키를 거꾸로 넣으면 처음 값 4b, a7로 돌아온다평문L₀ = 4bR₀ = a71라운드L₁ = a7R₁ = 864b ⊕ F(a7, 3c) = 4b ⊕ cd = 862라운드L₂ = 86R₂ = 12a7 ⊕ F(86, 91) = a7 ⊕ b5 = 123라운드L₃ = 12R₃ = 9c86 ⊕ F(12, 5e) = 86 ⊕ 1a = 9c새 R = 이전 L ⊕ F(이전 R, 키)복호화: 같은 구조에 키를 5e, 91, 3c 순으로 넣으면 (4b, a7)로 돌아온다.F(10, k) = F(30, k)처럼 F가 일대일이 아니어도 되돌릴 수 있다. 값은 16진수다.
8비트 반쪽 둘을 쓰는 장난감 페이스텔. F는 제곱을 써서 일부러 일대일이 아니게 만들었는데도, 키를 거꾸로 넣으면 평문이 정확히 돌아온다. 각 줄의 오른쪽에 새 R의 계산을 적었다.

SPN(치환–순열 네트워크)은 블록 전체를 바이트 치환(S-box)과 섞기 층에 통과시킨다. 각 층이 되돌릴 수 있어야 하는 대신 라운드마다 블록 전체가 섞인다. AES(FIPS 197)가 대표이고, 128비트 블록을 키 길이에 따라 10·12·14 라운드 돌린다. S-box는 GF(2⁸)의 역원 계산에 아핀 변환을 붙여 만들어, 선형·차분 공격에 강하도록 수학적으로 고른 것이다.

AES 한 라운드의 네 단계를 왼쪽에서 오른쪽으로 놓은 그림. 16바이트 상태를 4×4로 놓고 치환, 행 회전, 열 섞기, 라운드 키 XOR을 차례로 하고 이를 키 길이에 따라 10·12·14번 되풀이한다상태: 16바이트(128비트) 블록을 4×4 바이트 표로 놓고 한 라운드에 네 단계를 거친다SubBytes바이트마다S-box로 치환혼돈(비선형)ShiftRows행마다 0·1·2·3칸왼쪽으로 회전확산MixColumns열마다고정 행렬 곱확산AddRoundKey라운드 키와XOR키 섞기되풀이: 맨 앞에 AddRoundKey 한 번, 마지막 라운드는 MixColumns를 뺀다AES-128: 10라운드 · AES-192: 12라운드 · AES-256: 14라운드
AES 한 라운드. SubBytes만 비선형이고 나머지 셋은 선형이다. ShiftRows와 MixColumns가 두 라운드 만에 한 바이트의 변화를 블록 전체로 퍼뜨린다.

블록 암호 하나는 블록 하나만 암호화한다. 긴 메시지를 다루는 운용 모드(ECB를 쓰면 안 되는 이유, CTR, CBC)와, 기밀성과 변조 검사를 함께 주는 AEAD(AES-GCM, ChaCha20-Poly1305)는 보안 › 암호 노트에 그림과 함께 있다. 수학 쪽에서 덧붙일 것은 하나다. CTR·GCM은 블록 암호를 '키로 만든 의사 난수 함수'로만 쓰므로, 같은 키에서 논스(nonce)가 한 번이라도 겹치면 두 평문의 XOR이 드러나고 GCM은 인증 키까지 샌다.

난수: 암호의 숨은 재료

키, 논스, 패딩, 서명의 임시값은 모두 예측할 수 없는 난수여야 한다. 운영체제는 하드웨어 노이즈 같은 엔트로피를 모아 암호용 난수 생성기(CSPRNG)의 씨앗으로 쓰고, 프로그램은 이것을 getrandom(), /dev/urandom, 브라우저의 crypto.getRandomValues()로 받는다. 결정론적 생성기의 설계 기준은 NIST SP 800-90A에 있다. 일반 Math.random()은 출력 몇 개로 다음 값을 예측할 수 있어 암호에 쓰면 안 된다.

좋은 난수를 받아도 쓰는 법에서 새는 경우가 많다. 흔한 실수가 범위를 줄이는 나머지 연산이다. 0~255 바이트를 % 100으로 줄이면 0~55은 3번, 56~99는 2번씩 나와 앞쪽이 1.5배 잦다.

0부터 255까지 고른 난수 바이트를 100으로 나눈 나머지의 분포 막대그래프. 0부터 55까지는 세 번씩, 56부터 99까지는 두 번씩 나와 고르지 않다고르게 나뉜다면 2.56123세로: 나오는 횟수(256개 중) · 가로: byte % 100의 값0255075990~55: 3/256 = 1.17%56~99: 2/256 = 0.78%고치는 법: 범위를 넘는 값(200~255)은 버리고 다시 뽑는다(거부 표본 추출).
고른 바이트를 100으로 나눈 나머지의 분포. 256이 100의 배수가 아니라 앞쪽 56개 값이 한 번씩 더 나온다. 비밀번호나 토큰 생성에서 이런 치우침은 경우의 수를 줄인다.

서명에서는 치우침이 더 치명적이다. (EC)DSA 서명마다 쓰는 임시값 k가 한 번 되풀이되면 두 서명에서 비밀 키를 바로 계산할 수 있고, k의 몇 비트만 치우쳐도 서명이 많이 모이면 격자 알고리즘으로 키가 복원된다. 그래서 요즘 구현은 k를 메시지와 비밀 키에서 결정적으로 만들거나(RFC 6979), 처음부터 그렇게 설계된 EdDSA를 쓴다.

양자 컴퓨터와 양자내성 암호

쇼어 알고리즘은 군에서 주기를 찾는 문제를 양자 푸리에 변환으로 효율적으로 풀어, 소인수분해와 (타원 곡선) 이산 로그를 다항 시간에 끝낸다. 충분히 큰 오류 정정 양자 컴퓨터가 생기면 RSA, 디피–헬먼, ECDH, ECDSA가 한꺼번에 무너진다는 뜻이다. 그런 기계는 아직 없지만, 필요한 큐비트 추정은 계속 줄고 있다(Gidney 2025는 노이즈 있는 큐비트 100만 개 미만으로 RSA-2048을 일주일 안에 인수분해하는 설계를 냈다). 지금 엿들어 저장해 둔 암호문을 나중에 푸는 '지금 수집, 나중 해독'도 걱정거리라, 키 교환부터 바꾸는 중이다. 대칭키와 해시는 그로버 알고리즘이 탐색을 제곱근으로 줄이는 정도라 영향이 작다. 그로버는 병렬화가 잘 안 되어 실제 부담은 더 작고, 여유를 원하면 AES-256을 쓴다.

알고리즘별 양자 컴퓨터의 영향 표. RSA와 타원 곡선 암호는 쇼어 알고리즘에 깨지고, AES와 SHA는 그로버 알고리즘으로 여유가 줄며, ML-KEM, ML-DSA, SLH-DSA는 알려진 빠른 양자 공격이 없다알고리즘기대는 문제양자 컴퓨터의 영향RSA, 유한체 DH소인수분해 · 이산 로그쇼어: 다항 시간에 풀림ECDH, ECDSA, EdDSA타원 곡선 이산 로그쇼어: 다항 시간에 풀림AES-128 / AES-256키 전수 탐색그로버: 탐색이 제곱근으로SHA-256, SHA-3원상 · 충돌 찾기여유가 조금 줄 뿐ML-KEM, ML-DSA모듈 격자(MLWE)알려진 빠른 양자 공격 없음SLH-DSA해시 함수만해시가 안전하면 안전점선 아래가 2024년 NIST가 표준으로 낸 양자내성 알고리즘(FIPS 203·204·205)이다.
알고리즘별로 큰 양자 컴퓨터가 미치는 영향. 공개키 암호만 근본 문제가 풀려 버리고, 대칭키와 해시는 안전 여유가 줄어드는 정도다.

NIST는 2016년부터 공개 공모를 거쳐 2024년 8월 13일 첫 양자내성 표준 셋을 발표했다(NIST 발표). 키 캡슐화 ML-KEM(FIPS 203, CRYSTALS-Kyber에서 옴), 서명 ML-DSA(FIPS 204, CRYSTALS-Dilithium), 해시 기반 서명 SLH-DSA(FIPS 205, SPHINCS+)다. 격자와 다른 수학(부호 이론)에 기댄 예비 키 캡슐화로 HQC가 2025년 3월 선정됐고, Falcon 기반 서명(FN-DSA)과 HQC의 표준화가 진행 중이다(NIST PQC 프로젝트, 2026년 10월 기준). 전환 일정 초안(NIST IR 8547)은 지금의 공개키 알고리즘을 2030년 이후 폐기 예정, 2035년 이후 금지로 제안했다.

ML-KEM과 ML-DSA가 기대는 격자 문제의 직관은 이렇다. 격자는 기저 벡터의 정수 조합으로 생기는 점들이다. 같은 격자를 짧고 거의 직교하는 '좋은 기저'로도, 길고 비스듬한 '나쁜 기저'로도 나타낼 수 있다. 좋은 기저를 알면 아무 점에서 가장 가까운 격자점을 쉽게 찾지만, 나쁜 기저만으로는 차원이 수백일 때 사실상 불가능하다. 비밀 키는 좋은 기저나 짧은 벡터 쪽, 공개 키는 그것을 감춘 나쁜 쪽에 해당한다.

2차원 격자점 위에 짧고 직교에 가까운 좋은 기저와 길고 비스듬한 나쁜 기저를 함께 그린 그림. 표적 (7, 6)에서 좋은 기저로 반올림하면 가장 가까운 점 (6, 7)을, 나쁜 기저로 반올림하면 먼 점 (10, 8)을 고른다격자: 기저의 정수 조합 전체좋은 기저 (4, 1), (1, 3)나쁜 기저 (9, 5), (5, 4)둘 다 넓이(행렬식) 11, 같은 점들■ 표적 (7, 6)에서 가까운 점은?좋은 기저로 반올림 → (6, 7)거리 1.41 (최솟값 1.41)나쁜 기저로 반올림 → (10, 8)거리 3.61
같은 격자(행렬식 11)를 만드는 두 기저. 표적에서 계수를 반올림해 가까운 점을 찾으면(바바이 반올림) 좋은 기저는 진짜 가장 가까운 점을 고르고 나쁜 기저는 멀리 빗나간다. 2차원이라 눈으로도 풀리지만, 수백 차원에서는 이 차이가 곧 안전성이다.

실제 구성은 Regev(2005)의 LWE(learning with errors)를 쓴다. 비밀 벡터 s에 대해 무작위 행렬 A와 b = A·s + e (mod q)를 공개하는데, e는 작은 노이즈다. 노이즈가 없으면 가우스 소거로 s가 바로 나오지만, 노이즈가 섞이면 이것은 격자의 가까운 점 찾기 문제가 된다. ML-KEM은 이것을 다항식 환 위의 작은 행렬로 바꾼 모듈 LWE라 키와 암호문이 수 KB 수준으로 작다. 전환기에는 기존 X25519와 ML-KEM-768을 함께 써서 둘 중 하나만 버텨도 안전한 하이브리드 키 교환이 TLS에 표준으로 정리됐다(RFC 10024).

핵심 문헌

요지는 직접 정리한 한 줄이다. 실무 쪽 정리는 보안 › 암호 노트에, 메모리 안전과 코드 서명은 보안 › 시스템 노트에 있다.

문헌연도한 줄 요지
New Directions in Cryptography (Diffie, Hellman)1976공개 통로에서 비밀 키를 맞추는 키 교환과 공개키 암호·전자 서명이라는 생각을 처음 내놓았다.
A Method for Obtaining Digital Signatures and Public-Key Cryptosystems (Rivest, Shamir, Adleman)1978소인수분해의 어려움에 기댄 RSA로 암호화와 서명을 함께 실현했다.
Use of Elliptic Curves in Cryptography (Miller)1985Koblitz(1987)와 따로, 유한체 위 타원 곡선의 점 군에서 이산 로그 문제를 쓰자고 제안했다.
Polynomial-Time Algorithms for Prime Factorization and Discrete Logarithms on a Quantum Computer (Shor)1994양자 컴퓨터가 소인수분해와 이산 로그를 다항 시간에 푼다는 것을 보여, 오늘날 공개키 암호의 수명을 정했다.
A Fast Quantum Mechanical Algorithm for Database Search (Grover)1996N개 후보의 탐색을 약 √N 번으로 줄인다. 대칭키의 키 길이를 두 배로 잡으라는 권고의 근거다.
On Lattices, Learning with Errors, Random Linear Codes, and Cryptography (Regev)2005노이즈 섞인 선형 방정식을 푸는 LWE 문제를 세우고, 그 어려움을 최악의 격자 문제에 묶었다. ML-KEM·ML-DSA의 뿌리다.
FIPS 197 Advanced Encryption Standard2001Rijndael을 AES로 정한 표준. 라운드 구조와 키 확장을 정의한다(2023년 갱신).
FIPS 202 SHA-3 Standard2015스펀지 구조의 Keccak을 SHA-3와 SHAKE로 정했다.
FIPS 203 ML-KEM2024모듈 격자 기반 키 캡슐화. 양자내성 키 교환의 기본 표준이다.
FIPS 204 ML-DSA2024모듈 격자 기반 전자 서명의 기본 표준이다.
FIPS 205 SLH-DSA2024해시 함수만 믿는 상태 없는 해시 기반 서명. 느리고 크지만 가정이 가장 보수적이다.
A Graduate Course in Applied Cryptography (Boneh, Shoup)2023정의와 증명 중심의 무료 교과서. 이 노트의 거의 모든 주제를 깊게 다룬다.
Handbook of Applied Cryptography (Menezes, van Oorschot, Vanstone)1996알고리즘과 수론 계산을 꼼꼼히 정리한 고전 참고서. 장별 PDF가 무료로 공개되어 있다.
더 읽을거리