Exemple #1
0
    async def user_auth(self, username, token, totp, psbt_hash):
        if len(token) == 6 and token.isdigit():
            # assume TOTP if token (password) is 6-numeric digits
            totp_time = totp or int(time.time() // 30)
            token = token.encode('ascii')
        else:
            # assume it's a raw password. need to hash it up
            # TODO: move this hashing into browser
            secret = self.dev.hash_password(token.encode('utf8'))
            token = HMAC(secret, msg=psbt_hash, digestmod=sha256).digest()
            totp_time = 0

        await self.send_recv(
            CCProtocolPacker.user_auth(username.encode('ascii'), token,
                                       totp_time))
Exemple #2
0
def user_auth(username,
              token=None,
              password=None,
              prompt=None,
              totp=None,
              psbt_file=None,
              debug=False,
              version3=False):
    """
    Indicate specific user is present (for HSM).

    Username and 2FA (TOTP, 6-digits) value or password are required. To use
    password, the PSBT file in question must be provided.
    """
    import time
    from hmac import HMAC
    from hashlib import pbkdf2_hmac, sha256

    dryrun = True
    with get_device() as dev:
        dev.check_mitm()

        if psbt_file or password:
            if psbt_file:
                psbt_hash = sha256(psbt_file.read()).digest()
                dryrun = False
            else:
                psbt_hash = bytes(32)

            pw = token or click.prompt('Password (hidden)', hide_input=True)
            secret = dev.hash_password(pw.encode('utf8'), v3=version3)

            token = HMAC(secret, msg=psbt_hash, digestmod=sha256).digest()

            if debug:
                click.echo("  secret = %s" % B2A(secret))
                click.echo("    salt = %s" % B2A(salt))

            totp_time = 0
        else:
            if not token:
                token = click.prompt('2FA Token (6 digits)', hide_input=False)

            if len(token) != 6 or not token.isdigit():
                raise click.UsageError("2FA Token must be 6 decimal digits")

            token = token.encode('ascii')

            now = int(time.time())
            if now % 30 < 5:
                click.echo(
                    "NOTE: TOTP was on edge of expiry limit! Might not work.")
            totp_time = now // 30

        #raise click.UsageError("Need PSBT file as part of HMAC for password")

        assert token and len(token) in {6, 32}
        username = username.encode('ascii')

        if debug:
            click.echo(" username = %s" % username.decode('ascii'))
            click.echo(
                "    token = %s" %
                (B2A(token) if len(token) > 6 else token.decode('ascii')))
            click.echo("totp_time = %d" % totp_time)

        resp = dev.send_recv(
            CCProtocolPacker.user_auth(username, token, totp_time))

        if not resp:
            click.echo("Correct or queued")
        else:
            click.echo(f'Problem: {resp}')