first commit

This commit is contained in:
Ayxan
2022-05-23 00:16:32 +04:00
commit d660f2a4ca
24786 changed files with 4428337 additions and 0 deletions

View File

@ -0,0 +1,51 @@
# SPDX-License-Identifier: MIT
"""
The secure Argon2 password hashing algorithm.
"""
from . import exceptions, low_level, profiles
from ._legacy import hash_password, hash_password_raw, verify_password
from ._password_hasher import (
DEFAULT_HASH_LENGTH,
DEFAULT_MEMORY_COST,
DEFAULT_PARALLELISM,
DEFAULT_RANDOM_SALT_LENGTH,
DEFAULT_TIME_COST,
PasswordHasher,
)
from ._utils import Parameters, extract_parameters
from .low_level import Type
__version__ = "21.3.0"
__title__ = "argon2-cffi"
__description__ = (__doc__ or "").strip()
__url__ = "https://argon2-cffi.readthedocs.io/"
__uri__ = __url__
__author__ = "Hynek Schlawack"
__email__ = "hs@ox.cx"
__license__ = "MIT"
__copyright__ = "Copyright (c) 2015 " + __author__
__all__ = [
"DEFAULT_HASH_LENGTH",
"DEFAULT_MEMORY_COST",
"DEFAULT_PARALLELISM",
"DEFAULT_RANDOM_SALT_LENGTH",
"DEFAULT_TIME_COST",
"Parameters",
"PasswordHasher",
"Type",
"exceptions",
"extract_parameters",
"hash_password",
"hash_password_raw",
"low_level",
"profiles",
"verify_password",
]

View File

@ -0,0 +1,97 @@
# SPDX-License-Identifier: MIT
import argparse
import sys
import timeit
from typing import List
from . import (
DEFAULT_HASH_LENGTH,
DEFAULT_MEMORY_COST,
DEFAULT_PARALLELISM,
DEFAULT_TIME_COST,
PasswordHasher,
profiles,
)
def main(argv: List[str]) -> None:
parser = argparse.ArgumentParser(description="Benchmark Argon2.")
parser.add_argument(
"-n", type=int, default=100, help="Number of iterations to measure."
)
parser.add_argument(
"-t", type=int, help="`time_cost`", default=DEFAULT_TIME_COST
)
parser.add_argument(
"-m", type=int, help="`memory_cost`", default=DEFAULT_MEMORY_COST
)
parser.add_argument(
"-p", type=int, help="`parallelism`", default=DEFAULT_PARALLELISM
)
parser.add_argument(
"-l", type=int, help="`hash_length`", default=DEFAULT_HASH_LENGTH
)
parser.add_argument(
"--profile",
type=str,
help="A profile from `argon2.profiles. Takes precendence.",
default=None,
)
args = parser.parse_args(argv[1:])
password = b"secret"
if args.profile:
ph = PasswordHasher.from_parameters(
getattr(profiles, args.profile.upper())
)
else:
ph = PasswordHasher(
time_cost=args.t,
memory_cost=args.m,
parallelism=args.p,
hash_len=args.l,
)
hash = ph.hash(password)
params = {
"time_cost": (ph.time_cost, "iterations"),
"memory_cost": (ph.memory_cost, "KiB"),
"parallelism": (ph.parallelism, "threads"),
"hash_len": (ph.hash_len, "bytes"),
}
print("Running Argon2id %d times with:" % (args.n,))
for k, v in sorted(params.items()):
print("%s: %d %s" % (k, v[0], v[1]))
print("\nMeasuring...")
duration = timeit.timeit(
"ph.verify({hash!r}, {password!r})".format(
hash=hash, password=password
),
setup="""\
from argon2 import PasswordHasher, Type
ph = PasswordHasher(
time_cost={time_cost!r},
memory_cost={memory_cost!r},
parallelism={parallelism!r},
hash_len={hash_len!r},
)
gc.enable()""".format(
time_cost=args.t,
memory_cost=args.m,
parallelism=args.p,
hash_len=args.l,
),
number=args.n,
)
print(f"\n{duration / args.n * 1000:.1f}ms per password verification")
if __name__ == "__main__": # pragma: no cover
main(sys.argv)

