-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
9d4aae4
commit 435a22a
Showing
5 changed files
with
187 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
from __future__ import annotations | ||
|
||
import contextlib | ||
from typing import Literal | ||
|
||
import argon2 | ||
from argon2.exceptions import InvalidHashError, VerifyMismatchError | ||
|
||
from libpass._utils.bytes import StrOrBytes, as_bytes, as_str | ||
from libpass.hashers.abc import PasswordHasher | ||
from libpass.inspect.phc import inspect_phc | ||
from libpass.inspect.phc.defs import any_argon_phc | ||
|
||
|
||
class Argon2Hasher(PasswordHasher): | ||
def __init__( | ||
self, | ||
time_cost: int = argon2.DEFAULT_TIME_COST, | ||
memory_cost: int = argon2.DEFAULT_MEMORY_COST, | ||
parallelism: int = argon2.DEFAULT_PARALLELISM, | ||
hash_len: int = argon2.DEFAULT_HASH_LENGTH, | ||
salt_len: int = argon2.DEFAULT_RANDOM_SALT_LENGTH, | ||
type: Literal["d", "i", "id"] = "id", | ||
): | ||
self._hasher = argon2.PasswordHasher( | ||
time_cost=time_cost, | ||
memory_cost=memory_cost, | ||
parallelism=parallelism, | ||
hash_len=hash_len, | ||
salt_len=salt_len, | ||
type=argon2.Type[type.upper()], | ||
) | ||
|
||
def hash(self, secret: StrOrBytes, salt: str | None = None) -> str: | ||
return self._hasher.hash( | ||
password=secret, salt=as_bytes(salt) if salt is not None else None | ||
) | ||
|
||
def verify(self, hash: StrOrBytes, secret: StrOrBytes) -> bool: | ||
with contextlib.suppress(InvalidHashError, VerifyMismatchError): | ||
return self._hasher.verify(hash=hash, password=secret) | ||
return False | ||
|
||
def identify(self, hash: StrOrBytes) -> bool: | ||
return inspect_phc(hash=as_str(hash), definition=any_argon_phc) is not None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
from __future__ import annotations | ||
|
||
import pytest | ||
|
||
from libpass.errors import Panic | ||
from libpass.hashers.argon2 import Argon2Hasher | ||
from libpass.inspect.phc import inspect_phc | ||
from libpass.inspect.phc.defs import ( | ||
BaseArgon2PHC, | ||
any_argon_phc, | ||
) | ||
|
||
|
||
@pytest.fixture | ||
def hasher() -> Argon2Hasher: | ||
return Argon2Hasher() | ||
|
||
|
||
@pytest.mark.parametrize( | ||
("secret", "salt", "hash"), | ||
[ | ||
( | ||
"password", | ||
"somesalt", | ||
"$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$wWKIMhR9lyDFvRz9YTZweHKfbftvj+qf+YFY4NeBbtA", | ||
), | ||
( | ||
"password", | ||
"somesalt", | ||
"$argon2i$v=19$m=1048576,t=2,p=1$c29tZXNhbHQ$0Vh6ygkiw7XWqD7asxvuPE667zQu1hJ6VdGbI1GtH0E", | ||
), | ||
( | ||
"password", | ||
"somesalt", | ||
"$argon2i$v=19$m=262144,t=2,p=1$c29tZXNhbHQ$KW266AuAfNzqrUSudBtQbxTbCVkmexg7EY+bJCKbx8s", | ||
), | ||
( | ||
"password", | ||
"somesalt", | ||
"$argon2i$v=19$m=256,t=2,p=1$c29tZXNhbHQ$iekCn0Y3spW+sCcFanM2xBT63UP2sghkUoHLIUpWRS8", | ||
), | ||
( | ||
"password", | ||
"somesalt", | ||
"$argon2i$v=19$m=256,t=2,p=2$c29tZXNhbHQ$T/XOJ2mh1/TIpJHfCdQan76Q5esCFVoT5MAeIM1Oq2E", | ||
), | ||
( | ||
"password", | ||
"somesalt", | ||
"$argon2i$v=19$m=65536,t=1,p=1$c29tZXNhbHQ$0WgHXE2YXhPr6uVgz4uUw7XYoWxRkWtvSsLaOsEbvs8", | ||
), | ||
( | ||
"password", | ||
"somesalt", | ||
"$argon2i$v=19$m=65536,t=4,p=1$c29tZXNhbHQ$qqlT1YrzcGzj3xrv1KZKhOMdf1QXUjHxKFJZ+IF0zls", | ||
), | ||
( | ||
"differentpassword", | ||
"somesalt", | ||
"$argon2i$v=19$m=65536,t=2,p=1$c29tZXNhbHQ$FK6NoBr+qHAMI1jc73xTWNkCEoK9iGY6RWL1n7dNIu4", | ||
), | ||
( | ||
"password", | ||
"diffsalt", | ||
"$argon2i$v=19$m=65536,t=2,p=1$ZGlmZnNhbHQ$sDV8zPvvkfOGCw26RHsjSMvv7K2vmQq/6cxAcmxSEnE", | ||
), | ||
], | ||
) | ||
def test_hash_version_19( | ||
secret: str, | ||
salt: str, | ||
hash: str, | ||
) -> None: | ||
info: BaseArgon2PHC | None = inspect_phc(hash=hash, definition=any_argon_phc) | ||
if not info: | ||
raise Panic | ||
hasher = Argon2Hasher( | ||
parallelism=info.parallelism_cost, | ||
time_cost=info.time_cost, | ||
memory_cost=info.memory_cost, | ||
type=info.type, | ||
) | ||
hashed = hasher.hash(secret=secret, salt=salt) | ||
assert hashed == hash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters