From 8d1c76ec7caf247d5675e14260d20fc508977ffb Mon Sep 17 00:00:00 2001 From: Determinant Date: Fri, 23 Aug 2024 03:14:03 +0000 Subject: release v0.1.8 --- frozen_deps/Cryptodome/Protocol/DH.py | 101 +++++++++++++++++++++ frozen_deps/Cryptodome/Protocol/DH.pyi | 15 +++ frozen_deps/Cryptodome/Protocol/KDF.py | 80 ++++++++++++++-- frozen_deps/Cryptodome/Protocol/KDF.pyi | 20 +++- frozen_deps/Cryptodome/Protocol/__init__.py | 2 +- frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so | Bin 25024 -> 26176 bytes .../_scrypt.cpython-39-x86_64-linux-gnu.so | Bin 16510 -> 0 bytes 7 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 frozen_deps/Cryptodome/Protocol/DH.py create mode 100644 frozen_deps/Cryptodome/Protocol/DH.pyi delete mode 100755 frozen_deps/Cryptodome/Protocol/_scrypt.cpython-39-x86_64-linux-gnu.so (limited to 'frozen_deps/Cryptodome/Protocol') diff --git a/frozen_deps/Cryptodome/Protocol/DH.py b/frozen_deps/Cryptodome/Protocol/DH.py new file mode 100644 index 0000000..bb174f0 --- /dev/null +++ b/frozen_deps/Cryptodome/Protocol/DH.py @@ -0,0 +1,101 @@ +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.PublicKey.ECC import EccKey + + +def _compute_ecdh(key_priv, key_pub): + # See Section 5.7.1.2 in NIST SP 800-56Ar3 + pointP = key_pub.pointQ * key_priv.d + if pointP.is_point_at_infinity(): + raise ValueError("Invalid ECDH point") + z = long_to_bytes(pointP.x, pointP.size_in_bytes()) + return z + + +def key_agreement(**kwargs): + """Perform a Diffie-Hellman key agreement. + + Keywords: + kdf (callable): + A key derivation function that accepts ``bytes`` as input and returns + ``bytes``. + static_priv (EccKey): + The local static private key. Optional. + static_pub (EccKey): + The static public key that belongs to the peer. Optional. + eph_priv (EccKey): + The local ephemeral private key, generated for this session. Optional. + eph_pub (EccKey): + The ephemeral public key, received from the peer for this session. Optional. + + At least two keys must be passed, of which one is a private key and one + a public key. + + Returns (bytes): + The derived secret key material. + """ + + static_priv = kwargs.get('static_priv', None) + static_pub = kwargs.get('static_pub', None) + eph_priv = kwargs.get('eph_priv', None) + eph_pub = kwargs.get('eph_pub', None) + kdf = kwargs.get('kdf', None) + + if kdf is None: + raise ValueError("'kdf' is mandatory") + + count_priv = 0 + count_pub = 0 + curve = None + + def check_curve(curve, key, name, private): + if not isinstance(key, EccKey): + raise TypeError("'%s' must be an ECC key" % name) + if private and not key.has_private(): + raise TypeError("'%s' must be a private ECC key" % name) + if curve is None: + curve = key.curve + elif curve != key.curve: + raise TypeError("'%s' is defined on an incompatible curve" % name) + return curve + + if static_priv is not None: + curve = check_curve(curve, static_priv, 'static_priv', True) + count_priv += 1 + + if static_pub is not None: + curve = check_curve(curve, static_pub, 'static_pub', False) + count_pub += 1 + + if eph_priv is not None: + curve = check_curve(curve, eph_priv, 'eph_priv', True) + count_priv += 1 + + if eph_pub is not None: + curve = check_curve(curve, eph_pub, 'eph_pub', False) + count_pub += 1 + + if (count_priv + count_pub) < 2 or count_priv == 0 or count_pub == 0: + raise ValueError("Too few keys for the ECDH key agreement") + + Zs = b'' + Ze = b'' + + if static_priv and static_pub: + # C(*, 2s) + Zs = _compute_ecdh(static_priv, static_pub) + + if eph_priv and eph_pub: + # C(2e, 0s) or C(2e, 2s) + if bool(static_priv) != bool(static_pub): + raise ValueError("DH mode C(2e, 1s) is not supported") + Ze = _compute_ecdh(eph_priv, eph_pub) + elif eph_priv and static_pub: + # C(1e, 2s) or C(1e, 1s) + Ze = _compute_ecdh(eph_priv, static_pub) + elif eph_pub and static_priv: + # C(1e, 2s) or C(1e, 1s) + Ze = _compute_ecdh(static_priv, eph_pub) + + Z = Ze + Zs + + return kdf(Z) diff --git a/frozen_deps/Cryptodome/Protocol/DH.pyi b/frozen_deps/Cryptodome/Protocol/DH.pyi new file mode 100644 index 0000000..b1da888 --- /dev/null +++ b/frozen_deps/Cryptodome/Protocol/DH.pyi @@ -0,0 +1,15 @@ +from typing import TypedDict, Callable, TypeVar, Generic +from typing_extensions import Unpack, NotRequired + +from Cryptodome.PublicKey.ECC import EccKey + +T = TypeVar('T') + +class RequestParams(TypedDict, Generic[T]): + kdf: Callable[[bytes|bytearray|memoryview], T] + static_priv: NotRequired[EccKey] + static_pub: NotRequired[EccKey] + eph_priv: NotRequired[EccKey] + eph_pub: NotRequired[EccKey] + +def key_agreement(**kwargs: Unpack[RequestParams[T]]) -> T: ... diff --git a/frozen_deps/Cryptodome/Protocol/KDF.py b/frozen_deps/Cryptodome/Protocol/KDF.py index 4baa276..b6d747e 100644 --- a/frozen_deps/Cryptodome/Protocol/KDF.py +++ b/frozen_deps/Cryptodome/Protocol/KDF.py @@ -27,7 +27,7 @@ import struct from functools import reduce from Cryptodome.Util.py3compat import (tobytes, bord, _copy_bytes, iter_range, - tostr, bchr, bstr) + tostr, bchr, bstr) from Cryptodome.Hash import SHA1, SHA256, HMAC, CMAC, BLAKE2s from Cryptodome.Util.strxor import strxor @@ -103,10 +103,16 @@ def PBKDF2(password, salt, dkLen=16, count=1000, prf=None, hmac_hash_module=None Args: password (string or byte string): The secret password to generate the key from. + + Strings will be encoded as ISO 8859-1 (also known as Latin-1), + which does not allow any characters with codepoints > 255. salt (string or byte string): A (byte) string to use for better protection from dictionary attacks. This value does not need to be kept secret, but it should be randomly chosen for each derivation. It is recommended to use at least 16 bytes. + + Strings will be encoded as ISO 8859-1 (also known as Latin-1), + which does not allow any characters with codepoints > 255. dkLen (integer): The cumulative length of the keys to produce. @@ -201,10 +207,10 @@ class _S2V(object): self._key = _copy_bytes(None, None, key) self._ciphermod = ciphermod self._last_string = self._cache = b'\x00' * ciphermod.block_size - + # Max number of update() call we can process self._n_updates = ciphermod.block_size * 8 - 1 - + if cipher_params is None: self._cipher_params = {} else: @@ -281,13 +287,13 @@ def HKDF(master, key_len, salt, hashmod, num_keys=1, context=None): The unguessable value used by the KDF to generate the other keys. It must be a high-entropy secret, though not necessarily uniform. It must not be a password. + key_len (integer): + The length in bytes of every derived key. salt (byte string): A non-secret, reusable value that strengthens the randomness extraction step. Ideally, it is as long as the digest size of the chosen hash. If empty, a string of zeroes in used. - key_len (integer): - The length in bytes of every derived key. hashmod (module): A cryptographic hash algorithm from :mod:`Cryptodome.Hash`. :mod:`Cryptodome.Hash.SHA512` is a good choice. @@ -346,7 +352,7 @@ def scrypt(password, salt, key_len, N, r, p, num_keys=1): but it should be randomly chosen for each derivation. It is recommended to be at least 16 bytes long. key_len (integer): - The length in bytes of every derived key. + The length in bytes of each derived key. N (integer): CPU/Memory cost parameter. It must be a power of 2 and less than :math:`2^{32}`. @@ -572,3 +578,65 @@ def bcrypt_check(password, bcrypt_hash): mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=bcrypt_hash2).digest() if mac1 != mac2: raise ValueError("Incorrect bcrypt hash") + + +def SP800_108_Counter(master, key_len, prf, num_keys=None, label=b'', context=b''): + """Derive one or more keys from a master secret using + a pseudorandom function in Counter Mode, as specified in + `NIST SP 800-108r1 `_. + + Args: + master (byte string): + The secret value used by the KDF to derive the other keys. + It must not be a password. + The length on the secret must be consistent with the input expected by + the :data:`prf` function. + key_len (integer): + The length in bytes of each derived key. + prf (function): + A pseudorandom function that takes two byte strings as parameters: + the secret and an input. It returns another byte string. + num_keys (integer): + The number of keys to derive. Every key is :data:`key_len` bytes long. + By default, only 1 key is derived. + label (byte string): + Optional description of the purpose of the derived keys. + It must not contain zero bytes. + context (byte string): + Optional information pertaining to + the protocol that uses the keys, such as the identity of the + participants, nonces, session IDs, etc. + It must not contain zero bytes. + + Return: + - a byte string (if ``num_keys`` is not specified), or + - a tuple of byte strings (if ``num_key`` is specified). + """ + + if num_keys is None: + num_keys = 1 + + if label.find(b'\x00') != -1: + raise ValueError("Null byte found in label") + + if context.find(b'\x00') != -1: + raise ValueError("Null byte found in context") + + key_len_enc = long_to_bytes(key_len * num_keys * 8, 4) + output_len = key_len * num_keys + + i = 1 + dk = b"" + while len(dk) < output_len: + info = long_to_bytes(i, 4) + label + b'\x00' + context + key_len_enc + dk += prf(master, info) + i += 1 + if i > 0xFFFFFFFF: + raise ValueError("Overflow in SP800 108 counter") + + if num_keys == 1: + return dk[:key_len] + else: + kol = [dk[idx:idx + key_len] + for idx in iter_range(0, output_len, key_len)] + return kol diff --git a/frozen_deps/Cryptodome/Protocol/KDF.pyi b/frozen_deps/Cryptodome/Protocol/KDF.pyi index fb004bf..745f019 100644 --- a/frozen_deps/Cryptodome/Protocol/KDF.pyi +++ b/frozen_deps/Cryptodome/Protocol/KDF.pyi @@ -1,7 +1,11 @@ from types import ModuleType -from typing import Optional, Callable, Tuple, Union, Dict, Any +from typing import Optional, Callable, Tuple, Union, Dict, Any, overload +from typing_extensions import Literal + +Buffer=bytes|bytearray|memoryview RNG = Callable[[int], bytes] +PRF = Callable[[bytes, bytes], bytes] def PBKDF1(password: str, salt: bytes, dkLen: int, count: Optional[int]=1000, hashAlgo: Optional[ModuleType]=None) -> bytes: ... def PBKDF2(password: str, salt: bytes, dkLen: Optional[int]=16, count: Optional[int]=1000, prf: Optional[RNG]=None, hmac_hash_module: Optional[ModuleType]=None) -> bytes: ... @@ -22,3 +26,17 @@ def _bcrypt_decode(data: bytes) -> bytes: ... def _bcrypt_hash(password:bytes , cost: int, salt: bytes, constant:bytes, invert:bool) -> bytes: ... def bcrypt(password: Union[bytes, str], cost: int, salt: Optional[bytes]=None) -> bytes: ... def bcrypt_check(password: Union[bytes, str], bcrypt_hash: Union[bytes, bytearray, str]) -> None: ... + +@overload +def SP800_108_Counter(master: Buffer, + key_len: int, + prf: PRF, + num_keys: Literal[None] = None, + label: Buffer = b'', context: Buffer = b'') -> bytes: ... + +@overload +def SP800_108_Counter(master: Buffer, + key_len: int, + prf: PRF, + num_keys: int, + label: Buffer = b'', context: Buffer = b'') -> Tuple[bytes]: ... diff --git a/frozen_deps/Cryptodome/Protocol/__init__.py b/frozen_deps/Cryptodome/Protocol/__init__.py index efdf034..76e22bf 100644 --- a/frozen_deps/Cryptodome/Protocol/__init__.py +++ b/frozen_deps/Cryptodome/Protocol/__init__.py @@ -28,4 +28,4 @@ # POSSIBILITY OF SUCH DAMAGE. # =================================================================== -__all__ = ['KDF', 'SecretSharing'] +__all__ = ['KDF', 'SecretSharing', 'DH'] diff --git a/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so b/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so index 6ba8f35..baf83a8 100755 Binary files a/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so and b/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so differ diff --git a/frozen_deps/Cryptodome/Protocol/_scrypt.cpython-39-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Protocol/_scrypt.cpython-39-x86_64-linux-gnu.so deleted file mode 100755 index c979025..0000000 Binary files a/frozen_deps/Cryptodome/Protocol/_scrypt.cpython-39-x86_64-linux-gnu.so and /dev/null differ -- cgit v1.2.3-70-g09d2