View File

@ -0,0 +1,75 @@
# SPDX-License-Identifier: MIT
"""
Legacy mid-level functions.
"""
import os
from typing import Optional
from ._password_hasher import (
DEFAULT_HASH_LENGTH,
DEFAULT_MEMORY_COST,
DEFAULT_PARALLELISM,
DEFAULT_RANDOM_SALT_LENGTH,
DEFAULT_TIME_COST,
)
from ._typing import Literal
from .low_level import Type, hash_secret, hash_secret_raw, verify_secret
def hash_password(
password: bytes,
salt: Optional[bytes] = None,
time_cost: int = DEFAULT_TIME_COST,
memory_cost: int = DEFAULT_MEMORY_COST,
parallelism: int = DEFAULT_PARALLELISM,
hash_len: int = DEFAULT_HASH_LENGTH,
type: Type = Type.I,
) -> bytes:
"""
Legacy alias for :func:`hash_secret` with default parameters.
.. deprecated:: 16.0.0
Use :class:`argon2.PasswordHasher` for passwords.
"""
if salt is None:
salt = os.urandom(DEFAULT_RANDOM_SALT_LENGTH)
return hash_secret(
password, salt, time_cost, memory_cost, parallelism, hash_len, type
)
def hash_password_raw(
password: bytes,
salt: Optional[bytes] = None,
time_cost: int = DEFAULT_TIME_COST,
memory_cost: int = DEFAULT_MEMORY_COST,
parallelism: int = DEFAULT_PARALLELISM,
hash_len: int = DEFAULT_HASH_LENGTH,
type: Type = Type.I,
) -> bytes:
"""
Legacy alias for :func:`hash_secret_raw` with default parameters.
.. deprecated:: 16.0.0
Use :class:`argon2.PasswordHasher` for passwords.
"""
if salt is None:
salt = os.urandom(DEFAULT_RANDOM_SALT_LENGTH)
return hash_secret_raw(
password, salt, time_cost, memory_cost, parallelism, hash_len, type
)
def verify_password(
hash: bytes, password: bytes, type: Type = Type.I
) -> Literal[True]:
"""
Legacy alias for :func:`verify_secret` with default parameters.
.. deprecated:: 16.0.0
Use :class:`argon2.PasswordHasher` for passwords.
"""
return verify_secret(hash, password, type)

View File

