Files
nym/clients/native/examples/python-examples/websocket/filesend.py
T
Jędrzej Stuczyński d9d549fd0f Feature/reply surbs (#299)
* Changed identity keypair to use ed25519

* Encryption key is now x25519 based + compatibiltiy with sphinx

* Pathing and import fixes

* Moved all asymmetric keys to sub-module in crypto

* Extracted aes to separate module

* kdf module in crypto

* Ability to perform diffie hellman on encryption keys

* ecdsa on identity keys

* Extremely rough and incomplete registration handshake

* Authentication primitives

* Creating new random authenticationIV

* Wrapper type for the derived shared key

* Removed AuthToken in favour of using SharedKey for authentication

* Gateway identity keys

* Registration handshake without error mapping

* Gateway address in client config

* Added extra key for gateway presence

* Updated pemstore to work on borrows instead

* Gateway client trying to perform the handshake

* Gateway changes to allow for handshake and shared key

* Debug trait on sharedkey

* native client using updated gateway client

* Slightly updated gateway API

* Minor cleanup

* Fixed pemstore to correctly save multiple keypairs

* Gateway actually deriving shared key during handshake

* Gateway sending correct mid-handshake message

* Missing quotation mark in client config template

* Fixed template for correct shared key serialization

* Fixed gateway authentication

* Fixed tests

* Using correct gateway key when converting to sphinx node

* "get_all_clients" takes them from gateways as opposed to providers now

* cargo fmt

* Renamed pemstore methods

* Unused import

* Encryption of forward requests between client and gateway

* Updated sphinx dependency to use public revision

* Sending 'error' on handshake processing error

* Removed some dead code

* Dead code I forgot to remove before

* Extracted AckAes128Key into a struct

* Slight pemstore revamp allowing for symmetric key store

* ibid.

* PemStorableKey for SharedKey

* Introduced single location responsible for key management for client

* WIP

* Sphinx version update

* Stop using NodeAddressBytes for two distinct and confusing purposes

* Abstracting away SocketAddr from sphinx forwarding

* Passing the bool for reply surbs

* Attack plan for replies + encryption

* Comment + removed variable binding

* ReplySURB usage

* Topology import in nymsphinx

* Sphinx version update

* Changed 'Recipient' to contain client's encryption key

* Message preparation taking shape!

* reply surb also containing the encryption key

* Very initial message receiver

* Sphinx version update

* A possibly working way of receiving surbs

* Fixed incorrect field name in client config template

* camel casing all request arguments

* Renamed and moved `MessageMode` to more appropriate file

* Restored reconstruction tests

* Removed dead code from chunking

* Made rust examples compilable

* reply SURB key storage

* Replies as an InputMessage

* Forgotten commented code

* No retransmission processing for cover or replies

* Received reply processing

* Renamed client pathfinder to something more appropriate

* Made HasherOutputSize public

* Added key store path to config

* Reply surb attaching key digest when used

* Changes due to previous renaming

* Removed comment

* Fixed insert_encryption_key

* Assigning initial value of key store path

* Computing key digest with correct algorithm

* Initial and presumably temporary request serialization

* hacky way of introducing 'FragmentIdentifier' for replies

* Moved responsibility of reply encryption, padding, etc, to message preparer

* Optional recipient in try_get_valid_topology_ref

* Handling new reply surbs with acks and padding

* Updated go and python examples to include replies in text and binary cases

* Updated rust examples + binaryserverresponse

* Helpers in rust examples

* And updated JS example

* Moved shared key generation function to crypto crate

* Cover traffic encryption!

* hmac computation in crypto

* Updated aes imports due to new dependencies

* hkdf made more generic

* crypto cleanup + algorithms in params

* Clippy cleanup pass

* Generating encryption+mac shared keys between client and gateway

* MACs attached to forward requests to gateway

* Gateway messages encrypted and mac'd

* Lowered logging level

* compiler warning cleanup

* Some minor cleanup

* Generic stream cipher

* Generic shared key derivation + algorithm definitions

* Project-wide AES clean-up

* Comment fix

* Removed commented imports

* Updated comments

* Fixed topology test fixture
2020-08-07 18:16:54 +01:00

112 lines
4.6 KiB
Python

import asyncio
import base58
import json
import websockets
self_address_request = json.dumps({
"type": "selfAddress"
})
WITHOUT_REPLY: int = 0
WITH_REPLY: int = 1
REPLY: int = 2
# this is really flaky so ideally will be replaced by some proper serialization
# 16 - length of encryption key
# 32 - length of first hop
# 348 - current sphinx header size
# 192 - size of single payload key
# 4 - number of mix hops (gateway + 3 nodes)
REPLY_SURB_LEN: int = 16 + 32 + 348 + 4 * 192
async def send_file_with_reply():
uri = "ws://localhost:1977"
async with websockets.connect(uri) as websocket:
await websocket.send(self_address_request)
self_address = json.loads(await websocket.recv())
print("our address is: {}".format(self_address["address"]))
# we receive our address in string format of OUR_ID_PUB_KEY . OUR_ENC_PUB_KEY @ OUR_GATE_ID_PUB_KEY
# all keys are 32 bytes and we need to encode them as binary without the '.' or '@' signs
split_address = self_address["address"].split("@")
client_half = split_address[0]
gateway_half = split_address[1]
# to DH: I think at this point this should be replaced with some sort of protobuf / flatbuffers / Cap'n Proto, etc
split_client_address = client_half.split(".")
bin_payload = bytearray([WITH_REPLY])
bin_payload += base58.b58decode(split_client_address[0])
bin_payload += base58.b58decode(split_client_address[1])
bin_payload += base58.b58decode(gateway_half)
with open("dummy_file", "rb") as input_file:
read_data = input_file.read()
bin_payload += read_data
print("sending content of 'dummy_file' over the mix network...")
await websocket.send(bin_payload)
print("waiting to receive the 'dummy_file' from the mix network...")
received_data = await websocket.recv()
assert received_data[0] == WITH_REPLY
reply_surb = received_data[1:1 +REPLY_SURB_LEN]
output_file_data = received_data[1 + REPLY_SURB_LEN:]
with open("received_file_withreply", "wb") as output_file:
print("writing the file back to the disk!")
output_file.write(output_file_data)
reply_message = b"hello from reply SURB! - thanks for sending me the file!"
binary_reply = bytearray([REPLY])
binary_reply += reply_surb
binary_reply += reply_message
print("sending '{}' (using reply SURB!) over the mix network...".format(reply_message))
await websocket.send(binary_reply)
print("waiting to receive a message from the mix network...")
received_reply = await websocket.recv()
assert received_reply[0] == WITHOUT_REPLY
print("received '{}' from the mix network".format(received_reply[1:]))
async def send_file_without_reply():
uri = "ws://localhost:1977"
async with websockets.connect(uri) as websocket:
await websocket.send(self_address_request)
self_address = json.loads(await websocket.recv())
print("our address is: {}".format(self_address["address"]))
# we receive our address in string format of OUR_ID_PUB_KEY . OUR_ENC_PUB_KEY @ OUR_GATE_ID_PUB_KEY
# all keys are 32 bytes and we need to encode them as binary without the '.' or '@' signs
split_address = self_address["address"].split("@")
client_half = split_address[0]
gateway_half = split_address[1]
# to DH: I think at this point this should be replaced with some sort of protobuf / flatbuffers / Cap'n Proto, etc
split_client_address = client_half.split(".")
bin_payload = bytearray([WITHOUT_REPLY])
bin_payload += base58.b58decode(split_client_address[0])
bin_payload += base58.b58decode(split_client_address[1])
bin_payload += base58.b58decode(gateway_half)
with open("dummy_file", "rb") as input_file:
read_data = input_file.read()
bin_payload += read_data
print("sending content of 'dummy_file' over the mix network...")
await websocket.send(bin_payload)
print("waiting to receive the 'dummy_file' from the mix network...")
received_data = await websocket.recv()
assert received_data[0] == WITHOUT_REPLY
with open("received_file_noreply", "wb") as output_file:
print("writing the file back to the disk!")
output_file.write(received_data[1:])
# asyncio.get_event_loop().run_until_complete(send_file_without_reply())
asyncio.get_event_loop().run_until_complete(send_file_with_reply())