def _update_typo_cache_by_waitlist(self, typo_cache, freq_counts): """ Updates the hash cache according to waitlist and clears the waitlist @typo_cache: a list of typos in the cache, and @freq_counts are the corresponding frequencies. returns: Updated typo_cache and their frequencies. Also applies the permutations. """ logger.info("Updating TypoCache by Waitlist") good_typo_list = self._decrypt_n_filter_waitlist() mini, minf = min(enumerate(freq_counts), key=itemgetter(1)) for typo, f in good_typo_list: if UserTypoDB.cache_insert_policy(minf, f): logger.debug("Inserting: {} @ {}".format(typo, mini)) typo_cache[mini+1] = pwencrypt(typo, self._sk) freq_counts[mini] = max(minf + 1, f) # TODO: Check mini, minf = min(enumerate(freq_counts), key=itemgetter(1)) else: logger.debug("I miss you: {} ({} <-> {})".format(typo, minf, f)) logger.debug("Freq counts: {}".format(freq_counts)) # write the new typo_cache and freq_list # TODO: Apply permutation header_ctx = pkencrypt(self._pk, json.dumps({ REAL_PW: self._pw, HMAC_SALT: urlsafe_b64encode(self._hmac_salt), FREQ_COUNTS: freq_counts })) logger.debug("Real pw={!r}".format(self._pw)) self.set_in_auxtdb(HEADER_CTX, header_ctx) self.set_in_auxtdb(TYPO_CACHE, typo_cache) self.clear_waitlist()
def on_correct_password(typo_db, password): # log the entry of the original pwd logger.info("-^-") try: if not typo_db.is_typtop_init(): logger.error("Typtop DB wasn't initiated yet!") typo_db.init_typtop(password) # the initialization is now part of the installation process check_system_status(typo_db) # correct password but db fails to see it is_match = typo_db.check(password) if not is_match: logger.debug("Changing system status to {}.".format( SYSTEM_STATUS_PW_CHANGED )) typo_db.set_status(SYSTEM_STATUS_PW_CHANGED) logger.info("Changing the system status because: match={}".format(is_match)) except (ValueError, KeyError) as e: # most probably - an error of decryption as a result of pw change typo_db.set_status(SYSTEM_STATUS_PW_CHANGED) logger.exception("Key error raised. Probably a failure in decryption. Re-initializing...") typo_db.reinit_typtop(password) except Exception as e: logger.exception( "Unexpected error while on_correct_password:\n{}\n" .format(e) ) # In order to avoid locking out - always return true for correct password return True
def _decrypt_n_filter_waitlist(self): """Decrypts the waitlist and filters out the ones failed validity check. After that it combines the typos and returns a list of typos sorted by their frequency. return: [(typo_i, f_i)] """ filtered_typos = defaultdict(int) sk = deserialize_sk(self._sk) assert self._pwent >= 0, \ "pw={} is not initialized: {}".format(self._pw, self._pwent) ignore = set() install_id = self.get_installation_id() for typo_ctx in self.get_from_auxtdb(WAIT_LIST): # , yaml.load): typo_txt = pkdecrypt(sk, typo_ctx) typo, ts = yaml.safe_load(typo_txt) # starts with installation id, then must be garbage if typo.startswith(install_id): continue self.insert_log(typo, in_cache=False, ts=ts) if typo in ignore: continue if self.validate(self._pw, typo): filtered_typos[typo] += 1 else: logger.debug("Ignoring: {}".format(typo)) ignore.add(typo) logger.info("Waitlist decrypted successfully") return sorted(filtered_typos.items(), key=lambda a: a[1], reverse=True)
def get_last_unsent_logs_iter(self, force=False): """ Check what was the last time the log has been sent, And returns whether the log should be sent """ logger.debug("Getting last unsent logs") if not self.is_typtop_init(): logger.debug("Could not send. Typtop not initiated") return False, iter([]) if not self.is_allowed_upload(): logger.info("Not sending logs because send status set to False") return False, iter([]) last_sending = self.get_from_auxtdb(LOG_LAST_SENTTIME) # , float) update_gap = self.get_from_auxtdb(LOG_SENT_PERIOD) # , float) time_now = time.time() passed_enough_time = ((time_now - last_sending) >= update_gap) if not force and not passed_enough_time: logger.debug( "Not enough time has passed ({}) to send new logs.".format( str(last_sending))) return False, iter([]) log_t = self._db[logT] try: new_logs = iter( log_t) # .find(log_t.table.columns.ts >= last_sending) logger.info("Prepared new logs to be sent, from {} to {}".format( str(last_sending), str(time_now))) return True, new_logs except AttributeError: return False, iter([])
def _decrypt_n_filter_waitlist(self): """Decrypts the waitlist and filters out the ones failed validity check. After that it combines the typos and returns a list of typos sorted by their frequency. return: [(typo_i, f_i)] """ filtered_typos = defaultdict(int) sk = deserialize_sk(self._sk) assert self._pwent >= 0, \ "pw={} is not initialized: {}".format(self._pw, self._pwent) ignore = set() install_id = self.get_installation_id() for typo_ctx in self.get_from_auxtdb(WAIT_LIST): # , yaml.load): typo_txt = pkdecrypt(sk, typo_ctx) typo, ts = yaml.safe_load(typo_txt) # starts with installation id, then must be garbage if typo.startswith(install_id): continue self.insert_log(typo, in_cache=False, ts=ts) if typo in ignore: continue if self.validate(self._pw, typo): filtered_typos[typo] += 1 else: logger.debug("Ignoring: {}".format(typo)) ignore.add(typo) logger.info("Waitlist decrypted successfully") return sorted( filtered_typos.items(), key=lambda a: a[1], reverse=True )
def on_correct_password(typo_db, password): # log the entry of the original pwd logger.info("-^-") try: if not typo_db.is_typtop_init(): logger.error("Typtop DB wasn't initiated yet!") typo_db.init_typtop(password) # the initialization is now part of the installation process check_system_status(typo_db) # correct password but db fails to see it is_match = typo_db.check(password) if not is_match: logger.debug("Changing system status to {}.".format( SYSTEM_STATUS_PW_CHANGED)) typo_db.set_status(SYSTEM_STATUS_PW_CHANGED) logger.info("Changing the system status because: match={}".format( is_match)) except (ValueError, KeyError) as e: # most probably - an error of decryption as a result of pw change typo_db.set_status(SYSTEM_STATUS_PW_CHANGED) logger.exception( "Key error raised. Probably a failure in decryption. Re-initializing..." ) typo_db.reinit_typtop(password) except Exception as e: logger.exception( "Unexpected error while on_correct_password:\n{}\n".format(e)) # In order to avoid locking out - always return true for correct password return True
def get_last_unsent_logs_iter(self, force=False): """ Check what was the last time the log has been sent, And returns whether the log should be sent """ logger.debug("Getting last unsent logs") if not self.is_typtop_init(): logger.debug("Could not send. Typtop not initiated") return False, iter([]) if not self.is_allowed_upload(): logger.info("Not sending logs because send status set to False") return False, iter([]) last_sending = self.get_from_auxtdb(LOG_LAST_SENTTIME) # , float) update_gap = self.get_from_auxtdb(LOG_SENT_PERIOD) # , float) time_now = time.time() passed_enough_time = ((time_now - last_sending) >= update_gap) if not force and not passed_enough_time: logger.debug("Not enough time has passed ({}) to send new logs." .format(str(last_sending))) return False, iter([]) log_t = self._db[logT] try: new_logs = iter(log_t) # .find(log_t.table.columns.ts >= last_sending) logger.info("Prepared new logs to be sent, from {} to {}".format( str(last_sending), str(time_now)) ) return True, new_logs except AttributeError: return False, iter([])
def allow(self, what, how): self.assert_initialized() assert how in (True, False, 0, 1), "Expects a boolean" how = True if how else False self.set_in_auxtdb(what, how) state = "ON" if how else "OFF" logger.info("typtop::{} set to {}".format(what, state))
def on_wrong_password(typo_db, password): logger.info("-\/-") is_match = False try: if not typo_db.is_typtop_init(): logger.error("Typtop DB wasn't initiated yet!") # typo_db.init_typtop(password) return False check_system_status(typo_db) is_match = typo_db.check(password) # password has changed and this is an old password if is_match and typo_db.is_real_pw(password): logger.info( "Password changed, old password entered. Re-initializing..") typo_db.reinit_typtop(urlsafe_b64encode(os.urandom(16))) return False except (ValueError, KeyError) as e: # probably failure in decryption logger.exception( "Error!! Probably failure in decryption. Re-initializing...") typo_db.reinit_typtop(password) except Exception as e: logger.exception("Unexpected error while on_wrong_password:\n{}\n"\ .format(e)) print("TypToP is not initialized.\n $ sudo typtop --init") return is_match
def __del__(self): tmp_f = self._db_path + '.tmp' with open(tmp_f, 'wb') as f: json.dump(self._db, f, indent=2) f.flush(); os.fsync(f.fileno()) os.rename(tmp_f, self._db_path) change_db_ownership(self._db_path) logger.info("---UserTypoDB deleted---")
def __del__(self): tmp_f = self._db_path + '.tmp' with open(tmp_f, 'wb') as f: json.dump(self._db, f, indent=2) f.flush() os.fsync(f.fileno()) os.rename(tmp_f, self._db_path) change_db_ownership(self._db_path) logger.info("---UserTypoDB deleted---")
def check_login_count(self, update=False): # type: (boolean) -> boolean """Keeps track of how many times the user has successfully logged in.""" count_entry = self.get_from_auxtdb(LOGIN_COUNT) + 1 if update: self.set_in_auxtdb(LOGIN_COUNT, count_entry) allowed = count_entry > NUMBER_OF_ENTRIES_TO_ALLOW_TYPO_LOGIN if not allowed: logger.info("Checking login count. Allowed = {}".format(allowed)) return allowed
def __init__(self, user, debug_mode=False): # type: (str, bool) -> None assert is_user(user), "User {!r} does not exists".format(user) # Disable Typtop for root # assert pwd.getpwnam(user).pw_uid != 0,\ # "Currently Typtop is disabled for {} user.".format(user) self._user = user # this is a real user. # homedir = pwd.getpwnam(self._user).pw_dir typo_dir = os.path.join(SEC_DB_PATH, user) self._db_path = os.path.join(typo_dir, DB_NAME + '.json') self._log_path = os.path.join(LOG_DIR, DB_NAME + '.log') # First thing first -- setting the logger object setup_logger(self._log_path, debug_mode, user) self.logger = logger # just in case I need it logger.info("---UserTypoDB instantiated---") # creating dir only if it doesn't exist if not os.path.exists(typo_dir): try: os.makedirs(typo_dir) os.system( "chgrp {1} {0} && chmod -R g+w {0} && chmod -R o-rw {0} {0}" .format(typo_dir, GROUP)) except OSError as error: logger.error( "Trying to create: {}, but seems like the database" " is not initialized.".format(typo_dir)) raise UserTypoDB.NoneInitiatedDB(error) if not os.path.exists(self._db_path): with open(self._db_path, 'w') as dbf: json.dump({}, dbf) # cmd = 'chown root:{1} {0} && chmod o-rw {0};'.format(self._db_path, GROUP) change_db_ownership(self._db_path) try: self._db = json.load(open(self._db_path, 'r')) except (ValueError, IOError) as e: self._db = {} if auxT in self._db: self._aux_tab = self._db[auxT] else: self._aux_tab = self._db[auxT] = {} # always contains the serialized versin of sk, pk self._sk, self._pk = None, None # the global salt for the hmac-id only will be available if # correct pw is provided. self._hmac_salt, self._pw, self._pwent = None, '', -1
def __init__(self, user, debug_mode=False): # type: (str, bool) -> None assert is_user(user), "User {!r} does not exists".format(user) # Disable Typtop for root # assert pwd.getpwnam(user).pw_uid != 0,\ # "Currently Typtop is disabled for {} user.".format(user) self._user = user # this is a real user. # homedir = pwd.getpwnam(self._user).pw_dir typo_dir = os.path.join(SEC_DB_PATH, user) self._db_path = os.path.join(typo_dir, DB_NAME + '.json') self._log_path = os.path.join(LOG_DIR, DB_NAME + '.log') # First thing first -- setting the logger object setup_logger(self._log_path, debug_mode, user) self.logger = logger # just in case I need it logger.info("---UserTypoDB instantiated---") # creating dir only if it doesn't exist if not os.path.exists(typo_dir): try: os.makedirs(typo_dir) os.system( "chgrp {1} {0} && chmod -R g+w {0} && chmod -R o-rw {0} {0}".format(typo_dir, GROUP) ) except OSError as error: logger.error("Trying to create: {}, but seems like the database" " is not initialized.".format(typo_dir)) raise UserTypoDB.NoneInitiatedDB(error) if not os.path.exists(self._db_path): with open(self._db_path, 'w') as dbf: json.dump({}, dbf) # cmd = 'chown root:{1} {0} && chmod o-rw {0};'.format(self._db_path, GROUP) change_db_ownership(self._db_path) try: self._db = json.load(open(self._db_path, 'r')) except (ValueError, IOError) as e: self._db = {} if auxT in self._db: self._aux_tab = self._db[auxT] else: self._aux_tab = self._db[auxT] = {} # always contains the serialized versin of sk, pk self._sk, self._pk = None, None # the global salt for the hmac-id only will be available if # correct pw is provided. self._hmac_salt, self._pw, self._pwent = None, '', -1
def check(self, pw): logger.info("Checking entered password.") pk = self.get_pk() # cannot be tampered typo_cache = self.get_from_auxtdb(TYPO_CACHE) # , yaml.load) match_found = False freq_counts = [] i = 0 for i, sk_ctx in enumerate(typo_cache): try: sk = pwdecrypt(pw, sk_ctx) if not verify_pk_sk(pk, bytes(sk)): # Somehow the hash matched !! logger.error("pk-sk Verification failed!!") continue self._sk = sk except (TypeError, ValueError) as e: # Decryption Failed # print("Failed for {}.{} ({})".format(pw, i, e)) # that means password did not match. continue header = yaml.safe_load( pkdecrypt(sk, self.get_from_auxtdb(HEADER_CTX))) self._hmac_salt = urlsafe_b64decode(header[HMAC_SALT]) freq_counts = header[FREQ_COUNTS] if i > 0: freq_counts[i - 1] += 1 self._pw = header[REAL_PW] self._pwent = entropy(self._pw) self.insert_log(pw, in_cache=True, ts=get_time()) match_found = True break allowed = False if match_found: assert self._pwent >= 0, "PW is not initialized: {}".format( self._pwent) self._update_typo_cache_by_waitlist(typo_cache, freq_counts) if i == 0: # the real password entered self.check_login_count(update=True) allowed = True else: # A typo entered allowed = (self.check_login_count(update=False) and self.is_allowed_login()) else: self._add_typo_to_waitlist(pw) allowed = False logger.info("TypTop's decision: LoginAllowed = {}".format(allowed)) return allowed
def check(self, pw): logger.info("Checking entered password.") pk = self.get_pk() # cannot be tampered typo_cache = self.get_from_auxtdb(TYPO_CACHE) # , yaml.load) match_found = False freq_counts = [] i = 0 for i, sk_ctx in enumerate(typo_cache): try: sk = pwdecrypt(pw, sk_ctx) if not verify_pk_sk(pk, bytes(sk)): # Somehow the hash matched !! logger.error("pk-sk Verification failed!!") continue self._sk = sk except (TypeError, ValueError) as e: # Decryption Failed # print("Failed for {}.{} ({})".format(pw, i, e)) # that means password did not match. continue header = yaml.safe_load( pkdecrypt(sk, self.get_from_auxtdb(HEADER_CTX)) ) self._hmac_salt = urlsafe_b64decode(header[HMAC_SALT]) freq_counts = header[FREQ_COUNTS] if i > 0: freq_counts[i-1] += 1 self._pw = header[REAL_PW] self._pwent = entropy(self._pw) self.insert_log(pw, in_cache=True, ts=get_time()) match_found = True break allowed = False if match_found: assert self._pwent >= 0, "PW is not initialized: {}".format(self._pwent) self._update_typo_cache_by_waitlist(typo_cache, freq_counts) if i == 0: # the real password entered self.check_login_count(update=True) allowed = True else: # A typo entered allowed = (self.check_login_count(update=False) and self.is_allowed_login()) else: self._add_typo_to_waitlist(pw) allowed = False logger.info("TypTop's decision: LoginAllowed = {}".format(allowed)) return allowed
def reinit_typtop(self, newPw): """ Re-initiate the DB after a pw change. Most peripherial system settings don't change, including installID generates a new hmac salt, and encrypts the new pw, pw_ent, and the hmac salt """ if not self.is_typtop_init(): self.init_typtop(newPw) # Mostly a simple copy-paste of steps 1 to 2.5 logger.info("Re-intializing after a pw change") # 1. derive public_key from the original password # 2. encrypt the global salt with the enc pk self._hmac_salt = os.urandom(16) # global salt pk, sk = generate_key_pair() # ECC key pair self._pk, self._sk = pk, serialize_sk(sk) self._pw = newPw perm_index = self._fill_cache_w_garbage() if WARM_UP_CACHE: freq_counts = range(CACHE_SIZE, 0, -1) for i, f in enumerate(range(CACHE_SIZE)): freq_counts[perm_index[i]] = freq_counts[i] else: freq_counts = [0 for _ in range(CACHE_SIZE)] header_ctx = pkencrypt( self._pk, json.dumps({ REAL_PW: self._pw, HMAC_SALT: urlsafe_b64encode(self._hmac_salt), FREQ_COUNTS: freq_counts })) self.set_in_auxtdb(HEADER_CTX, header_ctx) self.set_in_auxtdb(ENC_PK, serialize_pk(self._pk)) # 3 sending logs and deleting tables: logger.debug("Sending logs, deleting tables") # 4. Filling the Typocache with garbage self._fill_waitlist_w_garbage() self.set_status(SYSTEM_STATUS_ALL_GOOD) logger.info("RE-Initialization Complete")
def reinit_typtop(self, newPw): """ Re-initiate the DB after a pw change. Most peripherial system settings don't change, including installID generates a new hmac salt, and encrypts the new pw, pw_ent, and the hmac salt """ if not self.is_typtop_init(): self.init_typtop(newPw) # Mostly a simple copy-paste of steps 1 to 2.5 logger.info("Re-intializing after a pw change") # 1. derive public_key from the original password # 2. encrypt the global salt with the enc pk self._hmac_salt = os.urandom(16) # global salt pk, sk = generate_key_pair() # ECC key pair self._pk, self._sk = pk, serialize_sk(sk) self._pw = newPw perm_index = self._fill_cache_w_garbage() if WARM_UP_CACHE: freq_counts = range(CACHE_SIZE, 0, -1) for i, f in enumerate(range(CACHE_SIZE)): freq_counts[perm_index[i]] = freq_counts[i] else: freq_counts = [0 for _ in range(CACHE_SIZE)] header_ctx = pkencrypt(self._pk, json.dumps({ REAL_PW: self._pw, HMAC_SALT: urlsafe_b64encode(self._hmac_salt), FREQ_COUNTS: freq_counts })) self.set_in_auxtdb(HEADER_CTX, header_ctx) self.set_in_auxtdb(ENC_PK, serialize_pk(self._pk)) # 3 sending logs and deleting tables: logger.debug("Sending logs, deleting tables") # 4. Filling the Typocache with garbage self._fill_waitlist_w_garbage() self.set_status(SYSTEM_STATUS_ALL_GOOD) logger.info("RE-Initialization Complete")
def _update_typo_cache_by_waitlist(self, typo_cache, freq_counts): """ Updates the hash cache according to waitlist and clears the waitlist @typo_cache: a list of typos in the cache, and @freq_counts are the corresponding frequencies. returns: Updated typo_cache and their frequencies. Also applies the permutations. """ logger.info("Updating TypoCache by Waitlist") good_typo_list = self._decrypt_n_filter_waitlist() mini, minf = min(enumerate(freq_counts), key=itemgetter(1)) for typo, f in good_typo_list: if UserTypoDB.cache_insert_policy(minf, f): logger.debug("Inserting: {} @ {}".format(typo, mini)) typo_cache[mini + 1] = pwencrypt(typo, self._sk) freq_counts[mini] = max(minf + 1, f) # TODO: Check mini, minf = min(enumerate(freq_counts), key=itemgetter(1)) else: logger.debug("I miss you: {} ({} <-> {})".format( typo, minf, f)) logger.debug("Freq counts: {}".format(freq_counts)) # write the new typo_cache and freq_list # TODO: Apply permutation header_ctx = pkencrypt( self._pk, json.dumps({ REAL_PW: self._pw, HMAC_SALT: urlsafe_b64encode(self._hmac_salt), FREQ_COUNTS: freq_counts })) logger.debug("Real pw={!r}".format(self._pw)) self.set_in_auxtdb(HEADER_CTX, header_ctx) self.set_in_auxtdb(TYPO_CACHE, typo_cache) self.clear_waitlist()
def on_wrong_password(typo_db, password): logger.info("-\/-") is_match = False try: if not typo_db.is_typtop_init(): logger.error("Typtop DB wasn't initiated yet!") # typo_db.init_typtop(password) return False check_system_status(typo_db) is_match = typo_db.check(password) # password has changed and this is an old password if is_match and typo_db.is_real_pw(password): logger.info("Password changed, old password entered. Re-initializing..") typo_db.reinit_typtop(urlsafe_b64encode(os.urandom(16))) return False except (ValueError, KeyError) as e: # probably failure in decryption logger.exception("Error!! Probably failure in decryption. Re-initializing...") typo_db.reinit_typtop(password) except Exception as e: logger.exception("Unexpected error while on_wrong_password:\n{}\n"\ .format(e)) print("TypToP is not initialized.\n $ sudo typtop --init") return is_match
def clear_waitlist(self): self._fill_waitlist_w_garbage() logger.info("Waitlist is deleted.")
def init_typtop(self, pw, allow_typo_login=True): """Create the 'typtop' database in user's home-directory. Changes Also, it initializes the required tables as well as the reuired variables, such as, the typo-cache size, the global salt etc. """ logger.info("Initiating typtop db with {}".format( dict(allow_typo_login=allow_typo_login))) change_db_ownership(self._db_path) # db[auxT].delete() # make sure there's no old unrelevent data # doesn't delete log because it will also be used # whenever a password is changed # *************** Initializing Aux Data ************************* # *************** add org password, its' pks && global salt: ******** # 1. derive public_key from the original password # 2. encrypt the global salt with the enc pk install_id = get_machine_id() install_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) last_sent_time = get_time() self._hmac_salt = os.urandom(SALT_LENGTH) # global salt self._pk, self._sk = generate_key_pair() # ECC key pair self._sk = serialize_sk(self._sk) self._pw = pw self._aux_tab.update({ INSTALLATION_ID: install_id, INSTALLATION_DATE: install_time, LOG_LAST_SENTTIME: last_sent_time, LOG_SENT_PERIOD: UPDATE_GAPS, SYSTEM_STATUS: SYSTEM_STATUS_NOT_INITIALIZED, LOGIN_COUNT: 0, ALLOWED_TYPO_LOGIN: allow_typo_login, ALLOWED_UPLOAD: True, ENC_PK: serialize_pk(self._pk), INDEX_J: random.randint(0, WAITLIST_SIZE - 1), }) # Just get the ids of all possible typo candidates for warming # up the cache. perm_index = self._fill_cache_w_garbage() if WARM_UP_CACHE: freq_counts = range(CACHE_SIZE, 0, -1) for i in range(CACHE_SIZE): freq_counts[perm_index[i]] = freq_counts[i] else: freq_counts = [0 for _ in range(CACHE_SIZE)] header_ctx = pkencrypt( self._pk, json.dumps({ REAL_PW: self._pw, HMAC_SALT: urlsafe_b64encode(self._hmac_salt), FREQ_COUNTS: freq_counts })) logger.info("Initializing the auxiliary data base ({})".format(auxT)) self._aux_tab[HEADER_CTX] = header_ctx # self._aux_tab.create_index(['desc']) self.set_status(SYSTEM_STATUS_ALL_GOOD) # 3. Filling the Typocache with garbage self._fill_waitlist_w_garbage() logger.debug("Initialization Complete") isON = self.get_from_auxtdb(ALLOWED_TYPO_LOGIN) # isON: boolean logger.info("typtop is ON? {}".format(isON))
def init_typtop(self, pw, allow_typo_login=True): """Create the 'typtop' database in user's home-directory. Changes Also, it initializes the required tables as well as the reuired variables, such as, the typo-cache size, the global salt etc. """ logger.info("Initiating typtop db with {}".format( dict(allow_typo_login=allow_typo_login) )) change_db_ownership(self._db_path) # db[auxT].delete() # make sure there's no old unrelevent data # doesn't delete log because it will also be used # whenever a password is changed # *************** Initializing Aux Data ************************* # *************** add org password, its' pks && global salt: ******** # 1. derive public_key from the original password # 2. encrypt the global salt with the enc pk install_id = get_machine_id() install_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()) last_sent_time = get_time() self._hmac_salt = os.urandom(SALT_LENGTH) # global salt self._pk, self._sk = generate_key_pair() # ECC key pair self._sk = serialize_sk(self._sk) self._pw = pw self._aux_tab.update({ INSTALLATION_ID: install_id, INSTALLATION_DATE: install_time, LOG_LAST_SENTTIME: last_sent_time, LOG_SENT_PERIOD: UPDATE_GAPS, SYSTEM_STATUS: SYSTEM_STATUS_NOT_INITIALIZED, LOGIN_COUNT: 0, ALLOWED_TYPO_LOGIN: allow_typo_login, ALLOWED_UPLOAD: True, ENC_PK: serialize_pk(self._pk), INDEX_J: random.randint(0, WAITLIST_SIZE-1), }) # Just get the ids of all possible typo candidates for warming # up the cache. perm_index = self._fill_cache_w_garbage() if WARM_UP_CACHE: freq_counts = range(CACHE_SIZE, 0, -1) for i in range(CACHE_SIZE): freq_counts[perm_index[i]] = freq_counts[i] else: freq_counts = [0 for _ in range(CACHE_SIZE)] header_ctx = pkencrypt(self._pk, json.dumps({ REAL_PW: self._pw, HMAC_SALT: urlsafe_b64encode(self._hmac_salt), FREQ_COUNTS: freq_counts })) logger.info("Initializing the auxiliary data base ({})".format(auxT)) self._aux_tab[HEADER_CTX] = header_ctx # self._aux_tab.create_index(['desc']) self.set_status(SYSTEM_STATUS_ALL_GOOD) # 3. Filling the Typocache with garbage self._fill_waitlist_w_garbage() logger.debug("Initialization Complete") isON = self.get_from_auxtdb(ALLOWED_TYPO_LOGIN) # isON: boolean logger.info("typtop is ON? {}".format(isON))