암호학에서의 디피 - 헬만 (Diffie-Hellman) 을 이용한 기본 키 교환

LinuxBeginner
지금 연습하기

소개

본 실습에서는 현대 암호학의 초석인 Diffie-Hellman (DH) 키 교환의 기본 사항을 탐구합니다. DH 프로토콜은 사전에 서로에 대해 아무것도 모르는 두 당사자가 안전하지 않은 통신 채널을 통해 공유 비밀 키를 공동으로 설정할 수 있도록 합니다. 이 공유 비밀은 이후 대칭 키 암호 (symmetric key cipher) 를 사용하여 후속 통신을 암호화하는 데 사용될 수 있습니다.

전체 DH 프로세스를 시뮬레이션하기 위해 강력한 openssl 명령줄 도구를 사용할 것입니다. 여기에는 공개 파라미터 생성, 두 당사자에 대한 개인 키 및 공개 키 생성, 그리고 최종적으로 공유 비밀 도출 및 검증이 포함됩니다. 이 실습이 끝날 때쯤에는 이 필수적인 암호화 핸드셰이크가 어떻게 작동하는지에 대한 실질적인 이해를 갖게 될 것입니다.

디피 - 헬만 키 교환 원리

이 단계에서는 Diffie-Hellman 키 교환의 이론적 원리를 다룹니다. 이 단계에서는 실행할 명령이 없으며, 목표는 구현하기 전에 개념을 이해하는 것입니다.

과정은 다음과 같이 진행됩니다.

  1. 공개 파라미터 합의: 앨리스 (Alice) 와 밥 (Bob) 이라고 부르는 두 당사자는 먼저 두 개의 공개 숫자, 즉 큰 소수 $p$ (모듈러스, modulus) 와 밑수 $g$ (생성자, generator) 에 대해 합의합니다. 이 숫자들은 비밀이 아니며 안전하지 않은 채널을 통해 전송될 수 있습니다.

  2. 개인 키 생성:

    • 앨리스는 비밀 개인 정수 $a$를 선택합니다. 그녀는 이 숫자를 자신만 알고 있습니다.
    • 밥은 비밀 개인 정수 $b$를 선택합니다. 그는 이 숫자를 자신만 알고 있습니다.
  3. 공개 키 계산:

    • 앨리스는 공식 $A = g^a \mod p$를 사용하여 자신의 공개 키 $A$를 계산합니다. 그녀는 이 공개 키 $A$를 밥에게 보냅니다.
    • 밥은 공식 $B = g^b \mod p$를 사용하여 자신의 공개 키 $B$를 계산합니다. 그는 이 공개 키 $B$를 앨리스에게 보냅니다.
  4. 공유 비밀 도출:

    • 앨리스는 밥의 공개 키 $B$를 받고 자신의 개인 키 $a$를 사용하여 공유 비밀 $S$를 계산합니다: $S = B^a \mod p$.
    • 밥은 앨리스의 공개 키 $A$를 받고 자신의 개인 키 $b$를 사용하여 공유 비밀 $S$를 계산합니다: $S = A^b \mod p$.

모듈러 산술 (modular arithmetic) 의 속성으로 인해 앨리스와 밥 모두 $S$에 대해 정확히 동일한 값에 도달하게 됩니다.

  • 앨리스의 계산: $S = (g^b \mod p)^a \mod p = g^{ba} \mod p$
  • 밥의 계산: $S = (g^a \mod p)^b \mod p = g^{ab} \mod p$

채널을 도청하는 사람은 $p$, $g$, $A$, $B$를 볼 수 있지만, 개인 키 $a$ 또는 $b$를 쉽게 계산할 수는 없습니다. 이러한 어려움을 이산 로그 문제 (discrete logarithm problem) 라고 하며, 이는 Diffie-Hellman 교환의 보안 기반을 형성합니다.

다음 단계에서는 openssl을 사용하여 이러한 작업을 수행할 것입니다.

디피 - 헬만 매개변수 생성

이 단계에서는 양 당사자가 사용할 공개 DH 파라미터 (pg) 를 생성합니다. openssl 도구는 적절한 소수와 생성자를 찾는 복잡한 수학적 계산을 대신 처리해 줄 수 있습니다. 본 실습의 모든 작업은 기본 디렉터리인 ~/project에서 수행됩니다.

openssl dhparam 명령을 사용하여 파라미터를 생성합니다. 이 목적을 위해 일반적이고 안전한 길이인 2048 비트의 키 크기를 지정할 것입니다.

