You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/Resources/WPy64-3720/python-3.7.2.amd64/Lib/site-packages/argon2/_utils.py

199 lines
4.6 KiB

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
from six import iteritems
from .exceptions import InvalidHash
from .low_level import Type
NoneType = type(None)
def _check_types(**kw):
"""
Check each ``name: (value, types)`` in *kw*.
Returns a human-readable string of all violations or `None``.
"""
errors = []
for name, (value, types) in iteritems(kw):
if not isinstance(value, types):
if isinstance(types, tuple):
types = ", or ".join(t.__name__ for t in types)
else:
types = types.__name__
errors.append(
"'{name}' must be a {type} (got {actual})".format(
name=name, type=types, actual=type(value).__name__
)
)
if errors != []:
return ", ".join(errors) + "."
def _encoded_str_len(l):
"""
Compute how long a byte string of length *l* becomes if encoded to hex.
"""
return (l << 2) / 3 + 2
def _decoded_str_len(l):
"""
Compute how long an encoded string of length *l* becomes.
"""
rem = l % 4
if rem == 3:
last_group_len = 2
elif rem == 2:
last_group_len = 1
else:
last_group_len = 0
return l // 4 * 3 + last_group_len
class Parameters(object):
"""
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
"""
__slots__ = [
"type",
"version",
"salt_len",
"hash_len",
"time_cost",
"memory_cost",
"parallelism",
]
def __init__(
self,
type,
version,
salt_len,
hash_len,
time_cost,
memory_cost,
parallelism,
):
self.type = type
self.version = version
self.salt_len = salt_len
self.hash_len = hash_len
self.time_cost = time_cost
self.memory_cost = memory_cost
self.parallelism = parallelism
def __repr__(self):
return (
"<Parameters(type=%r, version=%d, hash_len=%d, salt_len=%d, "
"time_cost=%d, memory_cost=%d, parallelelism=%d)>"
% (
self.type,
self.version,
self.hash_len,
self.salt_len,
self.time_cost,
self.memory_cost,
self.parallelism,
)
)
def __eq__(self, other):
if self.__class__ != other.__class__:
return NotImplemented
return (
self.type,
self.version,
self.salt_len,
self.hash_len,
self.time_cost,
self.memory_cost,
self.parallelism,
) == (
other.type,
other.version,
other.salt_len,
other.hash_len,
other.time_cost,
other.memory_cost,
other.parallelism,
)
def __ne__(self, other):
if self.__class__ != other.__class__:
return NotImplemented
return not self.__eq__(other)
_NAME_TO_TYPE = {"argon2id": Type.ID, "argon2i": Type.I, "argon2d": Type.D}
_REQUIRED_KEYS = sorted(("v", "m", "t", "p"))
def extract_parameters(hash):
"""
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 InvalidHash
if parts[0] != "":
raise InvalidHash
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:
raise InvalidHash
if sorted(kvs.keys()) != _REQUIRED_KEYS:
raise InvalidHash
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"],
)