Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Secret message #830

Merged
merged 10 commits into from
Aug 1, 2017
5 changes: 1 addition & 4 deletions raiden/api/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -542,10 +542,7 @@ def close(self, token_address, partner_address):
if channel.received_transfers:
first_transfer = channel.received_transfers[-1]

netting_channel = channel.external_state.netting_channel
netting_channel.close(
first_transfer,
)
channel.external_state.close(first_transfer)

return channel

Expand Down
44 changes: 42 additions & 2 deletions raiden/channel/netting_channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,48 @@ def query_settled(self):
def close(self, partner_transfer):
if not self._called_close:
self._called_close = True
return self.netting_channel.close(partner_transfer)

if partner_transfer:
nonce = partner_transfer.nonce
transferred_amount = partner_transfer.transferred_amount
locksroot = partner_transfer.locksroot
signature = partner_transfer.signature

packed = partner_transfer.packed()
message_hash = sha3(packed.data[:-65])

else:
nonce = 0
transferred_amount = 0
locksroot = ''
signature = ''
message_hash = ''

return self.netting_channel.close(
nonce,
transferred_amount,
locksroot,
message_hash,
signature,
)

def update_transfer(self, partner_transfer):
return self.netting_channel.update_transfer(partner_transfer)
if partner_transfer:
nonce = partner_transfer.nonce
transferred_amount = partner_transfer.transferred_amount
locksroot = partner_transfer.locksroot
signature = partner_transfer.signature

packed = partner_transfer.packed()
message_hash = sha3(packed.data[:-65])

return self.netting_channel.update_transfer(
nonce,
transferred_amount,
locksroot,
message_hash,
signature,
)

def withdraw(self, unlock_proofs):
return self.netting_channel.withdraw(unlock_proofs)
Expand Down Expand Up @@ -640,6 +678,7 @@ def create_directtransfer(self, amount, identifier):
identifier=identifier,
nonce=from_.nonce,
token=self.token_address,
channel=self.channel_address,
transferred_amount=transferred_amount,
recipient=to_.address,
locksroot=current_locksroot,
Expand Down Expand Up @@ -675,6 +714,7 @@ def create_lockedtransfer(self, amount, identifier, expiration, hashlock):
identifier=identifier,
nonce=from_.nonce,
token=self.token_address,
channel=self.channel_address,
transferred_amount=transferred_amount,
recipient=to_.address,
locksroot=updated_locksroot,
Expand Down
6 changes: 6 additions & 0 deletions raiden/encoding/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ def namedbuffer(buffer_name, fields_spec): # noqa (ignore ciclomatic complexity
names_slices = compute_slices(fields_spec)
sorted_names = sorted(names_fields.keys())

@staticmethod
def get_bytes_from(buffer_, name):
slice_ = names_slices[name]
return buffer_[slice_]

def __init__(self, data):
if len(data) != size:
raise ValueError('data buffer has the wrong size, expected {}'.format(size))
Expand Down Expand Up @@ -173,6 +178,7 @@ def __dir__(self):
'fields_spec': fields_spec,
'format': fields_format,
'size': size,
'get_bytes_from': get_bytes_from,
}

return type(buffer_name, (), attributes)
122 changes: 40 additions & 82 deletions raiden/encoding/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
namedbuffer,
pad,
)
from raiden.encoding.signing import recover_publickey


def to_bigendian(number):
Expand Down Expand Up @@ -69,6 +68,7 @@ def make_message(message, **attrs):
target = make_field('target', 20, '20s')
initiator = make_field('initiator', 20, '20s')
sender = make_field('sender', 20, '20s')
channel = make_field('channel', 20, '20s')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Question to make sure I properly comprehend the changes.
You have added the channel to all messages but it is not being consumed anywhere.

It seems to be consumed indirectly though through the hash of the first 65 bytes of the transfer. That would make messages unique per channel and would make the nonce ranges check for "replay attacks" irrelevant.

Correct?


locksroot = make_field('locksroot', 32, '32s')
hashlock = make_field('hashlock', 32, '32s')
Expand Down Expand Up @@ -140,12 +140,13 @@ def make_message(message, **attrs):
DirectTransfer = namedbuffer(
'direct_transfer',
[
cmdid(DIRECTTRANSFER), # [0:1]
pad(3), # [1:4]
nonce, # [4:12]
identifier, # [12:20]
token, # [20:40]
recipient, # [40:60]
cmdid(DIRECTTRANSFER),
pad(3),
nonce,
identifier,
token,
channel,
recipient,
transferred_amount,
optional_locksroot,
signature,
Expand All @@ -155,42 +156,44 @@ def make_message(message, **attrs):
MediatedTransfer = namedbuffer(
'mediated_transfer',
[
cmdid(MEDIATEDTRANSFER), # [0:1]
pad(3), # [1:4]
nonce, # [4:12]
identifier, # [12:20]
expiration, # [20:28]
token, # [28:48]
recipient, # [48:68]
target, # [68:88]
initiator, # [88:108]
locksroot, # [108:140]
hashlock, # [140:172]
transferred_amount, # [172:204]
amount, # [204:236]
fee, # [236:268]
signature, # [268:333]
cmdid(MEDIATEDTRANSFER),
pad(3),
nonce,
identifier,
expiration,
token,
channel,
recipient,
target,
initiator,
locksroot,
hashlock,
transferred_amount,
amount,
fee,
signature,
]
)

RefundTransfer = namedbuffer(
'refund_transfer',
[
cmdid(REFUNDTRANSFER), # [0:1]
pad(3), # [1:4]
nonce, # [4:12]
identifier, # [12:20]
expiration, # [20:28]
token, # [28:48]
recipient, # [48:68]
target, # [68:88]
initiator, # [88:108]
locksroot, # [108:140]
hashlock, # [140:172]
transferred_amount, # [172:204]
amount, # [204:236]
fee, # [236:268]
signature, # [268:333]
cmdid(REFUNDTRANSFER),
pad(3),
nonce,
identifier,
expiration,
token,
channel,
recipient,
target,
initiator,
locksroot,
hashlock,
transferred_amount,
amount,
fee,
signature,
]
)

Expand All @@ -216,51 +219,6 @@ def make_message(message, **attrs):
}


def wrap_and_validate(data):
''' Try to decode data into a message and validate the signature, might
return None if the data is invalid.
'''
try:
first_byte = data[0]
except KeyError:
log.warn('data is empty')
return

try:
message_type = CMDID_MESSAGE[first_byte]
except KeyError:
log.error('unknown cmdid %s', first_byte)
return

try:
message = message_type(data)
except ValueError:
log.error('trying to decode invalid message')
return

assert message_type.fields_spec[-1].name == 'signature', 'signature is not the last field'
# this slice must be from the end of the buffer
message_data = message.data[:-signature.size_bytes]
message_signature = message.data[-signature.size_bytes:]

try:
publickey = recover_publickey(message_data, message_signature)
except ValueError:
# raised if the signature has the wrong length
log.error('invalid signature')
return
except TypeError as e:
# raised if the PublicKey instantiation failed
log.error('invalid key data: {}'.format(e.message))
return
except Exception as e:
# secp256k1 is using bare Exception classes: raised if the recovery failed
log.error('error while recovering pubkey: {}'.format(e.message))
return

return message, publickey


def wrap(data):
''' Try to decode data into a message, might return None if the data is invalid. '''
try:
Expand Down
Loading