fix password digests

This commit is contained in:
evilchili 2025-10-04 13:27:38 -07:00
parent 7eb06b150e
commit 76e65def2c
2 changed files with 22 additions and 2 deletions

View File

@ -1,7 +1,9 @@
from __future__ import annotations
import hashlib
import hmac
import os
import re
from collections import namedtuple
from dataclasses import dataclass, field
from typing import Dict, List
@ -57,6 +59,21 @@ class Password(Field):
salt_size = 4
digest_size = 16
@classmethod
def is_digest(cls, passwd: str):
if not passwd:
return False
offset = 2 * cls.salt_size # each byte is 2 hex chars
try:
if passwd[offset] != ":":
return False
digest = passwd[offset + 1 :]
if len(digest) != cls.digest_size * 2:
return False
return re.match(r"^[0-9a-f]+$", digest)
except IndexError:
return False
@classmethod
def get_digest(cls, passwd: str, salt: bytes = None):
if not salt:
@ -68,10 +85,10 @@ class Password(Field):
def compare(cls, passwd: value_type, stored: value_type):
stored_salt, stored_digest = stored.split(":")
input_digest, input_salt = cls.get_digest(passwd, bytes.fromhex(stored_salt))
return input_digest == stored_digest
return hmac.compare_digest(input_digest, stored_digest)
def before_insert(self, value: value_type, db: TinyDB, record: Record) -> None:
if value:
if value and not self.__class__.is_digest(value):
digest, salt = self.__class__.get_digest(value)
record[self.name] = f"{salt}:{digest}"

View File

@ -123,6 +123,9 @@ def test_search(db):
def test_password(db):
user = db.save(examples.User(name="john", email="john@foo", password="fnord"))
# make sure we don't compute the digest on an existing digest
user = db.save(user)
assert ":" in user.password
assert user.password != "fnord"