def peek_message(self, input_buffer): """ Peeks message from input frame :param input_buffer: input buffer :return: tuple (flag if full message is received, message type) """ if not isinstance(input_buffer, InputBuffer): raise ValueError("Expected type InputBuffer") if self._full_message_received: raise ValueError("Get full message before trying to peek another one") if not self._receiving_frame and input_buffer.length >= eth_common_constants.FRAME_HDR_TOTAL_LEN: enc_header_bytes = input_buffer.remove_bytes(eth_common_constants.FRAME_HDR_TOTAL_LEN) header_bytes = self._rlpx_cipher.decrypt_frame_header(enc_header_bytes) body_size, protocol_id, sequence_id, total_payload_len = frame_utils.parse_frame_header(header_bytes) self._current_frame_body_size = body_size self._current_frame_protocol_id = protocol_id self._current_frame_size = frame_utils.get_full_frame_size(body_size) self._current_frame_enc_body_size = self._current_frame_size - eth_common_constants.FRAME_HDR_TOTAL_LEN self._current_frame_sequence_id = sequence_id if sequence_id == 0 and total_payload_len is not None: self._chunked_frames_in_progress = True self._chunked_frames_total_body_size = total_payload_len self._receiving_frame = True if self._receiving_frame and input_buffer.length >= self._current_frame_enc_body_size: frame_enc_body_bytes = input_buffer.remove_bytes(self._current_frame_enc_body_size) body = self._rlpx_cipher.decrypt_frame_body(frame_enc_body_bytes, self._current_frame_body_size) msg_type_is_expected = not self._chunked_frames_in_progress or self._current_frame_sequence_id == 0 payload, msg_type = frame_utils.parse_frame_body(body, msg_type_is_expected) if msg_type_is_expected: self._current_msg_type = msg_type self._payload_buffer.add_bytes(bytearray(rlp_utils.str_to_bytes(payload))) if not self._chunked_frames_in_progress: self._full_message_received = True else: self._chunked_frames_body_size_received += len(body) if self._chunked_frames_body_size_received > self._chunked_frames_total_body_size: raise ParseError("Expected total body length for frame message is {0} but received {1}" .format(self._chunked_frames_total_body_size, self._chunked_frames_body_size_received)) if self._chunked_frames_body_size_received == self._chunked_frames_total_body_size: self._full_message_received = True self._receiving_frame = False return self._full_message_received, self._current_msg_type
def get_raw_public_key(self): """ Raw public ley user by instance of ECCx :return: public key """ if self.pubkey_x and self.pubkey_y: return rlp_utils.str_to_bytes(self.pubkey_x + self.pubkey_y) return self.pubkey_x + self.pubkey_y
def get_raw_private_key(self): """ Raw private key used by instance of ECCx :return: private key """ if self.privkey: return rlp_utils.str_to_bytes(self.privkey) return self.privkey
def serialize(self): cmd_id = rlp_utils.str_to_bytes(chr(self.msg_type)) encoded_payload = self._serialize_rlp_payload() signed_data = eth_common_utils.keccak_hash(cmd_id + encoded_payload) signature = crypto_utils.sign(signed_data, self._private_key) assert len(signature) == eth_common_constants.SIGNATURE_LEN mdc = eth_common_utils.keccak_hash(signature + cmd_id + encoded_payload) assert len(mdc) == eth_common_constants.MDC_LEN msg_bytes = bytearray(mdc + signature + cmd_id + encoded_payload) self._set_raw_bytes(msg_bytes)
def encrypt(cls, data, raw_public_key, shared_mac_data=""): """ ECIES Encrypt, where P = recipient public key is: 1) generate r = random value 2) generate shared-secret = kdf( ecdhAgree(r, P) ) 3) generate R = rG [same op as generating a public key] 4) send 0x04 || R || AsymmetricEncrypt(shared-secret, plaintext) || tag currently used by go: ECIES_AES128_SHA256 = &ECIESParams{ Hash: sha256.New, hashAlgo: crypto.SHA256, Cipher: aes.NewCipher, BlockSize: aes.BlockSize, KeyLen: 16, } :param data: data to encrypt :param raw_public_key: public key used of encryption :param shared_mac_data: shared mac :return: encrypted data """ if not data: raise ValueError("Data is required") if len(raw_public_key) != eth_common_constants.PUBLIC_KEY_LEN: raise ValueError( "Public key of len {0} is expected but was {1}".format( eth_common_constants.PUBLIC_KEY_LEN, len(raw_public_key))) # 1) generate r = random value ephem = ECCx() # 2) generate shared-secret = kdf( ecdhAgree(r, P) ) pubkey_x = raw_public_key[:eth_common_constants.PUBLIC_KEY_X_Y_LEN] pubkey_y = raw_public_key[eth_common_constants.PUBLIC_KEY_X_Y_LEN:] key_material = ephem.raw_get_ecdh_key(pubkey_x=pubkey_x, pubkey_y=pubkey_y) key = crypto_utils.ecies_kdf(key_material, eth_common_constants.SHARED_KEY_LEN) assert len(key) == eth_common_constants.SHARED_KEY_LEN key_enc, key_mac = key[:eth_common_constants.ENC_KEY_LEN], key[ eth_common_constants.ENC_KEY_LEN:] key_mac = hashlib.sha256(key_mac).digest() # 3) generate R = rG [same op as generating a public key] ephem_pubkey = ephem.get_raw_public_key() # encrypt iv = pyelliptic.Cipher.gen_IV(eth_common_constants.ECIES_CIPHER_NAME) assert len(iv) == eth_common_constants.IV_LEN ctx = pyelliptic.Cipher(key_enc, iv, eth_common_constants.CIPHER_ENCRYPT_DO, eth_common_constants.ECIES_CIPHER_NAME) cipher_text = ctx.ciphering(data) assert len(cipher_text) == len(data) # 4) send 0x04 || R || AsymmetricEncrypt(shared-secret, plaintext) || tag msg = rlp_utils.ascii_chr(eth_common_constants.ECIES_HEADER ) + ephem_pubkey + iv + cipher_text # the MAC of a message (called the tag) as per SEC 1, 3.5. tag = pyelliptic.hmac_sha256( key_mac, msg[eth_common_constants.ECIES_HEADER_LEN + eth_common_constants.PUBLIC_KEY_LEN:] + rlp_utils.str_to_bytes(shared_mac_data)) assert len(tag) == eth_common_constants.MAC_LEN msg += tag assert len( msg) - eth_common_constants.ECIES_ENCRYPT_OVERHEAD_LENGTH == len( data) return msg
def mac_ingress(self, data=b""): data = rlp_utils.str_to_bytes(data) self._ingress_mac.update(data) return self._ingress_mac.digest()