@ -0,0 +1,235 @@
# SPDX-License-Identifier: MIT
import os
from typing import Union
from ._typing import Literal
from ._utils import Parameters, _check_types, extract_parameters
from .exceptions import InvalidHash
from .low_level import Type, hash_secret, verify_secret
from .profiles import RFC_9106_LOW_MEMORY
DEFAULT_RANDOM_SALT_LENGTH = RFC_9106_LOW_MEMORY.salt_len
DEFAULT_HASH_LENGTH = RFC_9106_LOW_MEMORY.hash_len
DEFAULT_TIME_COST = RFC_9106_LOW_MEMORY.time_cost
DEFAULT_MEMORY_COST = RFC_9106_LOW_MEMORY.memory_cost
DEFAULT_PARALLELISM = RFC_9106_LOW_MEMORY.parallelism
def _ensure_bytes(s: Union[bytes, str], encoding: str) -> bytes:
"""
Ensure *s* is a bytes string. Encode using *encoding* if it isn't.
"""
if isinstance(s, bytes):
return s
return s.encode(encoding)
class PasswordHasher:
r"""
High level class to hash passwords with sensible defaults.
Uses Argon2\ **id** by default and always uses a random salt_ for hashing.
But it can verify any type of *Argon2* as long as the hash is correctly
encoded.
The reason for this being a class is both for convenience to carry
parameters and to verify the parameters only *once*. Any unnecessary
slowdown when hashing is a tangible advantage for a brute force attacker.
:param int time_cost: Defines the amount of computation realized and
therefore the execution time, given in number of iterations.
:param int memory_cost: Defines the memory usage, given in kibibytes_.
:param int parallelism: Defines the number of parallel threads (*changes*
the resulting hash value).
:param int hash_len: Length of the hash in bytes.
:param int salt_len: Length of random salt to be generated for each
password.
:param str encoding: The *Argon2* C library expects bytes. So if
:meth:`hash` or :meth:`verify` are passed a ``str``, it will be
encoded using this encoding.
:param Type type: *Argon2* type to use. Only change for interoperability
with legacy systems.
.. versionadded:: 16.0.0
.. versionchanged:: 18.2.0
Switch from Argon2i to Argon2id based on the recommendation by the
current RFC draft. See also :doc:`parameters`.
.. versionchanged:: 18.2.0
Changed default *memory_cost* to 100 MiB and default *parallelism* to 8.
.. versionchanged:: 18.2.0 ``verify`` now will determine the type of hash.
.. versionchanged:: 18.3.0 The *Argon2* type is configurable now.
.. versionadded:: 21.2.0 :meth:`from_parameters`
.. versionchanged:: 21.2.0
Changed defaults to :data:`argon2.profiles.RFC_9106_LOW_MEMORY`.
.. _salt: https://en.wikipedia.org/wiki/Salt_(cryptography)
.. _kibibytes: https://en.wikipedia.org/wiki/Binary_prefix#kibi
"""
__slots__ = ["_parameters", "encoding"]
_parameters: Parameters
encoding: str
def __init__(
self,
time_cost: int = DEFAULT_TIME_COST,
memory_cost: int = DEFAULT_MEMORY_COST,
parallelism: int = DEFAULT_PARALLELISM,
hash_len: int = DEFAULT_HASH_LENGTH,
salt_len: int = DEFAULT_RANDOM_SALT_LENGTH,
encoding: str = "utf-8",
type: Type = Type.ID,
):
e = _check_types(
time_cost=(time_cost, int),
memory_cost=(memory_cost, int),
parallelism=(parallelism, int),
hash_len=(hash_len, int),
salt_len=(salt_len, int),
encoding=(encoding, str),
type=(type, Type),
)
if e:
raise TypeError(e)
# Cache a Parameters object for check_needs_rehash.
self._parameters = Parameters(
type=type,
version=19,
salt_len=salt_len,
hash_len=hash_len,
time_cost=time_cost,
memory_cost=memory_cost,
parallelism=parallelism,
)
self.encoding = encoding
@classmethod
def from_parameters(cls, params: Parameters) -> "PasswordHasher":
"""
Construct a `PasswordHasher` from *params*.
.. versionadded:: 21.2.0
"""
ph = cls()
ph._parameters = params
return ph
@property
def time_cost(self) -> int:
return self._parameters.time_cost
@property
def memory_cost(self) -> int:
return self._parameters.memory_cost
@property
def parallelism(self) -> int:
return self._parameters.parallelism
@property
def hash_len(self) -> int:
return self._parameters.hash_len
@property
def salt_len(self) -> int:
return self._parameters.salt_len
@property
def type(self) -> Type:
return self._parameters.type
def hash(self, password: Union[str, bytes]) -> str:
"""
Hash *password* and return an encoded hash.
:param password: Password to hash.
:type password: ``bytes`` or ``str``
:raises argon2.exceptions.HashingError: If hashing fails.
:rtype: str
"""
return hash_secret(
secret=_ensure_bytes(password, self.encoding),
salt=os.urandom(self.salt_len),
time_cost=self.time_cost,
memory_cost=self.memory_cost,
parallelism=self.parallelism,
hash_len=self.hash_len,
type=self.type,
).decode("ascii")
_header_to_type = {
b"$argon2i$": Type.I,
b"$argon2d$": Type.D,
b"$argon2id": Type.ID,
}
def verify(
self, hash: Union[str, bytes], password: Union[str, bytes]
) -> Literal[True]:
"""
Verify that *password* matches *hash*.
.. warning::
It is assumed that the caller is in full control of the hash. No
other parsing than the determination of the hash type is done by
*argon2-cffi*.
:param hash: An encoded hash as returned from
:meth:`PasswordHasher.hash`.
:type hash: ``bytes`` or ``str``
:param password: The password to verify.
:type password: ``bytes`` or ``str``
:raises argon2.exceptions.VerifyMismatchError: If verification fails
because *hash* is not valid for *password*.
:raises argon2.exceptions.VerificationError: If verification fails for
other reasons.
:raises argon2.exceptions.InvalidHash: If *hash* is so clearly
invalid, that it couldn't be passed to *Argon2*.
:return: ``True`` on success, raise
:exc:`~argon2.exceptions.VerificationError` otherwise.
:rtype: bool
.. versionchanged:: 16.1.0
Raise :exc:`~argon2.exceptions.VerifyMismatchError` on mismatches
instead of its more generic superclass.
.. versionadded:: 18.2.0 Hash type agility.
"""
hash = _ensure_bytes(hash, "ascii")
try:
hash_type = self._header_to_type[hash[:9]]
except (IndexError, KeyError, LookupError):
raise InvalidHash()
return verify_secret(
hash, _ensure_bytes(password, self.encoding), hash_type
)
def check_needs_rehash(self, hash: str) -> bool:
"""
Check whether *hash* was created using the instance's parameters.
Whenever your *Argon2* parameters -- or *argon2-cffi*'s defaults! --
change, you should rehash your passwords at the next opportunity. The
common approach is to do that whenever a user logs in, since that
should be the only time when you have access to the cleartext
password.
Therefore it's best practice to check -- and if necessary rehash --
passwords after each successful authentication.
:rtype: bool
.. versionadded:: 18.2.0
"""
return self._parameters != extract_parameters(hash)

