List of commits:
Subject Hash Author Date (UTC)
Clean up PFS handshake procedure fc23e9ffe4fad4555ef384f29b11153e75aa3497 GDR! 2017-11-27 18:06:48
Proper handling of incoming packets f254c2e022a905b3d52d87cc3bfa731d6279e2fb GDR! 2017-11-12 18:31:13
Working parsing of pong header 67373af393e3c7c412b495655ba7934e4e3dffb5 GDR! 2017-11-09 22:13:57
Use correct incoming/outgoing terminology for nonces 1ba500936c9f190bdd4dd1a02e648ad19ee610c9 GDR! 2017-11-09 20:51:34
util db7db2d7fcccbb320f7c041272a0f708f846d850 GDR! 2017-11-09 20:30:47
Working ping 090854611163edc23aec1b460b285770c6f5b806 GDR! 2017-11-09 20:30:37
Initial 5492ec94c8cab618b3e617e0ac2f8d5b27335f83 GDR! 2017-11-09 17:41:55
Commit fc23e9ffe4fad4555ef384f29b11153e75aa3497 - Clean up PFS handshake procedure
Author: GDR!
Author date (UTC): 2017-11-27 18:06
Committer name: GDR!
Committer date (UTC): 2017-11-27 18:06
Parent(s): f254c2e022a905b3d52d87cc3bfa731d6279e2fb
Signer:
Signing key:
Signing status: N
Tree: d9fee91b34103869d79c0d45e473410ed304ddb7
File Lines added Lines deleted
crap.py 15 21
tcp.py 70 3
File crap.py changed (mode: 100755) (index f49eed7..99a0c93)
1 1 #!/usr/bin/python3 #!/usr/bin/python3
2 2
3 3 import datetime import datetime
4 import socket
5 4 import time import time
6 5
7 6 from identity import Identity from identity import Identity
 
... ... if __name__ == "__main__":
15 14 print("toxid", identity.get_printable_public_key()) print("toxid", identity.get_printable_public_key())
16 15
17 16 #relay = TcpRelay("biribiri.org", 3389, "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67") #relay = TcpRelay("biribiri.org", 3389, "F404ABAA1C99A9D37D61AB54898F56793E1DEF8BD46B1038B9D822E8460FAB67")
18 relay = TcpRelay("localhost", 4443, "53DE181BF5AC9A62AFF790ACAD604822246881E4BB4A02A2C63BED426E14FA20")
17 relay = TcpRelay("localhost", 4443, "926496D61E73EB2DC2987A1DC2096D3A1DA59F4B7D2530665B4E93E27C5DDC11")
19 18 packet = relay.get_client_hello_packet(session, identity) packet = relay.get_client_hello_packet(session, identity)
20 19
21 s = socket.socket()
22 s.connect((relay.hostname, relay.port))
20 relay.connect()
23 21 print("connected") print("connected")
24 22
25 packet.send(s)
26
27 received = s.recv(4096)
28 packet = TcpServerHelloPacket()
29 packet.parse(received)
30 packet.decrypt_payload(relay, session)
31 print ("relay key", h(packet.relay_public_key))
32 print ("base nonce", h(packet.base_nonce))
33 relay.set_incoming_nonce(packet.base_nonce)
34 relay.set_outgoing_public_key(packet.relay_public_key)
23 relay.negotiate_forward_secret_keys(session, identity)
35 24
36 25 def on_ping_recvd(packet): def on_ping_recvd(packet):
37 print ("PING RECEIVED!", packet)
26 print ("<<< PING", packet)
27 def on_pong_recvd(packet):
28 print ("<<< PONG", packet)
38 29
39 30 TcpPingPacket.register_listener(on_ping_recvd) TcpPingPacket.register_listener(on_ping_recvd)
31 TcpPongPacket.register_listener(on_pong_recvd)
40 32
41 33 ping = TcpPingPacket(relay=relay) ping = TcpPingPacket(relay=relay)
42 ping.send(s)
43
44 s.setblocking(0)
34 ping.send()
45 35
46 incoming_stream_handler = IncomingStreamHandler(s, relay)
36 tick = 0
37 incoming_stream_handler = IncomingStreamHandler(relay)
47 38 while True: while True:
48 39 received_packets = incoming_stream_handler.tick() received_packets = incoming_stream_handler.tick()
49 40 if received_packets: if received_packets:
50 41 print (datetime.datetime.now().isoformat(), received_packets) print (datetime.datetime.now().isoformat(), received_packets)
51 42 time.sleep(0.1) time.sleep(0.1)
43 tick += 1
52 44
53 pong = TcpPongPacket(relay)
54 pong.parse(s.recv(4096)[2:]) # todo: parse length header
45 if tick % 30 == 0:
46 print (">>> PING")
47 ping = TcpPingPacket(relay=relay)
48 ping.send()
55 49
56 50 s.close() s.close()
File tcp.py changed (mode: 100644) (index 855dc0f..0b4efe4)
2 2
3 3 import binascii import binascii
4 4 import select import select
5 import socket
5 6 import struct import struct
6 7 import nacl.bindings import nacl.bindings
7 8 import nacl.utils import nacl.utils
 
