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/low_level.py

257 lines
6.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# -*- coding: utf-8 -*-
"""
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 __future__ import absolute_import, division, print_function
from enum import Enum
from six import PY3
from ._ffi import ffi, lib
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,
salt,
time_cost,
memory_cost,
parallelism,
hash_len,
type,
version=ARGON2_VERSION,
):
"""
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,
salt,
time_cost,
memory_cost,
parallelism,
hash_len,
type,
version=ARGON2_VERSION,
):
"""
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, secret, type):
"""
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, type):
"""
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):
"""
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))
if PY3:
msg = msg.decode("ascii")
return msg