from socket import socket import socketserver import argparse from core import connection_engine, connection_handle_socket import socket def banner(): print(''' ___ ___ ___ _ _ _ __ ___ ___ ___ _ __ _ __ / __|/ _ \/ __| | | | '__/ _ \/ __/ _ \| '_ \| '_ \ \__ \ __/ (__| |_| | | | __/ (_| (_) | | | | | | | |___/\___|\___|\__,_|_| \___|\___\___/|_| |_|_| |_| CLIENT ''') if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("-a", "--address", required=True, help="remote ip address") parser.add_argument( "-p", "--port", help="server running port", type=int, required=True) parser.add_argument("-d", "--dump", action="store_true", default=False, help="dump payload of packet") parser.add_argument("-e", "--encrypt", action="store_true", default=False, help="enable secure encrypted connection") args = parser.parse_args() HOST, PORT = args.address, args.port banner() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) handler = connection_handle_socket(s, "master", args.dump) connection_engine(handler, "master", args.encrypt)
import base64 from dataclasses import dataclass from enum import Enum from Crypto.Cipher import AES import random from telnetlib import SE import libscrc def bytes_xor_16(bytes1, bytes2): v1 = int.from_bytes(bytes1, 'big') v2 = int.from_bytes(bytes2, 'big') v3 = v1 ^ v2 return (v3).to_bytes(16, 'big') def secure_encrypt(key, plain): aes = AES.new(key=key, mode=AES.MODE_ECB) return aes.encrypt(plain) def secure_encrypt_packet(key, plain, nonce): aes = AES.new(key=key, mode=AES.MODE_CCM, nonce=nonce) return aes.encrypt(plain) def secure_decrypt_packet(key, plain, nonce): aes = AES.new(key=key, mode=AES.MODE_CCM, nonce=nonce) return aes.decrypt(plain) def secure_confirm(key, r, p1, p2): return secure_encrypt(key, bytes_xor_16(secure_encrypt(key, bytes_xor_16(r, p1)), p2)) class PktOpcode(Enum): HELLO = 1 SC_REQ = 2 SC_RSP = 3 M_CONFIRM = 4 S_CONFIRM = 5 M_RANDOM = 6 S_RANDOM = 7 DATA = 8 class connection_handle: def __init__(self, type) -> None: self.type = type def send(self, data) -> None: pass def recv(self, length) -> bytes: return b"" def dump_packet(prefix: str, pkt: bytes, logfile: str): log_content = "" print(prefix + "\t", end="") log_content += prefix + "\t" for i in range(len(pkt)): d = pkt[i] print(hex(d)[2:].rjust(2, '0'), end="") log_content += hex(d)[2:].rjust(2, '0') if (i + 1) % 16 == 0 and i + 1 != len(pkt): print("\n\t", end="") log_content += "\n\t" else: print(" ", end="") log_content += " " print("") log_content += "\n" with open(logfile, "a") as f: f.write(log_content) class connection_handle_socket(connection_handle): def __init__(self, s, role, dump) -> None: super().__init__("socket") self.socket = s self.role = role self.dump = dump self.dumpfile = self.role + ".txt" def send(self, data) -> None: self.socket.send(data) if self.dump: dump_packet(">", data, self.dumpfile) def recv(self, length) -> bytes: data = self.socket.recv(length) if self.dump: dump_packet("<", data, self.dumpfile) return data class connection_handle_request(connection_handle): def __init__(self, request, role, dump) -> None: super().__init__("request") self.request = request self.role = role self.dump = dump self.dumpfile = self.role + ".txt" def send(self, data) -> None: self.request.sendall(data) if self.dump: dump_packet(">", data, self.dumpfile) def recv(self, length) -> bytes: data = self.request.recv(length) if self.dump: dump_packet("<", data, self.dumpfile) return data class connection_state: def __init__(self, role, encrypt) -> None: self.role = role self.local_counter = 0 self.remote_counter = 0 self.encrypt = encrypt self.initCRC = b"" def inc_local_counter(self): self.local_counter += 1 def inc_remote_counter(self): self.remote_counter += 1 def calc_crc(self, pdu): initvalue = int.from_bytes(self.initCRC, "little") crc = libscrc.hacker24(data=pdu, poly=0x00065B, init=initvalue, xorout=0x00000000, refin=True, refout=True) return crc.to_bytes(3, "little") def prepare_hello_packet(self): hello_packet = b"" hello_packet += int(self.encrypt << 7 | (PktOpcode.HELLO.value & 0x3f)).to_bytes(1, "little") hello_packet += int(3).to_bytes(1, "little") if not self.initCRC: self.initCRC = random.randbytes(3) hello_packet += self.initCRC hello_packet += self.calc_crc(hello_packet) # no encryption for hello return hello_packet def decrypt_data_packet(self, data): if self.encrypt: return secure_decrypt_packet( self.sessionkey, data, (self.remote_counter).to_bytes( 13, "little") ) else: return data def prepare_data_packet(self, data, moredata): data_packet = b"" data_packet += int(self.encrypt << 7 | moredata << 6 | (PktOpcode.DATA.value & 0x3f)).to_bytes(1, "little") data_packet += len(data).to_bytes(1, "little") if self.encrypt: data_packet += secure_encrypt_packet( self.sessionkey, data, (self.local_counter).to_bytes( 13, "little") ) else: data_packet += data data_packet += self.calc_crc(data_packet) return data_packet def prepare_sc_request_packet(self): sc_request_packet = b"" sc_request_packet += int(self.encrypt << 7 | (PktOpcode.SC_REQ.value & 0x3f)).to_bytes(1, "little") sc_request_packet += int(16).to_bytes(1, "little") IV = random.randbytes(8) Secret = random.randbytes(8) self.IVm = IV self.Secretm = Secret sc_request_packet += IV sc_request_packet += Secret sc_request_packet += self.calc_crc(sc_request_packet) return sc_request_packet def prepare_sc_respond_packet(self): sc_request_packet = b"" sc_request_packet += int(self.encrypt << 7 | (PktOpcode.SC_RSP.value & 0x3f)).to_bytes(1, "little") sc_request_packet += int(16).to_bytes(1, "little") IV = random.randbytes(8) Secret = random.randbytes(8) self.IVs = IV self.Secrets = Secret sc_request_packet += IV sc_request_packet += Secret sc_request_packet += self.calc_crc(sc_request_packet) return sc_request_packet def prepare_master_confirm_packet(self): master_confirm_packet = b"" master_confirm_packet += int(self.encrypt << 7 | (PktOpcode.M_CONFIRM.value & 0x3f)).to_bytes(1, "little") master_confirm_packet += int(16).to_bytes(1, "little") master_random = random.randbytes(16) master_confirm = secure_confirm( self.numeric_key_bytes, master_random, b"\x00" * 16, b"\xff" * 16) self.MRandom = master_random self.MConfirm = master_confirm master_confirm_packet += master_confirm master_confirm_packet += self.calc_crc(master_confirm_packet) return master_confirm_packet def prepare_slave_confirm_packet(self): slave_confirm_packet = b"" slave_confirm_packet += int(self.encrypt << 7 | (PktOpcode.S_CONFIRM.value & 0x3f)).to_bytes(1, "little") slave_confirm_packet += int(16).to_bytes(1, "little") slave_random = random.randbytes(16) slave_confirm = secure_confirm( self.numeric_key_bytes, slave_random, b"\x00" * 16, b"\xff" * 16) self.SRandom = slave_random self.SConfirm = slave_confirm slave_confirm_packet += slave_confirm slave_confirm_packet += self.calc_crc(slave_confirm_packet) return slave_confirm_packet def prepare_master_random_packet(self): master_random_packet = b"" master_random_packet += int(self.encrypt << 7 | (PktOpcode.M_RANDOM.value & 0x3f)).to_bytes(1, "little") master_random_packet += int(16).to_bytes(1, "little") master_random_packet += self.MRandom master_random_packet += self.calc_crc(master_random_packet) return master_random_packet def prepare_slave_random_packet(self): slave_random_packet = b"" slave_random_packet += int(self.encrypt << 7 | (PktOpcode.S_RANDOM.value & 0x3f)).to_bytes(1, "little") slave_random_packet += int(16).to_bytes(1, "little") slave_random_packet += self.SRandom slave_random_packet += self.calc_crc(slave_random_packet) return slave_random_packet def check_master_confirm(self, recvMrandom): should_Mconfirm = secure_confirm( self.numeric_key_bytes, recvMrandom, b"\x00" * 16, b"\xff" * 16) if should_Mconfirm == self.MConfirm: self.MRandom = recvMrandom return True else: return False def check_slave_confirm(self, recvSrandom): should_Sconfirm = secure_confirm( self.numeric_key_bytes, recvSrandom, b"\x00" * 16, b"\xff" * 16) if should_Sconfirm == self.SConfirm: self.SRandom = recvSrandom return True else: return False def setup_session(self): self.storekey = secure_encrypt( self.numeric_key_bytes, self.MRandom[:8] + self.SRandom[8:]) self.sessionkey = secure_encrypt( self.storekey, self.Secretm + self.Secrets) def showChoice(): print("================ CHOICE ================") print("[0] Receive a message") print("[1] Send a message") print("[2] Leave") print("-----------------======-----------------") def goodBye(): print("-----------------======-----------------") print("See you next time\n") def recieve_message(state: connection_state, handler: connection_handle): entire_data_payload = b"" while True: dataheader = handler.recv(2) more_data = (dataheader[0] >> 6) & 0b1 opcode = dataheader[0] & 0x3f if opcode != PktOpcode.DATA.value: print("Weird not data packet receieved") return datalength = dataheader[1] payload = handler.recv(datalength) crc = handler.recv(3) should_crc = state.calc_crc(dataheader + payload) payload = state.decrypt_data_packet(payload) state.inc_remote_counter() if crc != should_crc: print("CRC check failed in receive message") return entire_data_payload += payload if not more_data: break decoded_data = base64.b64decode(entire_data_payload).decode() print("Your recv : " + decoded_data) def send_message(state: connection_state, handler: connection_handle): data = input("Your data > ").strip().encode() encoded_data = base64.b64encode(data) # split into segements encoded_data_len = len(encoded_data) for start in range(0, encoded_data_len, 255): if start + 255 > encoded_data_len: end = encoded_data_len moreData = False else: end = start + 255 moreData = True data_segment = encoded_data[start: end] data_packet = state.prepare_data_packet(data_segment, moreData) handler.send(data_packet) state.inc_local_counter() def master_hello_procedure(handler: connection_handle, state: connection_state): handler.send(state.prepare_hello_packet()) state.inc_local_counter() hello_pkt = handler.recv(2 + 255 + 3) state.inc_remote_counter() if hello_pkt[0] & 0x3f != PktOpcode.HELLO.value: return False encrypt_or_not = (hello_pkt[0] >> 7) & 0b1 if not encrypt_or_not: return True handler.send(state.prepare_sc_request_packet()) state.inc_local_counter() numeric_key = int(input("Shared numeric key > ")) numeric_key = numeric_key % 0x1000000 state.numeric_key = numeric_key state.numeric_key_bytes = (numeric_key).to_bytes(16, "little") sc_respond_pkt = handler.recv(2 + 255 + 3) state.inc_remote_counter() if sc_respond_pkt[0] & 0x3f != int(PktOpcode.SC_RSP.value): return False recvIVs = sc_respond_pkt[2: 10] recvSecrets = sc_respond_pkt[10: 18] crc = sc_respond_pkt[18: 18 + 3] should_crc = state.calc_crc(sc_respond_pkt[:18]) if crc != should_crc: print("CRC check failed in hello procedure") return False state.IVs = recvIVs state.Secrets = recvSecrets handler.send(state.prepare_master_confirm_packet()) state.inc_local_counter() sconfirm_pkt = handler.recv(2 + 255 + 3) state.inc_remote_counter() if sconfirm_pkt[0] & 0x3f != int(PktOpcode.S_CONFIRM.value): return False recvSConfirm = sconfirm_pkt[2: 18] crc = sconfirm_pkt[18: 18 + 3] should_crc = state.calc_crc(sconfirm_pkt[:18]) if crc != should_crc: print("CRC check failed in hello procedure") return False state.SConfirm = recvSConfirm handler.send(state.prepare_master_random_packet()) state.inc_local_counter() srandom_pkt = handler.recv(2 + 255 + 3) state.inc_remote_counter() if srandom_pkt[0] & 0x3f != int(PktOpcode.S_RANDOM.value): return False recvSRandom = srandom_pkt[2: 18] crc = srandom_pkt[18: 18 + 3] should_crc = state.calc_crc(srandom_pkt[:18]) if crc != should_crc: print("CRC check failed in hello procedure") return False if not state.check_slave_confirm(recvSRandom): return False state.setup_session() return True def slave_hello_procedure(handler: connection_handle, state: connection_state): hello_pkt = handler.recv(2 + 255 + 3) state.inc_remote_counter() if hello_pkt[0] & 0x3f != int(PktOpcode.HELLO.value): return False encrypt_or_not = (hello_pkt[0] >> 7) & 0b1 state.encrypt = encrypt_or_not hello_pkt_len = hello_pkt[1] hello_pkt_payload = hello_pkt[2: 2 + hello_pkt_len] state.initCRC = hello_pkt_payload handler.send(state.prepare_hello_packet()) state.inc_local_counter() if not encrypt_or_not: return True else: sc_request_pkt = handler.recv(2 + 255 + 3) state.inc_remote_counter() if sc_request_pkt[0] & 0x3f != int(PktOpcode.SC_REQ.value): return False recvIVm = sc_request_pkt[2: 10] recvSecretm = sc_request_pkt[10: 18] crc = sc_request_pkt[18: 18 + 3] should_crc = state.calc_crc(sc_request_pkt[:18]) if crc != should_crc: print("CRC check failed in hello procedure") return False state.IVm = recvIVm state.Secretm = recvSecretm handler.send(state.prepare_sc_respond_packet()) state.inc_local_counter() numeric_key = int(input("Shared numeric key > ")) numeric_key = numeric_key % 0x1000000 state.numeric_key = numeric_key state.numeric_key_bytes = (numeric_key).to_bytes(16, "little") mconfirm_packet = handler.recv(2 + 255 + 3) state.inc_remote_counter() if mconfirm_packet[0] & 0x3f != int(PktOpcode.M_CONFIRM.value): return False recvMConfirm = mconfirm_packet[2: 18] crc = mconfirm_packet[18: 18 + 3] should_crc = state.calc_crc(mconfirm_packet[:18]) if crc != should_crc: print("CRC check failed in hello procedure") return False state.MConfirm = recvMConfirm handler.send(state.prepare_slave_confirm_packet()) state.inc_local_counter() mrandom_packet = handler.recv(2 + 255 + 3) state.inc_remote_counter() if mrandom_packet[0] & 0x3f != int(PktOpcode.M_RANDOM.value): return False recvMRandom = mrandom_packet[2: 18] crc = mrandom_packet[18: 18 + 3] should_crc = state.calc_crc(mrandom_packet[:18]) if crc != should_crc: print("CRC check failed in hello procedure") return False if not state.check_master_confirm(recvMRandom): return False handler.send(state.prepare_slave_random_packet()) state.inc_local_counter() state.setup_session() return True def connection_engine(handler: connection_handle, role: str, encrypt: bool): state = connection_state(role, encrypt) if role == "master": if not master_hello_procedure(handler, state): print("hello fail") exit(1) if role == "slave": if not slave_hello_procedure(handler, state): print("hello fail") exit(1) while True: try: showChoice() choice = int(input("Your choice > ")) if choice < 0 or choice > 2: raise ValueError if choice == 0: recieve_message(state, handler) elif choice == 1: send_message(state, handler) elif choice == 2: goodBye() return except ValueError as err: print("Bad Input T.T") continue except KeyboardInterrupt as err: goodBye() return # except Exception as err: # print("Bad thing happens") # print(err) # return
> 01 03 6c 69 fa 95 c5 e6 < 01 03 6c 69 fa 95 c5 e6 > 08 30 53 47 56 73 62 47 38 67 64 47 68 6c 63 6d 55 73 49 47 78 76 62 6d 63 67 64 47 6c 74 5a 53 42 75 62 79 42 7a 5a 57 55 73 49 48 70 79 59 58 68 34 9e ab 52 < 08 44 < 65 57 56 68 61 43 77 67 53 53 42 68 62 53 42 78 64 57 6c 30 5a 53 42 69 64 58 4e 35 49 47 31 68 61 32 6c 75 5a 79 42 42 51 31 52 47 49 47 4e 79 65 58 42 30 62 79 42 6a 61 47 46 73 62 47 56 75 5a 32 56 7a < ab 08 96 > 08 40 64 32 56 73 62 43 77 67 53 53 42 6a 59 57 34 67 62 32 5a 6d 5a 58 49 67 65 57 39 31 49 47 45 67 62 6d 39 30 49 47 4a 68 5a 43 42 7a 61 57 64 75 61 57 34 67 59 32 68 68 62 47 78 6c 62 6d 64 6c d1 e8 ac < 08 0c < 63 32 68 76 64 79 42 74 5a 51 3d 3d < 06 eb 3b > 08 34 62 47 56 30 4a 33 4d 67 5a 6d 6c 79 63 33 51 67 5a 47 6c 32 5a 53 42 70 62 6e 52 76 49 48 4e 6c 59 33 56 79 5a 53 42 6a 62 32 35 75 5a 57 4e 30 61 57 39 75 2a 85 95 > 81 03 d9 b2 df e9 3b f9 < 81 03 d9 b2 df e9 3b f9 > 82 10 ec 36 e5 b0 69 55 d9 95 56 7e e5 de 45 07 37 f8 7d d5 57 < 83 10 68 b3 de d5 b8 40 14 dc f3 fb 75 02 d9 39 0e 34 a6 bf 63 > 84 10 9f 51 36 ca cd 9f 2a 53 87 39 4b 7d 0c 1c XX XX 58 46 05 < 85 10 XX d6 e4 XX XX 5c XX b7 ba 90 6e 57 05 5a 8e c8 2d db b8 > 86 10 4b d2 09 24 f0 c3 cd 30 ba 64 a0 f1 d9 64 69 1e fa a2 d5 < 87 10 dd 76 51 4f 57 36 81 3a a8 c2 17 8e XX f8 2d 5b 6f 68 ec > 88 44 ee 49 1a 84 62 41 16 fb 68 5e 5d 47 14 94 aa 6d 3e ac 7c 53 70 7c 46 50 50 90 7e a2 01 12 04 06 90 02 5e 92 a6 1d d8 29 1b 50 d0 c1 69 13 b9 cd 0f f5 29 0e da d9 c2 3d 69 38 46 49 76 5b 84 7f 15 f2 21 ce 3e 4f b4 < c8 ff < ea 4d 61 86 4a 51 5f e4 78 41 3b 4c 12 94 b5 7a 38 82 07 14 5b 56 22 4a 50 91 6a be 01 12 1f 12 80 10 6f c5 a5 77 a8 3a 1d 40 af 89 7a 07 a1 8d 0c df 13 18 f2 d2 d2 7e 42 4c 55 57 5c 20 90 7d 2d f2 47 8a 05 19 c8 17 06 33 f1 a9 4d b6 15 ac 37 bb a6 48 c1 33 df f4 26 c2 0a 28 f9 12 5f e1 fd 35 d0 af 55 07 01 85 16 92 62 6b 6f fa c7 43 4f 92 b5 68 c2 66 53 36 52 de 21 86 43 23 03 38 98 f5 14 fd 5c b0 ef 20 59 fe 9a b6 8e 29 17 d7 5d 5c cf c6 a8 c2 1d ba 69 d7 3b b7 99 44 c3 8b b5 20 8f fe 67 e0 28 64 9a 40 6a 2b d7 1d 86 70 f1 9f ef a7 19 cf db e6 72 f4 c5 8a 1e 2d 1c 09 2c 3f 21 db 23 bf 63 f7 da 5d 78 90 56 02 f2 22 e4 58 a5 ca 7a 04 83 5d 4c d9 0a 1a 5d 90 0a 78 f6 75 16 ea 44 32 89 97 1a 7f e2 da 15 7d 60 ce 1b 63 31 ac c8 7e f6 9c e9 58 9e fa 9c 54 69 < 10 b5 31 < c8 ff < 84 11 de 79 f3 a0 cf b3 04 f6 df ec 30 5c 00 ca 30 d7 69 82 9e 55 9b 42 8d c6 f0 ae 6d 8b 73 d9 af bb bf a8 b4 f4 e5 ad 6b be 55 3b eb 34 97 88 2b 8a 41 3f ee e3 20 f6 38 69 b7 9b 98 ac 6a 67 83 e0 e5 de e5 e1 8e 80 43 13 e2 2e 56 38 3a fd b4 ea a5 44 87 ad 8a ec 5a 5e 01 6e 5d db 39 44 81 39 57 e7 05 24 e0 58 e8 56 41 fa 4d cd b2 71 4d 6a a4 79 16 0b 43 68 c8 db ad d6 6d 8d 8a 9e 4c 8a 7f 58 45 54 f3 15 22 82 35 59 38 1e 75 4e 8c c8 c6 a0 0b e2 6d 75 0d 78 49 36 6e cc b2 24 90 9d c9 8b da 4e 51 81 15 3c 67 07 c0 f6 5c 9c 6d a1 14 8c fe fd c7 7a 65 63 69 17 f9 3c 8c 0d 44 7e bd 7e 49 89 4f b4 61 7a b6 b3 70 9e 2a b3 b9 c9 fe 18 94 7e b4 50 85 e7 b9 e7 2c db c0 10 92 ac 60 3c c2 f7 cb fb fb b6 9f f9 af fa ba 60 9b 99 cf 35 69 4b 9b 9e f4 ca b3 df bc 1d 7b < 30 a6 be < c8 ff < 4a 21 06 5d 5a b2 a0 e2 cb 4f 31 e2 2b dd d9 57 6e 81 cd 31 05 dc 91 a9 fb 9d b0 dc ec 19 7b e8 4e 44 1a 79 ec b4 15 53 85 2f 15 58 78 5d c3 1f 03 62 08 a4 52 c3 57 b1 52 4c f5 6d bc df 98 5e 64 35 b8 f6 17 4c fd 28 d9 2e 3d 30 ab e9 82 ee 10 d8 0a 75 31 55 be d8 9c 85 ba d3 64 9b ed 2f 2e 41 a5 3c 1a 1e dd 65 47 22 70 14 86 82 35 ac 5e bb e6 e8 c7 cb 92 64 0d 0c dd 81 a6 91 35 ad 3b 36 39 be e2 46 28 5c c5 13 cb 6d 21 64 47 34 2c 59 6d 77 df e6 4a 06 66 7b 64 f4 b7 5a c7 c6 03 cb 5c 02 ac ea f4 f7 80 ec 1c c4 3f ed 5f b8 cf 19 4b 02 9d 8e 48 5f ff 93 69 5f 37 86 21 02 b7 60 60 54 9e a9 d0 c5 f8 52 be 7c ed 74 e3 0d cd a4 bb 95 13 a9 57 fa e0 8e 41 aa 09 74 b5 b0 45 67 f8 a4 9d a9 4c 0f c8 f2 82 0a 45 71 18 da ec e7 5a 4e d4 5d 0d b8 75 7c 47 a9 d1 85 e5 < 64 27 6a < 88 5b < a6 36 7b 6a a5 55 af 69 a9 a9 7d 0e 09 aa 48 86 d5 27 20 c7 74 65 e3 37 18 76 8d 14 89 d9 d1 cc 84 d0 ed 7b d6 04 55 00 2e 04 ee 7f ae 36 8c 47 83 82 a2 ef 26 4b dd 91 73 d2 8c 29 31 5b 8f 3e 3c 19 24 89 50 be d6 5f e7 88 e4 ac 13 71 26 85 1b c8 8d 47 94 e6 41 85 9e 6f b2 < 0b 37 68 > c8 ff b7 29 d4 27 d4 a9 d5 95 2e c3 ce cc 1e 70 15 9c 27 c6 63 8d 8a 03 ed 6c f1 e4 f5 b1 43 96 1e d9 a7 9f ae e8 90 f5 ec ad 63 9e 4f 09 ce 13 cf bc 33 d8 4f 27 c8 ea 3a ce 11 78 a8 b1 8e 9f 6b 5f ac e2 e8 eb ed c4 8f ae 7a 36 d5 00 60 0a 53 ea 89 e8 c6 1a 95 c5 fc d8 54 45 71 15 63 fe 16 64 d1 21 42 ee 11 2a f2 6d cb 73 40 a3 45 d0 99 6a 49 52 b1 3f 1f 70 3d 4c 99 b1 b3 e9 02 87 8f f7 45 ac 61 21 6b 49 d8 38 05 8d 0a 68 37 00 1b 11 bc c6 c4 82 31 eb 51 44 5f 74 48 35 58 dd bc 11 9f f7 b9 85 cb 1e 69 b0 0b 42 48 75 e2 d0 4d 96 65 f2 01 85 e9 97 bc 48 72 47 42 54 e1 2d 99 54 76 59 b7 58 52 ba 5e 99 41 64 b7 cf 45 90 49 f2 80 ff ff 1d b3 70 bd 72 90 ed b3 c5 37 d6 a7 35 fa 99 3e 09 e8 c5 de bc d5 85 8a 98 f8 f4 aa 4d c9 ce ce 01 3d 6f 95 8f da d7 87 e0 99 36 44 de 22 74 > 88 1d 10 13 37 5c 5c a9 83 e3 90 5a 58 f7 05 de 88 33 7f b3 fc 34 1c da ab 9e ae cf 90 ab 8b 8c 60 1f < 88 28 < 18 ae e9 5e ca c0 9e e6 3d d2 87 07 b8 94 2d 4f 2a 70 52 d7 1b fd 27 d8 1b cc ef fd 20 8a 14 63 f9 a1 35 24 8d ef 57 81 < ec a0 94 > 88 60 a2 16 25 39 df 5b ac 45 95 86 53 58 12 db 74 a6 cb 54 1d d7 1f 64 ec 4d 12 71 9f 32 a6 de f8 99 e3 d7 eb 62 c4 12 77 02 17 3e c2 42 bc 32 aa 5e 82 fe e8 ea 33 5b c4 ad 7d c8 f2 2e 20 59 a3 04 19 17 1a be 73 af e6 5b fa a6 ad a3 2a 15 78 8d 0d b6 b3 59 b0 be 7f a6 af 68 cd e6 e2 4c a9 5d 0b 4a cb < 88 08 < fd 81 d2 b5 8c 5e 32 06 < e7 8a 0e
なげー
bluetoothの通信を模してるらしい
通信されている重要なデータは master_secret, master_random, master_confirm, slave_secret, slave_random, slave_confirm
互いに共有していた24bit 程度の数値(numeric key)と master_random, slave_random, master_secret, slave_secret を用いてセッションキーを作成してる
numeric key 全探索できそう
import libscrc from itertools import product from Crypto.Cipher import AES from tqdm import tqdm def calc_crc(initCRC, pdu): initvalue = int.from_bytes(initCRC, "little") crc = libscrc.hacker24(data=pdu, poly=0x00065B, init=initvalue, xorout=0x00000000, refin=True, refout=True) return crc.to_bytes(3, "little") def bytes_xor_16(bytes1, bytes2): v1 = int.from_bytes(bytes1, 'big') v2 = int.from_bytes(bytes2, 'big') v3 = v1 ^ v2 return (v3).to_bytes(16, 'big') def secure_encrypt(key, plain): aes = AES.new(key=key, mode=AES.MODE_ECB) return aes.encrypt(plain) def secure_encrypt_packet(key, plain, nonce): aes = AES.new(key=key, mode=AES.MODE_CCM, nonce=nonce) return aes.encrypt(plain) def secure_decrypt_packet(key, plain, nonce): aes = AES.new(key=key, mode=AES.MODE_CCM, nonce=nonce) return aes.decrypt(plain) def secure_confirm(key, r, p1, p2): return secure_encrypt(key, bytes_xor_16(secure_encrypt(key, bytes_xor_16(r, p1)), p2)) initCRC = bytes.fromhex("d9 b2 df".replace(" ", "")) # MASTER_CONFIRM: 9f 51 36 ca cd 9f 2a 53 87 39 4b 7d 0c 1c XX XX # CRC : 58 46 05 table = list(range(256)) master_prefix = bytes.fromhex("84109f5136cacd9f2a5387394b7d0c1c") master_crc = bytes.fromhex("584605") for pattern in product(table, repeat=2): data = master_prefix + bytes(pattern) if calc_crc(initCRC, data) == master_crc: print("master_confirm:", data[2:]) master_confirm = data[2:] break else: raise ValueError("X") # S_CONFIRM # SLAVE_CONFIRM: XX d6 e4 XX XX 5c XX b7 ba 90 6e 57 05 5a 8e c8 # CRC : 2d db b8 slave_postfix = bytes.fromhex("b7ba906e57055a8ec8") slave_crc = bytes.fromhex("2ddbb8") slave_confirm = b'\x02\xd6\xe4\xcdS\\\x86\xb7\xba\x90nW\x05Z\x8e\xc8' # for pattern in product(table, repeat=4): # data = bytes([0x85, 0x10, pattern[0], 0xd6, 0xe4, pattern[1], # pattern[2], 0x5c, pattern[3]]) + slave_postfix # if calc_crc(initCRC, data) == slave_crc: # print("slave_confirm:", data[2:]) # slave_confirm = data[2:] # break # else: # raise ValueError("X") # S_RANDOM # SLAVE_RANDOM: dd 76 51 4f 57 36 81 3a a8 c2 17 8e XX f8 2d 5b # CRC: 6f 68 ec for x in range(256): data = bytes.fromhex("8710dd76514f5736813aa8c2178e") + \ bytes([x, 0xf8, 0x2d, 0x5b]) if calc_crc(initCRC, data) == bytes.fromhex("6f68ec"): print("slave_random:", data) slave_random = data[2:] break else: raise ValueError("X") master_iv = bytes.fromhex("ec 36 e5 b0 69 55 d9 95".replace(" ", "")) master_secret = bytes.fromhex("56 7e e5 de 45 07 37 f8".replace(" ", "")) master_random = bytes.fromhex( "4b d2 09 24 f0 c3 cd 30 ba 64 a0 f1 d9 64 69 1e".replace(" ", "")) slave_iv = bytes.fromhex("83 10 68 b3 de d5 b8 40".replace(" ", "")) slave_secret = bytes.fromhex("14 dc f3 fb 75 02 d9 39".replace(" ", "")) for k in tqdm(range(0, 0x1000000)): numeric_key_bytes = (k).to_bytes(16, "little") should_Sconfirm = secure_confirm( numeric_key_bytes, slave_random, b"\x00" * 16, b"\xff" * 16) if should_Sconfirm == slave_confirm: print("slave_numberic_key_bytes:", numeric_key_bytes) break else: raise ValueError("X") for k in tqdm(range(9189958, 0x1000000)): numeric_key_bytes = (k).to_bytes(16, "little") should_Mconfirm = secure_confirm( numeric_key_bytes, master_random, b"\x00" * 16, b"\xff" * 16) if should_Mconfirm == master_confirm: print("master_numberic_key_bytes:", numeric_key_bytes) break else: raise ValueError("X")
復号
from Crypto.Cipher import AES import libscrc import re def bytes_xor_16(bytes1, bytes2): v1 = int.from_bytes(bytes1, 'big') v2 = int.from_bytes(bytes2, 'big') v3 = v1 ^ v2 return (v3).to_bytes(16, 'big') def secure_encrypt(key, plain): aes = AES.new(key=key, mode=AES.MODE_ECB) return aes.encrypt(plain) def secure_encrypt_packet(key, plain, nonce): aes = AES.new(key=key, mode=AES.MODE_CCM, nonce=nonce) return aes.encrypt(plain) def secure_decrypt_packet(key, plain, nonce): aes = AES.new(key=key, mode=AES.MODE_CCM, nonce=nonce) from base64 import b64decode p = aes.decrypt(plain) while True: try: return b64decode(p) except: p += b"=" def secure_confirm(key, r, p1, p2): return secure_encrypt(key, bytes_xor_16(secure_encrypt(key, bytes_xor_16(r, p1)), p2)) master_iv = bytes.fromhex("ec 36 e5 b0 69 55 d9 95".replace(" ", "")) master_secret = bytes.fromhex("56 7e e5 de 45 07 37 f8".replace(" ", "")) master_random = bytes.fromhex( "4b d2 09 24 f0 c3 cd 30 ba 64 a0 f1 d9 64 69 1e".replace(" ", "")) master_confirm = b'\x9fQ6\xca\xcd\x9f*S\x879K}\x0c\x1c\x16\xfa' slave_iv = "68 b3 de d5 b8 40 14 dc" slave_secret = bytes.fromhex("f3 fb 75 02 d9 39 0e 34".replace(" ", "")) slave_random = b'\xddvQOW6\x81:\xa8\xc2\x17\x8e|\xf8-[' slave_confirm = bytes.fromhex("02d6e4cd535c86b7ba906e57055a8ec8") numeric_key_bytes = b'%=\x8c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' storekey = secure_encrypt( numeric_key_bytes, master_random[:8] + slave_random[8:]) sessionkey = secure_encrypt( storekey, master_secret + slave_secret) should_Mconfirm = secure_confirm( numeric_key_bytes, master_random, b"\x00" * 16, b"\xff" * 16) assert should_Mconfirm == master_confirm should_Sconfirm = secure_confirm( numeric_key_bytes, slave_random, b"\x00" * 16, b"\xff" * 16) assert should_Sconfirm == slave_confirm master_counter = 4 slave_counter = 4 xs = [ "8844ee491a84624116fb685e5d471494aa6d3eac7c53707c465050907ea20112040690025e92a61dd8291b50d0c16913b9cd0ff5290edad9c23d69384649765b847f15f221ce3e4fb4", "c8ffea4d61864a515fe478413b4c1294b57a388207145b56224a50916abe01121f1280106fc5a577a83a1d40af897a07a18d0cdf1318f2d2d27e424c55575c20907d2df2478a0519c8170633f1a94db615ac37bba648c133dff426c20a28f9125fe1fd35d0af550701851692626b6ffac7434f92b568c266533652de21864323033898f514fd5cb0ef2059fe9ab68e2917d75d5ccfc6a8c21dba69d73bb79944c38bb5208ffe67e028649a406a2bd71d8670f19fefa719cfdbe672f4c58a1e2d1c092c3f21db23bf63f7da5d78905602f222e458a5ca7a04835d4cd90a1a5d900a78f67516ea443289971a7fe2da157d60ce1b6331acc87ef69ce9589efa9c546910b531", "c8ff8411de79f3a0cfb304f6dfec305c00ca30d769829e559b428dc6f0ae6d8b73d9afbbbfa8b4f4e5ad6bbe553beb3497882b8a413feee320f63869b79b98ac6a6783e0e5dee5e18e804313e22e56383afdb4eaa54487ad8aec5a5e016e5ddb3944813957e70524e058e85641fa4dcdb2714d6aa479160b4368c8dbadd66d8d8a9e4c8a7f584554f31522823559381e754e8cc8c6a00be26d750d7849366eccb224909dc98bda4e5181153c6707c0f65c9c6da1148cfefdc77a65636917f93c8c0d447ebd7e49894fb4617ab6b3709e2ab3b9c9fe18947eb45085e7b9e72cdbc01092ac603cc2f7cbfbfbb69ff9affaba609b99cf35694b9b9ef4cab3dfbc1d7b30a6be", "c8ff4a21065d5ab2a0e2cb4f31e22bddd9576e81cd3105dc91a9fb9db0dcec197be84e441a79ecb41553852f1558785dc31f036208a452c357b1524cf56dbcdf985e6435b8f6174cfd28d92e3d30abe982ee10d80a753155bed89c85bad3649bed2f2e41a53c1a1edd6547227014868235ac5ebbe6e8c7cb92640d0cdd81a69135ad3b3639bee246285cc513cb6d216447342c596d77dfe64a06667b64f4b75ac7c603cb5c02aceaf4f780ec1cc43fed5fb8cf194b029d8e485fff93695f37862102b76060549ea9d0c5f852be7ced74e30dcda4bb9513a957fae08e41aa0974b5b04567f8a49da94c0fc8f2820a457118daece75a4ed45d0db8757c47a9d185e564276a", "885ba6367b6aa555af69a9a97d0e09aa4886d52720c77465e33718768d1489d9d1cc84d0ed7bd60455002e04ee7fae368c478382a2ef264bdd9173d28c29315b8f3e3c19248950bed65fe788e4ac137126851bc88d4794e641859e6fb20b3768", "c8ffb729d427d4a9d5952ec3cecc1e70159c27c6638d8a03ed6cf1e4f5b143961ed9a79faee890f5ecad639e4f09ce13cfbc33d84f27c8ea3ace1178a8b18e9f6b5face2e8ebedc48fae7a36d500600a53ea89e8c61a95c5fcd85445711563fe1664d12142ee112af26dcb7340a345d0996a4952b13f1f703d4c99b1b3e902878ff745ac61216b49d838058d0a6837001b11bcc6c48231eb51445f74483558ddbc119ff7b985cb1e69b00b424875e2d04d9665f20185e997bc4872474254e12d99547659b75852ba5e994164b7cf459049f280ffff1db370bd7290edb3c537d6a735fa993e09e8c5debcd5858a98f8f4aa4dc9cece013d6f958fdad787e0993644de2274", "881d1013375c5ca983e3905a58f705de88337fb3fc341cdaab9eaecf90ab8b8c601f", "882818aee95ecac09ee63dd28707b8942d4f2a7052d71bfd27d81bcceffd208a1463f9a135248def5781eca094", "8860a2162539df5bac459586535812db74a6cb541dd71f64ec4d12719f32a6def899e3d7eb62c4127702173ec242bc32aa5e82fee8ea335bc4ad7dc8f22e2059a30419171abe73afe65bfaa6ada32a15788d0db6b359b0be7fa6af68cde6e24ca95d0b4acb", "8808fd81d2b58c5e3206e78a0e", ] def calc_crc(initCRC, pdu): initvalue = int.from_bytes(initCRC, "little") crc = libscrc.hacker24(data=pdu, poly=0x00065B, init=initvalue, xorout=0x00000000, refin=True, refout=True) return crc.to_bytes(3, "little") initCRC = bytes.fromhex("d9 b2 df".replace(" ", "")) # for x in xs: # y = bytes.fromhex(x) # assert y[1] == len(y[2:-3]) # assert calc_crc(initCRC, y[:-3]) == y[-3:] # for cnt in range(10): # print(secure_decrypt_packet( # sessionkey, y[2:-3], (cnt).to_bytes(13, "little") # )) data = re.split(r"\s+", open("data.txt").read()) master_counter = 4 slave_counter = 4 p = 0 while p < len(data): if data[p] == '>' or data[p] == "<": master = True if data[p] == ">" else False cnt = int(data[p+2], 16) p += 3 x = 0 buf = "" while x < cnt: if data[p + x] == ">" or data[p + x] == "<": p += 1 continue buf += data[p + x] x += 1 p += x + 3 # crc if master: print(secure_decrypt_packet( sessionkey, bytes.fromhex(buf), (master_counter).to_bytes( 13, "little") )) master_counter += 1 else: print(secure_decrypt_packet( sessionkey, bytes.fromhex(buf), (slave_counter).to_bytes( 13, "little") )) slave_counter += 1 else: print(data[p-1:p+1]) p += 1