Beispiel #1
0
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
Beispiel #2
0
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
Beispiel #3
0
    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
        )
Beispiel #4
0
 def insert_log(self, typo, in_cache, ts=None):
     # type: (str, bool, int) -> None
     """Updates the log with information about typo. Remember, if sk_dict is
     not provided it will insert @typo as typo_id and 0 as relative_entropy.
     Note the default values used in other_info, which is basically what
     is expected for the original password.
     """
     assert self._pw and self._hmac_salt
     rel_ent = entropy(typo) - self._pwent
     if rel_ent == -self._pwent:
         logger.debug(
             'typo (={!r}) is an empty string, should not happen!!'.format(
                 typo))
     # cap rel_ent to the +10, -10
     rel_ent = max(-10, min(rel_ent, 10))
     edit_dist = min(5, distance(str(self._pw), str(typo)))
     log_info = {
         'tid': compute_id(self._hmac_salt, typo),
         'edit_dist': edit_dist,
         'rel_entropy': rel_ent,
         'ts': get_time if ts is None else ts,
         'localtime':
         time.asctime(),  # without zone, but gives local time in string.
         'istop5fixable': is_in_top5_fixes(self._pw, typo),
         'in_cache': in_cache
     }
     try:
         self._db[logT].append(log_info)
     except KeyError:
         self._db[logT] = [log_info]
Beispiel #5
0
 def insert_log(self, typo, in_cache, ts=None):
     # type: (str, bool, int) -> None
     """Updates the log with information about typo. Remember, if sk_dict is
     not provided it will insert @typo as typo_id and 0 as relative_entropy.
     Note the default values used in other_info, which is basically what
     is expected for the original password.
     """
     assert self._pw and self._hmac_salt
     rel_ent = entropy(typo) - self._pwent
     if rel_ent == -self._pwent:
         logger.debug('typo (={!r}) is an empty string, should not happen!!'
                      .format(typo))
     # cap rel_ent to the +10, -10
     rel_ent = max(-10, min(rel_ent, 10))
     edit_dist = min(5, distance(str(self._pw), str(typo)))
     log_info = {
         'tid': compute_id(self._hmac_salt, typo),
         'edit_dist': edit_dist,
         'rel_entropy': rel_ent,
         'ts': get_time if ts is None else ts,
         'localtime': time.asctime(),  # without zone, but gives local time in string.
         'istop5fixable': is_in_top5_fixes(self._pw, typo),
         'in_cache': in_cache
     }
     try:
         self._db[logT].append(log_info)
     except KeyError:
         self._db[logT] = [log_info]
Beispiel #6
0
    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)
Beispiel #7
0
def entropy(typo):
    ent = 0
    if typo not in _entropy_cache:
        if not typo or len(typo) == 0:
            _entropy_cache[typo] = 0
        else:
            try:
                n_guesses = zxcvbn(typo)['guesses']
                _entropy_cache[typo] = math.log(n_guesses)
            except IndexError as e:
                logger.exception(e)
                logger.debug(typo)
    return _entropy_cache[typo]
Beispiel #8
0
def entropy(typo):
    ent = 0
    if typo not in _entropy_cache:
        if not typo or len(typo) == 0:
            _entropy_cache[typo] = 0
        else:
            try:
                n_guesses = zxcvbn(typo)['guesses']
                _entropy_cache[typo] = math.log(n_guesses)
            except IndexError as e:
                logger.exception(e)
                logger.debug(typo)
    return _entropy_cache[typo]
Beispiel #9
0
    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()
Beispiel #10
0
    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")
Beispiel #11
0
 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([])
Beispiel #12
0
 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([])
Beispiel #13
0
    def _fill_cache_w_garbage(self):
        logger.debug("Filling Typocache with garbage")
        perm_index = range(CACHE_SIZE)
        random.shuffle(perm_index)
        pw = self._pw
        popular_typos = [os.urandom(16) for _ in range(CACHE_SIZE)]
        self._pwent = entropy(self._pw)

        # if WARM_UP_CACHE: # No need to check, assumes always WARM_UP
        i = 0
        for tpw in warm_up_with(pw):
            if WARM_UP_CACHE and i < CACHE_SIZE and pw != tpw and tpw not in popular_typos:
                self.insert_log(typo=tpw, in_cache=True, ts=-1)
                popular_typos[perm_index[i]] = tpw
                i += 1
            elif pw != tpw:
                self.insert_log(typo=tpw, in_cache=False, ts=-1)

        popular_typos = [pw] + popular_typos
        garbage_list = [pwencrypt(tpw, self._sk) for tpw in popular_typos]
        self.set_in_auxtdb(TYPO_CACHE, garbage_list)
        return perm_index
