연습
SSL Handshake, Cipher Suite
onaeonae1
2024. 5. 14. 23:36
handshake 과정에 대해 구체적으로 파악 및 Cipher Suite에 대해 알아보자
1. SSL 통신 복습, handshake 중점으로
- SSL 통신은 공개키와 대칭키를 혼합해서 사용
- 대칭키로 실제 데이터를 암호화
- SSL 인증서의 웹 서버 공개키로 대칭키를 안전하게 공유
- CA의 SSL 인증서를 통해 다음과 같은 기본적인 보안기능 수행
- 신뢰할 수 있는 웹서비스 확인 → SSL 인증서가 CA 공개키로 decode 가능
- 통신내용 암호화 → 대칭키 생성 및 Server 공개키로 안전하게 공유
- SSL 통신 과정은 다음과 같은 순서로 이루어진다
- handshake, session, session 종료
- 여기서 handshake에서는 다음과 같은 역할을 수행
- 암호화 알고리즘 결정둘의 교집합을 Server 에서 정해서 알려줌
- Client 와 Server 가 서로 가능한 암호화 알고리즘을 공유
- 암호화에 사용할 대칭키(=session-key 생성)Client 측에서 서로의 random data로 pre-master-key 생성, 암호화Server에서는 pre-master-key를 Server 비공개키로 decode둘 사이에 공유된 master-key가 session-key 라고 불림. 데이터 대칭키 암호화에 사용
- 이를 master-key로 확정, Client 와 Sever 공유됨(Client가 생성, server 가 decode)
- 암호화된 pre-master-key를 Server에 전송
- Client 와 Server 각각에서 random data 를 생성, Server에서 Client에 random data 넘김
- 어제는 개념적으로 이에 대해 파악했는데 좀 더 구체적으로 알아보자
2. Handshake 과정
우선 handshake 의 목적은 크게 2개
- (대칭키) 암호화 알고리즘(Cipher Suite) 결정
- (대칭키) 암호화 알고리즘에 사용할 키 공유
2-1. Client Hello
- handshake의 시작 단계
- Server 에 연결을 시작하며 보내는 패킷
- 다음과 같은 데이터를 전송
- SSL Protocol Version
- Session ID
- 클라이언트 측 암호화 알고리즘 목록(Cipher Suites)
2-2. Server Hello
- ClientHello로 packet 이 전송되면 수행됨
- Client 로부터 받은 Cipher Suites 에서 하나를 선택 = 서로 사용할 암호화 알고리즘을 선택한 것
- random data를 생성(이후 대칭키 생성에 사용됨)
2-3. Certificate
- Server 가 자신의 SSL 인증서를 Client 에 전달
- 인증서에는 Server 정보(도메인 등), Server 공개키가 들어있음 CA 비공개키로 encode된 상태
- Client는 SSL 인증서를 CA 공개키로 decode, 신뢰할 수 있는 서비스임을 확인(=전자 서명)
- (사진)
2-4. Server Key Exchange, ServerHello Done
- Server Key Exchange: Server 공개키를 Client 에게 전달하기 위해 필요한 과정.
- Server Key Exchage 는 필수 아님. (SSL 인증서에 Server 공개키가 없는 경우에만 사용하므로)
- SSL 인증서 내부에 있으면 Client 가 알아서 CA 공개키로 가져가므로 Server Key Exchange X
- Server Key Exchange 가 실행 혹은 생략되었으면 ServerHello Done
2-5. Client Key Excnahge
- 실제 데이터를 암호화할 목적으로 사용하는 대칭키를 공유하기 위한 것 (생략불가)
- 대칭키(=pre-master-key)를 Client 측에서 생성 혹은 생성에 필요한 데이터 제공
- 어제 공부한 내용에서는 간단히 random-data 를 조합한다고 정리
- 그러나 실제로는 알고리즘마다 약간의 차이 존재
- RSA 알고리즘 에서는 알려진 대로 client 측에서 random-data 조합
- Diffie-Hellman(DH, DHE), ECDHE 알고리즘 등을 사용하면 Server 한테 생성 데이터 보냄
- 보내준 데이터로 Client-Server 에서 서로 동일한 데이터(=대칭키) 생성 가능한게 특징
- Server 공개키로 암호화해서 전달
2-6. ChangeCipherSpec, Finished
- Client - Server 모두에게 보내는 packet
- Packet으로 교환해야할 정보를 모두 교환했고, 이제부터 암호화 통신 시작할수 있다는 뜻
이렇게 SSL Handshake 에 대해 간단한 정리 완료. 나중에 실제 packet 을 뜯어보는게 도움 될 듯
3. Cipher Suites
3-1. 설명
- ClientHello ServerHello 과정 전달되는 packet 에서는 Cipher Suite(s)가 전달된다.
- 우선 packet을 살펴보자
- Cipher Suite는 사용할, 혹은 가능한 암호화 알고리즘에 대한 것이다.
- 아까 handshake 에 대해서 설명하면서 상당히 간략하게 "암호화" 한다라고 설명
- 그러나 이러한 암호화를 어케 할 것인지 다양한 알고리즘이 존재. 이들을 특정해줘야 함
3-2. Cipher Suites 구조
ServerHello의 Cipher Suite: 를 확인해보면 적당히 다음과 같은 구조임을 확인 가능
💡 Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
이는 "_" 를 기준으로 의미를 가지는데 위의 예제를 바탕으로 의미를 파악해보자.
"TLS"
=> 프로토콜
- TLS/SSL 프로토콜임을 의미
- Cipher Suites에서 이부분은 항상 TLS로 고정이므로 큰 의미는 없다.
"ECDHE"
=> 대칭키 교환 방식
- 아까 Client Key Exchange 에서 언급되었던 ECDHE 알고리즘을 사용중인 케이스
- 이 경우는 Client Key Exchange에서 Server로 생성에 필요한 데이터를 줄 것 같네
"RSA"
=> 인증서 검증 방식
- SSL 인증서를 어떤 알고리즘으로 풀어야 하는지 알려줌
- 당연히 전부 공개키 방식임은 고정인데 그 안에서 약간 갈리는듯
- 알려준 알고리즘에 브라우저가 가지고 있는 CA 공개키를 사용하면 됨
WITH은 일단 생략, 무조건 들어가는 부분임 TLS 처럼
"AES_128"
=> 데이터 암호화에 사용할 대칭키 암호화 알고리즘
- AES_128은 128 bit 단위로 암호화하는 블록 암호화 알고리즘임
- 블록 암호화 알고리즘이 뭐냐면 특정 단위로 데이터를 암호화 한다는 것
- 대칭키 알고리즘이니깐 같은 Key 로 encode, decode 가능
- 세부적으로 보려면 암호학 관련 지식이 필요
- 예전에 pycryptodome 으로 AES, CBC 모드 로 구현한게 있는데 첨부함 ㄱㄷ
"GCM"
=> 블록 암호화 알고리즘에서 사용할 모드
- 블록 암호화 알고리즘에는 CBC, GCM, ECB, OFB 등 많은 모드들 존재
- 우선은 블록 암호화 알고리즘에 대한 추가설명 정도로 이해할 수 있을 듯
"SHA384"
=> 무결성 확인에 사용할 hash 알고리즘
- handshake 완료 후 암호화된 통신을 할 때에 추가적으로 무결성 검증을 함
- 주고받는 암호화된 데이터가 누군가의 변조를 거치지 않았는지 hash로 검증
- hash 에 대해서는 자구나 알고리즘 등에서 한번 접했을 것으로 예상
- 입력값에 대해 동일한 출력값. 출력값에서 입력값으로 돌리기 ㅈㄴ 어려움
- 비밀번호를 DB에 저장할 때 이 기능을 사용(rainbow attack 등이 존재하긴 함)
이렇게 Cipher Suite에 대해서 정리할 수 있을 것 같다.
자세하게 알기 위해서는 우선 암호학 관련 지식이 필요할 것 같다.
4. (추가) pycryptodome 을 사용한 AES CBC 코드
- 8월 말에 CVE lao bomb 을 구현하면서 AES 관련 공부를 할 일이 생겼다.
- 간단하게 pycryptodome 으로 AES CBC 코드를 구현해봄
- 세부적인 암호화 알고리즘에 대해서는 아직 좀 부족해서 설명은 못하겠음
- 블록 암호화라서 16 단위로 맞춰줘야함, 이를 위해서 padding 을 추가해줌
- AES는 여러 bit 들이 존재하는데 16단위로 존재하므로 pycryptodome 에서 알아서 선택
- iv, key가 같아야 encode, decode 가 모두 가능함
- 일단 코드만 올림 나중에 설명할 수 있는 수준으로 공부해야겠다.
import random
import string
from Cryptodome.Cipher import AES
class AESCryptoCBC:
def __init__(self, key):
iv = bytes([0x00] * 16)
self.crypto = AES.new(key, AES.MODE_CBC, iv)
def encrypt(self, data: str) -> bytes:
data = self.check_padding(data)
data = bytes(str.encode(data, encoding="utf8"))
enc = self.crypto.encrypt(data)
return enc
def decrypt(self, encrypted_data: bytes):
dec = self.crypto.decrypt(encrypted_data).decode("utf8")
return dec
def check_padding(self, token:str):
padding = "".join(
random.choice(string.ascii_letters + string.digits) for _ in range(16)
)
if not len(token) % 16 == 0:
pad_length = 16 - len(token) % 16
pad = padding[:pad_length]
token = token + pad
return token
def local_test(payload):
key = [
0x10,
0x01,
0x15,
0x1B,
0xA1,
0x11,
0x57,
0x72,
0x6C,
0x21,
0x56,
0x57,
0x62,
0x16,
0x05,
0x3D,
0xFF,
0xFE,
0x11,
0x1B,
0x21,
0x31,
0x57,
0x72,
0x6B,
0x21,
0xA6,
0xA7,
0x6E,
0xE6,
0xE5,
0x3F,
]
data = payload
origin_length = len(data)
# 출력
print("Data is " + str(data))
# 키 생성
aes1 = AESCryptoCBC(bytes(key))
# 변경
encrypted_data = aes1.encrypt(data)
print("The encrypted value is " + str(list(encrypted_data)))
# encrypt 와 decrypt 는 같은 cipher 에서 불가. 무조건 새로 생성해야함 (AES.new)
aes2 = AESCryptoCBC(bytes(key))
dec = aes2.decrypt(bytes(encrypted_data))[:origin_length]
print(f"The Decrypted Value is: {''.join(dec)}")
local_test("abc def ghi jkl mno")
실행 결과 제대로 나오고 있다.
5. 참조