brunch

You can make anything
by writing

C.S.Lewis

by 테크유람 Apr 01. 2021

디피-할만알고리즘을사용한
API Key의 교환



대칭키 암호화(symmetric encryption) 방식은 송수신자 모두 동일한 키(key)로 메시지를 암호화하고, 암호화된 메시지를 복호화합니다. 만약 키가 외부에 노출된다면 인가되지 않은 사용자도 노출된 키를 사용해 메시지를 복호화할 수 있는 위험이 있습니다.


HMAC(Hash-based Message Authentication Code)은 송수신자가 메시지 무결성 확인을 위해 사용하는 메시지 무결성 알고리즘이며, 해시 알고리즘과 공유 비밀키(shared secret)를 조합하여 원본 메시지를 해싱 메시지로 변환합니다. 이를 위해 송수신자는 사전에 공유 비밀키를 나눠가져야 하는데, 이 과정에서 인가되지 않은 사용자에게 키가 노출된다면 결국 메시지 무결성에 문제가 생길 수 있습니다.


위의 두 가지 사례에서 보듯이 메시지 자체의 암호화도 중요하지만 송수신자 간에 안전하게 키를 공유하는 방법도 중요합니다. 웹 기반 시스템에서는 보안 채널로 HTTPS를 사용하지만 다른 이유로 키가 노출되거나 네트워크 상의 중간자 공격 등 100% 안전함을 보장할 수 없기에 추가적인 보완이 필요합니다.


디피-할만(Diffie-Hellman) 알고리즘은 1976년 Diffie와 Hellman이 개발한 공개키 방식의 알고리즘입니다. 그 역사는 오래되었지만 키 강도를 높이는 방식으로 진화하여 아직도 안전한 키 교환을 위해 현업에서 많이 사용하는 방법 중 하나입니다. 암호화/복호화 알고리즘이 아닌 키의 분배와 교환을 위한 알고리즘이라는 것을 혼동하지 않아야 합니다.


Wikipedia 페이지에서 가져온 아래 이미지는 Diffie-Hellman 알고리즘 방식을 잘 설명해주고 있습니다.


위 그림을 차례대로 설명하면,

① Alice와 Bob 두 사람은 처음에 같은 색(노란색)을 가지고 있다.

② 노란색에 서로의 비밀스러운 색(주황색, 코발트색)을 혼합하면, 각기 다른 색이 된다.

③ 혼합된 색을 서로가 교환한다.

④ ②번에서 사용한 서로의 비밀스러운 색(주황색, 코발트색)을 다시 한번 혼합하면 결국 같은 색(갈색)이 된다.

⑤ Alice와 Bob은 이제 공통된 "갈색"을 서로가 필요한 "공통" 정보로 사용할 수 있다.


만약 해커가 ③번 과정을 엿들었다 해도, 중간 단계의 섞인 상태의 색만 알 뿐입니다. 송수신자의 원래의 색(노란색)을 유추해서 brute-force 방법으로 두 사람의 비밀 색을 찾아내려 해도, 실제 세계에서는 수학적인 연산이 상당히 복잡하기 때문에 불가능합니다.


위의 시나리오를 실제 DH 알고리즘으로 대입하여 설명하면 다음과 같습니다.

① Alice와 Bob 모두 소수(prime number) p=23, 기본 숫자(generator) g=5를 동일하게 가지고 있다.

② Alice는 비밀 숫자 4를, Bob은 비밀 숫자 3을 골랐다.

- Alice는 23, 5, 4를 혼합하여 A = 54 mod 23 = 4를 만들었다.

- Bob은 23, 5, 3을 혼합하여 B = 53 mod 23 = 10을 만들었다.

③ Alice와 Bob은 각자 A(4), B(10)를 교환한다.

④ 각자 교환한 숫자에, 자신만의 비밀 숫자를 다시 연산한다.

- Alice는 받은 숫자 B(10)에 자신의 비밀 숫자 4를 혼합해 s = 104 mod 23 = 18을 만든다.

- Bob은 받은 숫자 A(4)에 자신의 비밀 숫자 3을 혼합해 s = 43 mod 23 = 18을 만든다.

⑤ Alice와 Bob은 이제 "18"을 서로의 공유 비밀키로 사용할 수 있다.


위 로직을 파이썬으로 간단히 슈도 코드로 만들어보았습니다.

#-*- coding:utf-8 -*-
#미리 공유된 소수와 기본수에 대한 변수 선언
sharedPrime = 23    #p
sharedBase = 5      #g 

aliceSecret = 4     #a
bobSecret = 3      #b 

print( "서로가 공유한 소수:" , sharedPrime )
print( "서로가 공유한 기본수" , sharedBase )
print( "\n")

#A = g^a mod p
A = (sharedBase**aliceSecret) % sharedPrime
print( "Alice가 Bob에게 보낸 수: " , A ) 

#B = g^b mod p
B = (sharedBase ** bobSecret) % sharedPrime
print( "Bob이 Alice에게 보낸 수: ", B )
print( "\n")

#Alice의 비밀키 = B^a mod p
aliceSharedSecret = (B ** aliceSecret) % sharedPrime
print( "Alice의 비밀 공유키:", aliceSharedSecret ) 

#Bob의 비밀키 = A^b mod p
bobSharedSecret = (A**bobSecret) % sharedPrime
print( "Bob의 비밀 공유키:", bobSharedSecret )

<실행 결과>
$python3 dh.py

서로가 공유한 소수: 23
서로가 공유한 기본수 5

Alice가 Bob에게 보낸 수:  4
Bob이 Alice에게 보낸 수:  10

Alice의 비밀 공유키: 18
Bob의 비밀 공유키: 18


지금까지의 과정은 Diffie-Hellman 알고리즘을 쉽게 설명하기 위한 예제였으며 실제 환경에서는 더욱 복잡한 비밀키와 연산을 사용합니다. 설령 제삼자가 Alice와 Bob의 소수(23), 기본 숫자(5)를 알아냈다고 해도, 비밀 공유키(18)를 알아낼 방법은 없습니다.


REST API 환경에서 이 알고리즘을 사용하는 경우를 생각해보면 API 인증을 위해 클라이언트와 서버가 동일한 API 키를 나누어야 하는 경우도 있고 API 요청과 응답의 데이터 무결성을 HMAC으로 확인하기 위해 사전에 비밀키를 안전하게 공유해야 하는 경우도 있습니다.


만약 모든 API 트랜잭션에 대해 동일한 키가 아닌 세션마다 다른 키를 사용하여 좀 더 보안성을 강화한다면 클라이언트-서버 사이에 맺어진 세션의 고유 번호인 SessionID를 Diffie-Hellman 알고리즘 적용을 위한 클라이언트와 서버의 사전 동일 정보로 활용할 수도 있습니다.


키의 안전한 교환 이후에는 그 키를 활용하여 메시지 암호화 및 메시지 무결성 확인 기능을 위해 사용할 수 있습니다. 다른 글 - "API 인증과 메시지 무결성 확인을 통한 API 보안"에서 이 부분을 다루었습니다.




브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari