정보보안핵심 · 20분 읽기

대칭키·공개키와 DES·AES의 내부 구조

대칭키와 공개키는 경쟁 기술이 아니라 역할을 나누는 도구다. 실제 보안은 알고리즘 이름뿐 아니라 키·Nonce·검증 실패 처리에 달려 있다.

개념부터 찾아보기

정의·역할·동작 원리를 독립 페이지에서 확인하세요. 본문의 밑줄 용어에도 설명이 있습니다.

이 노트에서 설명할 수 있게 되는 것

  1. 키 합의·서명·대칭 암호화의 입력과 출력을 구분한다.
  2. AEAD에서 Nonce·암호문·인증 태그의 관계를 설명한다.
  3. 복호화 실패와 키 교체 상황을 처리 흐름에 연결한다.

01개념과 구성 요소

  • 양쪽이 공유하는 비밀키로 데이터를 보호한다. DES와 는 고정 길이 블록을 변환하는 알고리즘이다.
  • 의 암호화·서명과 의 키 합의는 목적과 계산 구조가 다르다.
  • 통신에서는 공개키 기술로 상대와 키를 확인하고 대칭키로 많은 데이터를 처리할 수 있다.

02AES-128 한 블록의 암호화 순서

  1. 16바이트 입력을 4×4 에 열 방향으로 넣고 128비트 키에서 필요한 를 준비한다.
  2. 에 첫 를 XOR하는 를 수행한다.
  3. →→→를 9회 수행한다. 값 치환·위치 이동·확산·키 주입이 이어진다.
  4. 10번째 라운드는 →→이며 를 생략한다.
  5. 를 16바이트 암호문으로 읽는다. 긴 메시지의 연결과 인증은 운영 모드가 추가로 담당한다.

03암호 알고리즘·키·운영 모드를 분리해서 읽기

  • 암호 알고리즘은 공개되어도 되는 계산 규칙이고 키는 그 계산의 결과를 결정하는 비밀 매개변수다. 같은 알고리즘을 모두가 알아도 올바른 키를 모르면 보호된 내용을 복원하기 어려워야 한다.
  • 블록암호는 정해진 크기의 블록에 가역 변환을 적용하며, 긴 메시지에 그 변환을 배치하는 방법은 운영 모드가 담당한다. 라는 이름만으로 IV·Nonce·태그·패딩 처리까지 정해지지는 않는다.
  • 대칭키 방식에서는 암호화와 복호화에 연결된 비밀키를 양쪽이 가진다. 비대칭키 방식에서는 공개 가능한 키와 비밀 개인키를 구분한다.
  • 실제 통신은 공개키 기술로 인증과 키 합의를 처리한 뒤 대칭키 방식으로 많은 데이터를 보호하는 혼합 구조를 사용한다. 이는 공개키로 파일 전체를 계속 암호화하는 것과 처리 책임이 다르다.

04DES: 64비트 블록을 두 절반으로 나누는 이유

  • DES는 역사적 블록암호로 64비트 블록과 실효 56비트 키를 사용한다. 키를 표현하는 64비트 중 일부는 패리티 용도이므로 키 공간을 2^64로 세면 안 된다.
  • 초기 치환 뒤 32비트씩 L과 R로 나누고 16라운드 변환을 반복한다. 한 라운드에서는 이전 R을 새 L로 옮기고 이전 L에 F(R, )를 XOR하여 새 R을 만든다.
  • F 함수가 자체적으로 역함수를 갖지 않아도 전체는 복호화할 수 있다. 새 L이 곧 이전 R이고, XOR는 같은 값을 다시 XOR하면 취소되므로 이전 L도 되찾는다.
  • 암호화에 사용한 를 역순으로 적용하는 복호화 구조가 여기서 나온다.
text
L_i = R_(i-1)
R_i = L_(i-1) XOR F(R_(i-1), K_i)

이전 상태 복원:
R_(i-1) = L_i
L_(i-1) = R_i XOR F(L_i, K_i)

DES를 이해하는 한 라운드의 식이다. 초기·최종 치환과 마지막 배치는 생략했다.

