# -*- coding: utf-8 -*-

import hashlib
import secrets


def rfc2440_hash_password(password, salt=None):
    # Match tor --hash-password
    # secret_to_key_rfc2440

    EXPBIAS = 6
    c = 96
    count = (16 + (c & 15)) << ((c >> 4) + EXPBIAS)

    if salt is None:
        salt = secrets.token_bytes(8)
    assert len(salt) == 8

    hashbytes = salt + password.encode("utf-8")
    len_hashbytes = len(hashbytes)
    h = hashlib.sha1()

    while count > 0:
        if count >= len_hashbytes:
            h.update(hashbytes)
            count -= len_hashbytes
            continue
        h.update(hashbytes[:count])
        break
    rv = "16:" + salt.hex() + "60" + h.hexdigest()
    return rv.upper()


def verify_rfc2440_password(stored_hash, provided_password):
    """
    Verifies a password against a hash generated by rfc2440_hash_password.

    Args:
        stored_hash (str): The hash string stored (e.g., "16:<salt>60<hash>").
        provided_password (str): The password attempt to verify.

    Returns:
        bool: True if the password matches the hash, False otherwise.
    """
    try:
        parts = stored_hash.upper().split(":")
        if len(parts) != 2 or parts[0] != "16":
            return False

        salt_hex_plus_hash_hex = parts[1]
        separator_index = salt_hex_plus_hash_hex.find("60")
        if separator_index != 16:
            return False

        salt_hex = salt_hex_plus_hash_hex[:separator_index]
        expected_hash_hex = salt_hex_plus_hash_hex[separator_index + 2 :]

        salt = bytes.fromhex(salt_hex)
    except (ValueError, IndexError):
        return False

    EXPBIAS = 6
    c = 96
    count = (16 + (c & 15)) << ((c >> 4) + EXPBIAS)

    hashbytes = salt + provided_password.encode("utf-8")
    len_hashbytes = len(hashbytes)
    h = hashlib.sha1()

    while count > 0:
        if count >= len_hashbytes:
            h.update(hashbytes)
            count -= len_hashbytes
            continue
        h.update(hashbytes[:count])
        break

    calculated_hash_hex = h.hexdigest().upper()
    return secrets.compare_digest(calculated_hash_hex, expected_hash_hex)