Beispiel #14
0
    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")
Beispiel #15
0
 def update_last_log_sent_time(self, sent_time=0, delete_old_logs=True):
     logger.debug("updating log sent time")
     if not sent_time:
         sent_time = get_time()
         logger.debug("generating new timestamp={} ".format(sent_time))
     self._db[auxT][LOG_LAST_SENTTIME] = float(sent_time)
     if delete_old_logs:
         logger.debug("deleting old logs")
         del self._db[logT][:]
Beispiel #16
0
 def update_last_log_sent_time(self, sent_time=0, delete_old_logs=True):
     logger.debug("updating log sent time")
     if not sent_time:
         sent_time = get_time()
         logger.debug("generating new timestamp={} ".format(sent_time))
     self._db[auxT][LOG_LAST_SENTTIME] = float(sent_time)
     if delete_old_logs:
         logger.debug("deleting old logs")
         del self._db[logT][:]
Beispiel #17
0
    def _fill_cache_w_garbage(self):
        logger.debug("Filling Typocache with garbage")
        perm_index = range(CACHE_SIZE)
        random.shuffle(perm_index)
        pw = self._pw
        popular_typos = [os.urandom(16) for _ in range(CACHE_SIZE)]
        self._pwent = entropy(self._pw)

        # if WARM_UP_CACHE: # No need to check, assumes always WARM_UP
        i = 0
        for tpw in warm_up_with(pw):
            if WARM_UP_CACHE and i < CACHE_SIZE and pw != tpw and tpw not in popular_typos:
                self.insert_log(typo=tpw, in_cache=True, ts=-1)
                popular_typos[perm_index[i]] = tpw
                i += 1
            elif pw != tpw:
                self.insert_log(typo=tpw, in_cache=False, ts=-1)

        popular_typos = [pw] + popular_typos
        garbage_list = [
            pwencrypt(tpw, self._sk) for tpw in popular_typos
        ]
        self.set_in_auxtdb(TYPO_CACHE, garbage_list)
        return perm_index
Beispiel #18
0
 def _add_typo_to_waitlist(self, typo):
     """Adds the typo to the waitlist.
     @typo (string) : typo of the user's passwrod
     """
     logger.debug("Adding a new typo to waitlist")
     logger.debug("Adding: {}".format(typo))
     waitlist = self.get_from_auxtdb(WAIT_LIST)  # , yaml.load)
     indexj = int(self.get_from_auxtdb(INDEX_J))  # , int))
     ts = get_time()
     assert indexj < len(waitlist), \
         "Index_j={}, wait-list={}".format(indexj, waitlist)
     waitlist[indexj] = pkencrypt(self.get_pk(), json.dumps([typo, ts]))
     indexj = (indexj + 1) % WAITLIST_SIZE
     self.set_in_auxtdb(WAIT_LIST, waitlist)
     self.set_in_auxtdb(INDEX_J, indexj)
     logger.debug("Typo encrypted.")
Beispiel #19
0
 def _add_typo_to_waitlist(self, typo):
     """Adds the typo to the waitlist.
     @typo (string) : typo of the user's passwrod
     """
     logger.debug("Adding a new typo to waitlist")
     logger.debug("Adding: {}".format(typo))
     waitlist = self.get_from_auxtdb(WAIT_LIST)  # , yaml.load)
     indexj = int(self.get_from_auxtdb(INDEX_J))  # , int))
     ts = get_time()
     assert indexj < len(waitlist), \
         "Index_j={}, wait-list={}".format(indexj, waitlist)
     waitlist[indexj] = pkencrypt(self.get_pk(), json.dumps([typo, ts]))
     indexj = (indexj + 1) % WAITLIST_SIZE
     self.set_in_auxtdb(WAIT_LIST, waitlist)
     self.set_in_auxtdb(INDEX_J, indexj)
     logger.debug("Typo encrypted.")
Beispiel #20
0
    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()
Beispiel #21
0
    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))
Beispiel #22
0
    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))