05DES의 F 함수와 라운드키

  • F는 32비트 R을 확장 치환으로 48비트로 만든 뒤 48비트 와 XOR한다. 결과를 6비트씩 여덟 조각으로 나누고 여덟 가 각각 4비트로 바꾸어 다시 32비트를 만든다.
  • 각 에서는 바깥 두 비트가 행, 안쪽 네 비트가 열을 선택한다. 마지막 P 치환은 결과 비트를 다시 배치하여 다음 라운드의 여러 위치에 영향을 퍼뜨린다.
  • 키 스케줄은 패리티를 제외한 키를 두 28비트 부분으로 나누고 라운드별 순환 이동과 선택 치환으로 48비트 를 만든다. 의 비선형 변환과 비트 위치를 섞는 확산, 키 주입이 반복되어 평문과 암호문의 단순한 관계를 숨긴다.
  • 는 DES를 여러 키로 암호화·복호화·암호화하는 역사적 확장이다. 키 비트 수를 단순히 세 배 했다고 유효 보안 강도가 그대로 세 배 되는 것은 아니며 여기서는 새 구성의 선택지가 아니라 구조 비교 대상으로 다룬다.
  1. 32비트 R을 확장 치환으로 48비트로 만든다.
  2. 확장한 값과 해당 라운드의 48비트 키를 XOR한다.
  3. 6비트씩 여덟 조각을 에 넣는다. 바깥 두 비트가 행, 안쪽 네 비트가 열을 선택해 조각마다 4비트를 얻는다.
  4. 32비트 결과에 P 치환을 적용한다. 이 F 결과를 의 이전 L과 XOR해 다음 R을 만든다.

06AES의 state와 키 길이·라운드 수

  • 는 128비트, 즉 16바이트 블록을 사용한다. -128·192·256의 숫자는 블록 길이가 아니라 키 길이이고 라운드 수는 각각 10·12·14다.
  • 상태 는 4×4바이트로 배치한다. 입력 바이트 a0부터 a15를 열 방향으로 넣기 때문에 첫 열은 a0,a1,a2,a3이고 첫 행은 a0,a4,a8,a12다.
  • 암호화는 초기 뒤에 일반 라운드를 반복하고 마지막 라운드를 수행한다. 일반 라운드는 →→→ 순서이고 마지막 라운드에는 가 없다.
  • 암호화 라운드 수와 개수는 초기 키 주입 때문에 하나 차이가 난다. 예를 들어 -128에는 10라운드와 11개의 128비트 가 필요하다.
text
state =
[a0  a4  a8   a12]
[a1  a5  a9   a13]
[a2  a6  a10  a14]
[a3  a7  a11  a15]

초기: AddRoundKey
일반: SubBytes → ShiftRows → MixColumns → AddRoundKey
마지막: SubBytes → ShiftRows → AddRoundKey

원문의 배치를 0부터 시작하는 인덱스로 바로잡아 표시했다.

07SubBytes와 ShiftRows: 값의 치환과 위치의 이동

  • 는 각 바이트를 같은 로 치환한다. 의 위치는 그대로지만 값이 바뀐다.
  • 는 의 곱셈 역원에 아핀 변환을 결합한 구조로 설명되며 0에 대해서는 별도 정의가 포함된다. 단순한 XOR와 위치 이동만 반복하는 선형 구조에서 벗어나도록 하는 핵심 단계다.
  • 는 행별로 바이트를 순환 이동한다. 첫 행은 그대로, 두 번째 행은 한 칸, 세 번째 행은 두 칸, 네 번째 행은 세 칸 왼쪽으로 회전한다.
  • 비트를 버리는 일반 시프트와 다르게 끝으로 빠진 바이트가 앞쪽으로 돌아온다. 값 자체를 다시 계산하지 않고 서로 다른 열에 있던 바이트를 모으기 때문에 이어지는 가 여러 원래 열의 정보를 섞을 수 있다.

08GF(2^8)과 MixColumns의 실제 연산

  • 유한체의 덧셈은 보통 정수 덧셈과 다르다. GF(2)의 덧셈은 XOR와 같고, 에서는 바이트를 이진 계수 다항식으로 보아 XOR로 더한다.
  • 0x57은 x^6+x^4+x^2+x+1을 나타낸다. 곱셈은 다항식을 곱한 뒤 에서 정한 불가약다항식 x^8+x^4+x^3+x+1로 나머지를 구한다.
  • 이 구조를 정수에 단순히 mod 256을 적용한 것과 혼동하면 역원과 계산을 잘못 이해하게 된다.
  • 는 각 열의 네 바이트에 고정 행렬을 곱한다. 첫 출력 바이트는 02·a0 XOR 03·a1 XOR a2 XOR a3이며 여기서 곱셈은 유한체 연산이다.
  • 한 입력 바이트가 한 열의 여러 출력에 영향을 주고 와 다음 라운드를 거치며 전체 로 영향이 퍼진다. 이 선형 확산 단계와 비선형 의 역할은 서로 보완적이다.