View File

@ -0,0 +1,13 @@
# SPDX-License-Identifier: MIT
import sys
# try/except ImportError does NOT work.
# c.f. https://github.com/python/mypy/issues/8520
if sys.version_info >= (3, 8):
from typing import Literal
else:
from typing_extensions import Literal
__all__ = ["Literal"]

View File

@ -0,0 +1,140 @@
# SPDX-License-Identifier: MIT
from dataclasses import dataclass
from typing import Any, Optional
from .exceptions import InvalidHash
from .low_level import Type
NoneType = type(None)
def _check_types(**kw: Any) -> Optional[str]:
"""
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(
"'{name}' must be a {type} (got {actual})".format(
name=name, type=types, actual=type(value).__name__
)
)
if errors != []:
return ", ".join(errors) + "."
return None
def _decoded_str_len(l: int) -> int:
"""
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
@dataclass
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 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"],
)

View File

@ -0,0 +1,43 @@
# SPDX-License-Identifier: MIT
class Argon2Error(Exception):
"""
Superclass of all argon2 exceptions.
Never thrown directly.
"""
class VerificationError(Argon2Error):
"""
Verification failed.
You can find the original error message from Argon2 in ``args[0]``.
"""
class VerifyMismatchError(VerificationError):
"""
The secret does not match the hash.
Subclass of :exc:`argon2.exceptions.VerificationError`.
.. versionadded:: 16.1.0
"""
class HashingError(Argon2Error):
"""
Raised if hashing failed.
You can find the original error message from Argon2 in ``args[0]``.
"""
class InvalidHash(ValueError):
"""
Raised if the hash is invalid before passing it to Argon2.
.. versionadded:: 18.2.0
"""

View File