터미널에서 다음 명령을 실행하십시오:

openssl dhparam -out dhparam.pem 2048

이 명령을 분석해 보겠습니다:

  • openssl dhparam: OpenSSL 에서 DH 파라미터 관리 도구를 호출합니다.
  • -out dhparam.pem: 이 플래그는 출력을 dhparam.pem이라는 파일에 저장하도록 지정합니다.
  • 2048: 이는 소수 모듈러스 p의 원하는 비트 길이입니다.

이 명령은 강력한 소수를 찾는 데 시간이 걸리므로 완료하는 데 1 분이 걸릴 수 있습니다. 작업 중에는 다음과 유사한 출력이 표시될 수 있습니다:

Generating DH parameters, 2048 bit long safe prime

완료되면 현재 디렉터리에 dhparam.pem이라는 파일이 생성됩니다. 이 파일에는 키 교환에 양 당사자가 사용할 공개 파라미터가 포함되어 있습니다.

A 당사자 키 생성

이 단계에서는 "당사자 A(Party A)"의 동작을 시뮬레이션합니다. 당사자 A 는 이전 단계에서 공유된 DH 파라미터를 사용하여 자체 개인 키를 생성한 다음, 이에 상응하는 공개 키를 도출할 것입니다.

먼저, 당사자 A 의 개인 키를 생성합니다. 이 키는 이론적 예시에서 나온 비밀 숫자 a에 해당합니다. 범용 키 생성 유틸리티인 openssl genpkey 명령을 사용할 것입니다.

당사자 A 의 개인 키를 생성하려면 다음 명령을 실행하십시오:

openssl genpkey -paramfile dhparam.pem -out a_private_key.pem
  • genpkey: 개인 키를 생성하는 명령입니다.
  • -paramfile dhparam.pem: genpkey에게 dhparam.pem 파일의 파라미터를 사용하여 DH 키를 생성하도록 지시합니다.
  • -out a_private_key.pem: 생성된 개인 키를 a_private_key.pem 파일에 저장합니다.

다음으로, 당사자 A 는 개인 키로부터 공개 키를 도출해야 합니다. 이 공개 키는 당사자 B 와 공유될 내용입니다.

공개 키를 추출하려면 이 명령을 실행하십시오:

openssl pkey -in a_private_key.pem -pubout -out a_public_key.pem
  • pkey: 공개 키와 개인 키를 관리하는 명령입니다.
  • -in a_private_key.pem: 입력 개인 키를 지정합니다.
  • -pubout: 이 플래그는 명령에 키의 공개 부분을 출력하도록 지시합니다.
  • -out a_public_key.pem: 결과 공개 키를 a_public_key.pem에 저장합니다.

이제 두 개의 새 파일이 생겼습니다: 당사자 A 가 비밀로 유지해야 하는 a_private_key.pem과 당사자 A 가 안전하지 않은 채널을 통해 당사자 B 에게 보낼 a_public_key.pem입니다.

B 당사자 키 생성

이 단계에서는 두 번째 당사자인 "당사자 B(Party B)"에 대해 동일한 작업을 수행합니다. 당사자 B 는 당사자 A 와 독립적으로 작동하지만, dhparam.pem에서 가져온 동일한 공개 DH 파라미터를 사용합니다.

먼저, 당사자 B 의 개인 키를 생성합니다. 이는 이론적 예시에서 비밀 숫자 b에 해당합니다.

다음 명령을 실행하십시오:

openssl genpkey -paramfile dhparam.pem -out b_private_key.pem

이 명령의 구조는 당사자 A 의 명령과 동일하지만, 구분을 위해 출력을 b_private_key.pem에 저장합니다.

다음으로, 당사자 A 와 마찬가지로 당사자 B 도 새로 생성한 개인 키로부터 공개 키를 도출해야 합니다.

당사자 B 의 공개 키를 추출하려면 이 명령을 실행하십시오:

openssl pkey -in b_private_key.pem -pubout -out b_public_key.pem

실제 교환 시 이 시점에서 당사자 A 는 당사자 B 의 공개 키 (b_public_key.pem) 를 가지게 되며, 당사자 B 는 당사자 A 의 공개 키 (a_public_key.pem) 를 가지게 됩니다. 양 당사자는 각자의 개인 키를 비밀로 유지했습니다. 이제 프로토콜의 키 생성 및 교환 부분을 성공적으로 시뮬레이션했습니다.