text
[02 03 01 01]   [a0]
[01 02 03 01] × [a1]   (연산은 GF(2^8))
[01 01 02 03]   [a2]
[03 01 01 02]   [a3]

GF 덧셈: 0x57 XOR 0x57 = 0x00
GF 곱셈: 0x02 · 0x57 = 0xae

의 계수 행렬과 작은 연산 예시다. 일반 정수 행렬 곱셈의 올림 규칙을 사용하지 않는다.

09AddRoundKey·Key Expansion·복호화

  • 는 와 해당 를 위치별 XOR한다. 암호화 에 비밀키의 영향을 직접 주입하는 단계이며, 같은 키를 다시 XOR하면 원래 값으로 돌아온다.
  • 은 입력 키를 4바이트 word 단위로 다루고 RotWord·SubWord·Rcon 및 이전 word와의 XOR를 조합하여 필요한 를 만든다. 키 길이에 따라 상세 분기와 생성량이 다르다.
  • 복호화는 역변환들을 적절한 역순으로 적용한다. InvShiftRows는 반대 방향 회전, InvSubBytes는 역 , InvMixColumns는 역행렬을 사용한다.
  • 는 XOR라서 같은 연산으로 취소된다. 암호화 마지막 라운드가 를 생략한 구조도 복호화 순서에 반영된다.
  • 구현을 배울 때는 중간 를 표준 시험 벡터와 비교하면 어떤 변환에서 결과가 달라졌는지 구분할 수 있다.

10RSA의 공개 지수와 개인 지수

  • 공개키에는 모듈러스 n과 가 포함되고 개인키에는 대응하는 개인 지수와 계산에 필요한 비밀 정보가 들어간다. 교과서 식에서는 메시지 정수 m을 c=m^e mod n으로 변환하고 개인키 연산으로 되돌린다.
  • 하지만 이 식만으로 임의의 메시지를 그대로 처리하는 것은 안전한 암호화 방식이 아니다. 실제 표준은 메시지 인코딩·난수·길이 조건을 포함한 RSAES-OAEP 같은 스킴을 정의한다.
  • 서명도 단순히 암호화 방향을 바꾼 설명에 머무르면 안 된다. 는 해시와 인코딩 규칙을 사용하는 서명 스킴이며 OAEP와 목적이 다르다.
  • ECDSA·EdDSA처럼 와 구조가 다른 서명도 있으므로 공개키 기술 전체를 “한 키로 암호화하고 다른 키로 푼다”로 통일하지 않는다. 큰 데이터를 전달할 때는 대칭키 보호와 키 관리 역할을 분리하는 이유가 여기에 있다.
LEARN THROUGH PRACTICE

RSA 과제의 modulus와 서명 입력 바이트 읽기

modulus를 공개키 전체와 혼동하지 않고, 공개키 추출·서명·검증을 서로 다른 작업으로 구분한다.

실습 구성과 전제

  • 의 교육용 키 또는 자신이 만든 폐기 가능한 실습 키만 사용한다.
  • 작업 폴더에 키와 메시지를 분리해 저장하고 실제 운영 개인키는 가져오지 않는다.
  1. 과제가 요구하는 값을 구분한다

    • 공개키에는 과 가 필요하다. modulus의 16진수 문자열만 저장한 파일은 일반적인 PEM 공개키 파일이 아니다.
    • 문제는 modulus 문자열을 구한 다음 그 문자열에 서명하라고 요청한다. 키를 암호화하는 작업이나 modulus 자체를 공개키 인증서로 바꾸는 작업이 아니다.
    shell
    openssl rsa -in lab-private.pem -modulus -noout
    openssl pkey -in lab-private.pem -pubout -out lab-public.pem

    자신의 폐기 가능한 실습 키에서 modulus를 조회하고 공개키를 추출한다.

    WebGoat RSA 키 과제원본 크기로 보기 ↗
    • 화면은 개인 RSA 키를 교육용 입력으로 주고 modulus의 16진수 표현과 서명을 각각 요구한다.
    • BEGIN PRIVATE KEY 표시는 PEM 컨테이너의 시작이며, 답안 입력칸 두 개는 서로 다른 결과물을 받는다.
    확인 기준

    n만 추출한 파일과 공개키 PEM 파일을 이름부터 다르게 관리한다.

  2. 서명할 메시지의 바이트를 고정한다

    • 과제가 정한 16진수 대소문자·접두사·개행 포함 여부를 먼저 확인한다. 보이는 글자가 같아도 마지막 LF가 있으면 해시 입력이 달라진다.
    • 서명은 개인키로 수행하고 검증은 공개키로 수행한다. 는 생성된 서명 바이트를 답안에 넣기 쉬운 문자열로 바꾸는 표현이다.
    shell
    openssl dgst -sha256 -sign lab-private.pem -out signature.bin message.txt
    openssl dgst -sha256 -verify lab-public.pem -signature signature.bin message.txt

    메시지 파일을 중간에 수정하지 않고 서명·검증한다. 사진의 개인키 값은 재사용하지 않는다.

    확인 기준

    서명 검증이 실패하면 키 쌍과 함께 메시지 파일의 실제 바이트를 비교한다.

  3. 키 소유 증명과 신원 신뢰를 나눈다

    • 서명이 맞다는 것은 해당 공개키에 대응하는 개인키가 사용됐다는 증거다. 그 키가 누구의 것인지는 별도의 신뢰 관계가 필요하다.
    • 인증서 체인은 공개키를 이름·용도·기간과 묶는다. 서명 과제와 인증서 검증 도해는 서로 다른 단계의 비교 자료다.
    인증서 체인 · 인증서 체인은 왜 필요한가원본 크기로 보기 ↗
    • 서버 인증서 위에 Intermediate CA와 Root CA가 연결돼 있다.
    • 오른쪽에는 서버 이름·유효기간·용도·폐기 상태가 따로 나열되어, 서명 확인만으로 검증이 끝나지 않음을 보여 준다.
    확인 기준

    서명 성공을 곧바로 서버 신뢰 성공으로 보고하지 않는다.