@ -0,0 +1,255 @@
# SPDX-License-Identifier: MIT
"""
Low-level functions if you want to build your own higher level abstractions.
.. warning::
This is a "Hazardous Materials" module. You should **ONLY** use it if
you're 100% absolutely sure that you know what youre doing because this
module is full of land mines, dragons, and dinosaurs with laser guns.
"""
from enum import Enum
from typing import Any
from _argon2_cffi_bindings import ffi, lib
from ._typing import Literal
from .exceptions import HashingError, VerificationError, VerifyMismatchError
__all__ = [
"ARGON2_VERSION",
"Type",
"ffi",
"hash_secret",
"hash_secret_raw",
"verify_secret",
]
ARGON2_VERSION = lib.ARGON2_VERSION_NUMBER
"""
The latest version of the Argon2 algorithm that is supported (and used by
default).
.. versionadded:: 16.1.0
"""
class Type(Enum):
"""
Enum of Argon2 variants.
Please see :doc:`parameters` on how to pick one.
"""
D = lib.Argon2_d
r"""
Argon2\ **d** is faster and uses data-depending memory access, which makes
it less suitable for hashing secrets and more suitable for cryptocurrencies
and applications with no threats from side-channel timing attacks.
"""
I = lib.Argon2_i
r"""
Argon2\ **i** uses data-independent memory access. Argon2i is slower as
it makes more passes over the memory to protect from tradeoff attacks.
"""
ID = lib.Argon2_id
r"""
Argon2\ **id** is a hybrid of Argon2i and Argon2d, using a combination of
data-depending and data-independent memory accesses, which gives some of
Argon2i's resistance to side-channel cache timing attacks and much of
Argon2d's resistance to GPU cracking attacks.
That makes it the preferred type for password hashing and password-based
key derivation.
.. versionadded:: 16.3.0
"""
def hash_secret(
secret: bytes,
salt: bytes,
time_cost: int,
memory_cost: int,
parallelism: int,
hash_len: int,
type: Type,
version: int = ARGON2_VERSION,
) -> bytes:
"""
Hash *secret* and return an **encoded** hash.
An encoded hash can be directly passed into :func:`verify_secret` as it
contains all parameters and the salt.
:param bytes secret: Secret to hash.
:param bytes salt: A salt_. Should be random and different for each
secret.
:param Type type: Which Argon2 variant to use.
:param int version: Which Argon2 version to use.
For an explanation of the Argon2 parameters see :class:`PasswordHasher`.
:rtype: bytes
:raises argon2.exceptions.HashingError: If hashing fails.
.. versionadded:: 16.0.0
.. _salt: https://en.wikipedia.org/wiki/Salt_(cryptography)
.. _kibibytes: https://en.wikipedia.org/wiki/Binary_prefix#kibi
"""
size = (
lib.argon2_encodedlen(
time_cost,
memory_cost,
parallelism,
len(salt),
hash_len,
type.value,
)
+ 1
)
buf = ffi.new("char[]", size)
rv = lib.argon2_hash(
time_cost,
memory_cost,
parallelism,
ffi.new("uint8_t[]", secret),
len(secret),
ffi.new("uint8_t[]", salt),
len(salt),
ffi.NULL,
hash_len,
buf,
size,
type.value,
version,
)
if rv != lib.ARGON2_OK:
raise HashingError(error_to_str(rv))
return ffi.string(buf)
def hash_secret_raw(
secret: bytes,
salt: bytes,
time_cost: int,
memory_cost: int,
parallelism: int,
hash_len: int,
type: Type,
version: int = ARGON2_VERSION,
) -> bytes:
"""
Hash *password* and return a **raw** hash.
This function takes the same parameters as :func:`hash_secret`.
.. versionadded:: 16.0.0
"""
buf = ffi.new("uint8_t[]", hash_len)
rv = lib.argon2_hash(
time_cost,
memory_cost,
parallelism,
ffi.new("uint8_t[]", secret),
len(secret),
ffi.new("uint8_t[]", salt),
len(salt),
buf,
hash_len,
ffi.NULL,
0,
type.value,
version,
)
if rv != lib.ARGON2_OK:
raise HashingError(error_to_str(rv))
return bytes(ffi.buffer(buf, hash_len))
def verify_secret(hash: bytes, secret: bytes, type: Type) -> Literal[True]:
"""
Verify whether *secret* is correct for *hash* of *type*.
:param bytes hash: An encoded Argon2 hash as returned by
:func:`hash_secret`.
:param bytes secret: The secret to verify whether it matches the one
in *hash*.
:param Type type: Type for *hash*.
:raises argon2.exceptions.VerifyMismatchError: If verification fails
because *hash* is not valid for *secret* of *type*.
:raises argon2.exceptions.VerificationError: If verification fails for
other reasons.
:return: ``True`` on success, raise
:exc:`~argon2.exceptions.VerificationError` otherwise.
:rtype: bool
.. versionadded:: 16.0.0
.. versionchanged:: 16.1.0
Raise :exc:`~argon2.exceptions.VerifyMismatchError` on mismatches
instead of its more generic superclass.
"""
rv = lib.argon2_verify(
ffi.new("char[]", hash),
ffi.new("uint8_t[]", secret),
len(secret),
type.value,
)
if rv == lib.ARGON2_OK:
return True
elif rv == lib.ARGON2_VERIFY_MISMATCH:
raise VerifyMismatchError(error_to_str(rv))
else:
raise VerificationError(error_to_str(rv))
def core(context: Any, type: int) -> int:
"""
Direct binding to the ``argon2_ctx`` function.
.. warning::
This is a strictly advanced function working on raw C data structures.
Both *Argon2*'s and *argon2-cffi*'s higher-level bindings do a lot of
sanity checks and housekeeping work that *you* are now responsible for
(e.g. clearing buffers). The structure of the *context* object can,
has, and will change with *any* release!
Use at your own peril; *argon2-cffi* does *not* use this binding
itself.
:param context: A CFFI *Argon2* context object (i.e. an ``struct
Argon2_Context``/``argon2_context``).
:param int type: Which *Argon2* variant to use. You can use the ``value``
field of :class:`Type`'s fields.
:rtype: int
:return: An *Argon2* error code. Can be transformed into a string using
:func:`error_to_str`.
.. versionadded:: 16.0.0
"""
return lib.argon2_ctx(context, type)
def error_to_str(error: int) -> str:
"""
Convert an Argon2 error code into a native string.
:param int error: An Argon2 error code as returned by :func:`core`.
:rtype: str
.. versionadded:: 16.0.0
"""
msg = ffi.string(lib.argon2_error_message(error))
msg = msg.decode("ascii")
return msg

