def decoderlp(rlpdata): """Decode an RLP encoded object.""" try: item, end = consume_item(rlpdata, 0) except IndexError: raise DecodingError('RLP string to short', rlpdata) return item
def decode(self, data): # cmdid = rlp.peek(data, 0, sedes=t_int) # cmdid is first element t, l, pos = consume_length_prefix(data, 0) cmdid = t_int.deserialize(consume_item(data[pos], 0)[0]) cls = self.message_class_by_id[cmdid] print 'DECODING', cls return cls.decode(data)
def test_consume_item(): obj = [b'f', b'bar', b'a' * 100, 105, [b'nested', b'list']] rlp = encode(obj) item, per_item_rlp, end = consume_item(rlp, 0) assert per_item_rlp == [ (b'\xf8y' b'f' + b'\x83bar' + b'\xb8d' + b'a' * 100 + b'i' + b'\xcc\x86nested\x84list'), [b'f'], [b'\x83bar'], [b'\xb8d' + b'a' * 100], [b'i'], [b'\xcc\x86nested\x84list', [b'\x86nested'], [b'\x84list']] ] assert end == 123 assert per_item_rlp[0] == rlp
def decode_all(rlp: bytes, sedes: rlp.Serializable = None, recursive_cache: bool = False, **kwargs: Any) -> Iterable[Any]: """Decode multiple RLP encoded object. If the deserialized result `obj` has an attribute :attr:`_cached_rlp` (e.g. if `sedes` is a subclass of :class:`rlp.Serializable`) it will be set to `rlp`, which will improve performance on subsequent :func:`rlp.encode` calls. Bear in mind however that `obj` needs to make sure that this value is updated whenever one of its fields changes or prevent such changes entirely (:class:`rlp.sedes.Serializable` does the latter). :param sedes: an object implementing a function ``deserialize(code)`` which will be applied after decoding, or ``None`` if no deserialization should be performed :param **kwargs: additional keyword arguments that will be passed to the deserializer :param strict: if false inputs that are longer than necessary don't cause an exception :returns: the decoded and maybe deserialized Python object :raises: :exc:`rlp.DecodingError` if the input string does not end after the root item and `strict` is true :raises: :exc:`rlp.DeserializationError` if the deserialization fails """ if not is_bytes(rlp): raise DecodingError( 'Can only decode RLP bytes, got type %s' % type(rlp).__name__, rlp) end = 0 rlp_length = len(rlp) while rlp_length - end > 0: try: item, per_item_rlp, end = consume_item(rlp, end) except IndexError: raise DecodingError('RLP string too short', rlp) if sedes: obj = sedes.deserialize(item, **kwargs) if is_sequence(obj) or hasattr(obj, '_cached_rlp'): _apply_rlp_cache(obj, per_item_rlp, recursive_cache) yield obj else: yield item
def test_handshake(): tv = test_values initiator = RLPxSession(ECCx(raw_privkey=tv['initiator_private_key']), is_initiator=True, ephemeral_privkey=tv['initiator_ephemeral_private_key']) initiator_pubkey = initiator.ecc.raw_pubkey responder = RLPxSession(ECCx(raw_privkey=tv['receiver_private_key']), ephemeral_privkey=tv['receiver_ephemeral_private_key']) responder_pubkey = responder.ecc.raw_pubkey # test encryption _enc = initiator.encrypt_auth_message(tv['auth_plaintext'], responder_pubkey) assert len(_enc) == len(tv['auth_ciphertext']) assert len(tv['auth_ciphertext']) == 113 + len(tv['auth_plaintext']) # len # test auth_msg plain auth_msg = initiator.create_auth_message(remote_pubkey=responder_pubkey, ephemeral_privkey=tv['initiator_ephemeral_private_key'], nonce=tv['initiator_nonce']) # test auth_msg plain assert len(auth_msg) == len(tv['auth_plaintext']) == 194 assert auth_msg[65:] == tv['auth_plaintext'][65:] # starts with non deterministic k _auth_msg_cipher = initiator.encrypt_auth_message(auth_msg, responder_pubkey) # test shared responder.ecc.get_ecdh_key(initiator_pubkey) == \ initiator.ecc.get_ecdh_key(responder_pubkey) # test decrypt assert auth_msg == responder.ecc.ecies_decrypt(_auth_msg_cipher) # check receive responder_ephemeral_pubkey = privtopub(tv['receiver_ephemeral_private_key']) auth_msg_cipher = tv['auth_ciphertext'] auth_msg = responder.ecc.ecies_decrypt(auth_msg_cipher) assert auth_msg[65:] == tv['auth_plaintext'][65:] # starts with non deterministic k responder.decode_authentication(auth_msg_cipher) auth_ack_msg = responder.create_auth_ack_message(responder_ephemeral_pubkey, nonce=tv['receiver_nonce']) assert auth_ack_msg == tv['authresp_plaintext'] auth_ack_msg_cipher = responder.encrypt_auth_ack_message(auth_ack_msg, remote_pubkey=responder.remote_pubkey) # set auth ack msg cipher (needed later for mac calculation) responder.auth_ack = tv['authresp_ciphertext'] responder.setup_cipher() assert responder.ecdhe_shared_secret == tv['ecdhe_shared_secret'] assert len(responder.token) == len(tv['token']) assert responder.token == tv['token'] assert responder.aes_secret == tv['aes_secret'] assert responder.mac_secret == tv['mac_secret'] assert responder.initiator_nonce == tv['initiator_nonce'] assert responder.responder_nonce == tv['receiver_nonce'] assert responder.auth_init == tv['auth_ciphertext'] assert responder.auth_ack == tv['authresp_ciphertext'] # test values are from initiator perspective? assert responder.ingress_mac.digest() == tv['initial_egress_MAC'] assert responder.ingress_mac.digest() == tv['initial_egress_MAC'] assert responder.egress_mac.digest() == tv['initial_ingress_MAC'] assert responder.egress_mac.digest() == tv['initial_ingress_MAC'] r = responder.decrypt(tv['initiator_hello_packet']) # unpack hello packet import struct import rlp import rlp.sedes as sedes from rlp.codec import consume_item header = r['header'] frame_length = struct.unpack(b'>I', b'\x00' + header[:3])[0] header_sedes = sedes.List([sedes.big_endian_int, sedes.big_endian_int]) header_data = rlp.decode(header[3:], strict=False, sedes=header_sedes) print('header', repr(header_data)) # frame frame = r['frame'] # normal: rlp(packet-type) [|| rlp(packet-data)] || padding packet_type, end = consume_item(frame, start=0) packet_type = rlp.decode(frame, sedes=sedes.big_endian_int, strict=False) print('packet_type', repr(packet_type)) # decode hello body _sedes_capabilites_tuple = sedes.List([sedes.binary, sedes.big_endian_int]) structure = [ ('version', sedes.big_endian_int), ('client_version_string', sedes.big_endian_int), ('capabilities', sedes.CountableList(_sedes_capabilites_tuple)), ('listen_port', sedes.big_endian_int), ('remote_pubkey', sedes.binary) ] hello_sedes = sedes.List([x[1] for x in structure]) frame_data = rlp.decode(frame[end:], sedes=hello_sedes) frame_data = dict((structure[i][0], x) for i, x in enumerate(frame_data)) print('frame', frame_data)
def test_handshake(): tv = test_values initiator = RLPxSession(ECCx(raw_privkey=tv['initiator_private_key']), is_initiator=True, ephemeral_privkey=tv['initiator_ephemeral_private_key']) initiator_pubkey = initiator.ecc.raw_pubkey responder = RLPxSession(ECCx(raw_privkey=tv['receiver_private_key']), ephemeral_privkey=tv['receiver_ephemeral_private_key']) responder_pubkey = responder.ecc.raw_pubkey # test encryption _enc = initiator.encrypt_auth_message(tv['auth_plaintext'], responder_pubkey) assert len(_enc) == len(tv['auth_ciphertext']) assert len(tv['auth_ciphertext']) == 113 + len(tv['auth_plaintext']) # len # test auth_msg plain auth_msg = initiator.create_auth_message(remote_pubkey=responder_pubkey, ephemeral_privkey=tv[ 'initiator_ephemeral_private_key'], nonce=tv['initiator_nonce']) # test auth_msg plain assert len(auth_msg) == len(tv['auth_plaintext']) == 194 assert auth_msg[65:] == tv['auth_plaintext'][65:] # starts with non deterministic k _auth_msg_cipher = initiator.encrypt_auth_message(auth_msg, responder_pubkey) # test shared responder.ecc.get_ecdh_key(initiator_pubkey) == \ initiator.ecc.get_ecdh_key(responder_pubkey) # test decrypt assert auth_msg == responder.ecc.ecies_decrypt(_auth_msg_cipher) # check receive responder_ephemeral_pubkey = privtopub(tv['receiver_ephemeral_private_key']) auth_msg_cipher = tv['auth_ciphertext'] auth_msg = responder.ecc.ecies_decrypt(auth_msg_cipher) assert auth_msg[65:] == tv['auth_plaintext'][65:] # starts with non deterministic k responder.decode_authentication(auth_msg_cipher) auth_ack_msg = responder.create_auth_ack_message(responder_ephemeral_pubkey, tv['receiver_nonce'], responder.remote_token_found ) assert auth_ack_msg == tv['authresp_plaintext'] auth_ack_msg_cipher = responder.encrypt_auth_ack_message(auth_ack_msg, responder.remote_pubkey) # set auth ack msg cipher (needed later for mac calculation) responder.auth_ack = tv['authresp_ciphertext'] responder.setup_cipher() assert responder.ecdhe_shared_secret == tv['ecdhe_shared_secret'] assert len(responder.token) == len(tv['token']) assert responder.token == tv['token'] assert responder.aes_secret == tv['aes_secret'] assert responder.mac_secret == tv['mac_secret'] assert responder.initiator_nonce == tv['initiator_nonce'] assert responder.responder_nonce == tv['receiver_nonce'] assert responder.auth_init == tv['auth_ciphertext'] assert responder.auth_ack == tv['authresp_ciphertext'] # test values are from initiator perspective? assert responder.ingress_mac.digest() == tv['initial_egress_MAC'] assert responder.ingress_mac.digest() == tv['initial_egress_MAC'] assert responder.egress_mac.digest() == tv['initial_ingress_MAC'] assert responder.egress_mac.digest() == tv['initial_ingress_MAC'] r = responder.decrypt(tv['initiator_hello_packet']) # unpack hello packet import struct import rlp import rlp.sedes as sedes from rlp.codec import consume_item header = r['header'] frame_length = struct.unpack('>I', '\x00' + header[:3])[0] header_sedes = sedes.List([sedes.big_endian_int, sedes.big_endian_int]) header_data = rlp.decode(header[3:], strict=False, sedes=header_sedes) print 'header', repr(header_data) # frame frame = r['frame'] # normal: rlp(packet-type) [|| rlp(packet-data)] || padding packet_type, end = consume_item(frame, start=0) packet_type = rlp.decode(frame, sedes=sedes.big_endian_int, strict=False) print 'packet_type', repr(packet_type) # decode hello body _sedes_capabilites_tuple = sedes.List([sedes.binary, sedes.big_endian_int]) structure = [ ('version', sedes.big_endian_int), ('client_version', sedes.big_endian_int), ('capabilities', sedes.CountableList(_sedes_capabilites_tuple)), ('listen_port', sedes.big_endian_int), ('nodeid', sedes.binary) ] hello_sedes = sedes.List([x[1] for x in structure]) frame_data = rlp.decode(frame[end:], sedes=hello_sedes) frame_data = dict((structure[i][0], x) for i, x in enumerate(frame_data)) print 'frame', frame_data