Spaces:
Runtime error
Runtime error
# SPDX-License-Identifier: MIT | |
from __future__ import annotations | |
from dataclasses import dataclass | |
from typing import Any | |
from .exceptions import InvalidHashError | |
from .low_level import Type | |
NoneType = type(None) | |
def _check_types(**kw: Any) -> str | None: | |
""" | |
Check each ``name: (value, types)`` in *kw*. | |
Returns a human-readable string of all violations or `None``. | |
""" | |
errors = [] | |
for name, (value, types) in kw.items(): | |
if not isinstance(value, types): | |
if isinstance(types, tuple): | |
types = ", or ".join(t.__name__ for t in types) | |
else: | |
types = types.__name__ | |
errors.append( | |
f"'{name}' must be a {types} (got {type(value).__name__})" | |
) | |
if errors != []: | |
return ", ".join(errors) + "." | |
return None | |
def _decoded_str_len(length: int) -> int: | |
""" | |
Compute how long an encoded string of length *l* becomes. | |
""" | |
rem = length % 4 | |
if rem == 3: | |
last_group_len = 2 | |
elif rem == 2: | |
last_group_len = 1 | |
else: | |
last_group_len = 0 | |
return length // 4 * 3 + last_group_len | |
class Parameters: | |
""" | |
Argon2 hash parameters. | |
See :doc:`parameters` on how to pick them. | |
:ivar Type type: Hash type. | |
:ivar int version: Argon2 version. | |
:ivar int salt_len: Length of the salt in bytes. | |
:ivar int hash_len: Length of the hash in bytes. | |
:ivar int time_cost: Time cost in iterations. | |
:ivar int memory_cost: Memory cost in kibibytes. | |
:ivar int parallelism: Number of parallel threads. | |
.. versionadded:: 18.2.0 | |
""" | |
type: Type | |
version: int | |
salt_len: int | |
hash_len: int | |
time_cost: int | |
memory_cost: int | |
parallelism: int | |
__slots__ = ( | |
"type", | |
"version", | |
"salt_len", | |
"hash_len", | |
"time_cost", | |
"memory_cost", | |
"parallelism", | |
) | |
_NAME_TO_TYPE = {"argon2id": Type.ID, "argon2i": Type.I, "argon2d": Type.D} | |
_REQUIRED_KEYS = sorted(("v", "m", "t", "p")) | |
def extract_parameters(hash: str) -> Parameters: | |
""" | |
Extract parameters from an encoded *hash*. | |
:param str params: An encoded Argon2 hash string. | |
:rtype: Parameters | |
.. versionadded:: 18.2.0 | |
""" | |
parts = hash.split("$") | |
# Backwards compatibility for Argon v1.2 hashes | |
if len(parts) == 5: | |
parts.insert(2, "v=18") | |
if len(parts) != 6: | |
raise InvalidHashError | |
if parts[0]: | |
raise InvalidHashError | |
try: | |
type = _NAME_TO_TYPE[parts[1]] | |
kvs = { | |
k: int(v) | |
for k, v in ( | |
s.split("=") for s in [parts[2], *parts[3].split(",")] | |
) | |
} | |
except Exception: # noqa: BLE001 | |
raise InvalidHashError from None | |
if sorted(kvs.keys()) != _REQUIRED_KEYS: | |
raise InvalidHashError | |
return Parameters( | |
type=type, | |
salt_len=_decoded_str_len(len(parts[4])), | |
hash_len=_decoded_str_len(len(parts[5])), | |
version=kvs["v"], | |
time_cost=kvs["t"], | |
memory_cost=kvs["m"], | |
parallelism=kvs["p"], | |
) | |