View File

@ -0,0 +1,58 @@
# SPDX-License-Identifier: MIT
"""
This module offers access to standardized parameters that you can load using
:meth:`PasswordHasher.from_parameters()`. See the `source code
<https://github.com/hynek/argon2-cffi/blob/main/src/argon2/profiles.py>`_ for
concrete values and :doc:`parameters` for more information.
.. versionadded:: 21.2.0
"""
from ._utils import Parameters
from .low_level import Type
# FIRST RECOMMENDED option per RFC 9106.
RFC_9106_HIGH_MEMORY = Parameters(
type=Type.ID,
version=19,
salt_len=16,
hash_len=32,
time_cost=1,
memory_cost=2097152, # 2 GiB
parallelism=4,
)
# SECOND RECOMMENDED option per RFC 9106.
RFC_9106_LOW_MEMORY = Parameters(
type=Type.ID,
version=19,
salt_len=16,
hash_len=32,
time_cost=3,
memory_cost=65536, # 64 MiB
parallelism=4,
)
# The pre-RFC defaults in argon2-cffi 18.2.0 - 21.1.0.
PRE_21_2 = Parameters(
type=Type.ID,
version=19,
salt_len=16,
hash_len=16,
time_cost=2,
memory_cost=102400, # 100 MiB
parallelism=8,
)
# Only for testing!
CHEAPEST = Parameters(
type=Type.ID,
version=19,
salt_len=8,
hash_len=4,
time_cost=1,
memory_cost=8,
parallelism=1,
)

View File