실습에서 확인한 동작 원리

  • modulus는 공개키의 한 구성 요소다.
  • 서명은 메시지의 정확한 바이트와 키 쌍에 의존한다.
동작·명령 참고 문서
원리 심화

11RSA 정수 연산과 실제 스킴의 경계

  • 서로 다른 소수 p·q로 n=pq를 만들며 공개키는 n·e를 포함한다. p·q를 알면 비밀 지수 계산에 필요한 구조가 드러난다.
  • 교과서 예에서 gcd(e,)=1인 e를 고르고 ed≡1 mod 을 만족하는 d를 사용한다.
  • 기본 연산은 0≤m<n인 정수 대표값을 처리한다. 임의 길이 파일을 그대로 한 정수 연산에 넣는 구조가 아니다.
  • OAEP는 메시지·난수·해시·길이 조건을 인코딩하고, PSS는 서명용 인코딩을 정한다. 두 스킴을 교환해 쓸 수 없다.
  • 작은 정수는 계산 원리만 설명한다. 실제 안전성은 충분한 강도와 검증된 구현·난수·오류 처리까지 요구한다.
예제로 추적

12가상 RSA 숫자를 끝까지 계산하기

  1. 교육용 p=61, q=53이면 n=3233이고 =60×52=3120이다.
  2. e=17, d=2753을 쓰면 17×2753=46801=3120×15+1이므로 역원 관계가 성립한다.
  3. m=65를 교과서 식에 넣으면 c=65^17 mod 3233=2790이다.
  4. 2790^2753 mod 3233=65로 원래 대표값을 얻는다. 이는 수학식의 확인이지 안전한 파일 암호화 예제가 아니다.
  5. 실제 OAEP에서는 동일 평문도 인코딩의 난수 때문에 다른 대표값이 될 수 있다. 위 예에는 그 보호가 없다.
검증·예외

13암호 모듈의 실패를 입력 층별로 분리하기

  • PEM·DER 컨테이너와 실제 알고리즘·키 길이를 확인한다. 확장자만으로 키인지 인증서인지 판단하지 않는다.
  • OAEP 해시·MGF 설정·label이나 PSS 매개변수가 양쪽에서 다르면 같은 키 쌍이어도 검증·복호화가 실패할 수 있다.
  • 암호화의 최대 평문은 모듈러스 바이트 수에서 스킴 오버헤드를 뺀 값이다. 긴 자료는 혼합 암호화 구조로 처리한다.
  • 외부 오류 차이가 내부 패딩·파싱 성공 여부를 알려 주지 않도록 한다. 상세 원인은 비밀을 제거한 내부 진단으로 분리한다.

