Add comprehensive remote authentication system allowing users to log in from one device by authenticating from another trusted device. Features include: - Proof of Work (PoW) protection using PBKDF2-SHA512 to prevent abuse - Simple pairing codes (3 words) protected by dynamic PoW difficulty - Autocomplete pairing code input with error checking - Real-time WebSocket communication between devices Unlike device addition links and reset links with QR codes that only allow adding an authentication method, and that work offline over the duration of several days, this mechanism is strictly online, with 5 minute time limit.
46 lines
1.4 KiB
Python
46 lines
1.4 KiB
Python
"""
|
|
Proof of Work utility using PBKDF2-SHA512.
|
|
|
|
The PoW requires finding nonces where PBKDF2(challenge, nonce) produces
|
|
output with a zero first byte. Each work unit requires finding one such nonce.
|
|
All valid nonces are concatenated into a solution for server verification.
|
|
"""
|
|
|
|
import hashlib
|
|
import secrets
|
|
|
|
EASY = 2 # Around 0.25s
|
|
NORMAL = 8 # Around 1s
|
|
HARD = 32 # Around 4s
|
|
|
|
|
|
def generate_challenge() -> bytes:
|
|
"""Generate a random 8-byte challenge."""
|
|
return secrets.token_bytes(8)
|
|
|
|
|
|
def verify_pow(challenge: bytes, solution: bytes, work: int = NORMAL) -> None:
|
|
"""Verify a Proof of Work solution.
|
|
|
|
Args:
|
|
challenge: 8-byte server-provided challenge
|
|
solution: Concatenated 8-byte nonces (8 * work bytes)
|
|
work: Number of work units expected
|
|
|
|
Raises:
|
|
ValueError: If the solution is invalid
|
|
"""
|
|
if len(challenge) != 8:
|
|
raise ValueError("Invalid challenge length")
|
|
|
|
if len(solution) != 8 * work:
|
|
raise ValueError("Invalid solution length")
|
|
|
|
# Verify each work unit - check that PBKDF2 output starts with 0x00
|
|
for i in range(work):
|
|
nonce = solution[i * 8 : (i + 1) * 8]
|
|
# Require first byte of PBKDF2-SHA512 to be zero
|
|
result = hashlib.pbkdf2_hmac("sha512", challenge, nonce, 128, 2)
|
|
if result[0] or result[1] & 0x07:
|
|
raise ValueError("Invalid PoW solution")
|