저수준 ADNL
Abstract Datagram Network Layer (ADNL)는 네트워 크 피어들이 서로 통신하는 것을 돕는 TON의 핵심 프로토콜입니다.
피어 신원
각 피어는 최소 하나의 신원을 가져야 하며, 여러 개를 사용할 수 있지만 필수는 아닙니다. 각 신원은 피어 간 Diffie-Hellman을 수행하는 데 사용되는 키쌍입니다. 추상 네트워크 주소는 공개 키에서 다음과 같이 도출됩니다: address = SHA-256(type_id || public_key)
. type_id는 리틀 엔디안 uint32로 직렬화되어야 합니다.
공개 키 암호 시스템 목록
type_id | 암호시스템 |
---|---|
0x4813b4c6 | ed255191 |
1. x25519를 수행하려면 키쌍이 x25519 형식으로 생성되어야 합니다. 하지만 공개 키는 ed25519 형식으로 네트워크를 통해 전송되므로 공개 키를 x25519에서 ed25519로 변환해야 합니다. 이러한 변환의 예시는 Kotlin용 여기에서 찾을 수 있습니다.
클라이언트-서버 프로토콜 (TCP 기반 ADNL)
클라이언트는 TCP를 사용하여 서버에 연결하고 ADNL 핸드셰이크 패킷을 보냅니다. 이 패킷에는 서버 추상 주소, 클라이언트 공개 키 및 클라이언트가 결정한 암호화된 AES-CTR 세션 매개변수가 포함됩니다.
핸드셰이크
먼저, 클라이언트는 서버 키의 type_id
를 고려하여 자신의 개인 키와 서버 공개 키를 사용하여 키 합의 프로토콜(예: x25519)을 수행해야 합니다. 그 결과로 클라이언트는 이후 단계에서 세션 키 암호화에 사용되는 secret
을 얻게 됩니다.
그런 다음 클라이언트는 AES-CTR 세션 매개변수, 16바이트 논스 및 32바이트 키를 TX(클라이언트->서버)와 RX(서버->클라이언트) 방향 모두에 대해 생성하고 다음과 같이 160바이트 버퍼로 직렬화해야 합니다:
매개변수 | 크기 |
---|---|
rx_key | 32 바이트 |
tx_key | 32 바이트 |
rx_nonce | 16 바이트 |
tx_nonce | 16 바이트 |
padding | 64 바이트 |
패딩의 목적은 알려지지 않았으며 서버 구현에서 사용되지 않습니다. 160바이트 버퍼 전체를 무작위 바이트로 채우는 것이 권장됩니다. 그렇지 않으면 공격자가 손상된 AES-CTR 세션 매개변수를 사용하여 활성 MitM 공격을 수행할 수 있습니다.
다음 단계는 위의 키 합의 프로토콜을 통해 얻은 secret
을 사용하여 세션 매개변수를 암호화하는 것입니다. 이를 위해 AES-256은 128비트 빅 엔디안 카운터를 사용하는 CTR 모드에서 다음과 같이 계산된 (key, nonce) 쌍으로 초기화되어야 합니다(aes_params
는 위에서 구축된 160바이트 버퍼):
hash = SHA-256(aes_params)
key = secret[0..16] || hash[16..32]
nonce = hash[0..4] || secret[20..32]
aes_params
의 암호화(E(aes_params)
로 표시)가 끝나면 더 이상 필요하지 않으므로 AES는 제거되어야 합니다.
이제 모든 정보를 256바이트 핸드셰이크 패킷으로 직렬화하여 서버에 보낼 준비가 되었습니다:
매개변수 | 크기 | 참고 |
---|---|---|
receiver_address | 32 바이트 | 해당 섹션에 설명된 서버 피어 신원 |
sender_public | 32 바이트 | 클라이언트 공개 키 |
SHA-256(aes_params) | 32 바이트 | 세션 매개 변수의 무결성 증명 |
E(aes_params) | 160 바이트 | 암호화된 세션 매개변수 |
서버는 클라이언트와 동일한 방식으로 키 합의 프로토콜에서 도출된 secret을 사용하여 세션 매개변수를 복호화해야 합니다. 그런 다음 서버는 프로토콜의 보안 속성을 확인하기 위해 다음 검사를 수행해야 합니다:
- 서버는
receiver_address
에 해당하는 개인 키를 가지고 있어야 합니다. 그렇지 않으면 키 합의 프로토콜을 수행할 방법이 없습니다. SHA-256(aes_params) == SHA-256(D(E(aes_params)))
, 그렇지 않으면 키 합의 프로토콜이 실패했고 양쪽의secret
이 같지 않습니다.
이러한 검사 중 하나라도 실패하면 서버는 클라이언트에 응답하지 않고 즉시 연결을 끊습니다. 모든 검사가 통과되면 서버는 지정된 receiver_address
에 대한 개인 키를 소유하고 있음을 증명하기 위해 클라이언트에 빈 데이터그램(데이터그램 섹션 참조)을 발행해야 합니다.
데이터그램
클라이언트와 서버 모두 TX와 RX 방향 모두에 대해 각각 두 개의 AES-CTR 인스턴스를 초기화해야 합니다. 128비트 빅 엔디안 카운터를 사용하는 CTR 모드에서 AES-256을 사용해야 합니다. 각 AES 인스턴스는 핸드셰이크의 aes_params
에서 가져올 수 있는 해당 (key, nonce) 쌍을 사용하여 초기화됩니다.
데이터그램을 보내기 위해 피어(클라이언트 또는 서버)는 다음 구조를 구축하고 암호화하여 다른 피어에게 보내야 합니다:
매개변수 | 크기 |
---|