14DH: 비밀을 보내지 않고 공유 비밀을 만드는 계산

  • 유한체 의 단순 모델에서 두 참여자는 공개된 p와 g를 알고 각자 비밀 지수 a와 b를 고른다. A=g^a mod p와 B=g^b mod p를 교환한 뒤 한쪽은 B^a mod p, 다른 쪽은 A^b mod p를 계산한다.
  • 두 값은 g^(ab) mod p로 같아진다. 공개되는 것은 A와 B이며 a와 b 자체를 상대에게 전송하지 않는다.
  • 아주 작은 학습값 p=23, g=5, a=6, b=15를 쓰면 A=8, B=19이고 양쪽의 공유 값은 2다. 실제 보안용 매개변수가 아니라 손으로 계산하는 예제다.
  • 자체는 상대가 누구인지 인증하지 않으므로 중간자가 공개값을 각각 바꾸면 양쪽과 별도 비밀을 합의할 수 있다. 는 인증서와 서명을 통해 현재 핸드셰이크의 키 합의를 인증된 상대에 연결한다.
  1. 공개된 p·g 아래에서 두 참여자가 각자 비밀 지수 a·b를 고른다.
  2. A=g^a mod p와 B=g^b mod p를 교환하며 비밀 지수 자체는 보내지 않는다.
  3. 한쪽은 B^a, 다른 쪽은 A^b를 mod p로 계산하여 같은 g^(ab)를 얻는다.
  4. 만으로 상대가 인증되지는 않으므로 같은 프로토콜이 서명과 협상 문맥을 연결한다.
text
공개: p=23, g=5
A = 5^6 mod 23 = 8
B = 5^15 mod 23 = 19

한쪽: 19^6 mod 23 = 2
다른 쪽: 8^15 mod 23 = 2

등식을 보여 주기 위한 작은 가상 수치다. 실제 키 크기나 배포 설정으로 사용하지 않는다.

15DHE·ECDHE·Forward Secrecy와 Logjam의 교훈

  • 와 의 E는 임시 키 사용을 뜻한다. 는 타원곡선 위의 연산으로 공유 비밀을 계산한다.
  • 연결별 이 보존되지 않는 적절한 구조에서는 나중에 장기 인증 개인키가 노출되어도 그 키만으로 과거 세션의 공유 비밀을 바로 얻지 못한다. 이 성질이 이며 모든 키 유출이나 실행 중 메모리 노출까지 해결한다는 뜻은 아니다.
  • Logjam은 약한 export-grade 협상으로의 다운그레이드와 작은 유한체 그룹에 대한 사전 계산 문제를 보여 준다. 공격 비용은 그룹 크기와 구조에 영향을 받으므로 “표준 p,g를 함께 썼다” 자체가 곧 취약점은 아니다.
  • 검토된 충분한 강도의 표준 그룹을 사용하는 것과 작은 공통 그룹의 계산 비용을 여러 연결에 분산시키는 문제를 구분한다.

16NFS와 키 길이를 비교할 때의 주의

  • 는 큰 정수 소인수분해와 일부 유한체 이산로그 문제에 사용하는 계산 기법과 연결된다. 의 정수 인수분해 문제와 의 이산로그 문제는 서로 다른 문제이므로 한 알고리즘의 마지막 단계를 그대로 복사해 같은 설명으로 만들지 않는다.
  • 또한 256비트와 타원곡선 256비트는 보안 강도가 같은 숫자라는 뜻이 아니다.
  • 안전성은 키 길이뿐 아니라 난수 생성, 올바른 그룹과 입력 검증, 부채널 저항, 개인키 접근, 재사용 범위에 달려 있다. 나 가 수학적으로 견고하더라도 디버그 로그에 키를 남기면 공격자는 알고리즘을 해독할 필요가 없다.
  • 이 때문에 키 식별자는 기록할 수 있어도 키 원문은 진단 출력에서 제외하고, 새 쓰기용 키와 과거 자료 복호화용 키의 생명주기를 구분한다.

설명과 함께 보는 보조 도식

처리 과정

모식도 · 키 합의와 AEAD 데이터 처리

키를 준비하는 경로와 실제 데이터를 보호하는 경로를 분리한다.

전체 단계를 한 번에 읽기
  1. 01

    키 준비

    합의 결과에서 목적에 맞는 키를 도출한다.

  2. 02

    보호

    같은 키에서 재사용하지 않는 Nonce로 처리한다.

    입력
    평문 + 부가 데이터
  3. 03

    전달

    암호문과 검증에 필요한 값을 전달한다.

  4. 04

    검증

    태그가 맞을 때만 복호화 결과를 사용한다.

    실패
    평문 처리 중단
구성요소와 데이터 이동을 단순화한 학습용 모식도입니다. 실제 제품의 모든 내부 모듈을 나타내지는 않습니다.
학습 확인

이해했는지 확인하기

  • 암호화·서명·키 합의의 목적과 사용 키를 구분한다.
  • 선택한 모드의 Nonce·IV·인증 태그 요구를 확인한다.
  • 키 접근권한과 교체·복구 절차를 확인한다.

함께 확인할 공식 자료