... ... class TcpPacket:
31 32 def __init__(self): def __init__(self):
32 33 self.bytes = b"" self.bytes = b""
33 34
34 def send(self, socket):
35 def send(self, socket=None):
35 36 """ """
36 37 Serialize and send packet via socket Serialize and send packet via socket
37 38 """ """
38 39 serialized_b = self.serialize() serialized_b = self.serialize()
39 40 print(binascii.hexlify(serialized_b)) print(binascii.hexlify(serialized_b))
41 if socket is None:
42 socket = self.relay.get_socket()
40 43 socket.send(serialized_b) socket.send(serialized_b)
41 44 print ("sent %d bytes" % len(serialized_b)) print ("sent %d bytes" % len(serialized_b))
42 45
 
... ... class TcpPongPacket(EncryptedPacket):
127 130
128 131 def __repr__(self): def __repr__(self):
129 132 return "<TcpPongPacket(%s)>" % self.pong_message return "<TcpPongPacket(%s)>" % self.pong_message
133
134 class TcpRoutingRequestPacket(EncryptedPacket):
135 """
136 Routing request (0x00)
137 """
138 packet_id = 0x00
139 def __init__(self, relay=None):
140 super().__init__(relay)
130 141
131 142
132 143 class TcpClientHelloPacket(TcpPacket): class TcpClientHelloPacket(TcpPacket):
 
... ... class TcpClientHelloPacket(TcpPacket):
142 153 self.bytes += self.nonce self.bytes += self.nonce
143 154 self.bytes += self.get_payload(relay, session, identity) self.bytes += self.get_payload(relay, session, identity)
144 155
156 self.relay = relay
157
145 158 def get_payload(self, relay, session, identity): def get_payload(self, relay, session, identity):
146 159 payload = bytes(relay.get_incoming_public_key()) payload = bytes(relay.get_incoming_public_key())
147 160 payload += bytes(relay.get_outgoing_nonce_without_incrementing()) payload += bytes(relay.get_outgoing_nonce_without_incrementing())
 
