def send_handshake_finished( self, handshake_keys: HandshakeKeys, handshake_hash: bytes ): hh_payload = HandshakeFinishedHandshakePayload.generate( handshake_keys.client_handshake_traffic_secret, handshake_hash ) hh_header = HandshakeHeader( HandshakeFinishedHandshakePayload.default_htype(), len(hh_payload.verify_data), ) plaintext_payload = b"".join( [hh_header.serialize(), hh_payload.verify_data, b"\x16"] ) record_header = RecordHeader(rtype=0x17, size=len(plaintext_payload) + 16) encryptor = AES.new( handshake_keys.client_key, AES.MODE_GCM, handshake_keys.client_iv ) encryptor.update(record_header.serialize()) ciphertext_payload = encryptor.encrypt(plaintext_payload) tag = encryptor.digest() w = Wrapper(record_header=record_header, payload=ciphertext_payload + tag) self.socket.send(w.serialize())
def __init__(self, domain: bytes, public_key_bytes: bytes): self.record_header = RecordHeader( rtype=0x16, legacy_proto_version=0x0301, size=0 ) self.handshake_header = HandshakeHeader(message_type=0x01, size=0) self.client_version = 0x0303 self.client_random = secrets.token_bytes(32) self.session_id = secrets.token_bytes(32) # hard coded for now... # 13 01 - assigned value for TLS_AES_128_GCM_SHA256 # 13 02 - assigned value for TLS_AES_256_GCM_SHA384 # 13 03 - assigned value for TLS_CHACHA20_POLY1305_SHA256 self.cipher_suites = bytes.fromhex("130113021303") extensions = [ ExtensionServerName(domain), ExtensionSupportedGroups(), ExtensionSignatureAlgorithms(), ExtensionKeyShare(public_key_bytes), ExtensionPSKKeyExchangeModes(), ExtensionSupportedVersions(), ] self.extension_data = b"".join([ex.serialize() for ex in extensions]) self.extension_length = len(self.extension_data)
def deserialize(klass, byte_stream: BufferedReader): rh = RecordHeader.deserialize(byte_stream.read(5)) hh = HandshakeHeader.deserialize(byte_stream.read(4)) server_version, = struct.unpack(">h", byte_stream.read(2)) server_random = byte_stream.read(32) session_id_length, = struct.unpack("b", byte_stream.read(1)) session_id = byte_stream.read(session_id_length) cipher_suite, = struct.unpack(">h", byte_stream.read(2)) _compression_mode = byte_stream.read(1) extensions_length, = struct.unpack(">h", byte_stream.read(2)) extensions = [] while extensions_length > 0: assigned_value, = struct.unpack(">h", byte_stream.peek()[:2]) extension_klass = EXTENSIONS_MAP[assigned_value] res = extension_klass.deserialize(byte_stream) extensions.append(res) extensions_length -= res.size + 2 return ServerHello( rh=rh, hh=hh, server_version=server_version, server_random=server_random, session_id=session_id, cipher_suite=cipher_suite, extensions=extensions, )
def _recv(self): bytes_buffer = BufferedReader(BytesIO(self.socket.recv(4096))) if len(bytes_buffer.peek()) < 4: bytes_buffer = BufferedReader( BytesIO(bytes_buffer.read() + self.socket.recv(4096)) ) res = self.__recv(bytes_buffer) # while res[-1] != 0x17: # count =1 while True: if res[-1] == 0x17: yield res[:-1] if res[-1] == 0x16: plaintext_buffer = BufferedReader(BytesIO(res[:-1])) while plaintext_buffer.peek(): hh = HandshakeHeader.deserialize(plaintext_buffer.read(4)) hh_payload_buffer = plaintext_buffer.read(hh.size) # print("recv", len(hh_payload_buffer), hh.size, hh) # print(res[:-1]) hh_payload = HANDSHAKE_HEADER_TYPES[hh.message_type].deserialize( hh_payload_buffer ) # print(hh_payload) if type(hh_payload) is NewSessionTicketHandshakePayload: self.session_tickets.append(hh_payload) if len(bytes_buffer.peek()) < 4: bytes_buffer = BufferedReader( BytesIO(bytes_buffer.read() + self.socket.recv(4096)) ) res = self.__recv(bytes_buffer)
def recv_server_encrypted_extensions(self, bytes_buffer) -> bytes: def parse_wrapper(bytes_buffer): wrapper = Wrapper.deserialize(bytes_buffer) while wrapper.record_header.size > len(wrapper.payload): wrapper.payload += self.socket.recv( wrapper.record_header.size - len(wrapper.payload)) recdata = wrapper.record_header.serialize() authtag = wrapper.auth_tag ciphertext = wrapper.encrypted_data decryptor = AES.new( self.handshake_keys.server_key, AES.MODE_GCM, xor_iv(self.handshake_keys.server_iv, self.handshake_recv_counter), ) decryptor.update(recdata) plaintext = decryptor.decrypt(bytes(ciphertext)) self.handshake_recv_counter += 1 decryptor.verify(authtag) return plaintext[:-1] plaintext = bytearray() plaintext += parse_wrapper(bytes_buffer) plaintext_buffer = BufferedReader(BytesIO(plaintext)) # TODO: change this to walrus operator while True: if len(plaintext_buffer.peek()) < 4: res = parse_wrapper(bytes_buffer) plaintext += res plaintext_buffer = BufferedReader( BytesIO(plaintext_buffer.peek() + res)) hh = HandshakeHeader.deserialize(plaintext_buffer.read(4)) hh_payload_buffer = plaintext_buffer.read(hh.size) while len(hh_payload_buffer) < hh.size: res = parse_wrapper(bytes_buffer) plaintext += res plaintext_buffer = BufferedReader( BytesIO(plaintext_buffer.peek() + res)) prev_len = len(hh_payload_buffer) hh_payload_buffer = hh_payload_buffer + plaintext_buffer.read( hh.size - prev_len) hh_payload = HANDSHAKE_HEADER_TYPES[hh.message_type].deserialize( hh_payload_buffer) if type(hh_payload) is HandshakeFinishedHandshakePayload: break return plaintext
class ClientHello: def __init__(self, domain: bytes, public_key_bytes: bytes): self.record_header = RecordHeader(rtype=0x16, legacy_proto_version=0x0301, size=0) self.handshake_header = HandshakeHeader(message_type=0x01, size=0) self.client_version = 0x0303 self.client_random = secrets.token_bytes(32) self.session_id = secrets.token_bytes(32) # hard coded for now... # 13 01 - assigned value for TLS_AES_128_GCM_SHA256 # 13 02 - assigned value for TLS_AES_256_GCM_SHA384 # 13 03 - assigned value for TLS_CHACHA20_POLY1305_SHA256 self.cipher_suites = bytes.fromhex("130113021303") self.extensions = [ ExtensionServerName(domain), ExtensionSupportedGroups(), ExtensionSignatureAlgorithms(), ExtensionKeyShare(public_key_bytes), ExtensionPSKKeyExchangeModes(), ExtensionSupportedVersions(), ] def add_extension(self, extension: ClientHelloExtension): self.extensions.append(extension) def calc_record_size(self) -> int: data = self._serialize() self.record_header.size = len(data) - 5 self.handshake_header.size = self.record_header.size - 4 def _serialize(self) -> bytes: self.extension_data = b"".join( [ex.serialize() for ex in self.extensions]) self.extension_length = len(self.extension_data) return b"".join([ self.record_header.serialize(), self.handshake_header.serialize(), struct.pack(">h", self.client_version), struct.pack("32s", self.client_random), struct.pack("b32s", len(self.session_id), self.session_id), struct.pack( f">h{len(self.cipher_suites)}s", len(self.cipher_suites), self.cipher_suites, ), struct.pack("bb", 1, 0), # compression mode struct.pack(">h", self.extension_length), self.extension_data, ]) def serialize(self) -> bytes: self.calc_record_size() return self._serialize()
def test_handshake_headers(): plaintext = b"\x08\x00\x00\x02\x00\x00\x0b\x00\x0c\x1f\x00\x00\x0c\x1b\x00\x07W0\x82\x07S0\x82\x06;\xa0\x03\x02\x01\x02\x02\x10\x03}\xe4\x06\xf9@+$3\xc5\x95\xbc\x1c\xba\x8f\x880\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000u1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x150\x13\x06\x03U\x04\n\x13\x0cDigiCert Inc1\x190\x17\x06\x03U\x04\x0b\x13\x10www.digicert.com1402\x06\x03U\x04\x03\x13+DigiCert SHA2 Extended Validation Server CA0\x1e\x17\r181030000000Z\x17\r201103120000Z0\x81\xcf1\x1d0\x1b\x06\x03U\x04\x0f\x0c\x14Private Organization1\x130\x11\x06\x0b+\x06\x01\x04\x01\x827<\x02\x01\x03\x13\x02US1\x190\x17\x06\x0b+\x06\x01\x04\x01\x827<\x02\x01\x02\x13\x08Delaware1\x100\x0e\x06\x03U\x04\x05\x13\x0747108751\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\x08\x13\nCalifornia1\x160\x14\x06\x03U\x04\x07\x13\rSan Francisco1\x190\x17\x06\x03U\x04\n\x13\x10Cloudflare, Inc.1\x170\x15\x06\x03U\x04\x03\x13\x0ecloudflare.com0\x82\x01\"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\x9b\xaaW1\x80\x0815\xbf,\xee\\r\xae\xf9\x16\xdf\x01\xfe\xd9\xcf\xf5\xde=\xe4\xc4J\xa4\xdb\x85m\xb4]\xed2\xee\x98Lfl6\xe1\xdeM\x02\x07\xf6wB.\xbb\xcdG4\xa5\x9e\xba\xd9H5N\x8b\x81\xe9\xe9\xe46\xa6zo\x90t\xf0\x88;h\x9d\xa2\x7fC\xfdZ\xeb\x0e\x98\xbd\x9e#\xb27\x049m\x89~\xe8\x17:B]\x17\xe4\x83!\xf4}\xa2\xf7v\x93y\xe3\xa3_;\xc1Z\x90\xa2a\xb0\x89\xcc\x00U\x8a\x13IY\x06\xe5\xb3\x14\x03N\xfa\xa4tw\x11I\x12\x83B\x07Y\x02\xbaI\x14Qd\x9d[\xca\xa3\xd5\x06\x98\x95\xad\x00\x19B\x1a\xed\xc7\x1a\x96m.\xe7\xf5\xaa\xf4lz\xf3\xf8k]s\x07\xf0\xa0\xe0\x13\x1dv\xddh2p}1\xb6\xda\x96$\x98Q_\x12d;`\xaa\x8d\x0b\xeeHu\x8d\xbe`\xf5\xb8\x86\xd5\xb2\xe8x\tu\xca\x88XM!\x00\xa0\x8c\xe87F\x1d\x98P2-\x89$\x91\x06\xa5;\xbc\xd42w\xfeJC\xec|\xb9\x02\x03\x01\x00\x01\xa3\x82\x03\x820\x82\x03~0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14=\xd3P\xa5\xd6\xa0\xad\xee\xf3J`\ne\xd3!\xd4\xf8\xf8\xd6\x0f0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14\xbe\xb5\xc4\xce\r\xda\xe0T\xfb`S58\x07=;\xa4\x8a\x1e\xe20-\x06\x03U\x1d\x11\x04&0$\x82\x0ecloudflare.com\x82\x12www.cloudflare.com0\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x05\xa00\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x020u\x06\x03U\x1d\x1f\x04n0l04\xa02\xa00\x86.http://crl3.digicert.com/sha2-ev-server-g2.crl04\xa02\xa00\x86.http://crl4.digicert.com/sha2-ev-server-g2.crl0K\x06\x03U\x1d \x04D0B07\x06\t`\x86H\x01\x86\xfdl\x02\x010*0(\x06\x08+\x06\x01\x05\x05\x07\x02\x01\x16\x1chttps://www.digicert.com/CPS0\x07\x06\x05g\x81\x0c\x01\x010\x81\x88\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04|0z0$\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x18http://ocsp.digicert.com0R\x06\x08+\x06\x01\x05\x05\x070\x02\x86Fhttp://cacerts.digicert.com/DigiCertSHA2ExtendedValidationServerCA.crt0\x0c\x06\x03U\x1d\x13\x01\x01\xff\x04\x020\x000\x82\x01\x7f\x06\n+\x06\x01\x04\x01\xd6y\x02\x04\x02\x04\x82\x01o\x04\x82\x01k\x01i\x00w\x00\xa4\xb9\t\x90\xb4\x18X\x14\x87\xbb\x13\xa2\xccgp\n<5\x98\x04\xf9\x1b\xdf\xb8\xe3w\xcd\x0e\xc8\r\xdc\x10\x00\x00\x01f\xc6\x88{\xbf\x00\x00\x04\x03\x00H0F\x02!\x00\xc9\x12\x00\xdb\xcaxb#m\xaeQ\x0ee\xd5\xbdB\x1d\xec\x14\xd7o\xa2S\x02\x95\xe6\xf7\x06\xdc\xfc\x89\x9e\x02!\x00\xe7W\xf5\xbd]Z=\x9e\xae?0\n\x99\x13\xd6\x99\xbc\xd87\x0b\x83TXJ\xcc\xee\xf0<\x1c\xc6\xb3*\x00v\x00\x87u\xbf\xe7Y|\xf8\x8cC\x99_\xbd\xf3n\xffV\x8dGV6\xffJ\xb5`\xc1\xb4\xea\xff^\xa0\x83\x0f\x00\x00\x01f\xc6\x88}\x8e\x00\x00\x04\x03\x00G0E\x02!\x00\xacF43\x9e\xcd\xe6'a\x0e\x04R\xcb\x19%m\xfe\xe9\x88\xb9\xf2S[5V\x11\x8c\x03`-\x9e\xcf\x02 \\\xca\xaa\xdc\xb5\x1b\xb7\x0eX\xdb\x03\xa7&\x9d\xc4\x1bE\x9b*s\x893\x97\xee\xf3\xea\xf3\x15\xa5\xcd\xed?\x00v\x00\xeeK\xbd\xb7u\xce`\xba\xe1Bi\x1f\xab\xe1\x9ef\xa3\x0f~_\xb0r\xd8\x83\x00\xc4{\x89z\xa8\xfd\xcb\x00\x00\x01f\xc6\x88|\x0c\x00\x00\x04\x03\x00G0E\x02!\x00\xf0\x9b\xe0\x08\x9c\x0cpk\xf9\x88OU\xf8\x8c\x19\xd7\xe9\x8e\xbbi\x97\x7f\x8d}\xc9c\x92\r\xb5h7\xf9\x02 :/p\x94`\xbc5\x00Y\xa8\xafb\xb5[X>0\xdb#d\xf1$\xf5\xa2o\xfb\xdff\xda]\xb7B0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x88\xdd\x9b\xebN\x84\xb6-\xdc\x0c\xe5\x132M\xf9Q\x94\xae0\x92\x8e\xaf\xfd\x81Z\x86V|kR\xf19\x98\x16Oc@,\xfag\x00Ya\x94\xcb\x8c\xd5\x12H6|]\xa0\x95\xfb/0 j\xd8\x1e'\xc4u\n*\xfd\xaf\xaa;\xf8\x8e\xf8>\x83\xe598l\xc7\x87\x18\xb57\x82\x85\xcd0I\xb2\xd5\x129\r\xb6\x16\x1c\x95\x1aGyX\x9c\xb7\xe1\xe8\xfb\xa6\xbf\xc7\xa8\xee\x9f\xceC\xdf\xe9s\xff\xc5\n\xac\xb1\x9f\xdd\xab\xd7\xb7/rT\xf2\xe4\xed\xcb\\9\xb31\x81\xc0\x0f\xef\x91'\x9a\ra\x9f\xd3\xcd#*li\xcf\x0e\x0cS\x04~IK\\\xe9\xc9\x9dDT\x99\xa7\\\x95\x06\x0bn\x83L\x0b^\xed\x02D\x10\x88\xff\xf5gH\xd1J!@\xcf\xbe\xa1\xe1\xba|.\xd10U\xf0\xbd0\x1c~\x05]B\x97R\x00\xb8(\xfdWB\xdc\xa5\x8d\x14\xd1A\x06/\xf4+\x1f\xf0\xc5\xc1\xc9\xb0y\xa6E>\xb0\x8b%S\xd0}e\xfb\xb8n\xc9G/A\xc6&S\x00\x00\x00\x04\xba0\x82\x04\xb60\x82\x03\x9e\xa0\x03\x02\x01\x02\x02\x10\x0cy\xa9D\xb0\x8c\x11\x95 \x92a_\xe2k\x1d\x830\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x000l1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x150\x13\x06\x03U\x04\n\x13\x0cDigiCert Inc1\x190\x17\x06\x03U\x04\x0b\x13\x10www.digicert.com1+0)\x06\x03U\x04\x03\x13\"DigiCert High Assurance EV Root CA0\x1e\x17\r131022120000Z\x17\r281022120000Z0u1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x150\x13\x06\x03U\x04\n\x13\x0cDigiCert Inc1\x190\x17\x06\x03U\x04\x0b\x13\x10www.digicert.com1402\x06\x03U\x04\x03\x13+DigiCert SHA2 Extended Validation Server CA0\x82\x01\"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xd7S\xa4\x04Q\xf8\x99\xa6\x16HKg'\xaa\x93I\xd09\xed\x0c\xb0\xb0\x00\x87\xf1g(\x86\x85\x8c\x8ec\xda\xbc\xb1@8\xe2\xd3\xf5\xec\xa5\x05\x18\xb8=>\xc5\x99\x172\xec\x18\x8c\xfa\xf1\x0c\xa6d!\x85\xcb\x07\x104\xb0R\x88+\x1fh\x9b\xd2\xb1\x8f\x12\xb0\xb3\xd2\xe7\x88\x1f\x1f\xef8wTS_\x80y?.\x1a\xaa\xa8\x1eK+\r\xab\xb7c\xb95\xb7}\x14\xbcYK\xdfQJ\xd2\xa1\xe2\x0c\xe2\x90\x82\x87j\xae\xea\xd7d\xd6\x98U\xe8\xfd\xaf\x1aPlT\xbc\x11\xf2\xfdJ\xf2\x9d\xbb\x7f\x0e\xf4\xd5\xbe\x8e\x16\x89\x12U\xd8\xc0q4\xee\xf6\xdc-\xec\xc4\x87%\x86\x8d\xd8!\xe4\xb0M\x0c\x89\xdc9&\x17\xdd\xf6\xd7\x94\x85\xd8\x04!p\x9doo\xff\\\xba\x19\xe1E\xcbVW(~\x1c\rAW\xaa\xb7\xb8'\xbb\xb1\xe4\xfa*\xef!#u\x1a\xad-\x9b\x865\x8c\x9cw\xb5s\xad\xd8\x94-\xe4\xf3\x0c\x9d\xee\xc1Nb~\x17\xc0q\x9e,\xde\xf1\xf9\x10(\x193\x02\x03\x01\x00\x01\xa3\x82\x01I0\x82\x01E0\x12\x06\x03U\x1d\x13\x01\x01\xff\x04\x080\x06\x01\x01\xff\x02\x01\x000\x0e\x06\x03U\x1d\x0f\x01\x01\xff\x04\x04\x03\x02\x01\x860\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x0204\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04(0&0$\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x18http://ocsp.digicert.com0K\x06\x03U\x1d\x1f\x04D0B0@\xa0>\xa0<\x86:http://crl4.digicert.com/DigiCertHighAssuranceEVRootCA.crl0=\x06\x03U\x1d \x0460402\x06\x04U\x1d \x000*0(\x06\x08+\x06\x01\x05\x05\x07\x02\x01\x16\x1chttps://www.digicert.com/CPS0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14=\xd3P\xa5\xd6\xa0\xad\xee\xf3J`\ne\xd3!\xd4\xf8\xf8\xd6\x0f0\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14\xb1>\xc3i\x03\xf8\xbfG\x01\xd4\x98&\x1a\x08\x02\xefcd+\xc30\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x01\x01\x00\x9d\xb6\xd0\x90\x86\xe1\x86\x02\xed\xc5\xa0\xf04\x1ct\xc1\x8dv\xcc\x86\n\xa8\xf0J\x8aB\xd6?\xc8\xa9M\xad|\x08\xad\xe6\xb6P\xb8\xa2\x1aM\x88\x07\xb1)!\xdc\xe7\xda\xc6<!\xe0\xe3\x11Ip\xacz\x1d\x01\xa4\xca\x11:W\xab}W*@t\xfd\xd3\x1d\x85\x18P\xdfWGu\xa1}U .G7Pr\x8c\x7f\x82\x1b\xd2b\x8f-\x03Z\xda\xc3\xc8\xa1\xce,R\xa2\x00c\xebs\xbaq\xc8I'#\x97d\x85\x9e8\x0e\xadch<\xbaR\x81Xy\xa3,\x0c\xdf\xdem\xeb1\xf2\xba\xa0|l\xf1,\xd4\xe1\xbdw\x847\x03\xce2\xb5\xc8\x9a\x81\x1aJ\x92N;F\x9a\x85\xfe\x83\xa2\xf9\x9e\x8c\xa3\xcc\r^\xb3=\xcf\x04x\x8f\x14\x14{2\x9c\xc7\x00\xa6\\\xc4\xb5\xa1U\x8dZVh\xa4\"p\xaa<\x81q\xd9\x9d\xa8E;\xf4\xe5\xf6\xa2Q\xdd\xc7{b\xe8o\x0ct\xeb\xb8\xda\xf8\xbf\x87\ryP\x91\x90\x9b\x18;\x91Y'\xf15(\x13\xab&~\xd5\xf7z\x00\x00\x0f\x00\x01\x04\x08\x04\x01\x00\x17\xe2L\x95\xdb\xce\xa4\x96\xc8\xd6\x9b\xd4\x1c\x00\xc3\xb4\xfa\xdfY\"i\x13\xf7\x8e%\xc0\x8d),1\xcfo\xfe\xbd%\xa8p\xdc\x8c7P,\xdc\xd3O\xa7ocH\\\xf0\x9f\xb5[\xcf\x15\x08|Y\x12!\xfd\x03\xf6mD\xcab\xb3b9\xf3;tS\xee:\x93\x9a\x81\xfa\xd3Wv\"}\xbfE\xff\x8b\xb8\xf3\xf5\xdc\x0f?\x1e\x8f\x8c5\x10\xd5\xcc\xb4(^\xf5\xaa\xcb\xbe\x9f\x97\xdbe\xfc\x86('\xdc\x04\x8b\r\xdcV\xf4\x17O\n\xae|l\x06\xcbM&\x147\x10N\xe6\xb4\\\xbe\xae\xa7\xba\xca=\xbf*\x9f\xc1\xd1\xba\xeds\xa5\xfel\xbf\x1e\xe6r\x17\xdb\xa4x\x9b\x8a0)\xa31ef\x83\xec`\xa8\xb8-\xe2\x0f`\xae\x11\x03\xd2\x15n\x9b%\xe9P&\\3D\x96\xc6b!\x0f@}=Ft1\xfe\x0e\xccK\xe1\xdaE\x1e\xee\xa1\x95i\x06\xa6\x9b@k^\xff<\x10\x85\xbb\x16\"\xcf;i\x8ft\x10\xf3(\xcc\xc7!\xe9\xd8\x93m7s\xf7\xb1J\xcd-\x14\x00\x00 \xe4\x85\xf1\x7fL\x7f\x91Z\x03\xc08\xa3\x88\x83{\x18\xb2\x98Q\x13x\xb0_\xe60A\x0e:+\xd6Hp\x16" plaintext_buffer = BytesIO(plaintext) # TODO: change this to walrus operator while plaintext_buffer.tell() < len(plaintext) - 1: hh = HandshakeHeader.deserialize(plaintext_buffer.read(4)) hh_payload_buffer = plaintext_buffer.read(hh.size) hh_payload = HANDSHAKE_HEADER_TYPES[hh.message_type].deserialize( hh_payload_buffer) assert issubclass(type(hh_payload), HandshakePayload) assert len(hh_payload.data) == hh.size
def recv_server_encrypted_extensions(self, bytes_buffer) -> bytes: def parse_wrapper(bytes_buffer): wrapper = Wrapper.deserialize(bytes_buffer) while wrapper.record_header.size > len(wrapper.payload): wrapper.payload += self.socket.recv( wrapper.record_header.size - len(wrapper.payload) ) recdata = wrapper.record_header.serialize() authtag = wrapper.auth_tag ciphertext = wrapper.encrypted_data decryptor = AES.new( self.handshake_keys.server_key, AES.MODE_GCM, xor_iv(self.handshake_keys.server_iv, self.handshake_recv_counter), ) decryptor.update(recdata) plaintext = decryptor.decrypt(bytes(ciphertext)) self.handshake_recv_counter += 1 decryptor.verify(authtag) return plaintext[:-1] plaintext = bytearray() plaintext += parse_wrapper(bytes_buffer) plaintext_buffer = BufferedReader(BytesIO(plaintext)) # TODO: change this to walrus operator while True: # print("difference 1", plaintext_buffer.tell() < len(plaintext)) hh = HandshakeHeader.deserialize(plaintext_buffer.read(4)) # print("hh", hh) hh_payload_buffer = plaintext_buffer.read(hh.size) while len(hh_payload_buffer) < hh.size: res = parse_wrapper(bytes_buffer) plaintext += res plaintext_buffer = BufferedReader( BytesIO(plaintext_buffer.peek() + res) ) prev_len = len(hh_payload_buffer) hh_payload_buffer = hh_payload_buffer + plaintext_buffer.read( hh.size - prev_len ) # # print("difference", hh.size - len(hh_payload_buffer)) # new_bytes = parse_wrapper(bytes_buffer) # index = plaintext_buffer.tell() # plaintext_buffer.seek(0, 2) # plaintext_buffer.write(new_bytes) # plaintext_buffer.seek(index) # hh_payload_buffer = hh_payload_buffer + plaintext_buffer.read(hh.size - len(hh_payload_buffer)) # print("updated plaintext_buffer!!!") # print(bytes(plaintext_buffer.getbuffer())) # raise Exception("We need more data!!!") hh_payload = HANDSHAKE_HEADER_TYPES[hh.message_type].deserialize( hh_payload_buffer ) # print("hh_payload", len(hh_payload.data), hh, type(hh_payload)) if type(hh_payload) is HandshakeFinishedHandshakePayload: break # print("done!!") return plaintext
def test_HandshakeHeader(): hh = HandshakeHeader.deserialize(bytes.fromhex("02000076")) assert hh.size == 0x76 assert hh.message_type == 0x02
def test_handshake_header_serialize(): packet = bytes.fromhex("14000020") hh = HandshakeHeader.deserialize(packet) assert hh.serialize() == packet