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
This commit is contained in:
committed by
GitHub
parent
2a29bbd5a2
commit
d9d549fd0f
@@ -7,18 +7,37 @@ self_address_request = json.dumps({
|
||||
"type": "selfAddress"
|
||||
})
|
||||
|
||||
WITHOUT_REPLY: int = 0
|
||||
WITH_REPLY: int = 1
|
||||
REPLY: int = 2
|
||||
|
||||
async def send_file():
|
||||
# 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_PUB_KEY @ OUR_GATE_PUB_KEY
|
||||
# both keys are 32 bytes and we need to encode them as binary without the '@' sign
|
||||
# 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("@")
|
||||
bin_payload = bytearray(base58.b58decode(split_address[0]))
|
||||
bin_payload += base58.b58decode(split_address[1])
|
||||
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()
|
||||
@@ -29,8 +48,64 @@ async def send_file():
|
||||
|
||||
print("waiting to receive the 'dummy_file' from the mix network...")
|
||||
received_data = await websocket.recv()
|
||||
with open("received_file", "wb") as output_file:
|
||||
print("writing the file back to the disk!")
|
||||
output_file.write(received_data)
|
||||
assert received_data[0] == WITH_REPLY
|
||||
reply_surb = received_data[1:1 +REPLY_SURB_LEN]
|
||||
output_file_data = received_data[1 + REPLY_SURB_LEN:]
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(send_file())
|
||||
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())
|
||||
|
||||
@@ -7,7 +7,7 @@ self_address_request = json.dumps({
|
||||
})
|
||||
|
||||
|
||||
async def send_text():
|
||||
async def send_text_without_reply():
|
||||
message = "Hello Nym!"
|
||||
|
||||
uri = "ws://localhost:1977"
|
||||
@@ -19,14 +19,59 @@ async def send_text():
|
||||
text_send = json.dumps({
|
||||
"type": "send",
|
||||
"message": message,
|
||||
"recipient": self_address["address"]
|
||||
"recipient": self_address["address"],
|
||||
"withReplySurb": False,
|
||||
})
|
||||
|
||||
print("sending '{}' over the mix network...".format(message))
|
||||
print("sending '{}' (*without* reply SURB) over the mix network...".format(message))
|
||||
await websocket.send(text_send)
|
||||
|
||||
print("waiting to receive a message from the mix network...")
|
||||
received_message = await websocket.recv()
|
||||
print("received '{}' from the mix network".format(received_message))
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(send_text())
|
||||
|
||||
async def send_text_with_reply():
|
||||
message = "Hello Nym!"
|
||||
|
||||
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"]))
|
||||
|
||||
text_send = json.dumps({
|
||||
"type": "send",
|
||||
"message": message,
|
||||
"recipient": self_address["address"],
|
||||
"withReplySurb": True,
|
||||
})
|
||||
|
||||
print("sending '{}' (*with* reply SURB) over the mix network...".format(message))
|
||||
await websocket.send(text_send)
|
||||
|
||||
print("waiting to receive a message from the mix network...")
|
||||
received_message = json.loads(await websocket.recv())
|
||||
print("received '{}' from the mix network".format(received_message))
|
||||
|
||||
# use the received surb to send an anonymous reply!
|
||||
reply_surb = received_message["replySurb"]
|
||||
|
||||
reply_message = "hello from reply SURB!"
|
||||
reply = json.dumps({
|
||||
"type": "reply",
|
||||
"message": reply_message,
|
||||
"replySurb": reply_surb
|
||||
})
|
||||
|
||||
print("sending '{}' (using reply SURB!) over the mix network...".format(reply_message))
|
||||
await websocket.send(reply)
|
||||
|
||||
print("waiting to receive a message from the mix network...")
|
||||
received_message = await websocket.recv()
|
||||
print("received '{}' from the mix network".format(received_message))
|
||||
|
||||
|
||||
|
||||
# asyncio.get_event_loop().run_until_complete(send_text_without_reply())
|
||||
asyncio.get_event_loop().run_until_complete(send_text_with_reply())
|
||||
|
||||
Reference in New Issue
Block a user