... ... class TcpRelay:
201 214 # a temporary public key tied to this connection # a temporary public key tied to this connection
202 215 self.outgoing_public_key = None self.outgoing_public_key = None
203 216
217 # The socked used to connect to this relay
218 self._socket = None
219
220 def connect(self):
221 """
222 Establish a TCP connection
223 """
224 self._socket = socket.socket()
225 self._socket.connect((self.hostname, self.port))
226 return self._socket
227
228 def get_socket(self):
229 """
230 Return a socket to TCP relay, connect if necessary
231 """
232 if self._socket is not None:
233 return self._socket
234 return self.connect()
235
204 236 def get_client_hello_packet(self, session, identity): def get_client_hello_packet(self, session, identity):
205 237 return TcpClientHelloPacket(self, session, identity) return TcpClientHelloPacket(self, session, identity)
206 238
207 239 def get_incoming_nonce(self): def get_incoming_nonce(self):
240 """
241 Return nonce for decrypting incoming packets (TCP relay -> me), incrementing the nonce
242 """
208 243 nonce = self.tcp_incoming_nonce nonce = self.tcp_incoming_nonce
209 244 self.increment_incoming_nonce() self.increment_incoming_nonce()
210 245 return nonce return nonce
 
... ... class TcpRelay:
219 254 return self.private_key return self.private_key
220 255
221 256 def get_dht_public_key(self): def get_dht_public_key(self):
257 """
258 Return relay's DHT public key
259 """
222 260 return self.dht_public_key return self.dht_public_key
223 261
224 262 def set_incoming_nonce(self, nonce): def set_incoming_nonce(self, nonce):
225 263 self.tcp_incoming_nonce = nonce self.tcp_incoming_nonce = nonce
226 264
227 265 def set_outgoing_public_key(self, key): def set_outgoing_public_key(self, key):
266 """
267 Set the ephemeral relay's public key with which this connection is encrypted
268 """
228 269 self.tcp_outgoing_public_key = PublicKey(key) self.tcp_outgoing_public_key = PublicKey(key)
229 270
230 271 def get_outgoing_nonce(self): def get_outgoing_nonce(self):
272 """
273 Return the nonce used for encrypting outgoing packets (me -> TCP relay)
274 Increments the nonce.
275 """
231 276 rv = self.tcp_outgoing_nonce rv = self.tcp_outgoing_nonce
232 277 self.increment_outgoing_nonce() self.increment_outgoing_nonce()
233 278 return rv return rv
 
... ... class TcpRelay:
241 286 def get_outgoing_public_key(self): def get_outgoing_public_key(self):
242 287 return self.tcp_outgoing_public_key return self.tcp_outgoing_public_key
243 288
289 def negotiate_forward_secret_keys(self, session, identity):
290 """
291 Given our session (DHT key) and identity (long term key), send
292 hello packets to the TCP relay and agree on nonce and ephemeral
293 keys.
294 This is a high-level function.
295 """
296 hello_packet = self.get_client_hello_packet(session, identity)
297 hello_packet.send()
298
299 sock = self.get_socket()
300 received = sock.recv(4096)
301
302 packet = TcpServerHelloPacket()
303 packet.parse(received)
304 packet.decrypt_payload(self, session)
305 print ("relay key", h(packet.relay_public_key))
306 print ("base nonce", h(packet.base_nonce))
307 self.set_incoming_nonce(packet.base_nonce)
308 self.set_outgoing_public_key(packet.relay_public_key)
309 self._socket.setblocking(0)
310
244 311 class IncomingStreamHandler: class IncomingStreamHandler:
245 312 """ """
246 313 Split incoming TCP stream into packets Split incoming TCP stream into packets
247 314 """ """
248 def __init__(self, sock, relay):
315 def __init__(self, relay):
249 316 """ """
250 317 sock - tcp socket to read from sock - tcp socket to read from
251 318 relay - TcpRelay instance needed for decryption relay - TcpRelay instance needed for decryption
252 319 """ """
253 self.socket = sock
254 320 self.relay = relay self.relay = relay
321 self.socket = relay.get_socket()
255 322 self.buf = b"" self.buf = b""
256 323 self.packet_types = {} self.packet_types = {}
257 324 self.build_packet_types_table() self.build_packet_types_table()
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/gdr/PurePyTox

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/gdr/PurePyTox

Clone this repository using git:
git clone git://git.rocketgit.com/user/gdr/PurePyTox

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main