공유 비밀 (Shared Secret) 계산

이것이 마지막이자 가장 중요한 단계입니다. 여기서는 양 당사자가 각자의 개인 키와 상대방의 공개 키를 사용하여 독립적으로 공유 비밀 키를 계산합니다. 프로토콜이 성공하면 둘 다 정확히 동일한 비밀 값에 도달하게 됩니다.

먼저, 당사자 A 의 관점에서 공유 비밀 키를 계산해 보겠습니다. 당사자 A 는 자신의 개인 키 (a_private_key.pem) 와 당사자 B 의 공개 키 (b_public_key.pem) 를 사용합니다.

다음 명령을 실행하십시오:

openssl pkeyutl -derive -inkey a_private_key.pem -peerkey b_public_key.pem -out a_shared_secret.bin
  • pkeyutl: 공개 키 연산을 수행하는 유틸리티입니다.
  • -derive: 이 동작은 유틸리티에게 공유 비밀 키를 도출하도록 지시합니다.
  • -inkey a_private_key.pem: 당사자 A 자신의 개인 키를 지정합니다.
  • -peerkey b_public_key.pem: 상대방 (피어, "peer") 의 공개 키를 지정합니다.
  • -out a_shared_secret.bin: 결과로 나온 바이너리 비밀 값을 파일에 저장합니다.

다음으로, 당사자 B 의 관점에서 공유 비밀 키를 계산합니다. 당사자 B 는 자신의 개인 키 (b_private_key.pem) 와 당사자 A 의 공개 키 (a_public_key.pem) 를 사용합니다.

다음 명령을 실행하십시오:

openssl pkeyutl -derive -inkey b_private_key.pem -peerkey a_public_key.pem -out b_shared_secret.bin

이제 a_shared_secret.binb_shared_secret.bin이라는 두 개의 파일이 있습니다. 키 교환의 성공 여부를 확인하려면 이 두 파일이 동일해야 합니다. 이를 확인하기 위해 cmp (비교) 명령을 사용할 수 있습니다.

cmp a_shared_secret.bin b_shared_secret.bin

파일이 동일하면 이 명령은 아무 출력도 생성하지 않고 조용히 종료됩니다. 이 침묵은 성공을 의미합니다!

더 시각적인 확인을 위해 두 파일의 암호화 해시 (cryptographic hash) 를 계산할 수도 있습니다. 해시 값은 일치해야 합니다.

sha256sum *.bin

두 파일이 정확히 동일한 SHA256 해시를 갖는 출력을 보게 될 것입니다. 실제 해시 값은 실행할 때마다 달라지지만, a_shared_secret.binb_shared_secret.bin에 대해 해시가 동일해야 성공적으로 동일한 공유 비밀 키를 도출했음을 증명합니다.

e3705a4ab5ae5d86f59dfe968f0177b49d5144e2d731dbd8d41b2eda318412ec  a_shared_secret.bin
e3705a4ab5ae5d86f59dfe968f0177b49d5144e2d731dbd8d41b2eda318412ec  b_shared_secret.bin

축하합니다. Diffie-Hellman 키 교환을 성공적으로 수행했습니다!

요약

본 실습 (Lab) 에서는 openssl 명령줄 도구를 사용하여 완전한 Diffie-Hellman 키 교환을 성공적으로 시뮬레이션했습니다. 이 중요한 암호화 프로토콜의 기본 단계를 직접 경험해 보았습니다.

다음과 같은 방법을 배웠습니다:

  • 공유 공개 DH 파라미터 생성 (openssl dhparam).
  • 해당 파라미터를 기반으로 두 개의 독립적인 당사자에 대한 개인 키 및 공개 키 쌍 생성 (openssl genpkeyopenssl pkey).
  • 자신의 개인 키와 피어의 공개 키로부터 공유 비밀 키 도출 (openssl pkeyutl -derive).
  • 양 당사자가 독립적으로 정확히 동일한 비밀을 계산했는지 확인하여 교환의 성공을 입증.

이 과정은 인터넷 전반의 데이터를 보호하는 TLS/SSL과 같은 보안 통신 시스템의 기초적인 구성 요소입니다. 이제 보안되지 않은 네트워크에서 시작하더라도 두 당사자가 어떻게 안전한 통신 채널을 구축할 수 있는지에 대한 실질적인 이해를 갖게 되었습니다.