def _decrypt_token(self, id_phone, ciphertext): """ decrypts incoming tokens from SmartPhones if decryption succeeds, datetime of id_phone is updated alerts on invalid token, datetime not updated :param id_phone: skt of the token's phone :param ciphertext: ciphertext encrypted from beacon :return: None """ update_execution_log(["New Token", id_phone, ciphertext]) print("New Token from ID Phone: {0}, Ciphertext: {1}".format( id_phone, ciphertext)) key = self._get_key(id_phone) if key is not None: try: new_datetime_string = Fernet(key).decrypt( str.encode(ciphertext)).decode() new_datetime = dt.strptime(new_datetime_string, database_dt_format) database_datetime = dt.strptime(self._database[id_phone][2], database_dt_format) if new_datetime > database_datetime: self._database[id_phone][2] = new_datetime_string with open(self._database_path, 'w') as j: json.dump(self._database, j, indent=0) except InvalidToken: update_execution_log(["Invalid Token", id_phone, ciphertext])
def random_bluetooth(self, prob=0.5): """ called when the phone's bluetooth is off :param prob: probability of phone's bluetooth turning on :return: """ update_execution_log(["Smartphone Bluetooth Off", self._id_phone]) self._bluetooth = False if random.rand() < prob else True
def random_on(self, prob=0.5): """ called when the phone is off :param prob: probability of phone turning on :return: None """ update_execution_log(["Smartphone Off", self._id_phone]) self._on = False if random.rand() < prob else True
def routine(self, id_phone, id_beacon, key): """ Health Authority starts a client session to communicate a new patient :param id_phone: skt of the new patient's phone :param id_beacon: identifies the beacon associated to the patient :param key: key for symmetric encryption :return: None """ update_execution_log([health_authority_header, id_phone, id_beacon, key]) self._client_session(separator.join([health_authority_header, id_phone, id_beacon, key]))
def add_beacon(self, id_beacon, info): """ stores a new id_beacon with info into AuthorityBackend database :param id_beacon: identifies the new beacon added :param info: info regarding the new patient :return: None """ update_execution_log(["New Beacon", id_beacon, info]) self._database[id_beacon] = info with open(self._database_path, 'w') as j: json.dump(self._database, j, indent=0)
def _get_key(self, id_phone): """ retrieves key for symmetric encryption of id_phone alerts on invalid id_phone :param id_phone: skt of the phone sending the ciphertext to AppBackend :return: 44bit key """ if id_phone in self._database: return self._database[id_phone][1] else: update_execution_log(["Invalid Phone", id_phone])
def control_routine(self, td_expire): """ control routine used to check violations if datetime expires, AppBackend sends an alert to AuthorityBackend :param td_expire: time tolerance from last datetime update :return: None """ for id_phone in self._database: id_beacon = self._database[id_phone][0] expire_dt = dt.strptime(self._database[id_phone][2], database_dt_format) + td(seconds=td_expire) if dt.utcnow() > expire_dt: update_execution_log([app_header, id_beacon]) self._client_session(separator.join([app_header, id_beacon]))
def _add_phone(self, id_phone, id_beacon, key): """ adds a new phone to AppBackend's database stores the actual datetime database is stored on a json file in the root directory of AppBackend :param id_phone: skt of the phone :param id_beacon: identifies the associated beacon :param key: key for symmetric encryption :return: None """ update_execution_log(["New Patient", id_phone, id_beacon, key]) self._database[id_phone] = [ id_beacon, key, dt.utcnow().strftime(database_dt_format) ] with open(self._database_path, 'w') as j: json.dump(self._database, j, indent=0)
def routine(self, on=True, prob=0.5): """ can't build up properly Bluetooth transmission transmissions are simulated through a header.txt file if beacon is on, encrypts a plaintext for the SmartPhone on the header.txt file if beacon is off, there's no encryption and the file is truncated :param on: routine changes according to beacon on/off status :param prob: probability of beacon turning on :return: None """ if on: plaintext = str.encode(dt.utcnow().strftime(database_dt_format)) ciphertext = Fernet(self._key).encrypt(plaintext).decode() update_execution_log( ["New Encryption", self._id_beacon, self._header, ciphertext]) with open(self._packet, "w") as f: f.write(ciphertext) else: update_execution_log(["Beacon Off", self._id_beacon, self._header]) open(self._packet, "w").close() self._on = False if random.rand() < prob else True
def routine(self, wifi=True, prob=0.5): """ if wifi is on, forwards the last token received if wifi is off, stores all incoming tokens into a log file if wifi turns on, last stored token is sent to AppBackend :param wifi: routine changes according to phone's wifi on/off status :param prob: probability of phone's wifi turning on :return: None """ last_ciphertext = None for packet in [packet for packet in os.listdir(self._packets_root) if packet.startswith(self._header)]: if os.path.getsize(os.path.join(self._packets_root, packet)) > 0: with open(os.path.join(self._packets_root, packet), "r") as f: ciphertext = f.read() if wifi: update_execution_log([smartphone_header, self._id_phone, ciphertext]) self._client_session(separator.join([smartphone_header, self._id_phone, ciphertext])) else: last_ciphertext = ciphertext with open(self._log_path, "w") as j: self._log[dt.utcnow().strftime(database_dt_format)] = last_ciphertext json.dump(self._log, j, indent=0) if not wifi: update_execution_log(["Smartphone WiFi Off", self._id_phone]) self._wifi = False if random.rand() < prob else True if self._wifi and last_ciphertext is not None: update_execution_log([smartphone_header, self._id_phone, last_ciphertext]) self._client_session(separator.join([smartphone_header, self._id_phone, last_ciphertext]))
def _add_datetime(self, id_beacon): """ adds to log the datetime of id_beacon's violation :param id_beacon: identifies the beacon involved in the violation :return: None """ update_execution_log( ["Quarantine Violation", id_beacon, self._database[id_beacon]]) print("Quarantine Violation from ID Beacon: {0}, Info: {1}".format( id_beacon, self._database[id_beacon])) if id_beacon in self._database: if id_beacon not in self._log: self._log[id_beacon] = [ dt.utcnow().strftime(database_dt_format) ] else: self._log[id_beacon].append( dt.utcnow().strftime(database_dt_format)) with open(self._log_path, 'w') as j: json.dump(self._log, j, indent=0) else: update_execution_log(["Invalid Beacon", id_beacon])