Skip to content

Noise Protocol

Noise Protocol

#Derive ECDH 

Wireguard

Example Python Wireguard Connection:

import base64
import datetime
from hashlib import blake2s
import socket
import struct

from scapy.layers.inet import IP, ICMP

from noise.connection import NoiseConnection, Keypair


address = ('192.168.88.12', 51820)

our_private = base64.b64decode('KAeB4HGe78vSqQ0PUMNh6UOvEcvtvK5wcVJFhato3Vg=')
their_public = base64.b64decode('p0BYGoPj5OW4CfOmC8Etu2BHjXH7iLIXulVvZeTfHRQ=')
#preshared = bytes.fromhex('5573657231003132333435363344000000000000000000000000000000000000')
preshared = bytes.fromhex('0000000000000000000000000000000000000000000000000000000000000000')
prologue = b'WireGuard v1 zx2c4 [email protected]'

noise = NoiseConnection.from_name(b'Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s')
noise.set_as_initiator()
noise.set_keypair_from_private_bytes(Keypair.STATIC, our_private)
noise.set_keypair_from_public_bytes(Keypair.REMOTE_STATIC, their_public)
noise.set_psks(psk=preshared)
noise.set_prologue(prologue)
noise.start_handshake()

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)


print("Part 1")


# 1. Prepare and send handshake initiation packet
now = datetime.datetime.now()
tai = struct.pack('!qi', 4611686018427387914 + int(now.timestamp()), int(now.microsecond * 1e3))
initiation_packet = b'\x01'  # Type: initiation
initiation_packet += b'\x00' * 3  # Reserved
initiation_packet += struct.pack('<i', 28)  # Sender index: 28 (arbitrary)
initiation_packet += noise.write_message(payload=tai)
mac_key = blake2s(b'mac1----' + their_public).digest()
initiation_packet += blake2s(initiation_packet, digest_size=16, key=mac_key).digest()
initiation_packet += b'\x00' * 16

sock.sendto(initiation_packet, address)


print("Part 2")

# 2. Receive response to finalize handshake
response_packet = sock.recv(92)
print(response_packet)
assert response_packet[0] == 2  # Type: response
assert response_packet[1:4] == b'\x00' * 3  # Reserved
their_index, our_index = struct.unpack('<ii', response_packet[4:12])
assert our_index == 28
payload = noise.read_message(response_packet[12:60])
assert payload == b''
assert noise.handshake_finished


print("Part 3")

# 3. Prepare, encrypt and send ping packet
icmp_packet = ICMP(type=8, id=921, seq=438)/b'WireGuard'
ip_packet = IP(proto=1, ttl=20, src="10.200.100.2", dst="10.200.100.1", id=0)/icmp_packet
ping_packet = b'\x04'  # Type: data
ping_packet += b'\x00' * 3  # Reserved
ping_packet += struct.pack('<iq', their_index, 0)
ping_packet += noise.encrypt(bytes(ip_packet))

sock.sendto(ping_packet, address)


print("Part 4")

# 4. Retrieve ping response, decrypt and verify
encrypted_response = sock.recv(2048)
#print(encrypted_response)
assert encrypted_response[0] == 4  # Type: data
assert encrypted_response[1:4] == b'\x00' * 3  # Reserved
our_index, nonce = struct.unpack('<iq', encrypted_response[4:16])
assert our_index == 28
assert nonce == 0
ip = noise.decrypt(encrypted_response[16:])
ip = IP(ip)
ip.display()
"""
assert icmp.type == 0
assert icmp.code == 0
assert icmp.id == 921
assert icmp.seq == 438
assert payload.load == b'WireGuard'
"""


print("Part 5")

# 5. Send keepalive
keepalive = b'\x04'  # Type: data
keepalive += b'\x00' * 3  # Reserved
keepalive += struct.pack('<iq', their_index, 1)
keepalive += noise.encrypt(b'')

sock.sendto(keepalive, address)

print("Part 6")