diff options
Diffstat (limited to 'frozen_deps/Cryptodome')
185 files changed, 4717 insertions, 1272 deletions
diff --git a/frozen_deps/Cryptodome/Cipher/AES.py b/frozen_deps/Cryptodome/Cipher/AES.py index dd2671a..402a3d7 100644 --- a/frozen_deps/Cryptodome/Cipher/AES.py +++ b/frozen_deps/Cryptodome/Cipher/AES.py @@ -19,21 +19,6 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # =================================================================== -""" -Module's constants for the modes of operation supported with AES: - -:var MODE_ECB: :ref:`Electronic Code Book (ECB) <ecb_mode>` -:var MODE_CBC: :ref:`Cipher-Block Chaining (CBC) <cbc_mode>` -:var MODE_CFB: :ref:`Cipher FeedBack (CFB) <cfb_mode>` -:var MODE_OFB: :ref:`Output FeedBack (OFB) <ofb_mode>` -:var MODE_CTR: :ref:`CounTer Mode (CTR) <ctr_mode>` -:var MODE_OPENPGP: :ref:`OpenPGP Mode <openpgp_mode>` -:var MODE_CCM: :ref:`Counter with CBC-MAC (CCM) Mode <ccm_mode>` -:var MODE_EAX: :ref:`EAX Mode <eax_mode>` -:var MODE_GCM: :ref:`Galois Counter Mode (GCM) <gcm_mode>` -:var MODE_SIV: :ref:`Syntethic Initialization Vector (SIV) <siv_mode>` -:var MODE_OCB: :ref:`Offset Code Book (OCB) <ocb_mode>` -""" import sys @@ -45,6 +30,18 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, from Cryptodome.Util import _cpu_features from Cryptodome.Random import get_random_bytes +MODE_ECB = 1 #: Electronic Code Book (:ref:`ecb_mode`) +MODE_CBC = 2 #: Cipher-Block Chaining (:ref:`cbc_mode`) +MODE_CFB = 3 #: Cipher Feedback (:ref:`cfb_mode`) +MODE_OFB = 5 #: Output Feedback (:ref:`ofb_mode`) +MODE_CTR = 6 #: Counter mode (:ref:`ctr_mode`) +MODE_OPENPGP = 7 #: OpenPGP mode (:ref:`openpgp_mode`) +MODE_CCM = 8 #: Counter with CBC-MAC (:ref:`ccm_mode`) +MODE_EAX = 9 #: :ref:`eax_mode` +MODE_SIV = 10 #: Synthetic Initialization Vector (:ref:`siv_mode`) +MODE_GCM = 11 #: Galois Counter Mode (:ref:`gcm_mode`) +MODE_OCB = 12 #: Offset Code Book (:ref:`ocb_mode`) + _cproto = """ int AES_start_operation(const uint8_t key[], @@ -111,7 +108,7 @@ def _create_base_cipher(dict_parameters): def _derive_Poly1305_key_pair(key, nonce): """Derive a tuple (r, s, nonce) for a Poly1305 MAC. - + If nonce is ``None``, a new 16-byte nonce is generated. """ @@ -130,120 +127,107 @@ def _derive_Poly1305_key_pair(key, nonce): def new(key, mode, *args, **kwargs): """Create a new AES cipher. - :param key: + Args: + key(bytes/bytearray/memoryview): The secret key to use in the symmetric cipher. - It must be 16, 24 or 32 bytes long (respectively for *AES-128*, - *AES-192* or *AES-256*). + It must be 16 (*AES-128)*, 24 (*AES-192*) or 32 (*AES-256*) bytes long. For ``MODE_SIV`` only, it doubles to 32, 48, or 64 bytes. - :type key: bytes/bytearray/memoryview - - :param mode: + mode (a ``MODE_*`` constant): The chaining mode to use for encryption or decryption. If in doubt, use ``MODE_EAX``. - :type mode: One of the supported ``MODE_*`` constants - :Keyword Arguments: - * **iv** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, - and ``MODE_OPENPGP`` modes). + Keyword Args: + iv (bytes/bytearray/memoryview): + (Only applicable for ``MODE_CBC``, ``MODE_CFB``, ``MODE_OFB``, + and ``MODE_OPENPGP`` modes). - The initialization vector to use for encryption or decryption. + The initialization vector to use for encryption or decryption. - For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 16 bytes long. + For ``MODE_CBC``, ``MODE_CFB``, and ``MODE_OFB`` it must be 16 bytes long. - For ``MODE_OPENPGP`` mode only, - it must be 16 bytes long for encryption - and 18 bytes for decryption (in the latter case, it is - actually the *encrypted* IV which was prefixed to the ciphertext). + For ``MODE_OPENPGP`` mode only, + it must be 16 bytes long for encryption + and 18 bytes for decryption (in the latter case, it is + actually the *encrypted* IV which was prefixed to the ciphertext). - If not provided, a random byte string is generated (you must then - read its value with the :attr:`iv` attribute). + If not provided, a random byte string is generated (you must then + read its value with the :attr:`iv` attribute). - * **nonce** (*bytes*, *bytearray*, *memoryview*) -- - (Only applicable for ``MODE_CCM``, ``MODE_EAX``, ``MODE_GCM``, - ``MODE_SIV``, ``MODE_OCB``, and ``MODE_CTR``). + nonce (bytes/bytearray/memoryview): + (Only applicable for ``MODE_CCM``, ``MODE_EAX``, ``MODE_GCM``, + ``MODE_SIV``, ``MODE_OCB``, and ``MODE_CTR``). - A value that must never be reused for any other encryption done - with this key (except possibly for ``MODE_SIV``, see below). + A value that must never be reused for any other encryption done + with this key (except possibly for ``MODE_SIV``, see below). - For ``MODE_EAX``, ``MODE_GCM`` and ``MODE_SIV`` there are no - restrictions on its length (recommended: **16** bytes). + For ``MODE_EAX``, ``MODE_GCM`` and ``MODE_SIV`` there are no + restrictions on its length (recommended: **16** bytes). - For ``MODE_CCM``, its length must be in the range **[7..13]**. - Bear in mind that with CCM there is a trade-off between nonce - length and maximum message size. Recommendation: **11** bytes. + For ``MODE_CCM``, its length must be in the range **[7..13]**. + Bear in mind that with CCM there is a trade-off between nonce + length and maximum message size. Recommendation: **11** bytes. - For ``MODE_OCB``, its length must be in the range **[1..15]** - (recommended: **15**). + For ``MODE_OCB``, its length must be in the range **[1..15]** + (recommended: **15**). - For ``MODE_CTR``, its length must be in the range **[0..15]** - (recommended: **8**). - - For ``MODE_SIV``, the nonce is optional, if it is not specified, - then no nonce is being used, which renders the encryption - deterministic. + For ``MODE_CTR``, its length must be in the range **[0..15]** + (recommended: **8**). - If not provided, for modes other than ``MODE_SIV```, a random - byte string of the recommended length is used (you must then - read its value with the :attr:`nonce` attribute). + For ``MODE_SIV``, the nonce is optional, if it is not specified, + then no nonce is being used, which renders the encryption + deterministic. - * **segment_size** (*integer*) -- - (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext - are segmented in. It must be a multiple of 8. - If not specified, it will be assumed to be 8. + If not provided, for modes other than ``MODE_SIV``, a random + byte string of the recommended length is used (you must then + read its value with the :attr:`nonce` attribute). - * **mac_len** : (*integer*) -- - (Only ``MODE_EAX``, ``MODE_GCM``, ``MODE_OCB``, ``MODE_CCM``) - Length of the authentication tag, in bytes. + segment_size (integer): + (Only ``MODE_CFB``).The number of **bits** the plaintext and ciphertext + are segmented in. It must be a multiple of 8. + If not specified, it will be assumed to be 8. - It must be even and in the range **[4..16]**. - The recommended value (and the default, if not specified) is **16**. + mac_len (integer): + (Only ``MODE_EAX``, ``MODE_GCM``, ``MODE_OCB``, ``MODE_CCM``) + Length of the authentication tag, in bytes. - * **msg_len** : (*integer*) -- - (Only ``MODE_CCM``). Length of the message to (de)cipher. - If not specified, ``encrypt`` must be called with the entire message. - Similarly, ``decrypt`` can only be called once. + It must be even and in the range **[4..16]**. + The recommended value (and the default, if not specified) is **16**. - * **assoc_len** : (*integer*) -- - (Only ``MODE_CCM``). Length of the associated data. - If not specified, all associated data is buffered internally, - which may represent a problem for very large messages. + msg_len (integer): + (Only ``MODE_CCM``). Length of the message to (de)cipher. + If not specified, ``encrypt`` must be called with the entire message. + Similarly, ``decrypt`` can only be called once. - * **initial_value** : (*integer* or *bytes/bytearray/memoryview*) -- - (Only ``MODE_CTR``). - The initial value for the counter. If not present, the cipher will - start counting from 0. The value is incremented by one for each block. - The counter number is encoded in big endian mode. + assoc_len (integer): + (Only ``MODE_CCM``). Length of the associated data. + If not specified, all associated data is buffered internally, + which may represent a problem for very large messages. - * **counter** : (*object*) -- - Instance of ``Cryptodome.Util.Counter``, which allows full customization - of the counter block. This parameter is incompatible to both ``nonce`` - and ``initial_value``. + initial_value (integer or bytes/bytearray/memoryview): + (Only ``MODE_CTR``). + The initial value for the counter. If not present, the cipher will + start counting from 0. The value is incremented by one for each block. + The counter number is encoded in big endian mode. - * **use_aesni** : (*boolean*) -- - Use Intel AES-NI hardware extensions (default: use if available). + counter (object): + (Only ``MODE_CTR``). + Instance of ``Cryptodome.Util.Counter``, which allows full customization + of the counter block. This parameter is incompatible to both ``nonce`` + and ``initial_value``. - :Return: an AES object, of the applicable mode. + use_aesni: (boolean): + Use Intel AES-NI hardware extensions (default: use if available). + + Returns: + an AES object, of the applicable mode. """ kwargs["add_aes_modes"] = True return _create_cipher(sys.modules[__name__], key, mode, *args, **kwargs) -MODE_ECB = 1 -MODE_CBC = 2 -MODE_CFB = 3 -MODE_OFB = 5 -MODE_CTR = 6 -MODE_OPENPGP = 7 -MODE_CCM = 8 -MODE_EAX = 9 -MODE_SIV = 10 -MODE_GCM = 11 -MODE_OCB = 12 - # Size of a data block (in bytes) block_size = 16 # Size of a key (in bytes) diff --git a/frozen_deps/Cryptodome/Cipher/AES.pyi b/frozen_deps/Cryptodome/Cipher/AES.pyi index c150efb..3f07b65 100644 --- a/frozen_deps/Cryptodome/Cipher/AES.pyi +++ b/frozen_deps/Cryptodome/Cipher/AES.pyi @@ -1,4 +1,7 @@ -from typing import Union, Tuple, Optional, Dict +from typing import Dict, Optional, Tuple, Union, overload +from typing_extensions import Literal + +Buffer=bytes|bytearray|memoryview from Cryptodome.Cipher._mode_ecb import EcbMode from Cryptodome.Cipher._mode_cbc import CbcMode @@ -12,36 +15,142 @@ from Cryptodome.Cipher._mode_gcm import GcmMode from Cryptodome.Cipher._mode_siv import SivMode from Cryptodome.Cipher._mode_ocb import OcbMode -AESMode = int +MODE_ECB: Literal[1] +MODE_CBC: Literal[2] +MODE_CFB: Literal[3] +MODE_OFB: Literal[5] +MODE_CTR: Literal[6] +MODE_OPENPGP: Literal[7] +MODE_CCM: Literal[8] +MODE_EAX: Literal[9] +MODE_SIV: Literal[10] +MODE_GCM: Literal[11] +MODE_OCB: Literal[12] -MODE_ECB: AESMode -MODE_CBC: AESMode -MODE_CFB: AESMode -MODE_OFB: AESMode -MODE_CTR: AESMode -MODE_OPENPGP: AESMode -MODE_CCM: AESMode -MODE_EAX: AESMode -MODE_GCM: AESMode -MODE_SIV: AESMode -MODE_OCB: AESMode +# MODE_ECB +@overload +def new(key: Buffer, + mode: Literal[1], + use_aesni : bool = ...) -> \ + EcbMode: ... -Buffer = Union[bytes, bytearray, memoryview] +# MODE_CBC +@overload +def new(key: Buffer, + mode: Literal[2], + iv : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + CbcMode: ... +@overload def new(key: Buffer, - mode: AESMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., + mode: Literal[2], + IV : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + CbcMode: ... + +# MODE_CFB +@overload +def new(key: Buffer, + mode: Literal[3], + iv : Optional[Buffer] = ..., segment_size : int = ..., - mac_len : int = ..., - assoc_len : int = ..., + use_aesni : bool = ...) -> \ + CfbMode: ... + +@overload +def new(key: Buffer, + mode: Literal[3], + IV : Optional[Buffer] = ..., + segment_size : int = ..., + use_aesni : bool = ...) -> \ + CfbMode: ... + +# MODE_OFB +@overload +def new(key: Buffer, + mode: Literal[5], + iv : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OfbMode: ... + +@overload +def new(key: Buffer, + mode: Literal[5], + IV : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OfbMode: ... + +# MODE_CTR +@overload +def new(key: Buffer, + mode: Literal[6], + nonce : Optional[Buffer] = ..., initial_value : Union[int, Buffer] = ..., counter : Dict = ..., use_aesni : bool = ...) -> \ - Union[EcbMode, CbcMode, CfbMode, OfbMode, CtrMode, - OpenPgpMode, CcmMode, EaxMode, GcmMode, - SivMode, OcbMode]: ... + CtrMode: ... + +# MODE_OPENPGP +@overload +def new(key: Buffer, + mode: Literal[7], + iv : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OpenPgpMode: ... + +@overload +def new(key: Buffer, + mode: Literal[7], + IV : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + OpenPgpMode: ... + +# MODE_CCM +@overload +def new(key: Buffer, + mode: Literal[8], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + assoc_len : int = ..., + use_aesni : bool = ...) -> \ + CcmMode: ... + +# MODE_EAX +@overload +def new(key: Buffer, + mode: Literal[9], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + use_aesni : bool = ...) -> \ + EaxMode: ... + +# MODE_GCM +@overload +def new(key: Buffer, + mode: Literal[10], + nonce : Optional[Buffer] = ..., + use_aesni : bool = ...) -> \ + SivMode: ... + +# MODE_SIV +@overload +def new(key: Buffer, + mode: Literal[11], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + use_aesni : bool = ...) -> \ + GcmMode: ... + +# MODE_OCB +@overload +def new(key: Buffer, + mode: Literal[12], + nonce : Optional[Buffer] = ..., + mac_len : int = ..., + use_aesni : bool = ...) -> \ + OcbMode: ... + block_size: int key_size: Tuple[int, int, int] diff --git a/frozen_deps/Cryptodome/Cipher/ARC2.pyi b/frozen_deps/Cryptodome/Cipher/ARC2.pyi index 9659c68..a122a52 100644 --- a/frozen_deps/Cryptodome/Cipher/ARC2.pyi +++ b/frozen_deps/Cryptodome/Cipher/ARC2.pyi @@ -1,4 +1,6 @@ -from typing import Union, Dict, Iterable +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview from Cryptodome.Cipher._mode_ecb import EcbMode from Cryptodome.Cipher._mode_cbc import CbcMode @@ -18,13 +20,11 @@ MODE_CTR: ARC2Mode MODE_OPENPGP: ARC2Mode MODE_EAX: ARC2Mode -Buffer = Union[bytes, bytearray, memoryview] - def new(key: Buffer, mode: ARC2Mode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., segment_size : int = ..., mac_len : int = ..., initial_value : Union[int, Buffer] = ..., diff --git a/frozen_deps/Cryptodome/Cipher/ARC4.py b/frozen_deps/Cryptodome/Cipher/ARC4.py index e640e77..543a323 100644 --- a/frozen_deps/Cryptodome/Cipher/ARC4.py +++ b/frozen_deps/Cryptodome/Cipher/ARC4.py @@ -20,8 +20,6 @@ # SOFTWARE. # =================================================================== -from Cryptodome.Util.py3compat import b - from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, create_string_buffer, get_raw_buffer, SmartPointer, c_size_t, c_uint8_ptr) @@ -113,7 +111,7 @@ def new(key, *args, **kwargs): :param key: The secret key to use in the symmetric cipher. - Its length must be in the range ``[5..256]``. + Its length must be in the range ``[1..256]``. The recommended length is 16 bytes. :type key: bytes, bytearray, memoryview @@ -131,7 +129,8 @@ def new(key, *args, **kwargs): """ return ARC4Cipher(key, *args, **kwargs) + # Size of a data block (in bytes) block_size = 1 # Size of a key (in bytes) -key_size = range(5, 256+1) +key_size = range(1, 256+1) diff --git a/frozen_deps/Cryptodome/Cipher/ARC4.pyi b/frozen_deps/Cryptodome/Cipher/ARC4.pyi index 2e75d6f..b081585 100644 --- a/frozen_deps/Cryptodome/Cipher/ARC4.pyi +++ b/frozen_deps/Cryptodome/Cipher/ARC4.pyi @@ -1,6 +1,6 @@ from typing import Any, Union, Iterable -Buffer = Union[bytes, bytearray, memoryview] +Buffer = bytes|bytearray|memoryview class ARC4Cipher: block_size: int diff --git a/frozen_deps/Cryptodome/Cipher/Blowfish.pyi b/frozen_deps/Cryptodome/Cipher/Blowfish.pyi index a669240..b8b21c6 100644 --- a/frozen_deps/Cryptodome/Cipher/Blowfish.pyi +++ b/frozen_deps/Cryptodome/Cipher/Blowfish.pyi @@ -1,4 +1,6 @@ -from typing import Union, Dict, Iterable +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview from Cryptodome.Cipher._mode_ecb import EcbMode from Cryptodome.Cipher._mode_cbc import CbcMode @@ -18,13 +20,11 @@ MODE_CTR: BlowfishMode MODE_OPENPGP: BlowfishMode MODE_EAX: BlowfishMode -Buffer = Union[bytes, bytearray, memoryview] - def new(key: Buffer, mode: BlowfishMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., segment_size : int = ..., mac_len : int = ..., initial_value : Union[int, Buffer] = ..., diff --git a/frozen_deps/Cryptodome/Cipher/CAST.pyi b/frozen_deps/Cryptodome/Cipher/CAST.pyi index 6b411cf..be01f09 100644 --- a/frozen_deps/Cryptodome/Cipher/CAST.pyi +++ b/frozen_deps/Cryptodome/Cipher/CAST.pyi @@ -1,4 +1,6 @@ -from typing import Union, Dict, Iterable +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview from Cryptodome.Cipher._mode_ecb import EcbMode from Cryptodome.Cipher._mode_cbc import CbcMode @@ -18,13 +20,11 @@ MODE_CTR: CASTMode MODE_OPENPGP: CASTMode MODE_EAX: CASTMode -Buffer = Union[bytes, bytearray, memoryview] - def new(key: Buffer, mode: CASTMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., segment_size : int = ..., mac_len : int = ..., initial_value : Union[int, Buffer] = ..., diff --git a/frozen_deps/Cryptodome/Cipher/ChaCha20.py b/frozen_deps/Cryptodome/Cipher/ChaCha20.py index 0cd9102..648d692 100644 --- a/frozen_deps/Cryptodome/Cipher/ChaCha20.py +++ b/frozen_deps/Cryptodome/Cipher/ChaCha20.py @@ -94,6 +94,8 @@ class ChaCha20Cipher(object): See also `new()` at the module level.""" + self.nonce = _copy_bytes(None, None, nonce) + # XChaCha20 requires a key derivation with HChaCha20 # See 2.3 in https://tools.ietf.org/html/draft-arciszewski-xchacha-03 if len(nonce) == 24: @@ -102,17 +104,16 @@ class ChaCha20Cipher(object): self._name = "XChaCha20" else: self._name = "ChaCha20" + nonce = self.nonce - self.nonce = _copy_bytes(None, None, nonce) - - self._next = ( self.encrypt, self.decrypt ) + self._next = ("encrypt", "decrypt") self._state = VoidPointer() result = _raw_chacha20_lib.chacha20_init( self._state.address_of(), c_uint8_ptr(key), c_size_t(len(key)), - self.nonce, + nonce, c_size_t(len(nonce))) if result: raise ValueError("Error %d instantiating a %s cipher" % (result, @@ -133,9 +134,9 @@ class ChaCha20Cipher(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("Cipher object can only be used for decryption") - self._next = ( self.encrypt, ) + self._next = ("encrypt",) return self._encrypt(plaintext, output) def _encrypt(self, plaintext, output): @@ -179,9 +180,9 @@ class ChaCha20Cipher(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("Cipher object can only be used for encryption") - self._next = ( self.decrypt, ) + self._next = ("decrypt",) try: return self._encrypt(ciphertext, output) diff --git a/frozen_deps/Cryptodome/Cipher/ChaCha20.pyi b/frozen_deps/Cryptodome/Cipher/ChaCha20.pyi index 3d00a1d..f5001cd 100644 --- a/frozen_deps/Cryptodome/Cipher/ChaCha20.pyi +++ b/frozen_deps/Cryptodome/Cipher/ChaCha20.pyi @@ -1,6 +1,6 @@ -from typing import Union, overload +from typing import Union, overload, Optional -Buffer = Union[bytes, bytearray, memoryview] +Buffer = bytes|bytearray|memoryview def _HChaCha20(key: Buffer, nonce: Buffer) -> bytearray: ... @@ -19,7 +19,7 @@ class ChaCha20Cipher: def decrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... def seek(self, position: int) -> None: ... -def new(key: Buffer, nonce: Buffer = ...) -> ChaCha20Cipher: ... +def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Cipher: ... block_size: int key_size: int diff --git a/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.py b/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.py index b6bc7a6..b2923ed 100644 --- a/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.py +++ b/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.py @@ -63,10 +63,8 @@ class ChaCha20Poly1305Cipher(object): See also `new()` at the module level.""" - self.nonce = _copy_bytes(None, None, nonce) - - self._next = (self.update, self.encrypt, self.decrypt, self.digest, - self.verify) + self._next = ("update", "encrypt", "decrypt", "digest", + "verify") self._authenticator = Poly1305.new(key=key, nonce=nonce, cipher=ChaCha20) @@ -94,7 +92,7 @@ class ChaCha20Poly1305Cipher(object): A piece of associated data. There are no restrictions on its size. """ - if self.update not in self._next: + if "update" not in self._next: raise TypeError("update() method cannot be called") self._len_aad += len(data) @@ -120,13 +118,13 @@ class ChaCha20Poly1305Cipher(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() method cannot be called") if self._status == _CipherStatus.PROCESSING_AUTH_DATA: self._pad_aad() - self._next = (self.encrypt, self.digest) + self._next = ("encrypt", "digest") result = self._cipher.encrypt(plaintext, output=output) self._len_ct += len(plaintext) @@ -149,13 +147,13 @@ class ChaCha20Poly1305Cipher(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() method cannot be called") if self._status == _CipherStatus.PROCESSING_AUTH_DATA: self._pad_aad() - self._next = (self.decrypt, self.verify) + self._next = ("decrypt", "verify") self._len_ct += len(ciphertext) self._authenticator.update(ciphertext) @@ -189,9 +187,9 @@ class ChaCha20Poly1305Cipher(object): :Return: the MAC tag, as 16 ``bytes``. """ - if self.digest not in self._next: + if "digest" not in self._next: raise TypeError("digest() method cannot be called") - self._next = (self.digest,) + self._next = ("digest",) return self._compute_mac() @@ -218,10 +216,10 @@ class ChaCha20Poly1305Cipher(object): or the key is incorrect. """ - if self.verify not in self._next: + if "verify" not in self._next: raise TypeError("verify() cannot be called" " when encrypting a message") - self._next = (self.verify,) + self._next = ("verify",) secret = get_random_bytes(16) @@ -316,10 +314,10 @@ def new(**kwargs): nonce = get_random_bytes(12) if len(nonce) in (8, 12): - pass + chacha20_poly1305_nonce = nonce elif len(nonce) == 24: key = _HChaCha20(key, nonce[:16]) - nonce = b'\x00\x00\x00\x00' + nonce[16:] + chacha20_poly1305_nonce = b'\x00\x00\x00\x00' + nonce[16:] else: raise ValueError("Nonce must be 8, 12 or 24 bytes long") @@ -329,7 +327,9 @@ def new(**kwargs): if kwargs: raise TypeError("Unknown parameters: " + str(kwargs)) - return ChaCha20Poly1305Cipher(key, nonce) + cipher = ChaCha20Poly1305Cipher(key, chacha20_poly1305_nonce) + cipher.nonce = _copy_bytes(None, None, nonce) + return cipher # Size of a key (in bytes) diff --git a/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.pyi b/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.pyi index ef0450f..109e805 100644 --- a/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.pyi +++ b/frozen_deps/Cryptodome/Cipher/ChaCha20_Poly1305.pyi @@ -1,6 +1,6 @@ -from typing import Union, Tuple, overload +from typing import Union, Tuple, overload, Optional -Buffer = Union[bytes, bytearray, memoryview] +Buffer = bytes|bytearray|memoryview class ChaCha20Poly1305Cipher: nonce: bytes @@ -22,7 +22,7 @@ class ChaCha20Poly1305Cipher: def encrypt_and_digest(self, plaintext: Buffer) -> Tuple[bytes, bytes]: ... def decrypt_and_verify(self, ciphertext: Buffer, received_mac_tag: Buffer) -> bytes: ... -def new(key: Buffer, nonce: Buffer = ...) -> ChaCha20Poly1305Cipher: ... +def new(key: Buffer, nonce: Optional[Buffer] = ...) -> ChaCha20Poly1305Cipher: ... block_size: int key_size: int diff --git a/frozen_deps/Cryptodome/Cipher/DES.pyi b/frozen_deps/Cryptodome/Cipher/DES.pyi index 1ba2752..25a3b23 100644 --- a/frozen_deps/Cryptodome/Cipher/DES.pyi +++ b/frozen_deps/Cryptodome/Cipher/DES.pyi @@ -1,4 +1,6 @@ -from typing import Union, Dict, Iterable +from typing import Union, Dict, Iterable, Optional + +Buffer = bytes|bytearray|memoryview from Cryptodome.Cipher._mode_ecb import EcbMode from Cryptodome.Cipher._mode_cbc import CbcMode @@ -18,13 +20,11 @@ MODE_CTR: DESMode MODE_OPENPGP: DESMode MODE_EAX: DESMode -Buffer = Union[bytes, bytearray, memoryview] - def new(key: Buffer, mode: DESMode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., segment_size : int = ..., mac_len : int = ..., initial_value : Union[int, Buffer] = ..., diff --git a/frozen_deps/Cryptodome/Cipher/DES3.pyi b/frozen_deps/Cryptodome/Cipher/DES3.pyi index c1a524f..2c150f8 100644 --- a/frozen_deps/Cryptodome/Cipher/DES3.pyi +++ b/frozen_deps/Cryptodome/Cipher/DES3.pyi @@ -1,4 +1,6 @@ -from typing import Union, Dict, Tuple +from typing import Union, Dict, Tuple, Optional + +Buffer = bytes|bytearray|memoryview from Cryptodome.Cipher._mode_ecb import EcbMode from Cryptodome.Cipher._mode_cbc import CbcMode @@ -20,13 +22,11 @@ MODE_CTR: DES3Mode MODE_OPENPGP: DES3Mode MODE_EAX: DES3Mode -Buffer = Union[bytes, bytearray, memoryview] - def new(key: Buffer, mode: DES3Mode, - iv : Buffer = ..., - IV : Buffer = ..., - nonce : Buffer = ..., + iv : Optional[Buffer] = ..., + IV : Optional[Buffer] = ..., + nonce : Optional[Buffer] = ..., segment_size : int = ..., mac_len : int = ..., initial_value : Union[int, Buffer] = ..., diff --git a/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py b/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py index 3207bbe..08f9efe 100644 --- a/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py +++ b/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py @@ -23,11 +23,13 @@ from Cryptodome.Signature.pss import MGF1 import Cryptodome.Hash.SHA1 -from Cryptodome.Util.py3compat import bord, _copy_bytes +from Cryptodome.Util.py3compat import _copy_bytes import Cryptodome.Util.number -from Cryptodome.Util.number import ceil_div, bytes_to_long, long_to_bytes -from Cryptodome.Util.strxor import strxor +from Cryptodome.Util.number import ceil_div, bytes_to_long, long_to_bytes +from Cryptodome.Util.strxor import strxor from Cryptodome import Random +from ._pkcs1_oaep_decode import oaep_decode + class PKCS1OAEP_Cipher: """Cipher object for PKCS#1 v1.5 OAEP. @@ -68,7 +70,7 @@ class PKCS1OAEP_Cipher: if mgfunc: self._mgf = mgfunc else: - self._mgf = lambda x,y: MGF1(x,y,self._hashObj) + self._mgf = lambda x, y: MGF1(x, y, self._hashObj) self._label = _copy_bytes(None, None, label) self._randfunc = randfunc @@ -105,7 +107,7 @@ class PKCS1OAEP_Cipher: # See 7.1.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) - k = ceil_div(modBits, 8) # Convert from bits to bytes + k = ceil_div(modBits, 8) # Convert from bits to bytes hLen = self._hashObj.digest_size mLen = len(message) @@ -159,22 +161,18 @@ class PKCS1OAEP_Cipher: # See 7.1.2 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes + k = ceil_div(modBits, 8) # Convert from bits to bytes hLen = self._hashObj.digest_size # Step 1b and 1c - if len(ciphertext) != k or k<hLen+2: + if len(ciphertext) != k or k < hLen+2: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(ciphertext) - # Step 2b (RSADP) - m_int = self._key._decrypt(ct_int) - # Complete step 2c (I2OSP) - em = long_to_bytes(m_int, k) + # Step 2b (RSADP) and step 2c (I2OSP) + em = self._key._decrypt_to_bytes(ct_int) # Step 3a lHash = self._hashObj.new(self._label).digest() - # Step 3b - y = em[0] # y must be 0, but we MUST NOT check it here in order not to # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) maskedSeed = em[1:hLen+1] @@ -187,22 +185,17 @@ class PKCS1OAEP_Cipher: dbMask = self._mgf(seed, k-hLen-1) # Step 3f db = strxor(maskedDB, dbMask) - # Step 3g - one_pos = db[hLen:].find(b'\x01') - lHash1 = db[:hLen] - invalid = bord(y) | int(one_pos < 0) - hash_compare = strxor(lHash1, lHash) - for x in hash_compare: - invalid |= bord(x) - for x in db[hLen:one_pos]: - invalid |= bord(x) - if invalid != 0: + # Step 3b + 3g + res = oaep_decode(em, lHash, db) + if res <= 0: raise ValueError("Incorrect decryption.") # Step 4 - return db[hLen + one_pos + 1:] + return db[res:] + def new(key, hashAlgo=None, mgfunc=None, label=b'', randfunc=None): - """Return a cipher object :class:`PKCS1OAEP_Cipher` that can be used to perform PKCS#1 OAEP encryption or decryption. + """Return a cipher object :class:`PKCS1OAEP_Cipher` + that can be used to perform PKCS#1 OAEP encryption or decryption. :param key: The key object to use to encrypt or decrypt the message. @@ -236,4 +229,3 @@ def new(key, hashAlgo=None, mgfunc=None, label=b'', randfunc=None): if randfunc is None: randfunc = Random.get_random_bytes return PKCS1OAEP_Cipher(key, hashAlgo, mgfunc, label, randfunc) - diff --git a/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py b/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py index 1fd1626..d7a9b79 100644 --- a/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py +++ b/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py @@ -20,12 +20,13 @@ # SOFTWARE. # =================================================================== -__all__ = [ 'new', 'PKCS115_Cipher' ] +__all__ = ['new', 'PKCS115_Cipher'] -from Cryptodome.Util.number import ceil_div, bytes_to_long, long_to_bytes -from Cryptodome.Util.py3compat import bord, _copy_bytes -import Cryptodome.Util.number from Cryptodome import Random +from Cryptodome.Util.number import bytes_to_long, long_to_bytes +from Cryptodome.Util.py3compat import bord, is_bytes, _copy_bytes +from ._pkcs1_oaep_decode import pkcs1_decode + class PKCS115_Cipher: """This cipher can perform PKCS#1 v1.5 RSA encryption or decryption. @@ -74,8 +75,7 @@ class PKCS115_Cipher: """ # See 7.2.1 in RFC8017 - modBits = Cryptodome.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes + k = self._key.size_in_bytes() mLen = len(message) # Step 1 @@ -89,7 +89,6 @@ class PKCS115_Cipher: continue ps.append(new_byte) ps = b"".join(ps) - assert(len(ps) == k - mLen - 3) # Step 2b em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message) # Step 3a (OS2IP) @@ -100,81 +99,73 @@ class PKCS115_Cipher: c = long_to_bytes(m_int, k) return c - def decrypt(self, ciphertext, sentinel): + def decrypt(self, ciphertext, sentinel, expected_pt_len=0): r"""Decrypt a PKCS#1 v1.5 ciphertext. - This function is named ``RSAES-PKCS1-V1_5-DECRYPT``, and is specified in + This is the function ``RSAES-PKCS1-V1_5-DECRYPT`` specified in `section 7.2.2 of RFC8017 <https://tools.ietf.org/html/rfc8017#page-29>`_. - :param ciphertext: + Args: + ciphertext (bytes/bytearray/memoryview): The ciphertext that contains the message to recover. - :type ciphertext: bytes/bytearray/memoryview - - :param sentinel: + sentinel (any type): The object to return whenever an error is detected. - :type sentinel: any type + expected_pt_len (integer): + The length the plaintext is known to have, or 0 if unknown. - :Returns: A byte string. It is either the original message or the ``sentinel`` (in case of an error). - - :Raises ValueError: - If the ciphertext length is incorrect - :Raises TypeError: - If the RSA key has no private half (i.e. it cannot be used for - decyption). + Returns (byte string): + It is either the original message or the ``sentinel`` (in case of an error). .. warning:: - You should **never** let the party who submitted the ciphertext know that - this function returned the ``sentinel`` value. - Armed with such knowledge (for a fair amount of carefully crafted but invalid ciphertexts), - an attacker is able to recontruct the plaintext of any other encryption that were carried out - with the same RSA public key (see `Bleichenbacher's`__ attack). - - In general, it should not be possible for the other party to distinguish - whether processing at the server side failed because the value returned - was a ``sentinel`` as opposed to a random, invalid message. - - In fact, the second option is not that unlikely: encryption done according to PKCS#1 v1.5 - embeds no good integrity check. There is roughly one chance - in 2\ :sup:`16` for a random ciphertext to be returned as a valid message - (although random looking). - - It is therefore advisabled to: - - 1. Select as ``sentinel`` a value that resembles a plausable random, invalid message. - 2. Not report back an error as soon as you detect a ``sentinel`` value. - Put differently, you should not explicitly check if the returned value is the ``sentinel`` or not. - 3. Cover all possible errors with a single, generic error indicator. - 4. Embed into the definition of ``message`` (at the protocol level) a digest (e.g. ``SHA-1``). - It is recommended for it to be the rightmost part ``message``. - 5. Where possible, monitor the number of errors due to ciphertexts originating from the same party, - and slow down the rate of the requests from such party (or even blacklist it altogether). - - **If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.** - - .. __: http://www.bell-labs.com/user/bleichen/papers/pkcs.ps - + PKCS#1 v1.5 decryption is intrinsically vulnerable to timing + attacks (see `Bleichenbacher's`__ attack). + **Use PKCS#1 OAEP instead**. + + This implementation attempts to mitigate the risk + with some constant-time constructs. + However, they are not sufficient by themselves: the type of protocol you + implement and the way you handle errors make a big difference. + + Specifically, you should make it very hard for the (malicious) + party that submitted the ciphertext to quickly understand if decryption + succeeded or not. + + To this end, it is recommended that your protocol only encrypts + plaintexts of fixed length (``expected_pt_len``), + that ``sentinel`` is a random byte string of the same length, + and that processing continues for as long + as possible even if ``sentinel`` is returned (i.e. in case of + incorrect decryption). + + .. __: https://dx.doi.org/10.1007/BFb0055716 """ - # See 7.2.1 in RFC3447 - modBits = Cryptodome.Util.number.size(self._key.n) - k = ceil_div(modBits,8) # Convert from bits to bytes + # See 7.2.2 in RFC8017 + k = self._key.size_in_bytes() # Step 1 if len(ciphertext) != k: - raise ValueError("Ciphertext with incorrect length.") + raise ValueError("Ciphertext with incorrect length (not %d bytes)" % k) + # Step 2a (O2SIP) ct_int = bytes_to_long(ciphertext) - # Step 2b (RSADP) - m_int = self._key._decrypt(ct_int) - # Complete step 2c (I2OSP) - em = long_to_bytes(m_int, k) - # Step 3 - sep = em.find(b'\x00', 2) - if not em.startswith(b'\x00\x02') or sep < 10: - return sentinel - # Step 4 - return em[sep + 1:] + + # Step 2b (RSADP) and Step 2c (I2OSP) + em = self._key._decrypt_to_bytes(ct_int) + + # Step 3 (not constant time when the sentinel is not a byte string) + output = bytes(bytearray(k)) + if not is_bytes(sentinel) or len(sentinel) > k: + size = pkcs1_decode(em, b'', expected_pt_len, output) + if size < 0: + return sentinel + else: + return output[size:] + + # Step 3 (somewhat constant time) + size = pkcs1_decode(em, sentinel, expected_pt_len, output) + return output[size:] def new(key, randfunc=None): @@ -196,4 +187,3 @@ def new(key, randfunc=None): if randfunc is None: randfunc = Random.get_random_bytes return PKCS115_Cipher(key, randfunc) - diff --git a/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.pyi b/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.pyi index ff4e3f2..b69f509 100644 --- a/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.pyi +++ b/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.pyi @@ -1,8 +1,9 @@ -from typing import Callable, Union, Any, Optional +from typing import Callable, Union, Any, Optional, TypeVar from Cryptodome.PublicKey.RSA import RsaKey Buffer = Union[bytes, bytearray, memoryview] +T = TypeVar('T') class PKCS115_Cipher: def __init__(self, @@ -11,7 +12,9 @@ class PKCS115_Cipher: def can_encrypt(self) -> bool: ... def can_decrypt(self) -> bool: ... def encrypt(self, message: Buffer) -> bytes: ... - def decrypt(self, ciphertext: Buffer) -> bytes: ... + def decrypt(self, ciphertext: Buffer, + sentinel: T, + expected_pt_len: Optional[int] = ...) -> Union[bytes, T]: ... def new(key: RsaKey, randfunc: Optional[Callable[[int], bytes]] = ...) -> PKCS115_Cipher: ... diff --git a/frozen_deps/Cryptodome/Cipher/Salsa20.pyi b/frozen_deps/Cryptodome/Cipher/Salsa20.pyi index 9178f0d..cf8690e 100644 --- a/frozen_deps/Cryptodome/Cipher/Salsa20.pyi +++ b/frozen_deps/Cryptodome/Cipher/Salsa20.pyi @@ -1,7 +1,6 @@ -from typing import Union, Tuple, Optional, overload +from typing import Union, Tuple, Optional, overload, Optional - -Buffer = Union[bytes, bytearray, memoryview] +Buffer = bytes|bytearray|memoryview class Salsa20Cipher: nonce: bytes diff --git a/frozen_deps/Cryptodome/Cipher/_ARC4.abi3.so b/frozen_deps/Cryptodome/Cipher/_ARC4.abi3.so Binary files differnew file mode 100755 index 0000000..451d359 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_ARC4.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_ARC4.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_ARC4.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index e4d89af..0000000 --- a/frozen_deps/Cryptodome/Cipher/_ARC4.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_Salsa20.abi3.so b/frozen_deps/Cryptodome/Cipher/_Salsa20.abi3.so Binary files differnew file mode 100755 index 0000000..a303d91 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_Salsa20.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_Salsa20.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_Salsa20.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index df9884e..0000000 --- a/frozen_deps/Cryptodome/Cipher/_Salsa20.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_chacha20.abi3.so b/frozen_deps/Cryptodome/Cipher/_chacha20.abi3.so Binary files differnew file mode 100755 index 0000000..f1f1fa1 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_chacha20.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_chacha20.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_chacha20.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index ded8fd8..0000000 --- a/frozen_deps/Cryptodome/Cipher/_chacha20.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_mode_cbc.py b/frozen_deps/Cryptodome/Cipher/_mode_cbc.py index edc29ca..94d02e7 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_cbc.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_cbc.py @@ -120,7 +120,7 @@ class CbcMode(object): self.IV = self.iv """Alias for `iv`""" - self._next = [ self.encrypt, self.decrypt ] + self._next = ["encrypt", "decrypt"] def encrypt(self, plaintext, output=None): """Encrypt data with the key and the parameters set at initialization. @@ -158,18 +158,18 @@ class CbcMode(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [ self.encrypt ] - + self._next = ["encrypt"] + if output is None: ciphertext = create_string_buffer(len(plaintext)) else: ciphertext = output - + if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(plaintext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) @@ -221,10 +221,10 @@ class CbcMode(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [ self.decrypt ] - + self._next = ["decrypt"] + if output is None: plaintext = create_string_buffer(len(ciphertext)) else: @@ -232,7 +232,7 @@ class CbcMode(object): if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(ciphertext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) @@ -285,7 +285,7 @@ def _create_cbc_cipher(factory, **kwargs): if len(iv) != factory.block_size: raise ValueError("Incorrect IV length (it must be %d bytes long)" % - factory.block_size) + factory.block_size) if kwargs: raise TypeError("Unknown parameters for CBC: %s" % str(kwargs)) diff --git a/frozen_deps/Cryptodome/Cipher/_mode_ccm.py b/frozen_deps/Cryptodome/Cipher/_mode_ccm.py index 0e1c2f6..ec2e4f4 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_ccm.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_ccm.py @@ -155,8 +155,8 @@ class CcmMode(object): self._t = None # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] # Cumulative lengths self._cumul_assoc_len = 0 @@ -252,12 +252,12 @@ class CcmMode(object): A piece of associated data. There are no restrictions on its size. """ - if self.update not in self._next: + if "update" not in self._next: raise TypeError("update() can only be called" " immediately after initialization") - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] self._cumul_assoc_len += len(assoc_data) if self._assoc_len is not None and \ @@ -336,10 +336,10 @@ class CcmMode(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() can only be called after" " initialization or an update()") - self._next = [self.encrypt, self.digest] + self._next = ["encrypt", "digest"] # No more associated data allowed from now if self._assoc_len is None: @@ -356,7 +356,7 @@ class CcmMode(object): if self._msg_len is None: self._msg_len = len(plaintext) self._start_mac() - self._next = [self.digest] + self._next = ["digest"] self._cumul_msg_len += len(plaintext) if self._cumul_msg_len > self._msg_len: @@ -409,10 +409,10 @@ class CcmMode(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() can only be called" " after initialization or an update()") - self._next = [self.decrypt, self.verify] + self._next = ["decrypt", "verify"] # No more associated data allowed from now if self._assoc_len is None: @@ -429,7 +429,7 @@ class CcmMode(object): if self._msg_len is None: self._msg_len = len(ciphertext) self._start_mac() - self._next = [self.verify] + self._next = ["verify"] self._cumul_msg_len += len(ciphertext) if self._cumul_msg_len > self._msg_len: @@ -461,10 +461,10 @@ class CcmMode(object): :Return: the MAC, as a byte string. """ - if self.digest not in self._next: + if "digest" not in self._next: raise TypeError("digest() cannot be called when decrypting" " or validating a message") - self._next = [self.digest] + self._next = ["digest"] return self._digest() def _digest(self): @@ -523,10 +523,10 @@ class CcmMode(object): or the key is incorrect. """ - if self.verify not in self._next: + if "verify" not in self._next: raise TypeError("verify() cannot be called" " when encrypting a message") - self._next = [self.verify] + self._next = ["verify"] self._digest() secret = get_random_bytes(16) diff --git a/frozen_deps/Cryptodome/Cipher/_mode_cfb.py b/frozen_deps/Cryptodome/Cipher/_mode_cfb.py index b790dd4..1b1b6c3 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_cfb.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_cfb.py @@ -119,7 +119,7 @@ class CfbMode(object): self.IV = self.iv """Alias for `iv`""" - self._next = [ self.encrypt, self.decrypt ] + self._next = ["encrypt", "decrypt"] def encrypt(self, plaintext, output=None): """Encrypt data with the key and the parameters set at initialization. @@ -154,18 +154,18 @@ class CfbMode(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [ self.encrypt ] - + self._next = ["encrypt"] + if output is None: ciphertext = create_string_buffer(len(plaintext)) else: ciphertext = output - + if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(plaintext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) @@ -215,10 +215,10 @@ class CfbMode(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [ self.decrypt ] - + self._next = ["decrypt"] + if output is None: plaintext = create_string_buffer(len(ciphertext)) else: @@ -226,11 +226,11 @@ class CfbMode(object): if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(ciphertext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) - + result = raw_cfb_lib.CFB_decrypt(self._state.get(), c_uint8_ptr(ciphertext), c_uint8_ptr(plaintext), diff --git a/frozen_deps/Cryptodome/Cipher/_mode_ctr.py b/frozen_deps/Cryptodome/Cipher/_mode_ctr.py index 99712d0..9ce357f 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_ctr.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_ctr.py @@ -146,7 +146,7 @@ class CtrMode(object): self.block_size = len(initial_counter_block) """The block size of the underlying cipher, in bytes.""" - self._next = [self.encrypt, self.decrypt] + self._next = ["encrypt", "decrypt"] def encrypt(self, plaintext, output=None): """Encrypt data with the key and the parameters set at initialization. @@ -181,18 +181,18 @@ class CtrMode(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [self.encrypt] - + self._next = ["encrypt"] + if output is None: ciphertext = create_string_buffer(len(plaintext)) else: ciphertext = output - + if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(plaintext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) @@ -206,7 +206,7 @@ class CtrMode(object): raise OverflowError("The counter has wrapped around in" " CTR mode") raise ValueError("Error %X while encrypting in CTR mode" % result) - + if output is None: return get_raw_buffer(ciphertext) else: @@ -245,10 +245,10 @@ class CtrMode(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [self.decrypt] - + self._next = ["decrypt"] + if output is None: plaintext = create_string_buffer(len(ciphertext)) else: @@ -256,12 +256,11 @@ class CtrMode(object): if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(ciphertext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) - result = raw_ctr_lib.CTR_decrypt(self._state.get(), c_uint8_ptr(ciphertext), c_uint8_ptr(plaintext), @@ -271,7 +270,7 @@ class CtrMode(object): raise OverflowError("The counter has wrapped around in" " CTR mode") raise ValueError("Error %X while decrypting in CTR mode" % result) - + if output is None: return get_raw_buffer(plaintext) else: @@ -324,8 +323,8 @@ def _create_ctr_cipher(factory, **kwargs): raise TypeError("Invalid parameters for CTR mode: %s" % str(kwargs)) if counter is not None and (nonce, initial_value) != (None, None): - raise TypeError("'counter' and 'nonce'/'initial_value'" - " are mutually exclusive") + raise TypeError("'counter' and 'nonce'/'initial_value'" + " are mutually exclusive") if counter is None: # Cryptodome.Util.Counter is not used @@ -337,7 +336,7 @@ def _create_ctr_cipher(factory, **kwargs): else: if len(nonce) >= factory.block_size: raise ValueError("Nonce is too long") - + # What is not nonce is counter counter_len = factory.block_size - len(nonce) @@ -350,7 +349,8 @@ def _create_ctr_cipher(factory, **kwargs): initial_counter_block = nonce + long_to_bytes(initial_value, counter_len) else: if len(initial_value) != counter_len: - raise ValueError("Incorrect length for counter byte string (%d bytes, expected %d)" % (len(initial_value), counter_len)) + raise ValueError("Incorrect length for counter byte string (%d bytes, expected %d)" % + (len(initial_value), counter_len)) initial_counter_block = nonce + initial_value return CtrMode(cipher_state, @@ -379,7 +379,7 @@ def _create_ctr_cipher(factory, **kwargs): while initial_value > 0: words.append(struct.pack('B', initial_value & 255)) initial_value >>= 8 - words += [ b'\x00' ] * max(0, counter_len - len(words)) + words += [b'\x00'] * max(0, counter_len - len(words)) if not little_endian: words.reverse() initial_counter_block = prefix + b"".join(words) + suffix diff --git a/frozen_deps/Cryptodome/Cipher/_mode_eax.py b/frozen_deps/Cryptodome/Cipher/_mode_eax.py index 8efb77a..44ef21f 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_eax.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_eax.py @@ -90,12 +90,12 @@ class EaxMode(object): self._mac_tag = None # Cache for MAC tag # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] # MAC tag length - if not (4 <= self._mac_len <= self.block_size): - raise ValueError("Parameter 'mac_len' must not be larger than %d" + if not (2 <= self._mac_len <= self.block_size): + raise ValueError("'mac_len' must be at least 2 and not larger than %d" % self.block_size) # Nonce cannot be empty and must be a byte string @@ -145,12 +145,12 @@ class EaxMode(object): A piece of associated data. There are no restrictions on its size. """ - if self.update not in self._next: + if "update" not in self._next: raise TypeError("update() can only be called" " immediately after initialization") - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] self._signer.update(assoc_data) return self @@ -188,10 +188,10 @@ class EaxMode(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() can only be called after" " initialization or an update()") - self._next = [self.encrypt, self.digest] + self._next = ["encrypt", "digest"] ct = self._cipher.encrypt(plaintext, output=output) if output is None: self._omac[2].update(ct) @@ -232,10 +232,10 @@ class EaxMode(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() can only be called" " after initialization or an update()") - self._next = [self.decrypt, self.verify] + self._next = ["decrypt", "verify"] self._omac[2].update(ciphertext) return self._cipher.decrypt(ciphertext, output=output) @@ -250,10 +250,10 @@ class EaxMode(object): :Return: the MAC, as a byte string. """ - if self.digest not in self._next: + if "digest" not in self._next: raise TypeError("digest() cannot be called when decrypting" " or validating a message") - self._next = [self.digest] + self._next = ["digest"] if not self._mac_tag: tag = b'\x00' * self.block_size @@ -289,10 +289,10 @@ class EaxMode(object): or the key is incorrect. """ - if self.verify not in self._next: + if "verify" not in self._next: raise TypeError("verify() cannot be called" " when encrypting a message") - self._next = [self.verify] + self._next = ["verify"] if not self._mac_tag: tag = b'\x00' * self.block_size diff --git a/frozen_deps/Cryptodome/Cipher/_mode_ecb.py b/frozen_deps/Cryptodome/Cipher/_mode_ecb.py index 4c381f7..a01a16f 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_ecb.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_ecb.py @@ -72,6 +72,7 @@ class EcbMode(object): block_cipher : C pointer A smart pointer to the low-level block cipher instance. """ + self.block_size = block_cipher.block_size self._state = VoidPointer() result = raw_ecb_lib.ECB_start_operation(block_cipher.get(), @@ -213,6 +214,7 @@ def _create_ecb_cipher(factory, **kwargs): to be present""" cipher_state = factory._create_base_cipher(kwargs) + cipher_state.block_size = factory.block_size if kwargs: raise TypeError("Unknown parameters for ECB: %s" % str(kwargs)) return EcbMode(cipher_state) diff --git a/frozen_deps/Cryptodome/Cipher/_mode_gcm.py b/frozen_deps/Cryptodome/Cipher/_mode_gcm.py index c90061b..9914400 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_gcm.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_gcm.py @@ -186,7 +186,7 @@ class GcmMode(object): if len(nonce) == 0: raise ValueError("Nonce cannot be empty") - + if not is_buffer(nonce): raise TypeError("Nonce must be bytes, bytearray or memoryview") @@ -207,8 +207,8 @@ class GcmMode(object): raise ValueError("Parameter 'mac_len' must be in the range 4..16") # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] self._no_more_assoc_data = False @@ -229,10 +229,10 @@ class GcmMode(object): if len(self.nonce) == 12: j0 = self.nonce + b"\x00\x00\x00\x01" else: - fill = (16 - (len(nonce) % 16)) % 16 + 8 + fill = (16 - (len(self.nonce) % 16)) % 16 + 8 ghash_in = (self.nonce + b'\x00' * fill + - long_to_bytes(8 * len(nonce), 8)) + long_to_bytes(8 * len(self.nonce), 8)) j0 = _GHASH(hash_subkey, ghash_c).update(ghash_in).digest() # Step 3 - Prepare GCTR cipher for encryption/decryption @@ -282,12 +282,12 @@ class GcmMode(object): A piece of associated data. There are no restrictions on its size. """ - if self.update not in self._next: + if "update" not in self._next: raise TypeError("update() can only be called" " immediately after initialization") - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] self._update(assoc_data) self._auth_len += len(assoc_data) @@ -364,10 +364,10 @@ class GcmMode(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() can only be called after" " initialization or an update()") - self._next = [self.encrypt, self.digest] + self._next = ["encrypt", "digest"] ciphertext = self._cipher.encrypt(plaintext, output=output) @@ -417,10 +417,10 @@ class GcmMode(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() can only be called" " after initialization or an update()") - self._next = [self.decrypt, self.verify] + self._next = ["decrypt", "verify"] if self._status == MacStatus.PROCESSING_AUTH_DATA: self._pad_cache_and_update() @@ -442,10 +442,10 @@ class GcmMode(object): :Return: the MAC, as a byte string. """ - if self.digest not in self._next: + if "digest" not in self._next: raise TypeError("digest() cannot be called when decrypting" " or validating a message") - self._next = [self.digest] + self._next = ["digest"] return self._compute_mac() @@ -492,10 +492,10 @@ class GcmMode(object): or the key is incorrect. """ - if self.verify not in self._next: + if "verify" not in self._next: raise TypeError("verify() cannot be called" " when encrypting a message") - self._next = [self.verify] + self._next = ["verify"] secret = get_random_bytes(16) diff --git a/frozen_deps/Cryptodome/Cipher/_mode_ocb.py b/frozen_deps/Cryptodome/Cipher/_mode_ocb.py index 27c2797..1295e61 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_ocb.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_ocb.py @@ -71,7 +71,7 @@ Example: import struct from binascii import unhexlify -from Cryptodome.Util.py3compat import bord, _copy_bytes +from Cryptodome.Util.py3compat import bord, _copy_bytes, bchr from Cryptodome.Util.number import long_to_bytes, bytes_to_long from Cryptodome.Util.strxor import strxor @@ -142,15 +142,22 @@ class OcbMode(object): self._cache_P = b"" # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] # Compute Offset_0 params_without_key = dict(cipher_params) key = params_without_key.pop("key") - nonce = (struct.pack('B', self._mac_len << 4 & 0xFF) + - b'\x00' * (14 - len(nonce)) + - b'\x01' + self.nonce) + + taglen_mod128 = (self._mac_len * 8) % 128 + if len(self.nonce) < 15: + nonce = bchr(taglen_mod128 << 1) +\ + b'\x00' * (14 - len(nonce)) +\ + b'\x01' +\ + self.nonce + else: + nonce = bchr((taglen_mod128 << 1) | 0x01) +\ + self.nonce bottom_bits = bord(nonce[15]) & 0x3F # 6 bits, 0..63 top_bits = bord(nonce[15]) & 0xC0 # 2 bits @@ -217,12 +224,12 @@ class OcbMode(object): A piece of associated data. """ - if self.update not in self._next: + if "update" not in self._next: raise TypeError("update() can only be called" " immediately after initialization") - self._next = [self.encrypt, self.decrypt, self.digest, - self.verify, self.update] + self._next = ["encrypt", "decrypt", "digest", + "verify", "update"] if len(self._cache_A) > 0: filler = min(16 - len(self._cache_A), len(assoc_data)) @@ -316,14 +323,14 @@ class OcbMode(object): Its length may not match the length of the *plaintext*. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() can only be called after" " initialization or an update()") if plaintext is None: - self._next = [self.digest] + self._next = ["digest"] else: - self._next = [self.encrypt] + self._next = ["encrypt"] return self._transcrypt(plaintext, _raw_ocb_lib.OCB_encrypt, "encrypt") def decrypt(self, ciphertext=None): @@ -345,14 +352,14 @@ class OcbMode(object): Its length may not match the length of the *ciphertext*. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() can only be called after" " initialization or an update()") if ciphertext is None: - self._next = [self.verify] + self._next = ["verify"] else: - self._next = [self.decrypt] + self._next = ["decrypt"] return self._transcrypt(ciphertext, _raw_ocb_lib.OCB_decrypt, "decrypt") @@ -388,12 +395,12 @@ class OcbMode(object): :Return: the MAC, as a byte string. """ - if self.digest not in self._next: + if "digest" not in self._next: raise TypeError("digest() cannot be called now for this cipher") assert(len(self._cache_P) == 0) - self._next = [self.digest] + self._next = ["digest"] if self._mac_tag is None: self._compute_mac_tag() @@ -423,12 +430,12 @@ class OcbMode(object): or the key is incorrect. """ - if self.verify not in self._next: + if "verify" not in self._next: raise TypeError("verify() cannot be called now for this cipher") assert(len(self._cache_P) == 0) - self._next = [self.verify] + self._next = ["verify"] if self._mac_tag is None: self._compute_mac_tag() diff --git a/frozen_deps/Cryptodome/Cipher/_mode_ofb.py b/frozen_deps/Cryptodome/Cipher/_mode_ofb.py index 04aaccf..8c0ccf6 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_ofb.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_ofb.py @@ -116,7 +116,7 @@ class OfbMode(object): self.IV = self.iv """Alias for `iv`""" - self._next = [ self.encrypt, self.decrypt ] + self._next = ["encrypt", "decrypt"] def encrypt(self, plaintext, output=None): """Encrypt data with the key and the parameters set at initialization. @@ -151,18 +151,18 @@ class OfbMode(object): Otherwise, ``None``. """ - if self.encrypt not in self._next: + if "encrypt" not in self._next: raise TypeError("encrypt() cannot be called after decrypt()") - self._next = [ self.encrypt ] - + self._next = ["encrypt"] + if output is None: ciphertext = create_string_buffer(len(plaintext)) else: ciphertext = output - + if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(plaintext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) @@ -212,10 +212,10 @@ class OfbMode(object): Otherwise, ``None``. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() cannot be called after encrypt()") - self._next = [ self.decrypt ] - + self._next = ["decrypt"] + if output is None: plaintext = create_string_buffer(len(ciphertext)) else: @@ -223,7 +223,7 @@ class OfbMode(object): if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(ciphertext) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(plaintext)) diff --git a/frozen_deps/Cryptodome/Cipher/_mode_siv.py b/frozen_deps/Cryptodome/Cipher/_mode_siv.py index d10c4dc..4a76ad6 100644 --- a/frozen_deps/Cryptodome/Cipher/_mode_siv.py +++ b/frozen_deps/Cryptodome/Cipher/_mode_siv.py @@ -123,8 +123,8 @@ class SivMode(object): factory.new(key[:subkey_size], factory.MODE_ECB, **kwargs) # Allowed transitions after initialization - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] def _create_ctr_cipher(self, v): """Create a new CTR cipher from V in SIV mode""" @@ -164,12 +164,12 @@ class SivMode(object): The next associated data component. """ - if self.update not in self._next: + if "update" not in self._next: raise TypeError("update() can only be called" " immediately after initialization") - self._next = [self.update, self.encrypt, self.decrypt, - self.digest, self.verify] + self._next = ["update", "encrypt", "decrypt", + "digest", "verify"] return self._kdf.update(component) @@ -206,10 +206,10 @@ class SivMode(object): :Return: the MAC, as a byte string. """ - if self.digest not in self._next: + if "digest" not in self._next: raise TypeError("digest() cannot be called when decrypting" " or validating a message") - self._next = [self.digest] + self._next = ["digest"] if self._mac_tag is None: self._mac_tag = self._kdf.derive() return self._mac_tag @@ -240,10 +240,10 @@ class SivMode(object): or the key is incorrect. """ - if self.verify not in self._next: + if "verify" not in self._next: raise TypeError("verify() cannot be called" " when encrypting a message") - self._next = [self.verify] + self._next = ["verify"] if self._mac_tag is None: self._mac_tag = self._kdf.derive() @@ -290,19 +290,19 @@ class SivMode(object): The first item becomes ``None`` when the ``output`` parameter specified a location for the result. """ - - if self.encrypt not in self._next: + + if "encrypt" not in self._next: raise TypeError("encrypt() can only be called after" " initialization or an update()") - self._next = [ self.digest ] + self._next = ["digest"] # Compute V (MAC) if hasattr(self, 'nonce'): self._kdf.update(self.nonce) self._kdf.update(plaintext) self._mac_tag = self._kdf.derive() - + cipher = self._create_ctr_cipher(self._mac_tag) return cipher.encrypt(plaintext, output=output), self._mac_tag @@ -336,10 +336,10 @@ class SivMode(object): or the key is incorrect. """ - if self.decrypt not in self._next: + if "decrypt" not in self._next: raise TypeError("decrypt() can only be called" " after initialization or an update()") - self._next = [ self.verify ] + self._next = ["verify"] # Take the MAC and start the cipher for decryption self._cipher = self._create_ctr_cipher(mac_tag) @@ -350,7 +350,7 @@ class SivMode(object): self._kdf.update(self.nonce) self._kdf.update(plaintext if output is None else output) self.verify(mac_tag) - + return plaintext diff --git a/frozen_deps/Cryptodome/Cipher/_pkcs1_decode.abi3.so b/frozen_deps/Cryptodome/Cipher/_pkcs1_decode.abi3.so Binary files differnew file mode 100755 index 0000000..71cd311 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_pkcs1_decode.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_pkcs1_oaep_decode.py b/frozen_deps/Cryptodome/Cipher/_pkcs1_oaep_decode.py new file mode 100644 index 0000000..82bdaa7 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_pkcs1_oaep_decode.py @@ -0,0 +1,41 @@ +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, c_size_t, + c_uint8_ptr) + + +_raw_pkcs1_decode = load_pycryptodome_raw_lib("Cryptodome.Cipher._pkcs1_decode", + """ + int pkcs1_decode(const uint8_t *em, size_t len_em, + const uint8_t *sentinel, size_t len_sentinel, + size_t expected_pt_len, + uint8_t *output); + + int oaep_decode(const uint8_t *em, + size_t em_len, + const uint8_t *lHash, + size_t hLen, + const uint8_t *db, + size_t db_len); + """) + + +def pkcs1_decode(em, sentinel, expected_pt_len, output): + if len(em) != len(output): + raise ValueError("Incorrect output length") + + ret = _raw_pkcs1_decode.pkcs1_decode(c_uint8_ptr(em), + c_size_t(len(em)), + c_uint8_ptr(sentinel), + c_size_t(len(sentinel)), + c_size_t(expected_pt_len), + c_uint8_ptr(output)) + return ret + + +def oaep_decode(em, lHash, db): + ret = _raw_pkcs1_decode.oaep_decode(c_uint8_ptr(em), + c_size_t(len(em)), + c_uint8_ptr(lHash), + c_size_t(len(lHash)), + c_uint8_ptr(db), + c_size_t(len(db))) + return ret diff --git a/frozen_deps/Cryptodome/Cipher/_raw_aes.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_aes.abi3.so Binary files differnew file mode 100755 index 0000000..b37dd95 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_aes.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_aes.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_aes.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index e62f4d1..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_aes.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_aesni.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_aesni.abi3.so Binary files differnew file mode 100755 index 0000000..5f08fe7 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_aesni.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_aesni.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_aesni.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index b92e170..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_aesni.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_arc2.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_arc2.abi3.so Binary files differnew file mode 100755 index 0000000..2287d2e --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_arc2.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_arc2.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_arc2.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 07a720a..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_arc2.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_blowfish.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_blowfish.abi3.so Binary files differnew file mode 100755 index 0000000..ad77ccb --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_blowfish.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_blowfish.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_blowfish.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 05abfd1..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_blowfish.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cast.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_cast.abi3.so Binary files differnew file mode 100755 index 0000000..730e178 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_cast.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cast.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_cast.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 2523fcb..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_cast.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cbc.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_cbc.abi3.so Binary files differnew file mode 100755 index 0000000..847d824 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_cbc.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cbc.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_cbc.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 1b013f3..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_cbc.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cfb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_cfb.abi3.so Binary files differnew file mode 100755 index 0000000..2c9b852 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_cfb.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cfb.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_cfb.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 6a28991..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_cfb.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ctr.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ctr.abi3.so Binary files differnew file mode 100755 index 0000000..761cd36 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_ctr.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ctr.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_ctr.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 0529cf8..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_ctr.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_des.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_des.abi3.so Binary files differnew file mode 100755 index 0000000..7f1f824 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_des.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_des.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_des.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 1d73854..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_des.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_des3.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_des3.abi3.so Binary files differnew file mode 100755 index 0000000..b475c52 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_des3.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_des3.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_des3.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 8c4afa5..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_des3.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ecb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ecb.abi3.so Binary files differnew file mode 100755 index 0000000..91e8126 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_ecb.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ecb.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_ecb.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 0775c0b..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_ecb.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.abi3.so Binary files differnew file mode 100755 index 0000000..c3c45d5 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 979fe63..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ocb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ocb.abi3.so Binary files differnew file mode 100755 index 0000000..9685971 --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_ocb.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ocb.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_ocb.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index d545618..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_ocb.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ofb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ofb.abi3.so Binary files differnew file mode 100755 index 0000000..a4a629a --- /dev/null +++ b/frozen_deps/Cryptodome/Cipher/_raw_ofb.abi3.so diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ofb.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Cipher/_raw_ofb.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 7157784..0000000 --- a/frozen_deps/Cryptodome/Cipher/_raw_ofb.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/BLAKE2b.py b/frozen_deps/Cryptodome/Hash/BLAKE2b.py index d7e968f..85da887 100644 --- a/frozen_deps/Cryptodome/Hash/BLAKE2b.py +++ b/frozen_deps/Cryptodome/Hash/BLAKE2b.py @@ -233,13 +233,13 @@ def new(**kwargs): raise ValueError("'digest_bytes' not in range 1..64") else: if not (8 <= digest_bits <= 512) or (digest_bits % 8): - raise ValueError("'digest_bytes' not in range 8..512, " + raise ValueError("'digest_bits' not in range 8..512, " "with steps of 8") digest_bytes = digest_bits // 8 key = kwargs.pop("key", b"") if len(key) > 64: - raise ValueError("BLAKE2s key cannot exceed 64 bytes") + raise ValueError("BLAKE2b key cannot exceed 64 bytes") if kwargs: raise TypeError("Unknown parameters: " + str(kwargs)) diff --git a/frozen_deps/Cryptodome/Hash/BLAKE2b.pyi b/frozen_deps/Cryptodome/Hash/BLAKE2b.pyi index ac3bf57..d37c374 100644 --- a/frozen_deps/Cryptodome/Hash/BLAKE2b.pyi +++ b/frozen_deps/Cryptodome/Hash/BLAKE2b.pyi @@ -1,4 +1,5 @@ from typing import Any, Union +from types import ModuleType Buffer = Union[bytes, bytearray, memoryview] diff --git a/frozen_deps/Cryptodome/Hash/BLAKE2s.py b/frozen_deps/Cryptodome/Hash/BLAKE2s.py index a16b515..43be5c4 100644 --- a/frozen_deps/Cryptodome/Hash/BLAKE2s.py +++ b/frozen_deps/Cryptodome/Hash/BLAKE2s.py @@ -233,7 +233,7 @@ def new(**kwargs): raise ValueError("'digest_bytes' not in range 1..32") else: if not (8 <= digest_bits <= 256) or (digest_bits % 8): - raise ValueError("'digest_bytes' not in range 8..256, " + raise ValueError("'digest_bits' not in range 8..256, " "with steps of 8") digest_bytes = digest_bits // 8 diff --git a/frozen_deps/Cryptodome/Hash/CMAC.py b/frozen_deps/Cryptodome/Hash/CMAC.py index df69f00..8feb79f 100644 --- a/frozen_deps/Cryptodome/Hash/CMAC.py +++ b/frozen_deps/Cryptodome/Hash/CMAC.py @@ -20,7 +20,6 @@ # SOFTWARE. # =================================================================== -import sys from binascii import unhexlify from Cryptodome.Hash import BLAKE2s @@ -29,8 +28,6 @@ from Cryptodome.Util.number import long_to_bytes, bytes_to_long from Cryptodome.Util.py3compat import bord, tobytes, _copy_bytes from Cryptodome.Random import get_random_bytes -if sys.version_info[:2] == (2, 6): - memoryview = bytes # The size of the authentication tag produced by the MAC. digest_size = None @@ -245,11 +242,15 @@ class CMAC(object): raise ValueError("MAC check failed") def hexverify(self, hex_mac_tag): - """Return the **printable** MAC tag of the message authenticated so far. + """Verify that a given **printable** MAC (computed by another party) + is valid. - :return: The MAC tag, computed over the data processed so far. - Hexadecimal encoded. - :rtype: string + Args: + hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. """ self.verify(unhexlify(tobytes(hex_mac_tag))) diff --git a/frozen_deps/Cryptodome/Hash/CMAC.pyi b/frozen_deps/Cryptodome/Hash/CMAC.pyi index 33773aa..acdf055 100644 --- a/frozen_deps/Cryptodome/Hash/CMAC.pyi +++ b/frozen_deps/Cryptodome/Hash/CMAC.pyi @@ -1,5 +1,5 @@ from types import ModuleType -from typing import Union, Dict +from typing import Union, Dict, Any Buffer = Union[bytes, bytearray, memoryview] @@ -12,7 +12,7 @@ class CMAC(object): key: Buffer, msg: Buffer, ciphermod: ModuleType, - cipher_params: dict, + cipher_params: Dict[str, Any], mac_len: int, update_after_digest: bool) -> None: ... def update(self, data: Buffer) -> CMAC: ... def copy(self) -> CMAC: ... @@ -25,6 +25,6 @@ class CMAC(object): def new(key: Buffer, msg: Buffer = ..., ciphermod: ModuleType = ..., - cipher_params: Dict = ..., + cipher_params: Dict[str, Any] = ..., mac_len: int = ..., update_after_digest: bool = ...) -> CMAC: ... diff --git a/frozen_deps/Cryptodome/Hash/HMAC.py b/frozen_deps/Cryptodome/Hash/HMAC.py index ac94b20..615056a 100644 --- a/frozen_deps/Cryptodome/Hash/HMAC.py +++ b/frozen_deps/Cryptodome/Hash/HMAC.py @@ -31,17 +31,32 @@ # POSSIBILITY OF SUCH DAMAGE. # =================================================================== -from Cryptodome.Util.py3compat import bord, tobytes, _memoryview +from Cryptodome.Util.py3compat import bord, tobytes from binascii import unhexlify -from Cryptodome.Hash import MD5 from Cryptodome.Hash import BLAKE2s from Cryptodome.Util.strxor import strxor from Cryptodome.Random import get_random_bytes __all__ = ['new', 'HMAC'] +_hash2hmac_oid = { + '1.3.14.3.2.26': '1.2.840.113549.2.7', # SHA-1 + '2.16.840.1.101.3.4.2.4': '1.2.840.113549.2.8', # SHA-224 + '2.16.840.1.101.3.4.2.1': '1.2.840.113549.2.9', # SHA-256 + '2.16.840.1.101.3.4.2.2': '1.2.840.113549.2.10', # SHA-384 + '2.16.840.1.101.3.4.2.3': '1.2.840.113549.2.11', # SHA-512 + '2.16.840.1.101.3.4.2.5': '1.2.840.113549.2.12', # SHA-512_224 + '2.16.840.1.101.3.4.2.6': '1.2.840.113549.2.13', # SHA-512_256 + '2.16.840.1.101.3.4.2.7': '2.16.840.1.101.3.4.2.13', # SHA-3 224 + '2.16.840.1.101.3.4.2.8': '2.16.840.1.101.3.4.2.14', # SHA-3 256 + '2.16.840.1.101.3.4.2.9': '2.16.840.1.101.3.4.2.15', # SHA-3 384 + '2.16.840.1.101.3.4.2.10': '2.16.840.1.101.3.4.2.16', # SHA-3 512 +} + +_hmac2hash_oid = {v: k for k, v in _hash2hmac_oid.items()} + class HMAC(object): """An HMAC hash object. @@ -49,11 +64,15 @@ class HMAC(object): :ivar digest_size: the size in bytes of the resulting MAC tag :vartype digest_size: integer + + :ivar oid: the ASN.1 object ID of the HMAC algorithm. + Only present if the algorithm was officially assigned one. """ def __init__(self, key, msg=b"", digestmod=None): if digestmod is None: + from Cryptodome.Hash import MD5 digestmod = MD5 if msg is None: @@ -64,7 +83,13 @@ class HMAC(object): self._digestmod = digestmod - if isinstance(key, _memoryview): + # Hash OID --> HMAC OID + try: + self.oid = _hash2hmac_oid[digestmod.oid] + except (KeyError, AttributeError): + pass + + if isinstance(key, memoryview): key = key.tobytes() try: diff --git a/frozen_deps/Cryptodome/Hash/KMAC128.py b/frozen_deps/Cryptodome/Hash/KMAC128.py new file mode 100644 index 0000000..afd91c4 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/KMAC128.py @@ -0,0 +1,179 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from binascii import unhexlify + +from Cryptodome.Util.py3compat import bord, tobytes, is_bytes +from Cryptodome.Random import get_random_bytes + +from . import cSHAKE128, SHA3_256 +from .cSHAKE128 import _bytepad, _encode_str, _right_encode + + +class KMAC_Hash(object): + """A KMAC hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, data, key, mac_len, custom, + oid_variant, cshake, rate): + + # See https://tools.ietf.org/html/rfc8702 + self.oid = "2.16.840.1.101.3.4.2." + oid_variant + self.digest_size = mac_len + + self._mac = None + + partial_newX = _bytepad(_encode_str(tobytes(key)), rate) + self._cshake = cshake._new(partial_newX, custom, b"KMAC") + + if data: + self._cshake.update(data) + + def update(self, data): + """Authenticate the next chunk of message. + + Args: + data (bytes/bytearray/memoryview): The next chunk of the message to + authenticate. + """ + + if self._mac: + raise TypeError("You can only call 'digest' or 'hexdigest' on this object") + + self._cshake.update(data) + return self + + def digest(self): + """Return the **binary** (non-printable) MAC tag of the message. + + :return: The MAC tag. Binary form. + :rtype: byte string + """ + + if not self._mac: + self._cshake.update(_right_encode(self.digest_size * 8)) + self._mac = self._cshake.read(self.digest_size) + + return self._mac + + def hexdigest(self): + """Return the **printable** MAC tag of the message. + + :return: The MAC tag. Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) + + def verify(self, mac_tag): + """Verify that a given **binary** MAC (computed by another party) + is valid. + + Args: + mac_tag (bytes/bytearray/memoryview): the expected MAC of the message. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + secret = get_random_bytes(16) + + mac1 = SHA3_256.new(secret + mac_tag) + mac2 = SHA3_256.new(secret + self.digest()) + + if mac1.digest() != mac2.digest(): + raise ValueError("MAC check failed") + + def hexverify(self, hex_mac_tag): + """Verify that a given **printable** MAC (computed by another party) + is valid. + + Args: + hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string. + + Raises: + ValueError: if the MAC does not match. It means that the message + has been tampered with or that the MAC key is incorrect. + """ + + self.verify(unhexlify(tobytes(hex_mac_tag))) + + def new(self, **kwargs): + """Return a new instance of a KMAC hash object. + See :func:`new`. + """ + + if "mac_len" not in kwargs: + kwargs["mac_len"] = self.digest_size + + return new(**kwargs) + + +def new(**kwargs): + """Create a new KMAC128 object. + + Args: + key (bytes/bytearray/memoryview): + The key to use to compute the MAC. + It must be at least 128 bits long (16 bytes). + data (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to authenticate. + It is equivalent to an early call to :meth:`KMAC_Hash.update`. + mac_len (integer): + Optional. The size of the authentication tag, in bytes. + Default is 64. Minimum is 8. + custom (bytes/bytearray/memoryview): + Optional. A customization byte string (``S`` in SP 800-185). + + Returns: + A :class:`KMAC_Hash` hash object + """ + + key = kwargs.pop("key", None) + if not is_bytes(key): + raise TypeError("You must pass a key to KMAC128") + if len(key) < 16: + raise ValueError("The key must be at least 128 bits long (16 bytes)") + + data = kwargs.pop("data", None) + + mac_len = kwargs.pop("mac_len", 64) + if mac_len < 8: + raise ValueError("'mac_len' must be 8 bytes or more") + + custom = kwargs.pop("custom", b"") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return KMAC_Hash(data, key, mac_len, custom, "19", cSHAKE128, 168) diff --git a/frozen_deps/Cryptodome/Hash/KMAC128.pyi b/frozen_deps/Cryptodome/Hash/KMAC128.pyi new file mode 100644 index 0000000..8947dab --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/KMAC128.pyi @@ -0,0 +1,33 @@ +from typing import Union +from types import ModuleType + +Buffer = Union[bytes, bytearray, memoryview] + +class KMAC_Hash(object): + + def __init__(self, + data: Buffer, + key: Buffer, + mac_len: int, + custom: Buffer, + oid_variant: str, + cshake: ModuleType, + rate: int) -> None: ... + + def update(self, data: Buffer) -> KMAC_Hash: ... + + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def verify(self, mac_tag: Buffer) -> None: ... + def hexverify(self, hex_mac_tag: str) -> None: ... + def new(self, + data: Buffer = ..., + mac_len: int = ..., + key: Buffer = ..., + custom: Buffer = ...) -> KMAC_Hash: ... + + +def new(key: Buffer, + data: Buffer = ..., + mac_len: int = ..., + custom: Buffer = ...) -> KMAC_Hash: ... diff --git a/frozen_deps/Cryptodome/Hash/KMAC256.py b/frozen_deps/Cryptodome/Hash/KMAC256.py new file mode 100644 index 0000000..82da062 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/KMAC256.py @@ -0,0 +1,74 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import is_bytes + +from .KMAC128 import KMAC_Hash +from . import cSHAKE256 + + +def new(**kwargs): + """Create a new KMAC256 object. + + Args: + key (bytes/bytearray/memoryview): + The key to use to compute the MAC. + It must be at least 256 bits long (32 bytes). + data (bytes/bytearray/memoryview): + Optional. The very first chunk of the message to authenticate. + It is equivalent to an early call to :meth:`KMAC_Hash.update`. + mac_len (integer): + Optional. The size of the authentication tag, in bytes. + Default is 64. Minimum is 8. + custom (bytes/bytearray/memoryview): + Optional. A customization byte string (``S`` in SP 800-185). + + Returns: + A :class:`KMAC_Hash` hash object + """ + + key = kwargs.pop("key", None) + if not is_bytes(key): + raise TypeError("You must pass a key to KMAC256") + if len(key) < 32: + raise ValueError("The key must be at least 256 bits long (32 bytes)") + + data = kwargs.pop("data", None) + + mac_len = kwargs.pop("mac_len", 64) + if mac_len < 8: + raise ValueError("'mac_len' must be 8 bytes or more") + + custom = kwargs.pop("custom", b"") + + if kwargs: + raise TypeError("Unknown parameters: " + str(kwargs)) + + return KMAC_Hash(data, key, mac_len, custom, "20", cSHAKE256, 136) diff --git a/frozen_deps/Cryptodome/Hash/KMAC256.pyi b/frozen_deps/Cryptodome/Hash/KMAC256.pyi new file mode 100644 index 0000000..86cc500 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/KMAC256.pyi @@ -0,0 +1,10 @@ +from typing import Union + +from .KMAC128 import KMAC_Hash + +Buffer = Union[bytes, bytearray, memoryview] + +def new(key: Buffer, + data: Buffer = ..., + mac_len: int = ..., + custom: Buffer = ...) -> KMAC_Hash: ... diff --git a/frozen_deps/Cryptodome/Hash/KangarooTwelve.py b/frozen_deps/Cryptodome/Hash/KangarooTwelve.py new file mode 100644 index 0000000..60ced57 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/KangarooTwelve.py @@ -0,0 +1,222 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.Util.py3compat import bchr + +from . import TurboSHAKE128 + +def _length_encode(x): + if x == 0: + return b'\x00' + + S = long_to_bytes(x) + return S + bchr(len(S)) + + +# Possible states for a KangarooTwelve instance, which depend on the amount of data processed so far. +SHORT_MSG = 1 # Still within the first 8192 bytes, but it is not certain we will exceed them. +LONG_MSG_S0 = 2 # Still within the first 8192 bytes, and it is certain we will exceed them. +LONG_MSG_SX = 3 # Beyond the first 8192 bytes. +SQUEEZING = 4 # No more data to process. + + +class K12_XOF(object): + """A KangarooTwelve hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, data, custom): + + if custom == None: + custom = b'' + + self._custom = custom + _length_encode(len(custom)) + self._state = SHORT_MSG + self._padding = None # Final padding is only decided in read() + + # Internal hash that consumes FinalNode + # The real domain separation byte will be known before squeezing + self._hash1 = TurboSHAKE128.new(domain=1) + self._length1 = 0 + + # Internal hash that produces CV_i (reset each time) + self._hash2 = None + self._length2 = 0 + + # Incremented by one for each 8192-byte block + self._ctr = 0 + + if data: + self.update(data) + + def update(self, data): + """Hash the next piece of data. + + .. note:: + For better performance, submit chunks with a length multiple of 8192 bytes. + + Args: + data (byte string/byte array/memoryview): The next chunk of the + message to hash. + """ + + if self._state == SQUEEZING: + raise TypeError("You cannot call 'update' after the first 'read'") + + if self._state == SHORT_MSG: + next_length = self._length1 + len(data) + + if next_length + len(self._custom) <= 8192: + self._length1 = next_length + self._hash1.update(data) + return self + + # Switch to tree hashing + self._state = LONG_MSG_S0 + + if self._state == LONG_MSG_S0: + data_mem = memoryview(data) + assert(self._length1 < 8192) + dtc = min(len(data), 8192 - self._length1) + self._hash1.update(data_mem[:dtc]) + self._length1 += dtc + + if self._length1 < 8192: + return self + + # Finish hashing S_0 and start S_1 + assert(self._length1 == 8192) + + divider = b'\x03' + b'\x00' * 7 + self._hash1.update(divider) + self._length1 += 8 + + self._hash2 = TurboSHAKE128.new(domain=0x0B) + self._length2 = 0 + self._ctr = 1 + + self._state = LONG_MSG_SX + return self.update(data_mem[dtc:]) + + # LONG_MSG_SX + assert(self._state == LONG_MSG_SX) + index = 0 + len_data = len(data) + + # All iteractions could actually run in parallel + data_mem = memoryview(data) + while index < len_data: + + new_index = min(index + 8192 - self._length2, len_data) + self._hash2.update(data_mem[index:new_index]) + self._length2 += new_index - index + index = new_index + + if self._length2 == 8192: + cv_i = self._hash2.read(32) + self._hash1.update(cv_i) + self._length1 += 32 + self._hash2._reset() + self._length2 = 0 + self._ctr += 1 + + return self + + def read(self, length): + """ + Produce more bytes of the digest. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + custom_was_consumed = False + + if self._state == SHORT_MSG: + self._hash1.update(self._custom) + self._padding = 0x07 + self._state = SQUEEZING + + if self._state == LONG_MSG_S0: + self.update(self._custom) + custom_was_consumed = True + assert(self._state == LONG_MSG_SX) + + if self._state == LONG_MSG_SX: + if not custom_was_consumed: + self.update(self._custom) + + # Is there still some leftover data in hash2? + if self._length2 > 0: + cv_i = self._hash2.read(32) + self._hash1.update(cv_i) + self._length1 += 32 + self._hash2._reset() + self._length2 = 0 + self._ctr += 1 + + trailer = _length_encode(self._ctr - 1) + b'\xFF\xFF' + self._hash1.update(trailer) + + self._padding = 0x06 + self._state = SQUEEZING + + self._hash1._domain = self._padding + return self._hash1.read(length) + + def new(self, data=None, custom=b''): + return type(self)(data, custom) + + +def new(data=None, custom=None): + """Return a fresh instance of a KangarooTwelve object. + + Args: + data (bytes/bytearray/memoryview): + Optional. + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + custom (bytes): + Optional. + A customization byte string. + + :Return: A :class:`K12_XOF` object + """ + + return K12_XOF(data, custom) diff --git a/frozen_deps/Cryptodome/Hash/KangarooTwelve.pyi b/frozen_deps/Cryptodome/Hash/KangarooTwelve.pyi new file mode 100644 index 0000000..8b3fd74 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/KangarooTwelve.pyi @@ -0,0 +1,16 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class K12_XOF(object): + def __init__(self, + data: Optional[Buffer] = ..., + custom: Optional[bytes] = ...) -> None: ... + def update(self, data: Buffer) -> K12_XOF: ... + def read(self, length: int) -> bytes: ... + def new(self, + data: Optional[Buffer] = ..., + custom: Optional[bytes] = ...) -> None: ... + +def new(data: Optional[Buffer] = ..., + custom: Optional[Buffer] = ...) -> K12_XOF: ... diff --git a/frozen_deps/Cryptodome/Hash/SHA3_224.py b/frozen_deps/Cryptodome/Hash/SHA3_224.py index 3196bd6..34888c5 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_224.py +++ b/frozen_deps/Cryptodome/Hash/SHA3_224.py @@ -24,7 +24,7 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, SmartPointer, create_string_buffer, get_raw_buffer, c_size_t, - c_uint8_ptr) + c_uint8_ptr, c_ubyte) from Cryptodome.Hash.keccak import _raw_keccak_lib @@ -46,14 +46,18 @@ class SHA3_224_Hash(object): # ASN.1 Object ID oid = "2.16.840.1.101.3.4.2.7" + # Input block size for HMAC + block_size = 144 + def __init__(self, data, update_after_digest): self._update_after_digest = update_after_digest self._digest_done = False + self._padding = 0x06 state = VoidPointer() result = _raw_keccak_lib.keccak_init(state.address_of(), c_size_t(self.digest_size * 2), - 0x06) + c_ubyte(24)) if result: raise ValueError("Error %d while instantiating SHA-3/224" % result) @@ -74,7 +78,8 @@ class SHA3_224_Hash(object): result = _raw_keccak_lib.keccak_absorb(self._state.get(), c_uint8_ptr(data), - c_size_t(len(data))) + c_size_t(len(data)) + ) if result: raise ValueError("Error %d while updating SHA-3/224" % result) @@ -93,7 +98,8 @@ class SHA3_224_Hash(object): bfr = create_string_buffer(self.digest_size) result = _raw_keccak_lib.keccak_digest(self._state.get(), bfr, - c_size_t(self.digest_size)) + c_size_t(self.digest_size), + c_ubyte(self._padding)) if result: raise ValueError("Error %d while instantiating SHA-3/224" % result) @@ -111,10 +117,28 @@ class SHA3_224_Hash(object): return "".join(["%02x" % bord(x) for x in self.digest()]) - def new(self): + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-224" % result) + return clone + + def new(self, data=None): """Create a fresh SHA3-224 hash object.""" - return type(self)(None, self._update_after_digest) + return type(self)(data, self._update_after_digest) def new(*args, **kwargs): @@ -145,3 +169,6 @@ def new(*args, **kwargs): # The size of the resulting hash in bytes. digest_size = SHA3_224_Hash.digest_size + +# Input block size for HMAC +block_size = 144 diff --git a/frozen_deps/Cryptodome/Hash/SHA3_224.pyi b/frozen_deps/Cryptodome/Hash/SHA3_224.pyi index 3437042..2180821 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_224.pyi +++ b/frozen_deps/Cryptodome/Hash/SHA3_224.pyi @@ -4,13 +4,16 @@ Buffer = Union[bytes, bytearray, memoryview] class SHA3_224_Hash(object): digest_size: int + block_size: int oid: str def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... def update(self, data: Buffer) -> SHA3_224_Hash: ... def digest(self) -> bytes: ... def hexdigest(self) -> str: ... - def new(self) -> SHA3_224_Hash: ... + def copy(self) -> SHA3_224_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_224_Hash: ... def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_224_Hash: ... digest_size: int +block_size: int diff --git a/frozen_deps/Cryptodome/Hash/SHA3_256.py b/frozen_deps/Cryptodome/Hash/SHA3_256.py index 89e3b42..024962f 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_256.py +++ b/frozen_deps/Cryptodome/Hash/SHA3_256.py @@ -24,7 +24,7 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, SmartPointer, create_string_buffer, get_raw_buffer, c_size_t, - c_uint8_ptr) + c_uint8_ptr, c_ubyte) from Cryptodome.Hash.keccak import _raw_keccak_lib @@ -46,14 +46,18 @@ class SHA3_256_Hash(object): # ASN.1 Object ID oid = "2.16.840.1.101.3.4.2.8" + # Input block size for HMAC + block_size = 136 + def __init__(self, data, update_after_digest): self._update_after_digest = update_after_digest self._digest_done = False + self._padding = 0x06 state = VoidPointer() result = _raw_keccak_lib.keccak_init(state.address_of(), c_size_t(self.digest_size * 2), - 0x06) + c_ubyte(24)) if result: raise ValueError("Error %d while instantiating SHA-3/256" % result) @@ -74,7 +78,8 @@ class SHA3_256_Hash(object): result = _raw_keccak_lib.keccak_absorb(self._state.get(), c_uint8_ptr(data), - c_size_t(len(data))) + c_size_t(len(data)) + ) if result: raise ValueError("Error %d while updating SHA-3/256" % result) @@ -93,7 +98,8 @@ class SHA3_256_Hash(object): bfr = create_string_buffer(self.digest_size) result = _raw_keccak_lib.keccak_digest(self._state.get(), bfr, - c_size_t(self.digest_size)) + c_size_t(self.digest_size), + c_ubyte(self._padding)) if result: raise ValueError("Error %d while instantiating SHA-3/256" % result) @@ -111,10 +117,28 @@ class SHA3_256_Hash(object): return "".join(["%02x" % bord(x) for x in self.digest()]) - def new(self): + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-256" % result) + return clone + + def new(self, data=None): """Create a fresh SHA3-256 hash object.""" - return type(self)(None, self._update_after_digest) + return type(self)(data, self._update_after_digest) def new(*args, **kwargs): @@ -145,3 +169,6 @@ def new(*args, **kwargs): # The size of the resulting hash in bytes. digest_size = SHA3_256_Hash.digest_size + +# Input block size for HMAC +block_size = 136 diff --git a/frozen_deps/Cryptodome/Hash/SHA3_256.pyi b/frozen_deps/Cryptodome/Hash/SHA3_256.pyi index c1a07fa..88436bd 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_256.pyi +++ b/frozen_deps/Cryptodome/Hash/SHA3_256.pyi @@ -4,13 +4,16 @@ Buffer = Union[bytes, bytearray, memoryview] class SHA3_256_Hash(object): digest_size: int + block_size: int oid: str def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... def update(self, data: Buffer) -> SHA3_256_Hash: ... def digest(self) -> bytes: ... def hexdigest(self) -> str: ... - def new(self) -> SHA3_256_Hash: ... + def copy(self) -> SHA3_256_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_256_Hash: ... def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_256_Hash: ... digest_size: int +block_size: int diff --git a/frozen_deps/Cryptodome/Hash/SHA3_384.py b/frozen_deps/Cryptodome/Hash/SHA3_384.py index e6baf3f..26eeb79 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_384.py +++ b/frozen_deps/Cryptodome/Hash/SHA3_384.py @@ -24,7 +24,7 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, SmartPointer, create_string_buffer, get_raw_buffer, c_size_t, - c_uint8_ptr) + c_uint8_ptr, c_ubyte) from Cryptodome.Hash.keccak import _raw_keccak_lib @@ -46,14 +46,18 @@ class SHA3_384_Hash(object): # ASN.1 Object ID oid = "2.16.840.1.101.3.4.2.9" + # Input block size for HMAC + block_size = 104 + def __init__(self, data, update_after_digest): self._update_after_digest = update_after_digest self._digest_done = False + self._padding = 0x06 state = VoidPointer() result = _raw_keccak_lib.keccak_init(state.address_of(), c_size_t(self.digest_size * 2), - 0x06) + c_ubyte(24)) if result: raise ValueError("Error %d while instantiating SHA-3/384" % result) @@ -93,7 +97,8 @@ class SHA3_384_Hash(object): bfr = create_string_buffer(self.digest_size) result = _raw_keccak_lib.keccak_digest(self._state.get(), bfr, - c_size_t(self.digest_size)) + c_size_t(self.digest_size), + c_ubyte(self._padding)) if result: raise ValueError("Error %d while instantiating SHA-3/384" % result) @@ -111,10 +116,34 @@ class SHA3_384_Hash(object): return "".join(["%02x" % bord(x) for x in self.digest()]) - def new(self): + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-384" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA3-256 hash object.""" + + return type(self)(data, self._update_after_digest) + + + def new(self, data=None): """Create a fresh SHA3-384 hash object.""" - return type(self)(None, self._update_after_digest) + return type(self)(data, self._update_after_digest) def new(*args, **kwargs): @@ -145,3 +174,6 @@ def new(*args, **kwargs): # The size of the resulting hash in bytes. digest_size = SHA3_384_Hash.digest_size + +# Input block size for HMAC +block_size = 104 diff --git a/frozen_deps/Cryptodome/Hash/SHA3_384.pyi b/frozen_deps/Cryptodome/Hash/SHA3_384.pyi index d029ab6..98d00c6 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_384.pyi +++ b/frozen_deps/Cryptodome/Hash/SHA3_384.pyi @@ -4,13 +4,16 @@ Buffer = Union[bytes, bytearray, memoryview] class SHA3_384_Hash(object): digest_size: int + block_size: int oid: str def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... def update(self, data: Buffer) -> SHA3_384_Hash: ... def digest(self) -> bytes: ... def hexdigest(self) -> str: ... - def new(self) -> SHA3_384_Hash: ... + def copy(self) -> SHA3_384_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_384_Hash: ... def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_384_Hash: ... digest_size: int +block_size: int diff --git a/frozen_deps/Cryptodome/Hash/SHA3_512.py b/frozen_deps/Cryptodome/Hash/SHA3_512.py index 676ce2f..99b1c37 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_512.py +++ b/frozen_deps/Cryptodome/Hash/SHA3_512.py @@ -24,7 +24,7 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, SmartPointer, create_string_buffer, get_raw_buffer, c_size_t, - c_uint8_ptr) + c_uint8_ptr, c_ubyte) from Cryptodome.Hash.keccak import _raw_keccak_lib @@ -46,14 +46,18 @@ class SHA3_512_Hash(object): # ASN.1 Object ID oid = "2.16.840.1.101.3.4.2.10" + # Input block size for HMAC + block_size = 72 + def __init__(self, data, update_after_digest): self._update_after_digest = update_after_digest self._digest_done = False + self._padding = 0x06 state = VoidPointer() result = _raw_keccak_lib.keccak_init(state.address_of(), c_size_t(self.digest_size * 2), - 0x06) + c_ubyte(24)) if result: raise ValueError("Error %d while instantiating SHA-3/512" % result) @@ -94,7 +98,8 @@ class SHA3_512_Hash(object): bfr = create_string_buffer(self.digest_size) result = _raw_keccak_lib.keccak_digest(self._state.get(), bfr, - c_size_t(self.digest_size)) + c_size_t(self.digest_size), + c_ubyte(self._padding)) if result: raise ValueError("Error %d while instantiating SHA-3/512" % result) @@ -112,10 +117,28 @@ class SHA3_512_Hash(object): return "".join(["%02x" % bord(x) for x in self.digest()]) - def new(self): - """Create a fresh SHA3-512 hash object.""" + def copy(self): + """Return a copy ("clone") of the hash object. + + The copy will have the same internal state as the original hash + object. + This can be used to efficiently compute the digests of strings that + share a common initial substring. + + :return: A hash object of the same type + """ + + clone = self.new() + result = _raw_keccak_lib.keccak_copy(self._state.get(), + clone._state.get()) + if result: + raise ValueError("Error %d while copying SHA3-512" % result) + return clone + + def new(self, data=None): + """Create a fresh SHA3-521 hash object.""" - return type(self)(None, self._update_after_digest) + return type(self)(data, self._update_after_digest) def new(*args, **kwargs): @@ -146,3 +169,6 @@ def new(*args, **kwargs): # The size of the resulting hash in bytes. digest_size = SHA3_512_Hash.digest_size + +# Input block size for HMAC +block_size = 72 diff --git a/frozen_deps/Cryptodome/Hash/SHA3_512.pyi b/frozen_deps/Cryptodome/Hash/SHA3_512.pyi index 2c5403b..cdeec16 100644 --- a/frozen_deps/Cryptodome/Hash/SHA3_512.pyi +++ b/frozen_deps/Cryptodome/Hash/SHA3_512.pyi @@ -4,13 +4,16 @@ Buffer = Union[bytes, bytearray, memoryview] class SHA3_512_Hash(object): digest_size: int + block_size: int oid: str def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ... def update(self, data: Buffer) -> SHA3_512_Hash: ... def digest(self) -> bytes: ... def hexdigest(self) -> str: ... - def new(self) -> SHA3_512_Hash: ... + def copy(self) -> SHA3_512_Hash: ... + def new(self, data: Optional[Buffer]) -> SHA3_512_Hash: ... def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_512_Hash: ... digest_size: int +block_size: int diff --git a/frozen_deps/Cryptodome/Hash/SHAKE128.py b/frozen_deps/Cryptodome/Hash/SHAKE128.py index be2b22e..5bde2b6 100644 --- a/frozen_deps/Cryptodome/Hash/SHAKE128.py +++ b/frozen_deps/Cryptodome/Hash/SHAKE128.py @@ -34,7 +34,7 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, SmartPointer, create_string_buffer, get_raw_buffer, c_size_t, - c_uint8_ptr) + c_uint8_ptr, c_ubyte) from Cryptodome.Hash.keccak import _raw_keccak_lib @@ -54,13 +54,14 @@ class SHAKE128_XOF(object): state = VoidPointer() result = _raw_keccak_lib.keccak_init(state.address_of(), c_size_t(32), - 0x1F) + c_ubyte(24)) if result: raise ValueError("Error %d while instantiating SHAKE128" % result) self._state = SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy) self._is_squeezing = False + self._padding = 0x1F if data: self.update(data) @@ -101,7 +102,8 @@ class SHAKE128_XOF(object): bfr = create_string_buffer(length) result = _raw_keccak_lib.keccak_squeeze(self._state.get(), bfr, - c_size_t(length)) + c_size_t(length), + c_ubyte(self._padding)) if result: raise ValueError("Error %d while extracting from SHAKE128" % result) diff --git a/frozen_deps/Cryptodome/Hash/SHAKE256.py b/frozen_deps/Cryptodome/Hash/SHAKE256.py index 46040e1..8c37f6a 100644 --- a/frozen_deps/Cryptodome/Hash/SHAKE256.py +++ b/frozen_deps/Cryptodome/Hash/SHAKE256.py @@ -34,7 +34,7 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, SmartPointer, create_string_buffer, get_raw_buffer, c_size_t, - c_uint8_ptr) + c_uint8_ptr, c_ubyte) from Cryptodome.Hash.keccak import _raw_keccak_lib @@ -54,13 +54,15 @@ class SHAKE256_XOF(object): state = VoidPointer() result = _raw_keccak_lib.keccak_init(state.address_of(), c_size_t(64), - 0x1F) + c_ubyte(24)) if result: raise ValueError("Error %d while instantiating SHAKE256" % result) self._state = SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy) self._is_squeezing = False + self._padding = 0x1F + if data: self.update(data) @@ -101,7 +103,8 @@ class SHAKE256_XOF(object): bfr = create_string_buffer(length) result = _raw_keccak_lib.keccak_squeeze(self._state.get(), bfr, - c_size_t(length)) + c_size_t(length), + c_ubyte(self._padding)) if result: raise ValueError("Error %d while extracting from SHAKE256" % result) diff --git a/frozen_deps/Cryptodome/Hash/TupleHash128.py b/frozen_deps/Cryptodome/Hash/TupleHash128.py new file mode 100644 index 0000000..49aeccc --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TupleHash128.py @@ -0,0 +1,136 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bord, is_bytes, tobytes + +from . import cSHAKE128 +from .cSHAKE128 import _encode_str, _right_encode + + +class TupleHash(object): + """A Tuple hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, custom, cshake, digest_size): + + self.digest_size = digest_size + + self._cshake = cshake._new(b'', custom, b'TupleHash') + self._digest = None + + def update(self, *data): + """Authenticate the next tuple of byte strings. + TupleHash guarantees the logical separation between each byte string. + + Args: + data (bytes/bytearray/memoryview): One or more items to hash. + """ + + if self._digest is not None: + raise TypeError("You cannot call 'update' after 'digest' or 'hexdigest'") + + for item in data: + if not is_bytes(item): + raise TypeError("You can only call 'update' on bytes" ) + self._cshake.update(_encode_str(item)) + + return self + + def digest(self): + """Return the **binary** (non-printable) digest of the tuple of byte strings. + + :return: The hash digest. Binary form. + :rtype: byte string + """ + + if self._digest is None: + self._cshake.update(_right_encode(self.digest_size * 8)) + self._digest = self._cshake.read(self.digest_size) + + return self._digest + + def hexdigest(self): + """Return the **printable** digest of the tuple of byte strings. + + :return: The hash digest. Hexadecimal encoded. + :rtype: string + """ + + return "".join(["%02x" % bord(x) for x in tuple(self.digest())]) + + def new(self, **kwargs): + """Return a new instance of a TupleHash object. + See :func:`new`. + """ + + if "digest_bytes" not in kwargs and "digest_bits" not in kwargs: + kwargs["digest_bytes"] = self.digest_size + + return new(**kwargs) + + +def new(**kwargs): + """Create a new TupleHash128 object. + + Args: + digest_bytes (integer): + Optional. The size of the digest, in bytes. + Default is 64. Minimum is 8. + digest_bits (integer): + Optional and alternative to ``digest_bytes``. + The size of the digest, in bits (and in steps of 8). + Default is 512. Minimum is 64. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`TupleHash` object + """ + + digest_bytes = kwargs.pop("digest_bytes", None) + digest_bits = kwargs.pop("digest_bits", None) + if None not in (digest_bytes, digest_bits): + raise TypeError("Only one digest parameter must be provided") + if (None, None) == (digest_bytes, digest_bits): + digest_bytes = 64 + if digest_bytes is not None: + if digest_bytes < 8: + raise ValueError("'digest_bytes' must be at least 8") + else: + if digest_bits < 64 or digest_bits % 8: + raise ValueError("'digest_bytes' must be at least 64 " + "in steps of 8") + digest_bytes = digest_bits // 8 + + custom = kwargs.pop("custom", b'') + + return TupleHash(custom, cSHAKE128, digest_bytes) diff --git a/frozen_deps/Cryptodome/Hash/TupleHash128.pyi b/frozen_deps/Cryptodome/Hash/TupleHash128.pyi new file mode 100644 index 0000000..2e0ea83 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TupleHash128.pyi @@ -0,0 +1,22 @@ +from typing import Any, Union, List, Tuple +from types import ModuleType + +Buffer = Union[bytes, bytearray, memoryview] + +class TupleHash(object): + digest_size: int + def __init__(self, + custom: bytes, + cshake: ModuleType, + digest_size: int) -> None: ... + def update(self, *data: Buffer) -> TupleHash: ... + def digest(self) -> bytes: ... + def hexdigest(self) -> str: ... + def new(self, + digest_bytes: int = ..., + digest_bits: int = ..., + custom: int = ...) -> TupleHash: ... + +def new(digest_bytes: int = ..., + digest_bits: int = ..., + custom: int = ...) -> TupleHash: ... diff --git a/frozen_deps/Cryptodome/Hash/TupleHash256.py b/frozen_deps/Cryptodome/Hash/TupleHash256.py new file mode 100644 index 0000000..40a824a --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TupleHash256.py @@ -0,0 +1,70 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from . import cSHAKE256 +from .TupleHash128 import TupleHash + + +def new(**kwargs): + """Create a new TupleHash256 object. + + Args: + digest_bytes (integer): + Optional. The size of the digest, in bytes. + Default is 64. Minimum is 8. + digest_bits (integer): + Optional and alternative to ``digest_bytes``. + The size of the digest, in bits (and in steps of 8). + Default is 512. Minimum is 64. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`TupleHash` object + """ + + digest_bytes = kwargs.pop("digest_bytes", None) + digest_bits = kwargs.pop("digest_bits", None) + if None not in (digest_bytes, digest_bits): + raise TypeError("Only one digest parameter must be provided") + if (None, None) == (digest_bytes, digest_bits): + digest_bytes = 64 + if digest_bytes is not None: + if digest_bytes < 8: + raise ValueError("'digest_bytes' must be at least 8") + else: + if digest_bits < 64 or digest_bits % 8: + raise ValueError("'digest_bytes' must be at least 64 " + "in steps of 8") + digest_bytes = digest_bits // 8 + + custom = kwargs.pop("custom", b'') + + return TupleHash(custom, cSHAKE256, digest_bytes) diff --git a/frozen_deps/Cryptodome/Hash/TupleHash256.pyi b/frozen_deps/Cryptodome/Hash/TupleHash256.pyi new file mode 100644 index 0000000..82d943f --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TupleHash256.pyi @@ -0,0 +1,5 @@ +from .TupleHash128 import TupleHash + +def new(digest_bytes: int = ..., + digest_bits: int = ..., + custom: int = ...) -> TupleHash: ... diff --git a/frozen_deps/Cryptodome/Hash/TurboSHAKE128.py b/frozen_deps/Cryptodome/Hash/TurboSHAKE128.py new file mode 100644 index 0000000..92ac59e --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TurboSHAKE128.py @@ -0,0 +1,112 @@ +from Cryptodome.Util._raw_api import (VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Util.number import long_to_bytes +from Cryptodome.Util.py3compat import bchr + +from .keccak import _raw_keccak_lib + + +class TurboSHAKE(object): + """A TurboSHAKE hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, capacity, domain_separation, data): + + state = VoidPointer() + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(capacity), + c_ubyte(12)) # Reduced number of rounds + if result: + raise ValueError("Error %d while instantiating TurboSHAKE" + % result) + self._state = SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy) + + self._is_squeezing = False + self._capacity = capacity + self._domain = domain_separation + + if data: + self.update(data) + + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._is_squeezing: + raise TypeError("You cannot call 'update' after the first 'read'") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating TurboSHAKE state" + % result) + return self + + def read(self, length): + """ + Compute the next piece of XOF output. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + self._is_squeezing = True + bfr = create_string_buffer(length) + result = _raw_keccak_lib.keccak_squeeze(self._state.get(), + bfr, + c_size_t(length), + c_ubyte(self._domain)) + if result: + raise ValueError("Error %d while extracting from TurboSHAKE" + % result) + + return get_raw_buffer(bfr) + + def new(self, data=None): + return type(self)(self._capacity, self._domain, data) + + def _reset(self): + result = _raw_keccak_lib.keccak_reset(self._state.get()) + if result: + raise ValueError("Error %d while resetting TurboSHAKE state" + % result) + self._is_squeezing = False + + +def new(**kwargs): + """Create a new TurboSHAKE128 object. + + Args: + domain (integer): + Optional - A domain separation byte, between 0x01 and 0x7F. + The default value is 0x1F. + data (bytes/bytearray/memoryview): + Optional - The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + + :Return: A :class:`TurboSHAKE` object + """ + + domain_separation = kwargs.get('domain', 0x1F) + if not (0x01 <= domain_separation <= 0x7F): + raise ValueError("Incorrect domain separation value (%d)" % + domain_separation) + data = kwargs.get('data') + return TurboSHAKE(32, domain_separation, data=data) diff --git a/frozen_deps/Cryptodome/Hash/TurboSHAKE128.pyi b/frozen_deps/Cryptodome/Hash/TurboSHAKE128.pyi new file mode 100644 index 0000000..d74c9c0 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TurboSHAKE128.pyi @@ -0,0 +1,17 @@ +from typing import Union, Optional +from typing_extensions import TypedDict, Unpack, NotRequired + +Buffer = Union[bytes, bytearray, memoryview] + +class TurboSHAKE(object): + + def __init__(self, capacity: int, domain_separation: int, data: Union[Buffer, None]) -> None: ... + def update(self, data: Buffer) -> TurboSHAKE : ... + def read(self, length: int) -> bytes: ... + def new(self, data: Optional[Buffer]=None) -> TurboSHAKE: ... + +class Args(TypedDict): + domain: NotRequired[int] + data: NotRequired[Buffer] + +def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ... diff --git a/frozen_deps/Cryptodome/Hash/TurboSHAKE256.py b/frozen_deps/Cryptodome/Hash/TurboSHAKE256.py new file mode 100644 index 0000000..ce27a48 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TurboSHAKE256.py @@ -0,0 +1,22 @@ +from .TurboSHAKE128 import TurboSHAKE + +def new(**kwargs): + """Create a new TurboSHAKE256 object. + + Args: + domain (integer): + Optional - A domain separation byte, between 0x01 and 0x7F. + The default value is 0x1F. + data (bytes/bytearray/memoryview): + Optional - The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + + :Return: A :class:`TurboSHAKE` object + """ + + domain_separation = kwargs.get('domain', 0x1F) + if not (0x01 <= domain_separation <= 0x7F): + raise ValueError("Incorrect domain separation value (%d)" % + domain_separation) + data = kwargs.get('data') + return TurboSHAKE(64, domain_separation, data=data) diff --git a/frozen_deps/Cryptodome/Hash/TurboSHAKE256.pyi b/frozen_deps/Cryptodome/Hash/TurboSHAKE256.pyi new file mode 100644 index 0000000..561e946 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/TurboSHAKE256.pyi @@ -0,0 +1,12 @@ +from typing import Union +from typing_extensions import TypedDict, Unpack, NotRequired + +from .TurboSHAKE128 import TurboSHAKE + +Buffer = Union[bytes, bytearray, memoryview] + +class Args(TypedDict): + domain: NotRequired[int] + data: NotRequired[Buffer] + +def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ... diff --git a/frozen_deps/Cryptodome/Hash/_BLAKE2b.abi3.so b/frozen_deps/Cryptodome/Hash/_BLAKE2b.abi3.so Binary files differnew file mode 100755 index 0000000..40cf664 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_BLAKE2b.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_BLAKE2b.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_BLAKE2b.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 35ee701..0000000 --- a/frozen_deps/Cryptodome/Hash/_BLAKE2b.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_BLAKE2s.abi3.so b/frozen_deps/Cryptodome/Hash/_BLAKE2s.abi3.so Binary files differnew file mode 100755 index 0000000..04a1ace --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_BLAKE2s.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_BLAKE2s.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_BLAKE2s.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 7f391c9..0000000 --- a/frozen_deps/Cryptodome/Hash/_BLAKE2s.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_MD2.abi3.so b/frozen_deps/Cryptodome/Hash/_MD2.abi3.so Binary files differnew file mode 100755 index 0000000..1573ca3 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_MD2.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_MD2.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_MD2.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 8fffa21..0000000 --- a/frozen_deps/Cryptodome/Hash/_MD2.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_MD4.abi3.so b/frozen_deps/Cryptodome/Hash/_MD4.abi3.so Binary files differnew file mode 100755 index 0000000..8f41e31 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_MD4.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_MD4.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_MD4.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 12b4c06..0000000 --- a/frozen_deps/Cryptodome/Hash/_MD4.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_MD5.abi3.so b/frozen_deps/Cryptodome/Hash/_MD5.abi3.so Binary files differnew file mode 100755 index 0000000..b22cf36 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_MD5.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_MD5.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_MD5.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 6fb6942..0000000 --- a/frozen_deps/Cryptodome/Hash/_MD5.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_RIPEMD160.abi3.so b/frozen_deps/Cryptodome/Hash/_RIPEMD160.abi3.so Binary files differnew file mode 100755 index 0000000..78faa00 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_RIPEMD160.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_RIPEMD160.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_RIPEMD160.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 2d8928d..0000000 --- a/frozen_deps/Cryptodome/Hash/_RIPEMD160.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_SHA1.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA1.abi3.so Binary files differnew file mode 100755 index 0000000..acd08ad --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_SHA1.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_SHA1.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_SHA1.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 7324a29..0000000 --- a/frozen_deps/Cryptodome/Hash/_SHA1.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_SHA224.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA224.abi3.so Binary files differnew file mode 100755 index 0000000..9cf3ef6 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_SHA224.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_SHA224.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_SHA224.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index c60f2ae..0000000 --- a/frozen_deps/Cryptodome/Hash/_SHA224.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_SHA256.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA256.abi3.so Binary files differnew file mode 100755 index 0000000..6dffb17 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_SHA256.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_SHA256.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_SHA256.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 0b8212d..0000000 --- a/frozen_deps/Cryptodome/Hash/_SHA256.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_SHA384.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA384.abi3.so Binary files differnew file mode 100755 index 0000000..7c72fd0 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_SHA384.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_SHA384.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_SHA384.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index b3ef7ab..0000000 --- a/frozen_deps/Cryptodome/Hash/_SHA384.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_SHA512.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA512.abi3.so Binary files differnew file mode 100755 index 0000000..058653c --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_SHA512.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_SHA512.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_SHA512.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 424a00b..0000000 --- a/frozen_deps/Cryptodome/Hash/_SHA512.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/__init__.py b/frozen_deps/Cryptodome/Hash/__init__.py index 719cd8d..80446e4 100644 --- a/frozen_deps/Cryptodome/Hash/__init__.py +++ b/frozen_deps/Cryptodome/Hash/__init__.py @@ -19,4 +19,51 @@ # =================================================================== __all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1', - 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'CMAC', 'Poly1305'] + 'SHA224', 'SHA256', 'SHA384', 'SHA512', + 'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512', + 'CMAC', 'Poly1305', + 'cSHAKE128', 'cSHAKE256', 'KMAC128', 'KMAC256', + 'TupleHash128', 'TupleHash256', 'KangarooTwelve', + 'TurboSHAKE128', 'TurboSHAKE256'] + +def new(name): + """Return a new hash instance, based on its name or + on its ASN.1 Object ID""" + + name = name.upper() + if name in ("1.3.14.3.2.26", "SHA1", "SHA-1"): + from . import SHA1 + return SHA1.new() + if name in ("2.16.840.1.101.3.4.2.4", "SHA224", "SHA-224"): + from . import SHA224 + return SHA224.new() + if name in ("2.16.840.1.101.3.4.2.1", "SHA256", "SHA-256"): + from . import SHA256 + return SHA256.new() + if name in ("2.16.840.1.101.3.4.2.2", "SHA384", "SHA-384"): + from . import SHA384 + return SHA384.new() + if name in ("2.16.840.1.101.3.4.2.3", "SHA512", "SHA-512"): + from . import SHA512 + return SHA512.new() + if name in ("2.16.840.1.101.3.4.2.5", "SHA512-224", "SHA-512-224"): + from . import SHA512 + return SHA512.new(truncate='224') + if name in ("2.16.840.1.101.3.4.2.6", "SHA512-256", "SHA-512-256"): + from . import SHA512 + return SHA512.new(truncate='256') + if name in ("2.16.840.1.101.3.4.2.7", "SHA3-224", "SHA-3-224"): + from . import SHA3_224 + return SHA3_224.new() + if name in ("2.16.840.1.101.3.4.2.8", "SHA3-256", "SHA-3-256"): + from . import SHA3_256 + return SHA3_256.new() + if name in ("2.16.840.1.101.3.4.2.9", "SHA3-384", "SHA-3-384"): + from . import SHA3_384 + return SHA3_384.new() + if name in ("2.16.840.1.101.3.4.2.10", "SHA3-512", "SHA-3-512"): + from . import SHA3_512 + return SHA3_512.new() + else: + raise ValueError("Unknown hash %s" % str(name)) + diff --git a/frozen_deps/Cryptodome/Hash/__init__.pyi b/frozen_deps/Cryptodome/Hash/__init__.pyi index e69de29..b072157 100644 --- a/frozen_deps/Cryptodome/Hash/__init__.pyi +++ b/frozen_deps/Cryptodome/Hash/__init__.pyi @@ -0,0 +1,57 @@ +from typing import overload +from typing_extensions import Literal + +from Cryptodome.Hash.SHA1 import SHA1Hash +from Cryptodome.Hash.SHA224 import SHA224Hash +from Cryptodome.Hash.SHA256 import SHA256Hash +from Cryptodome.Hash.SHA384 import SHA384Hash +from Cryptodome.Hash.SHA512 import SHA512Hash +from Cryptodome.Hash.SHA3_224 import SHA3_224_Hash +from Cryptodome.Hash.SHA3_256 import SHA3_256_Hash +from Cryptodome.Hash.SHA3_384 import SHA3_384_Hash +from Cryptodome.Hash.SHA3_512 import SHA3_512_Hash + +@overload +def new(name: Literal["1.3.14.3.2.26"]) -> SHA1Hash: ... +@overload +def new(name: Literal["SHA1"]) -> SHA1Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.4"]) -> SHA224Hash: ... +@overload +def new(name: Literal["SHA224"]) -> SHA224Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.1"]) -> SHA256Hash: ... +@overload +def new(name: Literal["SHA256"]) -> SHA256Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.2"]) -> SHA384Hash: ... +@overload +def new(name: Literal["SHA384"]) -> SHA384Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.3"]) -> SHA512Hash: ... +@overload +def new(name: Literal["SHA512"]) -> SHA512Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.5"]) -> SHA512Hash: ... +@overload +def new(name: Literal["SHA512-224"]) -> SHA512Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.6"]) -> SHA512Hash: ... +@overload +def new(name: Literal["SHA512-256"]) -> SHA512Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.7"]) -> SHA3_224_Hash: ... +@overload +def new(name: Literal["SHA3-224"]) -> SHA3_224_Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.8"]) -> SHA3_256_Hash: ... +@overload +def new(name: Literal["SHA3-256"]) -> SHA3_256_Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.9"]) -> SHA3_384_Hash: ... +@overload +def new(name: Literal["SHA3-384"]) -> SHA3_384_Hash: ... +@overload +def new(name: Literal["2.16.840.1.101.3.4.2.10"]) -> SHA3_512_Hash: ... +@overload +def new(name: Literal["SHA3-512"]) -> SHA3_512_Hash: ... diff --git a/frozen_deps/Cryptodome/Hash/_ghash_clmul.abi3.so b/frozen_deps/Cryptodome/Hash/_ghash_clmul.abi3.so Binary files differnew file mode 100755 index 0000000..d13832c --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_ghash_clmul.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_ghash_clmul.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_ghash_clmul.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index c4387d7..0000000 --- a/frozen_deps/Cryptodome/Hash/_ghash_clmul.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_ghash_portable.abi3.so b/frozen_deps/Cryptodome/Hash/_ghash_portable.abi3.so Binary files differnew file mode 100755 index 0000000..555c6fc --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_ghash_portable.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_ghash_portable.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_ghash_portable.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index ed1479f..0000000 --- a/frozen_deps/Cryptodome/Hash/_ghash_portable.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_keccak.abi3.so b/frozen_deps/Cryptodome/Hash/_keccak.abi3.so Binary files differnew file mode 100755 index 0000000..4e494b0 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_keccak.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_keccak.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_keccak.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 074d7c4..0000000 --- a/frozen_deps/Cryptodome/Hash/_keccak.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/_poly1305.abi3.so b/frozen_deps/Cryptodome/Hash/_poly1305.abi3.so Binary files differnew file mode 100755 index 0000000..901b8c2 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/_poly1305.abi3.so diff --git a/frozen_deps/Cryptodome/Hash/_poly1305.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Hash/_poly1305.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index b9ae83f..0000000 --- a/frozen_deps/Cryptodome/Hash/_poly1305.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Hash/cSHAKE128.py b/frozen_deps/Cryptodome/Hash/cSHAKE128.py new file mode 100644 index 0000000..064b3d6 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/cSHAKE128.py @@ -0,0 +1,187 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util.py3compat import bchr, concat_buffers + +from Cryptodome.Util._raw_api import (VoidPointer, SmartPointer, + create_string_buffer, + get_raw_buffer, c_size_t, + c_uint8_ptr, c_ubyte) + +from Cryptodome.Util.number import long_to_bytes + +from Cryptodome.Hash.keccak import _raw_keccak_lib + + +def _left_encode(x): + """Left encode function as defined in NIST SP 800-185""" + + assert (x < (1 << 2040) and x >= 0) + + # Get number of bytes needed to represent this integer. + num = 1 if x == 0 else (x.bit_length() + 7) // 8 + + return bchr(num) + long_to_bytes(x) + + +def _right_encode(x): + """Right encode function as defined in NIST SP 800-185""" + + assert (x < (1 << 2040) and x >= 0) + + # Get number of bytes needed to represent this integer. + num = 1 if x == 0 else (x.bit_length() + 7) // 8 + + return long_to_bytes(x) + bchr(num) + + +def _encode_str(x): + """Encode string function as defined in NIST SP 800-185""" + + bitlen = len(x) * 8 + if bitlen >= (1 << 2040): + raise ValueError("String too large to encode in cSHAKE") + + return concat_buffers(_left_encode(bitlen), x) + + +def _bytepad(x, length): + """Zero pad byte string as defined in NIST SP 800-185""" + + to_pad = concat_buffers(_left_encode(length), x) + + # Note: this implementation works with byte aligned strings, + # hence no additional bit padding is needed at this point. + npad = (length - len(to_pad) % length) % length + + return to_pad + b'\x00' * npad + + +class cSHAKE_XOF(object): + """A cSHAKE hash object. + Do not instantiate directly. + Use the :func:`new` function. + """ + + def __init__(self, data, custom, capacity, function): + state = VoidPointer() + + if custom or function: + prefix_unpad = _encode_str(function) + _encode_str(custom) + prefix = _bytepad(prefix_unpad, (1600 - capacity)//8) + self._padding = 0x04 + else: + prefix = None + self._padding = 0x1F # for SHAKE + + result = _raw_keccak_lib.keccak_init(state.address_of(), + c_size_t(capacity//8), + c_ubyte(24)) + if result: + raise ValueError("Error %d while instantiating cSHAKE" + % result) + self._state = SmartPointer(state.get(), + _raw_keccak_lib.keccak_destroy) + self._is_squeezing = False + + if prefix: + self.update(prefix) + + if data: + self.update(data) + + def update(self, data): + """Continue hashing of a message by consuming the next chunk of data. + + Args: + data (byte string/byte array/memoryview): The next chunk of the message being hashed. + """ + + if self._is_squeezing: + raise TypeError("You cannot call 'update' after the first 'read'") + + result = _raw_keccak_lib.keccak_absorb(self._state.get(), + c_uint8_ptr(data), + c_size_t(len(data))) + if result: + raise ValueError("Error %d while updating %s state" + % (result, self.name)) + return self + + def read(self, length): + """ + Compute the next piece of XOF output. + + .. note:: + You cannot use :meth:`update` anymore after the first call to + :meth:`read`. + + Args: + length (integer): the amount of bytes this method must return + + :return: the next piece of XOF output (of the given length) + :rtype: byte string + """ + + self._is_squeezing = True + bfr = create_string_buffer(length) + result = _raw_keccak_lib.keccak_squeeze(self._state.get(), + bfr, + c_size_t(length), + c_ubyte(self._padding)) + if result: + raise ValueError("Error %d while extracting from %s" + % (result, self.name)) + + return get_raw_buffer(bfr) + + +def _new(data, custom, function): + # Use Keccak[256] + return cSHAKE_XOF(data, custom, 256, function) + + +def new(data=None, custom=None): + """Return a fresh instance of a cSHAKE128 object. + + Args: + data (bytes/bytearray/memoryview): + Optional. + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`cSHAKE_XOF` object + """ + + # Use Keccak[256] + return cSHAKE_XOF(data, custom, 256, b'') diff --git a/frozen_deps/Cryptodome/Hash/cSHAKE128.pyi b/frozen_deps/Cryptodome/Hash/cSHAKE128.pyi new file mode 100644 index 0000000..1452fea --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/cSHAKE128.pyi @@ -0,0 +1,14 @@ +from typing import Union, Optional + +Buffer = Union[bytes, bytearray, memoryview] + +class cSHAKE_XOF(object): + def __init__(self, + data: Optional[Buffer] = ..., + function: Optional[bytes] = ..., + custom: Optional[bytes] = ...) -> None: ... + def update(self, data: Buffer) -> cSHAKE_XOF: ... + def read(self, length: int) -> bytes: ... + +def new(data: Optional[Buffer] = ..., + custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ... diff --git a/frozen_deps/Cryptodome/Hash/cSHAKE256.py b/frozen_deps/Cryptodome/Hash/cSHAKE256.py new file mode 100644 index 0000000..a5b8701 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/cSHAKE256.py @@ -0,0 +1,56 @@ +# =================================================================== +# +# Copyright (c) 2021, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Util._raw_api import c_size_t +from Cryptodome.Hash.cSHAKE128 import cSHAKE_XOF + + +def _new(data, custom, function): + # Use Keccak[512] + return cSHAKE_XOF(data, custom, 512, function) + + +def new(data=None, custom=None): + """Return a fresh instance of a cSHAKE256 object. + + Args: + data (bytes/bytearray/memoryview): + The very first chunk of the message to hash. + It is equivalent to an early call to :meth:`update`. + Optional. + custom (bytes): + Optional. + A customization bytestring (``S`` in SP 800-185). + + :Return: A :class:`cSHAKE_XOF` object + """ + + # Use Keccak[512] + return cSHAKE_XOF(data, custom, 512, b'') diff --git a/frozen_deps/Cryptodome/Hash/cSHAKE256.pyi b/frozen_deps/Cryptodome/Hash/cSHAKE256.pyi new file mode 100644 index 0000000..b910bb6 --- /dev/null +++ b/frozen_deps/Cryptodome/Hash/cSHAKE256.pyi @@ -0,0 +1,8 @@ +from typing import Union, Optional + +from Cryptodome.Hash.cSHAKE128 import cSHAKE_XOF + +Buffer = Union[bytes, bytearray, memoryview] + +def new(data: Optional[Buffer] = ..., + custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ... diff --git a/frozen_deps/Cryptodome/Hash/keccak.py b/frozen_deps/Cryptodome/Hash/keccak.py index 9ae8ec5..f2af202 100644 --- a/frozen_deps/Cryptodome/Hash/keccak.py +++ b/frozen_deps/Cryptodome/Hash/keccak.py @@ -34,21 +34,27 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, SmartPointer, create_string_buffer, get_raw_buffer, c_size_t, - c_uint8_ptr) + c_uint8_ptr, c_ubyte) _raw_keccak_lib = load_pycryptodome_raw_lib("Cryptodome.Hash._keccak", """ int keccak_init(void **state, size_t capacity_bytes, - uint8_t padding_byte); + uint8_t rounds); int keccak_destroy(void *state); int keccak_absorb(void *state, const uint8_t *in, size_t len); int keccak_squeeze(const void *state, uint8_t *out, - size_t len); - int keccak_digest(void *state, uint8_t *digest, size_t len); + size_t len, + uint8_t padding); + int keccak_digest(void *state, + uint8_t *digest, + size_t len, + uint8_t padding); + int keccak_copy(const void *src, void *dst); + int keccak_reset(void *state); """) class Keccak_Hash(object): @@ -66,11 +72,12 @@ class Keccak_Hash(object): self._update_after_digest = update_after_digest self._digest_done = False + self._padding = 0x01 state = VoidPointer() result = _raw_keccak_lib.keccak_init(state.address_of(), c_size_t(self.digest_size * 2), - 0x01) + c_ubyte(24)) if result: raise ValueError("Error %d while instantiating keccak" % result) self._state = SmartPointer(state.get(), @@ -107,7 +114,8 @@ class Keccak_Hash(object): bfr = create_string_buffer(self.digest_size) result = _raw_keccak_lib.keccak_digest(self._state.get(), bfr, - c_size_t(self.digest_size)) + c_size_t(self.digest_size), + c_ubyte(self._padding)) if result: raise ValueError("Error %d while squeezing keccak" % result) diff --git a/frozen_deps/Cryptodome/IO/PKCS8.py b/frozen_deps/Cryptodome/IO/PKCS8.py index 7365476..3041545 100644 --- a/frozen_deps/Cryptodome/IO/PKCS8.py +++ b/frozen_deps/Cryptodome/IO/PKCS8.py @@ -48,53 +48,39 @@ __all__ = ['wrap', 'unwrap'] def wrap(private_key, key_oid, passphrase=None, protection=None, - prot_params=None, key_params=None, randfunc=None): + prot_params=None, key_params=DerNull(), randfunc=None): """Wrap a private key into a PKCS#8 blob (clear or encrypted). Args: - private_key (byte string): + private_key (bytes): The private key encoded in binary form. The actual encoding is algorithm specific. In most cases, it is DER. key_oid (string): The object identifier (OID) of the private key to wrap. - It is a dotted string, like ``1.2.840.113549.1.1.1`` (for RSA keys). + It is a dotted string, like ``'1.2.840.113549.1.1.1'`` (for RSA keys) + or ``'1.2.840.10045.2.1'`` (for ECC keys). - passphrase (bytes string or string): + Keyword Args: + + passphrase (bytes or string): The secret passphrase from which the wrapping key is derived. Set it only if encryption is required. protection (string): The identifier of the algorithm to use for securely wrapping the key. - The default value is ``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``. + Refer to :ref:`the encryption parameters<enc_params>` . + The default value is ``'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'``. prot_params (dictionary): - Parameters for the protection algorithm. - - +------------------+-----------------------------------------------+ - | Key | Description | - +==================+===============================================+ - | iteration_count | The KDF algorithm is repeated several times to| - | | slow down brute force attacks on passwords | - | | (called *N* or CPU/memory cost in scrypt). | - | | The default value for PBKDF2 is 1000. | - | | The default value for scrypt is 16384. | - +------------------+-----------------------------------------------+ - | salt_size | Salt is used to thwart dictionary and rainbow | - | | attacks on passwords. The default value is 8 | - | | bytes. | - +------------------+-----------------------------------------------+ - | block_size | *(scrypt only)* Memory-cost (r). The default | - | | value is 8. | - +------------------+-----------------------------------------------+ - | parallelization | *(scrypt only)* CPU-cost (p). The default | - | | value is 1. | - +------------------+-----------------------------------------------+ - - key_params (DER object): - The algorithm parameters associated to the private key. - It is required for algorithms like DSA, but not for others like RSA. + Parameters for the key derivation function (KDF). + Refer to :ref:`the encryption parameters<enc_params>` . + + key_params (DER object or None): + The ``parameters`` field to use in the ``AlgorithmIdentifier`` + SEQUENCE. If ``None``, no ``parameters`` field will be added. + By default, the ASN.1 type ``NULL`` is used. randfunc (callable): Random number generation function; it should accept a single integer @@ -102,13 +88,10 @@ def wrap(private_key, key_oid, passphrase=None, protection=None, If not specified, a new RNG will be instantiated from :mod:`Cryptodome.Random`. - Return: - The PKCS#8-wrapped private key (possibly encrypted), as a byte string. + Returns: + bytes: The PKCS#8-wrapped private key (possibly encrypted). """ - if key_params is None: - key_params = DerNull() - # # PrivateKeyInfo ::= SEQUENCE { # version Version, @@ -117,12 +100,14 @@ def wrap(private_key, key_oid, passphrase=None, protection=None, # attributes [0] IMPLICIT Attributes OPTIONAL # } # + if key_params is None: + algorithm = DerSequence([DerObjectId(key_oid)]) + else: + algorithm = DerSequence([DerObjectId(key_oid), key_params]) + pk_info = DerSequence([ 0, - DerSequence([ - DerObjectId(key_oid), - key_params - ]), + algorithm, DerOctetString(private_key) ]) pk_info_der = pk_info.encode() @@ -145,8 +130,10 @@ def unwrap(p8_private_key, passphrase=None): """Unwrap a private key from a PKCS#8 blob (clear or encrypted). Args: - p8_private_key (byte string): - The private key wrapped into a PKCS#8 blob, DER encoded. + p8_private_key (bytes): + The private key wrapped into a PKCS#8 container, DER encoded. + + Keyword Args: passphrase (byte string or string): The passphrase to use to decrypt the blob (if it is encrypted). @@ -154,8 +141,8 @@ def unwrap(p8_private_key, passphrase=None): A tuple containing #. the algorithm identifier of the wrapped key (OID, dotted string) - #. the private key (byte string, DER encoded) - #. the associated parameters (byte string, DER encoded) or ``None`` + #. the private key (bytes, DER encoded) + #. the associated parameters (bytes, DER encoded) or ``None`` Raises: ValueError : if decoding fails @@ -185,11 +172,12 @@ def unwrap(p8_private_key, passphrase=None): if not found: raise ValueError("Error decoding PKCS#8 (%s)" % error_str) - pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4)) + pk_info = DerSequence().decode(p8_private_key, nr_elements=(2, 3, 4, 5)) if len(pk_info) == 2 and not passphrase: raise ValueError("Not a valid clear PKCS#8 structure " "(maybe it is encrypted?)") + # RFC5208, PKCS#8, version is v1(0) # # PrivateKeyInfo ::= SEQUENCE { # version Version, @@ -197,22 +185,27 @@ def unwrap(p8_private_key, passphrase=None): # privateKey PrivateKey, # attributes [0] IMPLICIT Attributes OPTIONAL # } - # Version ::= INTEGER - if pk_info[0] != 0: - raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") - - # PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier # - # EncryptedPrivateKeyInfo ::= SEQUENCE { - # encryptionAlgorithm EncryptionAlgorithmIdentifier, - # encryptedData EncryptedData + # RFC5915, Asymmetric Key Package, version is v2(1) + # + # OneAsymmetricKey ::= SEQUENCE { + # version Version, + # privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + # privateKey PrivateKey, + # attributes [0] Attributes OPTIONAL, + # ..., + # [[2: publicKey [1] PublicKey OPTIONAL ]], + # ... # } - # EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier - # AlgorithmIdentifier ::= SEQUENCE { - # algorithm OBJECT IDENTIFIER, - # parameters ANY DEFINED BY algorithm OPTIONAL - # } + if pk_info[0] == 0: + if len(pk_info) not in (3, 4): + raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") + elif pk_info[0] == 1: + if len(pk_info) not in (3, 4, 5): + raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") + else: + raise ValueError("Not a valid PrivateKeyInfo SEQUENCE") algo = DerSequence().decode(pk_info[1], nr_elements=(1, 2)) algo_oid = DerObjectId().decode(algo[0]).value @@ -225,7 +218,9 @@ def unwrap(p8_private_key, passphrase=None): except: algo_params = algo[1] - # EncryptedData ::= OCTET STRING + # PrivateKey ::= OCTET STRING private_key = DerOctetString().decode(pk_info[2]).payload + # We ignore attributes and (for v2 only) publickey + return (algo_oid, private_key, algo_params) diff --git a/frozen_deps/Cryptodome/IO/PKCS8.pyi b/frozen_deps/Cryptodome/IO/PKCS8.pyi index 135b638..c8d0c10 100644 --- a/frozen_deps/Cryptodome/IO/PKCS8.pyi +++ b/frozen_deps/Cryptodome/IO/PKCS8.pyi @@ -1,14 +1,17 @@ -from typing import Dict, Tuple, Optional, Union, Callable +from typing import Tuple, Optional, Union, Callable +from typing_extensions import NotRequired from Cryptodome.Util.asn1 import DerObject +from Cryptodome.IO._PBES import ProtParams + def wrap(private_key: bytes, key_oid: str, - passphrase: Union[bytes, str] = ..., - protection: str = ..., - prot_params: Dict = ..., - key_params: DerObject = ..., - randfunc: Optional[Callable[[int],str]] = ...) -> bytes: ... + passphrase: Union[bytes, str] = ..., + protection: str = ..., + prot_params: Optional[ProtParams] = ..., + key_params: Optional[DerObject] = ..., + randfunc: Optional[Callable[[int], str]] = ...) -> bytes: ... def unwrap(p8_private_key: bytes, passphrase: Optional[Union[bytes, str]] = ...) -> Tuple[str, bytes, Optional[bytes]]: ... diff --git a/frozen_deps/Cryptodome/IO/_PBES.py b/frozen_deps/Cryptodome/IO/_PBES.py index 9ee5385..75d8cde 100644 --- a/frozen_deps/Cryptodome/IO/_PBES.py +++ b/frozen_deps/Cryptodome/IO/_PBES.py @@ -31,15 +31,17 @@ # POSSIBILITY OF SUCH DAMAGE. # =================================================================== +import re + +from Cryptodome import Hash from Cryptodome import Random from Cryptodome.Util.asn1 import ( DerSequence, DerOctetString, DerObjectId, DerInteger, ) +from Cryptodome.Cipher import AES from Cryptodome.Util.Padding import pad, unpad -from Cryptodome.Hash import MD5, SHA1, SHA224, SHA256, SHA384, SHA512 -from Cryptodome.Cipher import DES, ARC2, DES3, AES from Cryptodome.Protocol.KDF import PBKDF1, PBKDF2, scrypt _OID_PBE_WITH_MD5_AND_DES_CBC = "1.2.840.113549.1.5.3" @@ -53,16 +55,14 @@ _OID_PBKDF2 = "1.2.840.113549.1.5.12" _OID_SCRYPT = "1.3.6.1.4.1.11591.4.11" _OID_HMAC_SHA1 = "1.2.840.113549.2.7" -_OID_HMAC_SHA224 = "1.2.840.113549.2.8" -_OID_HMAC_SHA256 = "1.2.840.113549.2.9" -_OID_HMAC_SHA384 = "1.2.840.113549.2.10" -_OID_HMAC_SHA512 = "1.2.840.113549.2.11" _OID_DES_EDE3_CBC = "1.2.840.113549.3.7" _OID_AES128_CBC = "2.16.840.1.101.3.4.1.2" _OID_AES192_CBC = "2.16.840.1.101.3.4.1.22" _OID_AES256_CBC = "2.16.840.1.101.3.4.1.42" - +_OID_AES128_GCM = "2.16.840.1.101.3.4.1.6" +_OID_AES192_GCM = "2.16.840.1.101.3.4.1.26" +_OID_AES256_GCM = "2.16.840.1.101.3.4.1.46" class PbesError(ValueError): pass @@ -103,6 +103,16 @@ class PbesError(ValueError): # prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT algid-hmacWithSHA1 # } # +# PBKDF2-PRFs ALGORITHM-IDENTIFIER ::= { +# {NULL IDENTIFIED BY id-hmacWithSHA1}, +# {NULL IDENTIFIED BY id-hmacWithSHA224}, +# {NULL IDENTIFIED BY id-hmacWithSHA256}, +# {NULL IDENTIFIED BY id-hmacWithSHA384}, +# {NULL IDENTIFIED BY id-hmacWithSHA512}, +# {NULL IDENTIFIED BY id-hmacWithSHA512-224}, +# {NULL IDENTIFIED BY id-hmacWithSHA512-256}, +# ... +# } # scrypt-params ::= SEQUENCE { # salt OCTET STRING, # costParameter INTEGER (1..MAX), @@ -111,6 +121,7 @@ class PbesError(ValueError): # keyLength INTEGER (1..MAX) OPTIONAL # } + class PBES1(object): """Deprecated encryption scheme with password-based key derivation (originally defined in PKCS#5 v1.5, but still present in `v2.0`__). @@ -141,21 +152,29 @@ class PBES1(object): cipher_params = {} if pbe_oid == _OID_PBE_WITH_MD5_AND_DES_CBC: # PBE_MD5_DES_CBC + from Cryptodome.Hash import MD5 + from Cryptodome.Cipher import DES hashmod = MD5 - ciphermod = DES + module = DES elif pbe_oid == _OID_PBE_WITH_MD5_AND_RC2_CBC: # PBE_MD5_RC2_CBC + from Cryptodome.Hash import MD5 + from Cryptodome.Cipher import ARC2 hashmod = MD5 - ciphermod = ARC2 + module = ARC2 cipher_params['effective_keylen'] = 64 elif pbe_oid == _OID_PBE_WITH_SHA1_AND_DES_CBC: # PBE_SHA1_DES_CBC + from Cryptodome.Hash import SHA1 + from Cryptodome.Cipher import DES hashmod = SHA1 - ciphermod = DES + module = DES elif pbe_oid == _OID_PBE_WITH_SHA1_AND_RC2_CBC: # PBE_SHA1_RC2_CBC + from Cryptodome.Hash import SHA1 + from Cryptodome.Cipher import ARC2 hashmod = SHA1 - ciphermod = ARC2 + module = ARC2 cipher_params['effective_keylen'] = 64 else: raise PbesError("Unknown OID for PBES1") @@ -167,7 +186,7 @@ class PBES1(object): key_iv = PBKDF1(passphrase, salt, 16, iterations, hashmod) key, iv = key_iv[:8], key_iv[8:] - cipher = ciphermod.new(key, ciphermod.MODE_CBC, iv, **cipher_params) + cipher = module.new(key, module.MODE_CBC, iv, **cipher_params) pt = cipher.decrypt(encrypted_data) return unpad(pt, cipher.block_size) @@ -231,49 +250,103 @@ class PBES2(object): if randfunc is None: randfunc = Random.new().read - if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC': + pattern = re.compile(r'^(PBKDF2WithHMAC-([0-9A-Z-]+)|scrypt)And([0-9A-Z-]+)$') + res = pattern.match(protection) + if res is None: + raise ValueError("Unknown protection %s" % protection) + + if protection.startswith("PBKDF"): + pbkdf = "pbkdf2" + pbkdf2_hmac_algo = res.group(2) + enc_algo = res.group(3) + else: + pbkdf = "scrypt" + enc_algo = res.group(3) + + aead = False + if enc_algo == 'DES-EDE3-CBC': + from Cryptodome.Cipher import DES3 key_size = 24 module = DES3 cipher_mode = DES3.MODE_CBC enc_oid = _OID_DES_EDE3_CBC - elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC', - 'scryptAndAES128-CBC'): + enc_param = {'iv': randfunc(8)} + elif enc_algo == 'AES128-CBC': key_size = 16 module = AES cipher_mode = AES.MODE_CBC enc_oid = _OID_AES128_CBC - elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC', - 'scryptAndAES192-CBC'): + enc_param = {'iv': randfunc(16)} + elif enc_algo == 'AES192-CBC': key_size = 24 module = AES cipher_mode = AES.MODE_CBC enc_oid = _OID_AES192_CBC - elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC', - 'scryptAndAES256-CBC'): + enc_param = {'iv': randfunc(16)} + elif enc_algo == 'AES256-CBC': key_size = 32 module = AES cipher_mode = AES.MODE_CBC enc_oid = _OID_AES256_CBC + enc_param = {'iv': randfunc(16)} + elif enc_algo == 'AES128-GCM': + key_size = 16 + module = AES + cipher_mode = AES.MODE_GCM + enc_oid = _OID_AES128_GCM + enc_param = {'nonce': randfunc(12)} + aead = True + elif enc_algo == 'AES192-GCM': + key_size = 24 + module = AES + cipher_mode = AES.MODE_GCM + enc_oid = _OID_AES192_GCM + enc_param = {'nonce': randfunc(12)} + aead = True + elif enc_algo == 'AES256-GCM': + key_size = 32 + module = AES + cipher_mode = AES.MODE_GCM + enc_oid = _OID_AES256_GCM + enc_param = {'nonce': randfunc(12)} + aead = True else: - raise ValueError("Unknown PBES2 mode") + raise ValueError("Unknown encryption mode '%s'" % enc_algo) - # Get random data - iv = randfunc(module.block_size) + iv_nonce = list(enc_param.values())[0] salt = randfunc(prot_params.get("salt_size", 8)) # Derive key from password - if protection.startswith('PBKDF2'): + if pbkdf == 'pbkdf2': + count = prot_params.get("iteration_count", 1000) - key = PBKDF2(passphrase, salt, key_size, count) + digestmod = Hash.new(pbkdf2_hmac_algo) + + key = PBKDF2(passphrase, + salt, + key_size, + count, + hmac_hash_module=digestmod) + + pbkdf2_params = DerSequence([ + DerOctetString(salt), + DerInteger(count) + ]) + + if pbkdf2_hmac_algo != 'SHA1': + try: + hmac_oid = Hash.HMAC.new(b'', digestmod=digestmod).oid + except KeyError: + raise ValueError("No OID for HMAC hash algorithm") + pbkdf2_params.append(DerSequence([DerObjectId(hmac_oid)])) + kdf_info = DerSequence([ DerObjectId(_OID_PBKDF2), # PBKDF2 - DerSequence([ - DerOctetString(salt), - DerInteger(count) - ]) + pbkdf2_params ]) - else: - # It must be scrypt + + elif pbkdf == 'scrypt': + count = prot_params.get("iteration_count", 16384) scrypt_r = prot_params.get('block_size', 8) scrypt_p = prot_params.get('parallelization', 1) @@ -289,12 +362,19 @@ class PBES2(object): ]) ]) + else: + raise ValueError("Unknown KDF " + res.group(1)) + # Create cipher and use it - cipher = module.new(key, cipher_mode, iv) - encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) + cipher = module.new(key, cipher_mode, **enc_param) + if aead: + ct, tag = cipher.encrypt_and_digest(data) + encrypted_data = ct + tag + else: + encrypted_data = cipher.encrypt(pad(data, cipher.block_size)) enc_info = DerSequence([ DerObjectId(enc_oid), - DerOctetString(iv) + DerOctetString(iv_nonce) ]) # Result @@ -336,7 +416,7 @@ class PBES2(object): pbes2_params = DerSequence().decode(enc_algo[1], nr_elements=2) - ### Key Derivation Function selection + # Key Derivation Function selection kdf_info = DerSequence().decode(pbes2_params[0], nr_elements=2) kdf_oid = DerObjectId().decode(kdf_info[0]).value @@ -354,14 +434,16 @@ class PBES2(object): if left > 0: try: + # Check if it's an INTEGER kdf_key_length = pbkdf2_params[idx] - 0 left -= 1 idx += 1 except TypeError: + # keyLength is not present pass # Default is HMAC-SHA1 - pbkdf2_prf_oid = "1.2.840.113549.2.7" + pbkdf2_prf_oid = _OID_HMAC_SHA1 if left > 0: pbkdf2_prf_algo_id = DerSequence().decode(pbkdf2_params[idx]) pbkdf2_prf_oid = DerObjectId().decode(pbkdf2_prf_algo_id[0]).value @@ -379,57 +461,86 @@ class PBES2(object): else: raise PbesError("Unsupported PBES2 KDF") - ### Cipher selection + # Cipher selection enc_info = DerSequence().decode(pbes2_params[1]) enc_oid = DerObjectId().decode(enc_info[0]).value + aead = False if enc_oid == _OID_DES_EDE3_CBC: # DES_EDE3_CBC - ciphermod = DES3 + from Cryptodome.Cipher import DES3 + module = DES3 + cipher_mode = DES3.MODE_CBC key_size = 24 + cipher_param = 'iv' elif enc_oid == _OID_AES128_CBC: - # AES128_CBC - ciphermod = AES + module = AES + cipher_mode = AES.MODE_CBC key_size = 16 + cipher_param = 'iv' elif enc_oid == _OID_AES192_CBC: - # AES192_CBC - ciphermod = AES + module = AES + cipher_mode = AES.MODE_CBC key_size = 24 + cipher_param = 'iv' elif enc_oid == _OID_AES256_CBC: - # AES256_CBC - ciphermod = AES + module = AES + cipher_mode = AES.MODE_CBC + key_size = 32 + cipher_param = 'iv' + elif enc_oid == _OID_AES128_GCM: + module = AES + cipher_mode = AES.MODE_GCM + key_size = 16 + cipher_param = 'nonce' + aead = True + elif enc_oid == _OID_AES192_GCM: + module = AES + cipher_mode = AES.MODE_GCM + key_size = 24 + cipher_param = 'nonce' + aead = True + elif enc_oid == _OID_AES256_GCM: + module = AES + cipher_mode = AES.MODE_GCM key_size = 32 + cipher_param = 'nonce' + aead = True else: - raise PbesError("Unsupported PBES2 cipher") + raise PbesError("Unsupported PBES2 cipher " + enc_algo) if kdf_key_length and kdf_key_length != key_size: raise PbesError("Mismatch between PBES2 KDF parameters" " and selected cipher") - IV = DerOctetString().decode(enc_info[1]).payload + iv_nonce = DerOctetString().decode(enc_info[1]).payload # Create cipher if kdf_oid == _OID_PBKDF2: - if pbkdf2_prf_oid == _OID_HMAC_SHA1: - hmac_hash_module = SHA1 - elif pbkdf2_prf_oid == _OID_HMAC_SHA224: - hmac_hash_module = SHA224 - elif pbkdf2_prf_oid == _OID_HMAC_SHA256: - hmac_hash_module = SHA256 - elif pbkdf2_prf_oid == _OID_HMAC_SHA384: - hmac_hash_module = SHA384 - elif pbkdf2_prf_oid == _OID_HMAC_SHA512: - hmac_hash_module = SHA512 - else: + + try: + hmac_hash_module_oid = Hash.HMAC._hmac2hash_oid[pbkdf2_prf_oid] + except KeyError: raise PbesError("Unsupported HMAC %s" % pbkdf2_prf_oid) + hmac_hash_module = Hash.new(hmac_hash_module_oid) key = PBKDF2(passphrase, salt, key_size, iteration_count, hmac_hash_module=hmac_hash_module) else: key = scrypt(passphrase, salt, key_size, iteration_count, scrypt_r, scrypt_p) - cipher = ciphermod.new(key, ciphermod.MODE_CBC, IV) + cipher = module.new(key, cipher_mode, **{cipher_param:iv_nonce}) # Decrypt data - pt = cipher.decrypt(encrypted_data) - return unpad(pt, cipher.block_size) + if len(encrypted_data) < cipher.block_size: + raise ValueError("Too little data to decrypt") + + if aead: + tag_len = cipher.block_size + pt = cipher.decrypt_and_verify(encrypted_data[:-tag_len], + encrypted_data[-tag_len:]) + else: + pt_padded = cipher.decrypt(encrypted_data) + pt = unpad(pt_padded, cipher.block_size) + + return pt diff --git a/frozen_deps/Cryptodome/IO/_PBES.pyi b/frozen_deps/Cryptodome/IO/_PBES.pyi index a8a34ce..0673364 100644 --- a/frozen_deps/Cryptodome/IO/_PBES.pyi +++ b/frozen_deps/Cryptodome/IO/_PBES.pyi @@ -1,4 +1,5 @@ -from typing import Dict, Optional, Callable +from typing import Optional, Callable, TypedDict +from typing_extensions import NotRequired class PbesError(ValueError): ... @@ -7,13 +8,19 @@ class PBES1(object): @staticmethod def decrypt(data: bytes, passphrase: bytes) -> bytes: ... +class ProtParams(TypedDict): + iteration_count: NotRequired[int] + salt_size: NotRequired[int] + block_size: NotRequired[int] + parallelization: NotRequired[int] + class PBES2(object): @staticmethod def encrypt(data: bytes, passphrase: bytes, - protection: str, - prot_params: Optional[Dict] = ..., - randfunc: Optional[Callable[[int],bytes]] = ...) -> bytes: ... + protection: str, + prot_params: Optional[ProtParams] = ..., + randfunc: Optional[Callable[[int],bytes]] = ...) -> bytes: ... @staticmethod def decrypt(data:bytes, passphrase: bytes) -> bytes: ... diff --git a/frozen_deps/Cryptodome/Math/Numbers.pyi b/frozen_deps/Cryptodome/Math/Numbers.pyi index 2285a3b..b0206ca 100644 --- a/frozen_deps/Cryptodome/Math/Numbers.pyi +++ b/frozen_deps/Cryptodome/Math/Numbers.pyi @@ -1,4 +1,2 @@ -from Cryptodome.Math._IntegerBase import IntegerBase - -class Integer(IntegerBase): - pass +from Cryptodome.Math._IntegerBase import IntegerBase as Integer +__all__ = ['Integer'] diff --git a/frozen_deps/Cryptodome/Math/Primality.py b/frozen_deps/Cryptodome/Math/Primality.py index 08ea3ff..33814fa 100644 --- a/frozen_deps/Cryptodome/Math/Primality.py +++ b/frozen_deps/Cryptodome/Math/Primality.py @@ -67,7 +67,7 @@ def miller_rabin_test(candidate, iterations, randfunc=None): if candidate in (1, 2, 3, 5): return PROBABLY_PRIME - + if candidate.is_even(): return COMPOSITE @@ -93,7 +93,8 @@ def miller_rabin_test(candidate, iterations, randfunc=None): base = 1 while base in (one, minus_one): base = Integer.random_range(min_inclusive=2, - max_inclusive=candidate - 2) + max_inclusive=candidate - 2, + randfunc=randfunc) assert(2 <= base <= candidate - 2) # Step 4.3-4.4 diff --git a/frozen_deps/Cryptodome/Math/_IntegerBase.py b/frozen_deps/Cryptodome/Math/_IntegerBase.py index f8cf333..03dd591 100644 --- a/frozen_deps/Cryptodome/Math/_IntegerBase.py +++ b/frozen_deps/Cryptodome/Math/_IntegerBase.py @@ -51,12 +51,12 @@ class IntegerBase(ABC): pass @abc.abstractmethod - def to_bytes(self, block_size=0): + def to_bytes(self, block_size=0, byteorder='big'): pass @staticmethod @abc.abstractmethod - def from_bytes(byte_string): + def from_bytes(byte_string, byteorder='big'): pass # Relations @@ -228,7 +228,7 @@ class IntegerBase(ABC): @abc.abstractmethod def jacobi_symbol(a, n): pass - + @staticmethod def _tonelli_shanks(n, p): """Tonelli-shanks algorithm for computing the square root @@ -390,3 +390,23 @@ class IntegerBase(ABC): ) return norm_candidate + min_inclusive + @staticmethod + @abc.abstractmethod + def _mult_modulo_bytes(term1, term2, modulus): + """Multiply two integers, take the modulo, and encode as big endian. + This specialized method is used for RSA decryption. + + Args: + term1 : integer + The first term of the multiplication, non-negative. + term2 : integer + The second term of the multiplication, non-negative. + modulus: integer + The modulus, a positive odd number. + :Returns: + A byte string, with the result of the modular multiplication + encoded in big endian mode. + It is as long as the modulus would be, with zero padding + on the left if needed. + """ + pass diff --git a/frozen_deps/Cryptodome/Math/_IntegerBase.pyi b/frozen_deps/Cryptodome/Math/_IntegerBase.pyi index 3f534db..ea23532 100644 --- a/frozen_deps/Cryptodome/Math/_IntegerBase.pyi +++ b/frozen_deps/Cryptodome/Math/_IntegerBase.pyi @@ -4,12 +4,14 @@ RandFunc = Callable[[int],int] class IntegerBase: + def __init__(self, value: Union[IntegerBase, int]): ... + def __int__(self) -> int: ... def __str__(self) -> str: ... def __repr__(self) -> str: ... - def to_bytes(self, block_size: Optional[int]=0) -> bytes: ... + def to_bytes(self, block_size: Optional[int]=0, byteorder: str= ...) -> bytes: ... @staticmethod - def from_bytes(byte_string: bytes) -> IntegerBase: ... + def from_bytes(byte_string: bytes, byteorder: Optional[str] = ...) -> IntegerBase: ... def __eq__(self, term: object) -> bool: ... def __ne__(self, term: object) -> bool: ... def __lt__(self, term: Union[IntegerBase, int]) -> bool: ... @@ -58,4 +60,8 @@ class IntegerBase: def random(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... @classmethod def random_range(cls, **kwargs: Union[int,RandFunc]) -> IntegerBase : ... + @staticmethod + def _mult_modulo_bytes(term1: Union[IntegerBase, int], + term2: Union[IntegerBase, int], + modulus: Union[IntegerBase, int]) -> bytes: ... diff --git a/frozen_deps/Cryptodome/Math/_IntegerCustom.py b/frozen_deps/Cryptodome/Math/_IntegerCustom.py index b626014..20eadca 100644 --- a/frozen_deps/Cryptodome/Math/_IntegerCustom.py +++ b/frozen_deps/Cryptodome/Math/_IntegerCustom.py @@ -41,12 +41,18 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, from Cryptodome.Random.random import getrandbits c_defs = """ -int monty_pow(const uint8_t *base, - const uint8_t *exp, - const uint8_t *modulus, - uint8_t *out, - size_t len, - uint64_t seed); +int monty_pow(uint8_t *out, + const uint8_t *base, + const uint8_t *exp, + const uint8_t *modulus, + size_t len, + uint64_t seed); + +int monty_multiply(uint8_t *out, + const uint8_t *term1, + const uint8_t *term2, + const uint8_t *modulus, + size_t len); """ @@ -57,7 +63,14 @@ implementation = {"library": "custom", "api": backend} class IntegerCustom(IntegerNative): @staticmethod - def from_bytes(byte_string): + def from_bytes(byte_string, byteorder='big'): + if byteorder == 'big': + pass + elif byteorder == 'little': + byte_string = bytearray(byte_string) + byte_string.reverse() + else: + raise ValueError("Incorrect byteorder") return IntegerCustom(bytes_to_long(byte_string)) def inplace_pow(self, exponent, modulus=None): @@ -109,3 +122,41 @@ class IntegerCustom(IntegerNative): result = bytes_to_long(get_raw_buffer(out)) self._value = result return self + + @staticmethod + def _mult_modulo_bytes(term1, term2, modulus): + + # With modular reduction + mod_value = int(modulus) + if mod_value < 0: + raise ValueError("Modulus must be positive") + if mod_value == 0: + raise ZeroDivisionError("Modulus cannot be zero") + + # C extension only works with odd moduli + if (mod_value & 1) == 0: + raise ValueError("Odd modulus is required") + + # C extension only works with non-negative terms smaller than modulus + if term1 >= mod_value or term1 < 0: + term1 %= mod_value + if term2 >= mod_value or term2 < 0: + term2 %= mod_value + + modulus_b = long_to_bytes(mod_value) + numbers_len = len(modulus_b) + term1_b = long_to_bytes(term1, numbers_len) + term2_b = long_to_bytes(term2, numbers_len) + out = create_string_buffer(numbers_len) + + error = _raw_montgomery.monty_multiply( + out, + term1_b, + term2_b, + modulus_b, + c_size_t(numbers_len) + ) + if error: + raise ValueError("monty_multiply failed with error: %d" % error) + + return get_raw_buffer(out) diff --git a/frozen_deps/Cryptodome/Math/_IntegerGMP.py b/frozen_deps/Cryptodome/Math/_IntegerGMP.py index c860020..f58f044 100644 --- a/frozen_deps/Cryptodome/Math/_IntegerGMP.py +++ b/frozen_deps/Cryptodome/Math/_IntegerGMP.py @@ -35,7 +35,7 @@ from Cryptodome.Util.py3compat import tobytes, is_native_int from Cryptodome.Util._raw_api import (backend, load_lib, get_raw_buffer, get_c_string, null_pointer, create_string_buffer, - c_ulong, c_size_t) + c_ulong, c_size_t, c_uint8_ptr) from ._IntegerBase import IntegerBase @@ -43,12 +43,14 @@ gmp_defs = """typedef unsigned long UNIX_ULONG; typedef struct { int a; int b; void *c; } MPZ; typedef MPZ mpz_t[1]; typedef UNIX_ULONG mp_bitcnt_t; + void __gmpz_init (mpz_t x); void __gmpz_init_set (mpz_t rop, const mpz_t op); void __gmpz_init_set_ui (mpz_t rop, UNIX_ULONG op); - int __gmp_sscanf (const char *s, const char *fmt, ...); + + UNIX_ULONG __gmpz_get_ui (const mpz_t op); void __gmpz_set (mpz_t rop, const mpz_t op); - int __gmp_snprintf (uint8_t *buf, size_t size, const char *fmt, ...); + void __gmpz_set_ui (mpz_t rop, UNIX_ULONG op); void __gmpz_add (mpz_t rop, const mpz_t op1, const mpz_t op2); void __gmpz_add_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); void __gmpz_sub_ui (mpz_t rop, const mpz_t op1, UNIX_ULONG op2); @@ -156,28 +158,58 @@ class IntegerGMP(IntegerBase): if isinstance(value, float): raise ValueError("A floating point type is not a natural number") - self._initialized = True - if is_native_int(value): _gmp.mpz_init(self._mpz_p) - result = _gmp.gmp_sscanf(tobytes(str(value)), b"%Zd", self._mpz_p) - if result != 1: - raise ValueError("Error converting '%d'" % value) + self._initialized = True + if value == 0: + return + + tmp = new_mpz() + _gmp.mpz_init(tmp) + + try: + positive = value >= 0 + reduce = abs(value) + slots = (reduce.bit_length() - 1) // 32 + 1 + + while slots > 0: + slots = slots - 1 + _gmp.mpz_set_ui(tmp, + c_ulong(0xFFFFFFFF & (reduce >> (slots * 32)))) + _gmp.mpz_mul_2exp(tmp, tmp, c_ulong(slots * 32)) + _gmp.mpz_add(self._mpz_p, self._mpz_p, tmp) + finally: + _gmp.mpz_clear(tmp) + + if not positive: + _gmp.mpz_neg(self._mpz_p, self._mpz_p) + elif isinstance(value, IntegerGMP): _gmp.mpz_init_set(self._mpz_p, value._mpz_p) + self._initialized = True else: raise NotImplementedError + # Conversions def __int__(self): - # buf will contain the integer encoded in decimal plus the trailing - # zero, and possibly the negative sign. - # dig10(x) < log10(x) + 1 = log2(x)/log2(10) + 1 < log2(x)/3 + 1 - buf_len = _gmp.mpz_sizeinbase(self._mpz_p, 2) // 3 + 3 - buf = create_string_buffer(buf_len) + tmp = new_mpz() + _gmp.mpz_init_set(tmp, self._mpz_p) - _gmp.gmp_snprintf(buf, c_size_t(buf_len), b"%Zd", self._mpz_p) - return int(get_c_string(buf)) + try: + value = 0 + slot = 0 + while _gmp.mpz_cmp(tmp, self._zero_mpz_p) != 0: + lsb = _gmp.mpz_get_ui(tmp) & 0xFFFFFFFF + value |= lsb << (slot * 32) + _gmp.mpz_tdiv_q_2exp(tmp, tmp, c_ulong(32)) + slot = slot + 1 + finally: + _gmp.mpz_clear(tmp) + + if self < 0: + value = -value + return int(value) def __str__(self): return str(int(self)) @@ -193,7 +225,7 @@ class IntegerGMP(IntegerBase): def __index__(self): return int(self) - def to_bytes(self, block_size=0): + def to_bytes(self, block_size=0, byteorder='big'): """Convert the number into a byte string. This method encodes the number in network order and prepends @@ -204,6 +236,8 @@ class IntegerGMP(IntegerBase): block_size : integer The exact size the output byte string must have. If zero, the string has the minimal length. + byteorder : string + 'big' for big-endian integers (default), 'little' for litte-endian. :Returns: A byte string. :Raise ValueError: @@ -217,9 +251,10 @@ class IntegerGMP(IntegerBase): buf_len = (_gmp.mpz_sizeinbase(self._mpz_p, 2) + 7) // 8 if buf_len > block_size > 0: raise ValueError("Number is too big to convert to byte string" - "of prescribed length") + " of prescribed length") buf = create_string_buffer(buf_len) + _gmp.mpz_export( buf, null_pointer, # Ignore countp @@ -229,20 +264,39 @@ class IntegerGMP(IntegerBase): c_size_t(0), # No nails self._mpz_p) - return b'\x00' * max(0, block_size - buf_len) + get_raw_buffer(buf) + result = b'\x00' * max(0, block_size - buf_len) + get_raw_buffer(buf) + if byteorder == 'big': + pass + elif byteorder == 'little': + result = bytearray(result) + result.reverse() + result = bytes(result) + else: + raise ValueError("Incorrect byteorder") + return result @staticmethod - def from_bytes(byte_string): + def from_bytes(byte_string, byteorder='big'): """Convert a byte string into a number. :Parameters: byte_string : byte string The input number, encoded in network order. It can only be non-negative. + byteorder : string + 'big' for big-endian integers (default), 'little' for litte-endian. + :Return: The ``Integer`` object carrying the same value as the input. """ result = IntegerGMP(0) + if byteorder == 'big': + pass + elif byteorder == 'little': + byte_string = bytearray(byte_string) + byte_string.reverse() + else: + raise ValueError("Incorrect byteorder") _gmp.mpz_import( result._mpz_p, c_size_t(len(byte_string)), # Amount of words to read @@ -250,7 +304,7 @@ class IntegerGMP(IntegerBase): c_size_t(1), # Each word is 1 byte long 0, # Endianess within a word - not relevant c_size_t(0), # No nails - byte_string) + c_uint8_ptr(byte_string)) return result # Relations @@ -692,9 +746,29 @@ class IntegerGMP(IntegerBase): if not isinstance(n, IntegerGMP): n = IntegerGMP(n) if n <= 0 or n.is_even(): - raise ValueError("n must be positive even for the Jacobi symbol") + raise ValueError("n must be positive odd for the Jacobi symbol") return _gmp.mpz_jacobi(a._mpz_p, n._mpz_p) + @staticmethod + def _mult_modulo_bytes(term1, term2, modulus): + if not isinstance(term1, IntegerGMP): + term1 = IntegerGMP(term1) + if not isinstance(term2, IntegerGMP): + term2 = IntegerGMP(term2) + if not isinstance(modulus, IntegerGMP): + modulus = IntegerGMP(modulus) + + if modulus < 0: + raise ValueError("Modulus must be positive") + if modulus == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if (modulus & 1) == 0: + raise ValueError("Odd modulus is required") + + numbers_len = len(modulus.to_bytes()) + result = ((term1 * term2) % modulus).to_bytes(numbers_len) + return result + # Clean-up def __del__(self): diff --git a/frozen_deps/Cryptodome/Math/_IntegerNative.py b/frozen_deps/Cryptodome/Math/_IntegerNative.py index 896107f..5f768e2 100644 --- a/frozen_deps/Cryptodome/Math/_IntegerNative.py +++ b/frozen_deps/Cryptodome/Math/_IntegerNative.py @@ -30,7 +30,7 @@ from ._IntegerBase import IntegerBase -from Cryptodome.Util.number import long_to_bytes, bytes_to_long +from Cryptodome.Util.number import long_to_bytes, bytes_to_long, inverse, GCD class IntegerNative(IntegerBase): @@ -62,16 +62,31 @@ class IntegerNative(IntegerBase): def __index__(self): return int(self._value) - def to_bytes(self, block_size=0): + def to_bytes(self, block_size=0, byteorder='big'): if self._value < 0: raise ValueError("Conversion only valid for non-negative numbers") result = long_to_bytes(self._value, block_size) if len(result) > block_size > 0: raise ValueError("Value too large to encode") + if byteorder == 'big': + pass + elif byteorder == 'little': + result = bytearray(result) + result.reverse() + result = bytes(result) + else: + raise ValueError("Incorrect byteorder") return result @classmethod - def from_bytes(cls, byte_string): + def from_bytes(cls, byte_string, byteorder='big'): + if byteorder == 'big': + pass + elif byteorder == 'little': + byte_string = bytearray(byte_string) + byte_string.reverse() + else: + raise ValueError("Incorrect byteorder") return cls(bytes_to_long(byte_string)) # Relations @@ -265,13 +280,7 @@ class IntegerNative(IntegerBase): if self._value == 0: return 1 - bit_size = 0 - tmp = self._value - while tmp: - tmp >>= 1 - bit_size += 1 - - return bit_size + return self._value.bit_length() def size_in_bytes(self): return (self.size_in_bits() - 1) // 8 + 1 @@ -303,22 +312,7 @@ class IntegerNative(IntegerBase): self._value = int(source) def inplace_inverse(self, modulus): - modulus = int(modulus) - if modulus == 0: - raise ZeroDivisionError("Modulus cannot be zero") - if modulus < 0: - raise ValueError("Modulus cannot be negative") - r_p, r_n = self._value, modulus - s_p, s_n = 1, 0 - while r_n > 0: - q = r_p // r_n - r_p, r_n = r_n, r_p - q * r_n - s_p, s_n = s_n, s_p - q * s_n - if r_p != 1: - raise ValueError("No inverse value can be computed" + str(r_p)) - while s_p < 0: - s_p += modulus - self._value = s_p + self._value = inverse(self._value, int(modulus)) return self def inverse(self, modulus): @@ -327,11 +321,7 @@ class IntegerNative(IntegerBase): return result def gcd(self, term): - r_p, r_n = abs(self._value), abs(int(term)) - while r_n > 0: - q = r_p // r_n - r_p, r_n = r_n, r_p - q * r_n - return self.__class__(r_p) + return self.__class__(GCD(abs(self._value), abs(int(term)))) def lcm(self, term): term = int(term) @@ -348,7 +338,7 @@ class IntegerNative(IntegerBase): raise ValueError("n must be a positive integer") if (n & 1) == 0: - raise ValueError("n must be even for the Jacobi symbol") + raise ValueError("n must be odd for the Jacobi symbol") # Step 1 a = a % n @@ -378,3 +368,15 @@ class IntegerNative(IntegerBase): n1 = n % a1 # Step 8 return s * IntegerNative.jacobi_symbol(n1, a1) + + @staticmethod + def _mult_modulo_bytes(term1, term2, modulus): + if modulus < 0: + raise ValueError("Modulus must be positive") + if modulus == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if (modulus & 1) == 0: + raise ValueError("Odd modulus is required") + + number_len = len(long_to_bytes(modulus)) + return long_to_bytes((term1 * term2) % modulus, number_len) diff --git a/frozen_deps/Cryptodome/Math/_modexp.abi3.so b/frozen_deps/Cryptodome/Math/_modexp.abi3.so Binary files differnew file mode 100755 index 0000000..d11de72 --- /dev/null +++ b/frozen_deps/Cryptodome/Math/_modexp.abi3.so diff --git a/frozen_deps/Cryptodome/Math/_modexp.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Math/_modexp.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 9b8cd0a..0000000 --- a/frozen_deps/Cryptodome/Math/_modexp.cpython-38-x86_64-linux-gnu.so +++ /dev/null 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 <https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-108r1.pdf>`_. + + 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 Binary files differnew file mode 100755 index 0000000..baf83a8 --- /dev/null +++ b/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so diff --git a/frozen_deps/Cryptodome/Protocol/_scrypt.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Protocol/_scrypt.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index dbc8ca2..0000000 --- a/frozen_deps/Cryptodome/Protocol/_scrypt.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/PublicKey/DSA.py b/frozen_deps/Cryptodome/PublicKey/DSA.py index 2aaf864..dddd304 100644 --- a/frozen_deps/Cryptodome/PublicKey/DSA.py +++ b/frozen_deps/Cryptodome/PublicKey/DSA.py @@ -94,6 +94,8 @@ class DsaKey(object): :ivar x: Private key :vartype x: integer + + :undocumented: exportKey, publickey """ _keydata = ['y', 'g', 'p', 'q', 'x'] @@ -149,7 +151,7 @@ class DsaKey(object): def can_sign(self): # legacy return True - def publickey(self): + def public_key(self): """A matching DSA public key. Returns: @@ -332,6 +334,7 @@ class DsaKey(object): # Backward-compatibility exportKey = export_key + publickey = public_key # Methods defined in PyCryptodome that we don't support anymore @@ -449,7 +452,7 @@ def generate(bits, randfunc=None, domain=None): ## Perform consistency check on domain parameters # P and Q must be prime fmt_error = test_probable_prime(p) == COMPOSITE - fmt_error = test_probable_prime(q) == COMPOSITE + fmt_error |= test_probable_prime(q) == COMPOSITE # Verify Lagrange's theorem for sub-group fmt_error |= ((p - 1) % q) != 0 fmt_error |= g <= 1 or g >= p @@ -515,7 +518,7 @@ def construct(tup, consistency_check=True): if consistency_check: # P and Q must be prime fmt_error = test_probable_prime(key.p) == COMPOSITE - fmt_error = test_probable_prime(key.q) == COMPOSITE + fmt_error |= test_probable_prime(key.q) == COMPOSITE # Verify Lagrange's theorem for sub-group fmt_error |= ((key.p - 1) % key.q) != 0 fmt_error |= key.g <= 1 or key.g >= key.p diff --git a/frozen_deps/Cryptodome/PublicKey/DSA.pyi b/frozen_deps/Cryptodome/PublicKey/DSA.pyi index 9977a0f..354ac1f 100644 --- a/frozen_deps/Cryptodome/PublicKey/DSA.pyi +++ b/frozen_deps/Cryptodome/PublicKey/DSA.pyi @@ -9,7 +9,7 @@ class DsaKey(object): def has_private(self) -> bool: ... def can_encrypt(self) -> bool: ... # legacy def can_sign(self) -> bool: ... # legacy - def publickey(self) -> DsaKey: ... + def public_key(self) -> DsaKey: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... def __getstate__(self) -> None: ... @@ -20,6 +20,7 @@ class DsaKey(object): protection: Optional[str]=None, randfunc: Optional[RNG]=None) -> bytes: ... # Backward-compatibility exportKey = export_key + publickey = public_key def generate(bits: int, randfunc: Optional[RNG]=None, domain: Optional[Tuple[int, int, int]]=None) -> DsaKey: ... def construct(tup: Union[Tuple[int, int, int, int], Tuple[int, int, int, int, int]], consistency_check: Optional[bool]=True) -> DsaKey: ... diff --git a/frozen_deps/Cryptodome/PublicKey/ECC.py b/frozen_deps/Cryptodome/PublicKey/ECC.py index e83664b..4546742 100644 --- a/frozen_deps/Cryptodome/PublicKey/ECC.py +++ b/frozen_deps/Cryptodome/PublicKey/ECC.py @@ -31,7 +31,6 @@ from __future__ import print_function import re -import sys import struct import binascii from collections import namedtuple @@ -43,13 +42,15 @@ from Cryptodome.Math.Numbers import Integer from Cryptodome.Util.asn1 import (DerObjectId, DerOctetString, DerSequence, DerBitString) +from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, + SmartPointer, c_size_t, c_uint8_ptr, + c_ulonglong, null_pointer) + from Cryptodome.PublicKey import (_expand_subject_public_key_info, _create_subject_public_key_info, _extract_subject_public_key_info) -from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, - SmartPointer, c_size_t, c_uint8_ptr, - c_ulonglong) +from Cryptodome.Hash import SHA512, SHAKE256 from Cryptodome.Random import get_random_bytes from Cryptodome.Random.random import getrandbits @@ -70,7 +71,7 @@ int ec_ws_new_point(EcPoint **pecp, const uint8_t *y, size_t len, const EcContext *ec_ctx); -void ec_free_point(EcPoint *ecp); +void ec_ws_free_point(EcPoint *ecp); int ec_ws_get_xy(uint8_t *x, uint8_t *y, size_t len, @@ -82,17 +83,173 @@ int ec_ws_scalar(EcPoint *ecp, size_t len, uint64_t seed); int ec_ws_clone(EcPoint **pecp2, const EcPoint *ecp); -int ec_ws_copy(EcPoint *ecp1, const EcPoint *ecp2); int ec_ws_cmp(const EcPoint *ecp1, const EcPoint *ecp2); int ec_ws_neg(EcPoint *p); -int ec_ws_normalize(EcPoint *ecp); -int ec_ws_is_pai(EcPoint *ecp); """) -_Curve = namedtuple("_Curve", "p b order Gx Gy G modulus_bits oid context desc openssh") +_ed25519_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._ed25519", """ +typedef void Point; +int ed25519_new_point(Point **out, + const uint8_t x[32], + const uint8_t y[32], + size_t modsize, + const void *context); +int ed25519_clone(Point **P, const Point *Q); +void ed25519_free_point(Point *p); +int ed25519_cmp(const Point *p1, const Point *p2); +int ed25519_neg(Point *p); +int ed25519_get_xy(uint8_t *xb, uint8_t *yb, size_t modsize, Point *p); +int ed25519_double(Point *p); +int ed25519_add(Point *P1, const Point *P2); +int ed25519_scalar(Point *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); +""") + +_ed448_lib = load_pycryptodome_raw_lib("Cryptodome.PublicKey._ed448", """ +typedef void EcContext; +typedef void PointEd448; +int ed448_new_context(EcContext **pec_ctx); +void ed448_context(EcContext *ec_ctx); +void ed448_free_context(EcContext *ec_ctx); +int ed448_new_point(PointEd448 **out, + const uint8_t x[56], + const uint8_t y[56], + size_t len, + const EcContext *context); +int ed448_clone(PointEd448 **P, const PointEd448 *Q); +void ed448_free_point(PointEd448 *p); +int ed448_cmp(const PointEd448 *p1, const PointEd448 *p2); +int ed448_neg(PointEd448 *p); +int ed448_get_xy(uint8_t *xb, uint8_t *yb, size_t len, const PointEd448 *p); +int ed448_double(PointEd448 *p); +int ed448_add(PointEd448 *P1, const PointEd448 *P2); +int ed448_scalar(PointEd448 *P, const uint8_t *scalar, size_t scalar_len, uint64_t seed); +""") + + +def lib_func(ecc_obj, func_name): + if ecc_obj._curve.desc == "Ed25519": + result = getattr(_ed25519_lib, "ed25519_" + func_name) + elif ecc_obj._curve.desc == "Ed448": + result = getattr(_ed448_lib, "ed448_" + func_name) + else: + result = getattr(_ec_lib, "ec_ws_" + func_name) + return result + +# +# _curves is a database of curve parameters. Items are indexed by their +# human-friendly name, suchas "P-256". Each item has the following fields: +# - p: the prime number that defines the finite field for all modulo operations +# - b: the constant in the Short Weierstrass curve equation +# - order: the number of elements in the group with the generator below +# - Gx the affine coordinate X of the generator point +# - Gy the affine coordinate Y of the generator point +# - G the generator, as an EccPoint object +# - modulus_bits the minimum number of bits for encoding the modulus p +# - oid an ASCII string with the registered ASN.1 Object ID +# - context a raw pointer to memory holding a context for all curve operations (can be NULL) +# - desc an ASCII string describing the curve +# - openssh the ASCII string used in OpenSSH id files for public keys on this curve +# - name the ASCII string which is also a valid key in _curves + + +_Curve = namedtuple("_Curve", "p b order Gx Gy G modulus_bits oid context desc openssh name") _curves = {} +p192_names = ["p192", "NIST P-192", "P-192", "prime192v1", "secp192r1", + "nistp192"] + + +def init_p192(): + p = 0xfffffffffffffffffffffffffffffffeffffffffffffffff + b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1 + order = 0xffffffffffffffffffffffff99def836146bc9b1b4d22831 + Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012 + Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811 + + p192_modulus = long_to_bytes(p, 24) + p192_b = long_to_bytes(b, 24) + p192_order = long_to_bytes(order, 24) + + ec_p192_context = VoidPointer() + result = _ec_lib.ec_ws_new_context(ec_p192_context.address_of(), + c_uint8_ptr(p192_modulus), + c_uint8_ptr(p192_b), + c_uint8_ptr(p192_order), + c_size_t(len(p192_modulus)), + c_ulonglong(getrandbits(64)) + ) + if result: + raise ImportError("Error %d initializing P-192 context" % result) + + context = SmartPointer(ec_p192_context.get(), _ec_lib.ec_free_context) + p192 = _Curve(Integer(p), + Integer(b), + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 192, + "1.2.840.10045.3.1.1", # ANSI X9.62 / SEC2 + context, + "NIST P-192", + "ecdsa-sha2-nistp192", + "p192") + global p192_names + _curves.update(dict.fromkeys(p192_names, p192)) + + +init_p192() +del init_p192 + + +p224_names = ["p224", "NIST P-224", "P-224", "prime224v1", "secp224r1", + "nistp224"] + + +def init_p224(): + p = 0xffffffffffffffffffffffffffffffff000000000000000000000001 + b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4 + order = 0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d + Gx = 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21 + Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34 + + p224_modulus = long_to_bytes(p, 28) + p224_b = long_to_bytes(b, 28) + p224_order = long_to_bytes(order, 28) + + ec_p224_context = VoidPointer() + result = _ec_lib.ec_ws_new_context(ec_p224_context.address_of(), + c_uint8_ptr(p224_modulus), + c_uint8_ptr(p224_b), + c_uint8_ptr(p224_order), + c_size_t(len(p224_modulus)), + c_ulonglong(getrandbits(64)) + ) + if result: + raise ImportError("Error %d initializing P-224 context" % result) + + context = SmartPointer(ec_p224_context.get(), _ec_lib.ec_free_context) + p224 = _Curve(Integer(p), + Integer(b), + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 224, + "1.3.132.0.33", # SEC 2 + context, + "NIST P-224", + "ecdsa-sha2-nistp224", + "p224") + global p224_names + _curves.update(dict.fromkeys(p224_names, p224)) + + +init_p224() +del init_p224 + + p256_names = ["p256", "NIST P-256", "P-256", "prime256v1", "secp256r1", "nistp256"] @@ -127,10 +284,11 @@ def init_p256(): Integer(Gy), None, 256, - "1.2.840.10045.3.1.7", # ANSI X9.62 + "1.2.840.10045.3.1.7", # ANSI X9.62 / SEC2 context, "NIST P-256", - "ecdsa-sha2-nistp256") + "ecdsa-sha2-nistp256", + "p256") global p256_names _curves.update(dict.fromkeys(p256_names, p256)) @@ -176,7 +334,8 @@ def init_p384(): "1.3.132.0.34", # SEC 2 context, "NIST P-384", - "ecdsa-sha2-nistp384") + "ecdsa-sha2-nistp384", + "p384") global p384_names _curves.update(dict.fromkeys(p384_names, p384)) @@ -222,7 +381,8 @@ def init_p521(): "1.3.132.0.35", # SEC 2 context, "NIST P-521", - "ecdsa-sha2-nistp521") + "ecdsa-sha2-nistp521", + "p521") global p521_names _curves.update(dict.fromkeys(p521_names, p521)) @@ -231,19 +391,84 @@ init_p521() del init_p521 +ed25519_names = ["ed25519", "Ed25519"] + + +def init_ed25519(): + p = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed # 2**255 - 19 + order = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed + Gx = 0x216936d3cd6e53fec0a4e231fdd6dc5c692cc7609525a7b2c9562d608f25d51a + Gy = 0x6666666666666666666666666666666666666666666666666666666666666658 + + ed25519 = _Curve(Integer(p), + None, + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 255, + "1.3.101.112", # RFC8410 + None, + "Ed25519", # Used throughout; do not change + "ssh-ed25519", + "ed25519") + global ed25519_names + _curves.update(dict.fromkeys(ed25519_names, ed25519)) + + +init_ed25519() +del init_ed25519 + + +ed448_names = ["ed448", "Ed448"] + + +def init_ed448(): + p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff # 2**448 - 2**224 - 1 + order = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3 + Gx = 0x4f1970c66bed0ded221d15a622bf36da9e146570470f1767ea6de324a3d3a46412ae1af72ab66511433b80e18b00938e2626a82bc70cc05e + Gy = 0x693f46716eb6bc248876203756c9c7624bea73736ca3984087789c1e05a0c2d73ad3ff1ce67c39c4fdbd132c4ed7c8ad9808795bf230fa14 + + ed448_context = VoidPointer() + result = _ed448_lib.ed448_new_context(ed448_context.address_of()) + if result: + raise ImportError("Error %d initializing Ed448 context" % result) + + context = SmartPointer(ed448_context.get(), _ed448_lib.ed448_free_context) + + ed448 = _Curve(Integer(p), + None, + Integer(order), + Integer(Gx), + Integer(Gy), + None, + 448, + "1.3.101.113", # RFC8410 + context, + "Ed448", # Used throughout; do not change + None, + "ed448") + global ed448_names + _curves.update(dict.fromkeys(ed448_names, ed448)) + + +init_ed448() +del init_ed448 + + class UnsupportedEccFeature(ValueError): pass class EccPoint(object): - """A class to abstract a point over an Elliptic Curve. + """A class to model a point on an Elliptic Curve. - The class support special methods for: + The class supports operators for: * Adding two points: ``R = S + T`` * In-place addition: ``S += T`` * Negating a point: ``R = -T`` - * Comparing two points: ``if S == T: ...`` + * Comparing two points: ``if S == T: ...`` or ``if S != T: ...`` * Multiplying a point by a scalar: ``R = S*k`` * In-place multiplication by a scalar: ``T *= k`` @@ -253,7 +478,7 @@ class EccPoint(object): :ivar y: The affine Y-coordinate of the ECC point :vartype y: integer - :ivar xy: The tuple with X- and Y- coordinates + :ivar xy: The tuple with affine X- and Y- coordinates """ def __init__(self, x, y, curve="p256"): @@ -265,19 +490,26 @@ class EccPoint(object): self._curve_name = curve modulus_bytes = self.size_in_bytes() - context = self._curve.context xb = long_to_bytes(x, modulus_bytes) yb = long_to_bytes(y, modulus_bytes) if len(xb) != modulus_bytes or len(yb) != modulus_bytes: raise ValueError("Incorrect coordinate length") + new_point = lib_func(self, "new_point") + free_func = lib_func(self, "free_point") + self._point = VoidPointer() - result = _ec_lib.ec_ws_new_point(self._point.address_of(), - c_uint8_ptr(xb), - c_uint8_ptr(yb), - c_size_t(modulus_bytes), - context.get()) + try: + context = self._curve.context.get() + except AttributeError: + context = null_pointer + result = new_point(self._point.address_of(), + c_uint8_ptr(xb), + c_uint8_ptr(yb), + c_size_t(modulus_bytes), + context) + if result: if result == 15: raise ValueError("The EC point does not belong to the curve") @@ -285,26 +517,37 @@ class EccPoint(object): # Ensure that object disposal of this Python object will (eventually) # free the memory allocated by the raw library for the EC point - self._point = SmartPointer(self._point.get(), - _ec_lib.ec_free_point) + self._point = SmartPointer(self._point.get(), free_func) def set(self, point): + clone = lib_func(self, "clone") + free_func = lib_func(self, "free_point") + self._point = VoidPointer() - result = _ec_lib.ec_ws_clone(self._point.address_of(), - point._point.get()) + result = clone(self._point.address_of(), + point._point.get()) + if result: raise ValueError("Error %d while cloning an EC point" % result) - self._point = SmartPointer(self._point.get(), - _ec_lib.ec_free_point) + self._point = SmartPointer(self._point.get(), free_func) return self def __eq__(self, point): - return 0 == _ec_lib.ec_ws_cmp(self._point.get(), point._point.get()) + if not isinstance(point, EccPoint): + return False + + cmp_func = lib_func(self, "cmp") + return 0 == cmp_func(self._point.get(), point._point.get()) + + # Only needed for Python 2 + def __ne__(self, point): + return not self == point def __neg__(self): + neg_func = lib_func(self, "neg") np = self.copy() - result = _ec_lib.ec_ws_neg(np._point.get()) + result = neg_func(np._point.get()) if result: raise ValueError("Error %d while inverting an EC point" % result) return np @@ -315,13 +558,24 @@ class EccPoint(object): np = EccPoint(x, y, self._curve_name) return np + def _is_eddsa(self): + return self._curve.name in ("ed25519", "ed448") + def is_point_at_infinity(self): - """``True`` if this is the point-at-infinity.""" - return self.xy == (0, 0) + """``True`` if this is the *point-at-infinity*.""" + + if self._is_eddsa(): + return self.x == 0 + else: + return self.xy == (0, 0) def point_at_infinity(self): - """Return the point-at-infinity for the curve this point is on.""" - return EccPoint(0, 0, self._curve_name) + """Return the *point-at-infinity* for the curve.""" + + if self._is_eddsa(): + return EccPoint(0, 1, self._curve_name) + else: + return EccPoint(0, 0, self._curve_name) @property def x(self): @@ -336,10 +590,11 @@ class EccPoint(object): modulus_bytes = self.size_in_bytes() xb = bytearray(modulus_bytes) yb = bytearray(modulus_bytes) - result = _ec_lib.ec_ws_get_xy(c_uint8_ptr(xb), - c_uint8_ptr(yb), - c_size_t(modulus_bytes), - self._point.get()) + get_xy = lib_func(self, "get_xy") + result = get_xy(c_uint8_ptr(xb), + c_uint8_ptr(yb), + c_size_t(modulus_bytes), + self._point.get()) if result: raise ValueError("Error %d while encoding an EC point" % result) @@ -356,11 +611,12 @@ class EccPoint(object): def double(self): """Double this point (in-place operation). - :Return: - :class:`EccPoint` : this same object (to enable chaining) + Returns: + This same object (to enable chaining). """ - result = _ec_lib.ec_ws_double(self._point.get()) + double_func = lib_func(self, "double") + result = double_func(self._point.get()) if result: raise ValueError("Error %d while doubling an EC point" % result) return self @@ -368,7 +624,8 @@ class EccPoint(object): def __iadd__(self, point): """Add a second point to this one""" - result = _ec_lib.ec_ws_add(self._point.get(), point._point.get()) + add_func = lib_func(self, "add") + result = add_func(self._point.get(), point._point.get()) if result: if result == 16: raise ValueError("EC points are not on the same curve") @@ -385,13 +642,14 @@ class EccPoint(object): def __imul__(self, scalar): """Multiply this point by a scalar""" + scalar_func = lib_func(self, "scalar") if scalar < 0: raise ValueError("Scalar multiplication is only defined for non-negative integers") sb = long_to_bytes(scalar) - result = _ec_lib.ec_ws_scalar(self._point.get(), - c_uint8_ptr(sb), - c_size_t(len(sb)), - c_ulonglong(getrandbits(64))) + result = scalar_func(self._point.get(), + c_uint8_ptr(sb), + c_size_t(len(sb)), + c_ulonglong(getrandbits(64))) if result: raise ValueError("Error %d during scalar multiplication" % result) return self @@ -408,6 +666,16 @@ class EccPoint(object): # Last piece of initialization +p192_G = EccPoint(_curves['p192'].Gx, _curves['p192'].Gy, "p192") +p192 = _curves['p192']._replace(G=p192_G) +_curves.update(dict.fromkeys(p192_names, p192)) +del p192_G, p192, p192_names + +p224_G = EccPoint(_curves['p224'].Gx, _curves['p224'].Gy, "p224") +p224 = _curves['p224']._replace(G=p224_G) +_curves.update(dict.fromkeys(p224_names, p224)) +del p224_G, p224, p224_names + p256_G = EccPoint(_curves['p256'].Gx, _curves['p256'].Gy, "p256") p256 = _curves['p256']._replace(G=p256_G) _curves.update(dict.fromkeys(p256_names, p256)) @@ -423,20 +691,37 @@ p521 = _curves['p521']._replace(G=p521_G) _curves.update(dict.fromkeys(p521_names, p521)) del p521_G, p521, p521_names +ed25519_G = EccPoint(_curves['Ed25519'].Gx, _curves['Ed25519'].Gy, "Ed25519") +ed25519 = _curves['Ed25519']._replace(G=ed25519_G) +_curves.update(dict.fromkeys(ed25519_names, ed25519)) +del ed25519_G, ed25519, ed25519_names + +ed448_G = EccPoint(_curves['Ed448'].Gx, _curves['Ed448'].Gy, "Ed448") +ed448 = _curves['Ed448']._replace(G=ed448_G) +_curves.update(dict.fromkeys(ed448_names, ed448)) +del ed448_G, ed448, ed448_names + class EccKey(object): r"""Class defining an ECC key. Do not instantiate directly. Use :func:`generate`, :func:`construct` or :func:`import_key` instead. - :ivar curve: The name of the ECC as defined in :numref:`curve_names`. + :ivar curve: The name of the curve as defined in the `ECC table`_. :vartype curve: string - :ivar pointQ: an ECC point representating the public component + :ivar pointQ: an ECC point representating the public component. :vartype pointQ: :class:`EccPoint` - :ivar d: A scalar representating the private component + :ivar d: A scalar that represents the private component + in NIST P curves. It is smaller than the + order of the generator point. :vartype d: integer + + :ivar seed: A seed that representats the private component + in EdDSA curves + (Ed25519, 32 bytes; Ed448, 57 bytes). + :vartype seed: bytes """ def __init__(self, **kwargs): @@ -444,36 +729,84 @@ class EccKey(object): Keywords: curve : string - It must be *"p256"*, *"P-256"*, *"prime256v1"* or *"secp256r1"*. + The name of the curve. d : integer - Only for a private key. It must be in the range ``[1..order-1]``. + Mandatory for a private key one NIST P curves. + It must be in the range ``[1..order-1]``. + seed : bytes + Mandatory for a private key on the Ed25519 (32 bytes) + or Ed448 (57 bytes) curve. point : EccPoint Mandatory for a public key. If provided for a private key, the implementation will NOT check whether it matches ``d``. + + Only one parameter among ``d``, ``seed`` or ``point`` may be used. """ kwargs_ = dict(kwargs) curve_name = kwargs_.pop("curve", None) self._d = kwargs_.pop("d", None) + self._seed = kwargs_.pop("seed", None) self._point = kwargs_.pop("point", None) + if curve_name is None and self._point: + curve_name = self._point._curve_name if kwargs_: raise TypeError("Unknown parameters: " + str(kwargs_)) if curve_name not in _curves: - raise ValueError("Unsupported curve (%s)", curve_name) + raise ValueError("Unsupported curve (%s)" % curve_name) self._curve = _curves[curve_name] + self.curve = self._curve.desc + + count = int(self._d is not None) + int(self._seed is not None) - if self._d is None: + if count == 0: if self._point is None: - raise ValueError("Either private or public ECC component must be specified, not both") - else: + raise ValueError("At lest one between parameters 'point', 'd' or 'seed' must be specified") + return + + if count == 2: + raise ValueError("Parameters d and seed are mutually exclusive") + + # NIST P curves work with d, EdDSA works with seed + + if not self._is_eddsa(): + if self._seed is not None: + raise ValueError("Parameter 'seed' can only be used with Ed25519 or Ed448") self._d = Integer(self._d) if not 1 <= self._d < self._curve.order: - raise ValueError("Invalid ECC private component") - - self.curve = self._curve.desc + raise ValueError("Parameter d must be an integer smaller than the curve order") + else: + if self._d is not None: + raise ValueError("Parameter d can only be used with NIST P curves") + # RFC 8032, 5.1.5 + if self._curve.name == "ed25519": + if len(self._seed) != 32: + raise ValueError("Parameter seed must be 32 bytes long for Ed25519") + seed_hash = SHA512.new(self._seed).digest() # h + self._prefix = seed_hash[32:] + tmp = bytearray(seed_hash[:32]) + tmp[0] &= 0xF8 + tmp[31] = (tmp[31] & 0x7F) | 0x40 + # RFC 8032, 5.2.5 + elif self._curve.name == "ed448": + if len(self._seed) != 57: + raise ValueError("Parameter seed must be 57 bytes long for Ed448") + seed_hash = SHAKE256.new(self._seed).read(114) # h + self._prefix = seed_hash[57:] + tmp = bytearray(seed_hash[:57]) + tmp[0] &= 0xFC + tmp[55] |= 0x80 + tmp[56] = 0 + self._d = Integer.from_bytes(tmp, byteorder='little') + + def _is_eddsa(self): + return self._curve.desc in ("Ed25519", "Ed448") def __eq__(self, other): + if not isinstance(other, EccKey): + return False + if other.has_private() != self.has_private(): return False @@ -481,7 +814,10 @@ class EccKey(object): def __repr__(self): if self.has_private(): - extra = ", d=%d" % int(self._d) + if self._is_eddsa(): + extra = ", seed=%s" % tostr(binascii.hexlify(self._seed)) + else: + extra = ", d=%d" % int(self._d) else: extra = "" x, y = self.pointQ.xy @@ -492,6 +828,7 @@ class EccKey(object): return self._d is not None + # ECDSA def _sign(self, z, k): assert 0 < k < self._curve.order @@ -506,6 +843,7 @@ class EccKey(object): s = inv_blind_k * (blind * z + blind_d * r) % order return (r, s) + # ECDSA def _verify(self, z, rs): order = self._curve.order sinv = rs[1].inverse(order) @@ -520,6 +858,12 @@ class EccKey(object): return self._d @property + def seed(self): + if not self.has_private(): + raise ValueError("This is not a private ECC key") + return self._seed + + @property def pointQ(self): if self._point is None: self._point = self._curve.G * self._d @@ -534,9 +878,12 @@ class EccKey(object): return EccKey(curve=self._curve.desc, point=self.pointQ) - def _export_subjectPublicKeyInfo(self, compress): + def _export_SEC1(self, compress): + if self._is_eddsa(): + raise ValueError("SEC1 format is unsupported for EdDSA curves") # See 2.2 in RFC5480 and 2.3.3 in SEC1 + # # The first byte is: # - 0x02: compressed, only X-coordinate, Y-coordinate is even # - 0x03: compressed, only X-coordinate, Y-coordinate is odd @@ -547,20 +894,45 @@ class EccKey(object): modulus_bytes = self.pointQ.size_in_bytes() if compress: - first_byte = 2 + self.pointQ.y.is_odd() - public_key = (bchr(first_byte) + + if self.pointQ.y.is_odd(): + first_byte = b'\x03' + else: + first_byte = b'\x02' + public_key = (first_byte + self.pointQ.x.to_bytes(modulus_bytes)) else: public_key = (b'\x04' + self.pointQ.x.to_bytes(modulus_bytes) + self.pointQ.y.to_bytes(modulus_bytes)) + return public_key + + def _export_eddsa(self): + x, y = self.pointQ.xy + if self._curve.name == "ed25519": + result = bytearray(y.to_bytes(32, byteorder='little')) + result[31] = ((x & 1) << 7) | result[31] + elif self._curve.name == "ed448": + result = bytearray(y.to_bytes(57, byteorder='little')) + result[56] = (x & 1) << 7 + else: + raise ValueError("Not an EdDSA key to export") + return bytes(result) + + def _export_subjectPublicKeyInfo(self, compress): + if self._is_eddsa(): + oid = self._curve.oid + public_key = self._export_eddsa() + params = None + else: + oid = "1.2.840.10045.2.1" # unrestricted + public_key = self._export_SEC1(compress) + params = DerObjectId(self._curve.oid) - unrestricted_oid = "1.2.840.10045.2.1" - return _create_subject_public_key_info(unrestricted_oid, + return _create_subject_public_key_info(oid, public_key, - DerObjectId(self._curve.oid)) + params) - def _export_private_der(self, include_ec_params=True): + def _export_rfc5915_private_der(self, include_ec_params=True): assert self.has_private() @@ -591,13 +963,20 @@ class EccKey(object): from Cryptodome.IO import PKCS8 if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs: - raise ValueError("At least the 'protection' parameter should be present") + raise ValueError("At least the 'protection' parameter must be present") + + if self._is_eddsa(): + oid = self._curve.oid + private_key = DerOctetString(self._seed).encode() + params = None + else: + oid = "1.2.840.10045.2.1" # unrestricted + private_key = self._export_rfc5915_private_der(include_ec_params=False) + params = DerObjectId(self._curve.oid) - unrestricted_oid = "1.2.840.10045.2.1" - private_key = self._export_private_der(include_ec_params=False) result = PKCS8.wrap(private_key, - unrestricted_oid, - key_params=DerObjectId(self._curve.oid), + oid, + key_params=params, **kwargs) return result @@ -610,7 +989,7 @@ class EccKey(object): def _export_private_pem(self, passphrase, **kwargs): from Cryptodome.IO import PEM - encoded_der = self._export_private_der() + encoded_der = self._export_rfc5915_private_der() return PEM.encode(encoded_der, "EC PRIVATE KEY", passphrase, **kwargs) def _export_private_clear_pkcs8_in_clear_pem(self): @@ -633,19 +1012,27 @@ class EccKey(object): raise ValueError("Cannot export OpenSSH private keys") desc = self._curve.openssh - modulus_bytes = self.pointQ.size_in_bytes() - if compress: - first_byte = 2 + self.pointQ.y.is_odd() - public_key = (bchr(first_byte) + - self.pointQ.x.to_bytes(modulus_bytes)) + if desc is None: + raise ValueError("Cannot export %s keys as OpenSSH" % self._curve.name) + elif desc == "ssh-ed25519": + public_key = self._export_eddsa() + comps = (tobytes(desc), tobytes(public_key)) else: - public_key = (b'\x04' + - self.pointQ.x.to_bytes(modulus_bytes) + - self.pointQ.y.to_bytes(modulus_bytes)) + modulus_bytes = self.pointQ.size_in_bytes() + + if compress: + first_byte = 2 + self.pointQ.y.is_odd() + public_key = (bchr(first_byte) + + self.pointQ.x.to_bytes(modulus_bytes)) + else: + public_key = (b'\x04' + + self.pointQ.x.to_bytes(modulus_bytes) + + self.pointQ.y.to_bytes(modulus_bytes)) + + middle = desc.split("-")[2] + comps = (tobytes(desc), tobytes(middle), public_key) - middle = desc.split("-")[2] - comps = (tobytes(desc), tobytes(middle), public_key) blob = b"".join([struct.pack(">I", len(x)) + x for x in comps]) return desc + " " + tostr(binascii.b2a_base64(blob)) @@ -654,7 +1041,7 @@ class EccKey(object): Args: format (string): - The format to use for encoding the key: + The output format: - ``'DER'``. The key will be encoded in ASN.1 DER format (binary). For a public key, the ASN.1 ``subjectPublicKeyInfo`` structure @@ -665,29 +1052,54 @@ class EccKey(object): - ``'PEM'``. The key will be encoded in a PEM_ envelope (ASCII). - ``'OpenSSH'``. The key will be encoded in the OpenSSH_ format (ASCII, public keys only). + - ``'SEC1'``. The public key (i.e., the EC point) will be encoded + into ``bytes`` according to Section 2.3.3 of `SEC1`_ + (which is a subset of the older X9.62 ITU standard). + Only for NIST P-curves. + - ``'raw'``. The public key will be encoded as ``bytes``, + without any metadata. - passphrase (byte string or string): - The passphrase to use for protecting the private key. + * For NIST P-curves: equivalent to ``'SEC1'``. + * For EdDSA curves: ``bytes`` in the format defined in `RFC8032`_. - use_pkcs8 (boolean): - Only relevant for private keys. + passphrase (bytes or string): + (*Private keys only*) The passphrase to protect the + private key. + use_pkcs8 (boolean): + (*Private keys only*) If ``True`` (default and recommended), the `PKCS#8`_ representation - will be used. + will be used. It must be ``True`` for EdDSA curves. - If ``False``, the much weaker `PEM encryption`_ mechanism will be used. + If ``False`` and a passphrase is present, the obsolete PEM + encryption will be used. protection (string): When a private key is exported with password-protection and PKCS#8 (both ``DER`` and ``PEM`` formats), this parameter MUST be - present and be a valid algorithm supported by :mod:`Cryptodome.IO.PKCS8`. - It is recommended to use ``PBKDF2WithHMAC-SHA1AndAES128-CBC``. + present, + For all possible protection schemes, + refer to :ref:`the encryption parameters of PKCS#8<enc_params>`. + It is recommended to use ``'PBKDF2WithHMAC-SHA5126AndAES128-CBC'``. compress (boolean): - If ``True``, a more compact representation of the public key - with the X-coordinate only is used. + If ``True``, the method returns a more compact representation + of the public key, with the X-coordinate only. - If ``False`` (default), the full public key will be exported. + If ``False`` (default), the method returns the full public key. + + This parameter is ignored for EdDSA curves, as compression is + mandatory. + + prot_params (dict): + When a private key is exported with password-protection + and PKCS#8 (both ``DER`` and ``PEM`` formats), this dictionary + contains the parameters to use to derive the encryption key + from the passphrase. + For all possible values, + refer to :ref:`the encryption parameters of PKCS#8<enc_params>`. + The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2, + and ``{'iteration_count':131072}`` for scrypt. .. warning:: If you don't provide a passphrase, the private key will be @@ -700,18 +1112,18 @@ class EccKey(object): .. _PEM: http://www.ietf.org/rfc/rfc1421.txt .. _`PEM encryption`: http://www.ietf.org/rfc/rfc1423.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt .. _OpenSSH: http://www.openssh.com/txt/rfc5656.txt .. _RFC5480: https://tools.ietf.org/html/rfc5480 - .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt + .. _SEC1: https://www.secg.org/sec1-v2.pdf Returns: - A multi-line string (for PEM and OpenSSH) or bytes (for DER) with the encoded key. + A multi-line string (for ``'PEM'`` and ``'OpenSSH'``) or + ``bytes`` (for ``'DER'``, ``'SEC1'``, and ``'raw'``) with the encoded key. """ args = kwargs.copy() ext_format = args.pop("format") - if ext_format not in ("PEM", "DER", "OpenSSH"): + if ext_format not in ("PEM", "DER", "OpenSSH", "SEC1", "raw"): raise ValueError("Unknown format '%s'" % ext_format) compress = args.pop("compress", False) @@ -723,6 +1135,13 @@ class EccKey(object): if not passphrase: raise ValueError("Empty passphrase") use_pkcs8 = args.pop("use_pkcs8", True) + + if not use_pkcs8: + if self._is_eddsa(): + raise ValueError("'pkcs8' must be True for EdDSA curves") + if 'protection' in args: + raise ValueError("'protection' is only supported for PKCS#8") + if ext_format == "PEM": if use_pkcs8: if passphrase: @@ -738,9 +1157,10 @@ class EccKey(object): if use_pkcs8: return self._export_pkcs8(passphrase=passphrase, **args) else: - return self._export_private_der() + return self._export_rfc5915_private_der() else: - raise ValueError("Private keys cannot be exported in OpenSSH format") + raise ValueError("Private keys cannot be exported " + "in the '%s' format" % ext_format) else: # Public key if args: raise ValueError("Unexpected parameters: '%s'" % args) @@ -748,6 +1168,13 @@ class EccKey(object): return self._export_public_pem(compress) elif ext_format == "DER": return self._export_subjectPublicKeyInfo(compress) + elif ext_format == "SEC1": + return self._export_SEC1(compress) + elif ext_format == "raw": + if self._curve.name in ('ed25519', 'ed448'): + return self._export_eddsa() + else: + return self._export_SEC1(compress) else: return self._export_openssh(compress) @@ -758,7 +1185,7 @@ def generate(**kwargs): Args: curve (string): - Mandatory. It must be a curve name defined in :numref:`curve_names`. + Mandatory. It must be a curve name defined in the `ECC table`_. randfunc (callable): Optional. The RNG to read randomness from. @@ -771,30 +1198,46 @@ def generate(**kwargs): if kwargs: raise TypeError("Unknown parameters: " + str(kwargs)) - d = Integer.random_range(min_inclusive=1, - max_exclusive=curve.order, - randfunc=randfunc) + if _curves[curve_name].name == "ed25519": + seed = randfunc(32) + new_key = EccKey(curve=curve_name, seed=seed) + elif _curves[curve_name].name == "ed448": + seed = randfunc(57) + new_key = EccKey(curve=curve_name, seed=seed) + else: + d = Integer.random_range(min_inclusive=1, + max_exclusive=curve.order, + randfunc=randfunc) + new_key = EccKey(curve=curve_name, d=d) - return EccKey(curve=curve_name, d=d) + return new_key def construct(**kwargs): """Build a new ECC key (private or public) starting from some base components. - Args: + In most cases, you will already have an existing key + which you can read in with :func:`import_key` instead + of this function. + Args: curve (string): - Mandatory. It must be a curve name defined in :numref:`curve_names`. + Mandatory. The name of the elliptic curve, as defined in the `ECC table`_. d (integer): - Only for a private key. It must be in the range ``[1..order-1]``. + Mandatory for a private key and a NIST P-curve (e.g., P-256): + the integer in the range ``[1..order-1]`` that represents the key. + + seed (bytes): + Mandatory for a private key and an EdDSA curve. + It must be 32 bytes for Ed25519, and 57 bytes for Ed448. point_x (integer): - Mandatory for a public key. X coordinate (affine) of the ECC point. + Mandatory for a public key: the X coordinate (affine) of the ECC point. point_y (integer): - Mandatory for a public key. Y coordinate (affine) of the ECC point. + Mandatory for a public key: the Y coordinate (affine) of the ECC point. Returns: :class:`EccKey` : a new ECC key object @@ -812,29 +1255,39 @@ def construct(**kwargs): # ValueError is raised if the point is not on the curve kwargs["point"] = EccPoint(point_x, point_y, curve_name) + new_key = EccKey(**kwargs) + # Validate that the private key matches the public one - d = kwargs.get("d", None) - if d is not None and "point" in kwargs: - pub_key = curve.G * d + # because EccKey will not do that automatically + if new_key.has_private() and 'point' in kwargs: + pub_key = curve.G * new_key.d if pub_key.xy != (point_x, point_y): raise ValueError("Private and public ECC keys do not match") - return EccKey(**kwargs) + return new_key -def _import_public_der(curve_oid, ec_point): +def _import_public_der(ec_point, curve_oid=None, curve_name=None): """Convert an encoded EC point into an EccKey object + ec_point: byte string with the EC point (SEC1-encoded) + curve_oid: string with the name the curve curve_name: string with the OID of the curve - ec_point: byte string with the EC point (not DER encoded) + + Either curve_id or curve_name must be specified """ - for curve_name, curve in _curves.items(): - if curve.oid == curve_oid: + for _curve_name, curve in _curves.items(): + if curve_oid and curve.oid == curve_oid: + break + if curve_name == _curve_name: break else: - raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) + if curve_oid: + raise UnsupportedEccFeature("Unsupported ECC curve (OID: %s)" % curve_oid) + else: + raise UnsupportedEccFeature("Unsupported ECC curve (%s)" % curve_name) # See 2.2 in RFC5480 and 2.3.3 in SEC1 # The first byte is: @@ -854,11 +1307,12 @@ def _import_public_der(curve_oid, ec_point): x = Integer.from_bytes(ec_point[1:modulus_bytes+1]) y = Integer.from_bytes(ec_point[modulus_bytes+1:]) # Compressed point - elif point_type in (0x02, 0x3): + elif point_type in (0x02, 0x03): if len(ec_point) != (1 + modulus_bytes): raise ValueError("Incorrect EC point length") x = Integer.from_bytes(ec_point[1:]) - y = (x**3 - x*3 + curve.b).sqrt(curve.p) # Short Weierstrass + # Right now, we only support Short Weierstrass curves + y = (x**3 - x*3 + curve.b).sqrt(curve.p) if point_type == 0x02 and y.is_odd(): y = curve.p - y if point_type == 0x03 and y.is_even(): @@ -866,7 +1320,7 @@ def _import_public_der(curve_oid, ec_point): else: raise ValueError("Incorrect EC point encoding") - return construct(curve=curve_name, point_x=x, point_y=y) + return construct(curve=_curve_name, point_x=x, point_y=y) def _import_subjectPublicKeyInfo(encoded, *kwargs): @@ -877,38 +1331,51 @@ def _import_subjectPublicKeyInfo(encoded, *kwargs): # Parse the generic subjectPublicKeyInfo structure oid, ec_point, params = _expand_subject_public_key_info(encoded) - # ec_point must be an encoded OCTET STRING - # params is encoded ECParameters - - # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any - # distiction for now. - - # Restrictions can be captured in the key usage certificate - # extension - unrestricted_oid = "1.2.840.10045.2.1" - ecdh_oid = "1.3.132.1.12" - ecmqv_oid = "1.3.132.1.13" + nist_p_oids = ( + "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted) + "1.3.132.1.12", # id-ecDH + "1.3.132.1.13" # id-ecMQV + ) + eddsa_oids = { + "1.3.101.112": ("Ed25519", _import_ed25519_public_key), # id-Ed25519 + "1.3.101.113": ("Ed448", _import_ed448_public_key) # id-Ed448 + } + + if oid in nist_p_oids: + # See RFC5480 + + # Parameters are mandatory and encoded as ECParameters + # ECParameters ::= CHOICE { + # namedCurve OBJECT IDENTIFIER + # -- implicitCurve NULL + # -- specifiedCurve SpecifiedECDomain + # } + # implicitCurve and specifiedCurve are not supported (as per RFC) + if not params: + raise ValueError("Missing ECC parameters for ECC OID %s" % oid) + try: + curve_oid = DerObjectId().decode(params).value + except ValueError: + raise ValueError("Error decoding namedCurve") - if oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid): - raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % oid) + # ECPoint ::= OCTET STRING + return _import_public_der(ec_point, curve_oid=curve_oid) - # Parameters are mandatory for all three types - if not params: - raise ValueError("Missing ECC parameters") + elif oid in eddsa_oids: + # See RFC8410 + curve_name, import_eddsa_public_key = eddsa_oids[oid] - # ECParameters ::= CHOICE { - # namedCurve OBJECT IDENTIFIER - # -- implicitCurve NULL - # -- specifiedCurve SpecifiedECDomain - # } - # - # implicitCurve and specifiedCurve are not supported (as per RFC) - curve_oid = DerObjectId().decode(params).value + # Parameters must be absent + if params: + raise ValueError("Unexpected ECC parameters for ECC OID %s" % oid) - return _import_public_der(curve_oid, ec_point) + x, y = import_eddsa_public_key(ec_point) + return construct(point_x=x, point_y=y, curve=curve_name) + else: + raise UnsupportedEccFeature("Unsupported ECC OID: %s" % oid) -def _import_private_der(encoded, passphrase, curve_oid=None): +def _import_rfc5915_der(encoded, passphrase, curve_oid=None): # See RFC5915 https://tools.ietf.org/html/rfc5915 # @@ -947,9 +1414,9 @@ def _import_private_der(encoded, passphrase, curve_oid=None): d = Integer.from_bytes(scalar_bytes) # Decode public key (if any) - if len(private_key) == 4: - public_key_enc = DerBitString(explicit=1).decode(private_key[3]).value - public_key = _import_public_der(curve_oid, public_key_enc) + if len(private_key) > 2: + public_key_enc = DerBitString(explicit=1).decode(private_key[-1]).value + public_key = _import_public_der(public_key_enc, curve_oid=curve_oid) point_x = public_key.pointQ.x point_y = public_key.pointQ.y else: @@ -961,28 +1428,30 @@ def _import_private_der(encoded, passphrase, curve_oid=None): def _import_pkcs8(encoded, passphrase): from Cryptodome.IO import PKCS8 - # From RFC5915, Section 1: - # - # Distributing an EC private key with PKCS#8 [RFC5208] involves including: - # a) id-ecPublicKey, id-ecDH, or id-ecMQV (from [RFC5480]) with the - # namedCurve as the parameters in the privateKeyAlgorithm field; and - # b) ECPrivateKey in the PrivateKey field, which is an OCTET STRING. - algo_oid, private_key, params = PKCS8.unwrap(encoded, passphrase) - # We accept id-ecPublicKey, id-ecDH, id-ecMQV without making any - # distiction for now. - unrestricted_oid = "1.2.840.10045.2.1" - ecdh_oid = "1.3.132.1.12" - ecmqv_oid = "1.3.132.1.13" - - if algo_oid not in (unrestricted_oid, ecdh_oid, ecmqv_oid): + nist_p_oids = ( + "1.2.840.10045.2.1", # id-ecPublicKey (unrestricted) + "1.3.132.1.12", # id-ecDH + "1.3.132.1.13" # id-ecMQV + ) + eddsa_oids = { + "1.3.101.112": "Ed25519", # id-Ed25519 + "1.3.101.113": "Ed448", # id-Ed448 + } + + if algo_oid in nist_p_oids: + curve_oid = DerObjectId().decode(params).value + return _import_rfc5915_der(private_key, passphrase, curve_oid) + elif algo_oid in eddsa_oids: + if params is not None: + raise ValueError("EdDSA ECC private key must not have parameters") + curve_oid = None + seed = DerOctetString().decode(private_key).payload + return construct(curve=eddsa_oids[algo_oid], seed=seed) + else: raise UnsupportedEccFeature("Unsupported ECC purpose (OID: %s)" % algo_oid) - curve_oid = DerObjectId().decode(params).value - - return _import_private_der(private_key, passphrase, curve_oid) - def _import_x509_cert(encoded, *kwargs): @@ -1007,7 +1476,7 @@ def _import_der(encoded, passphrase): pass try: - return _import_private_der(encoded, passphrase) + return _import_rfc5915_der(encoded, passphrase) except UnsupportedEccFeature as err: raise err except (ValueError, TypeError, IndexError): @@ -1024,22 +1493,49 @@ def _import_der(encoded, passphrase): def _import_openssh_public(encoded): - keystring = binascii.a2b_base64(encoded.split(b' ')[1]) + parts = encoded.split(b' ') + if len(parts) not in (2, 3): + raise ValueError("Not an openssh public key") - keyparts = [] - while len(keystring) > 4: - lk = struct.unpack(">I", keystring[:4])[0] - keyparts.append(keystring[4:4 + lk]) - keystring = keystring[4 + lk:] + try: + keystring = binascii.a2b_base64(parts[1]) + + keyparts = [] + while len(keystring) > 4: + lk = struct.unpack(">I", keystring[:4])[0] + keyparts.append(keystring[4:4 + lk]) + keystring = keystring[4 + lk:] + + if parts[0] != keyparts[0]: + raise ValueError("Mismatch in openssh public key") + + # NIST P curves + if parts[0].startswith(b"ecdsa-sha2-"): + + for curve_name, curve in _curves.items(): + if curve.openssh is None: + continue + if not curve.openssh.startswith("ecdsa-sha2"): + continue + middle = tobytes(curve.openssh.split("-")[2]) + if keyparts[1] == middle: + break + else: + raise ValueError("Unsupported ECC curve: " + middle) - for curve_name, curve in _curves.items(): - middle = tobytes(curve.openssh.split("-")[2]) - if keyparts[1] == middle: - break - else: - raise ValueError("Unsupported ECC curve") + ecc_key = _import_public_der(keyparts[2], curve_oid=curve.oid) + + # EdDSA + elif parts[0] == b"ssh-ed25519": + x, y = _import_ed25519_public_key(keyparts[1]) + ecc_key = construct(curve="Ed25519", point_x=x, point_y=y) + else: + raise ValueError("Unsupported SSH key type: " + parts[0]) - return _import_public_der(curve.oid, keyparts[2]) + except (IndexError, TypeError, binascii.Error): + raise ValueError("Error parsing SSH key type: " + parts[0]) + + return ecc_key def _import_openssh_private_ecc(data, password): @@ -1047,51 +1543,168 @@ def _import_openssh_private_ecc(data, password): from ._openssh import (import_openssh_private_generic, read_bytes, read_string, check_padding) - ssh_name, decrypted = import_openssh_private_generic(data, password) + key_type, decrypted = import_openssh_private_generic(data, password) + + eddsa_keys = { + "ssh-ed25519": ("Ed25519", _import_ed25519_public_key, 32), + } + + # https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-04 + if key_type.startswith("ecdsa-sha2"): - name, decrypted = read_string(decrypted) - if name not in _curves: - raise UnsupportedEccFeature("Unsupported ECC curve %s" % name) - curve = _curves[name] - modulus_bytes = (curve.modulus_bits + 7) // 8 + ecdsa_curve_name, decrypted = read_string(decrypted) + if ecdsa_curve_name not in _curves: + raise UnsupportedEccFeature("Unsupported ECC curve %s" % ecdsa_curve_name) + curve = _curves[ecdsa_curve_name] + modulus_bytes = (curve.modulus_bits + 7) // 8 - public_key, decrypted = read_bytes(decrypted) + public_key, decrypted = read_bytes(decrypted) - if bord(public_key[0]) != 4: - raise ValueError("Only uncompressed OpenSSH EC keys are supported") - if len(public_key) != 2 * modulus_bytes + 1: - raise ValueError("Incorrect public key length") + if bord(public_key[0]) != 4: + raise ValueError("Only uncompressed OpenSSH EC keys are supported") + if len(public_key) != 2 * modulus_bytes + 1: + raise ValueError("Incorrect public key length") - point_x = Integer.from_bytes(public_key[1:1+modulus_bytes]) - point_y = Integer.from_bytes(public_key[1+modulus_bytes:]) - point = EccPoint(point_x, point_y, curve=name) + point_x = Integer.from_bytes(public_key[1:1+modulus_bytes]) + point_y = Integer.from_bytes(public_key[1+modulus_bytes:]) - private_key, decrypted = read_bytes(decrypted) - d = Integer.from_bytes(private_key) + private_key, decrypted = read_bytes(decrypted) + d = Integer.from_bytes(private_key) + + params = {'d': d, 'curve': ecdsa_curve_name} + + elif key_type in eddsa_keys: + + curve_name, import_eddsa_public_key, seed_len = eddsa_keys[key_type] + + public_key, decrypted = read_bytes(decrypted) + point_x, point_y = import_eddsa_public_key(public_key) + + private_public_key, decrypted = read_bytes(decrypted) + seed = private_public_key[:seed_len] + + params = {'seed': seed, 'curve': curve_name} + else: + raise ValueError("Unsupport SSH agent key type:" + key_type) _, padded = read_string(decrypted) # Comment check_padding(padded) - return EccKey(curve=name, d=d, point=point) + return construct(point_x=point_x, point_y=point_y, **params) + + +def _import_ed25519_public_key(encoded): + """Import an Ed25519 ECC public key, encoded as raw bytes as described + in RFC8032_. + + Args: + encoded (bytes): + The Ed25519 public key to import. It must be 32 bytes long. + + Returns: + :class:`EccKey` : a new ECC key object + + Raises: + ValueError: when the given key cannot be parsed. + + .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032 + """ + + if len(encoded) != 32: + raise ValueError("Incorrect length. Only Ed25519 public keys are supported.") + + p = Integer(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed) # 2**255 - 19 + d = 37095705934669439343138083508754565189542113879843219016388785533085940283555 + y = bytearray(encoded) + x_lsb = y[31] >> 7 + y[31] &= 0x7F + point_y = Integer.from_bytes(y, byteorder='little') + if point_y >= p: + raise ValueError("Invalid Ed25519 key (y)") + if point_y == 1: + return 0, 1 -def import_key(encoded, passphrase=None): + u = (point_y**2 - 1) % p + v = ((point_y**2 % p) * d + 1) % p + try: + v_inv = v.inverse(p) + x2 = (u * v_inv) % p + point_x = Integer._tonelli_shanks(x2, p) + if (point_x & 1) != x_lsb: + point_x = p - point_x + except ValueError: + raise ValueError("Invalid Ed25519 public key") + return point_x, point_y + + +def _import_ed448_public_key(encoded): + """Import an Ed448 ECC public key, encoded as raw bytes as described + in RFC8032_. + + Args: + encoded (bytes): + The Ed448 public key to import. It must be 57 bytes long. + + Returns: + :class:`EccKey` : a new ECC key object + + Raises: + ValueError: when the given key cannot be parsed. + + .. _RFC8032: https://datatracker.ietf.org/doc/html/rfc8032 + """ + + if len(encoded) != 57: + raise ValueError("Incorrect length. Only Ed448 public keys are supported.") + + p = Integer(0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff) # 2**448 - 2**224 - 1 + d = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6756 + + y = encoded[:56] + x_lsb = bord(encoded[56]) >> 7 + point_y = Integer.from_bytes(y, byteorder='little') + if point_y >= p: + raise ValueError("Invalid Ed448 key (y)") + if point_y == 1: + return 0, 1 + + u = (point_y**2 - 1) % p + v = ((point_y**2 % p) * d - 1) % p + try: + v_inv = v.inverse(p) + x2 = (u * v_inv) % p + point_x = Integer._tonelli_shanks(x2, p) + if (point_x & 1) != x_lsb: + point_x = p - point_x + except ValueError: + raise ValueError("Invalid Ed448 public key") + return point_x, point_y + + +def import_key(encoded, passphrase=None, curve_name=None): """Import an ECC key (public or private). Args: encoded (bytes or multi-line string): The ECC key to import. + The function will try to automatically detect the right format. - An ECC **public** key can be: + Supported formats for an ECC **public** key: - - An X.509 certificate, binary (DER) or ASCII (PEM) - - An X.509 ``subjectPublicKeyInfo``, binary (DER) or ASCII (PEM) - - An OpenSSH line (e.g. the content of ``~/.ssh/id_ecdsa``, ASCII) + * X.509 certificate: binary (DER) or ASCII (PEM). + * X.509 ``subjectPublicKeyInfo``: binary (DER) or ASCII (PEM). + * SEC1_ (or X9.62), as ``bytes``. NIST P curves only. + You must also provide the ``curve_name`` (with a value from the `ECC table`_) + * OpenSSH line, defined in RFC5656_ and RFC8709_ (ASCII). + This is normally the content of files like ``~/.ssh/id_ecdsa.pub``. - An ECC **private** key can be: + Supported formats for an ECC **private** key: - - In binary format (DER, see section 3 of `RFC5915`_ or `PKCS#8`_) - - In ASCII format (PEM or `OpenSSH 6.5+`_) + * A binary ``ECPrivateKey`` structure, as defined in `RFC5915`_ (DER). + NIST P curves only. + * A `PKCS#8`_ structure (or the more recent Asymmetric Key Package, RFC5958_): binary (DER) or ASCII (PEM). + * `OpenSSH 6.5`_ and newer versions (ASCII). Private keys can be in the clear or password-protected. @@ -1099,9 +1712,21 @@ def import_key(encoded, passphrase=None): passphrase (byte string): The passphrase to use for decrypting a private key. - Encryption may be applied protected at the PEM level or at the PKCS#8 level. + Encryption may be applied protected at the PEM level (not recommended) + or at the PKCS#8 level (recommended). This parameter is ignored if the key in input is not encrypted. + curve_name (string): + For a SEC1 encoding only. This is the name of the curve, + as defined in the `ECC table`_. + + .. note:: + + To import EdDSA private and public keys, when encoded as raw ``bytes``, use: + + * :func:`Cryptodome.Signature.eddsa.import_public_key`, or + * :func:`Cryptodome.Signature.eddsa.import_private_key`. + Returns: :class:`EccKey` : a new ECC key object @@ -1109,11 +1734,15 @@ def import_key(encoded, passphrase=None): ValueError: when the given key cannot be parsed (possibly because the pass phrase is wrong). - .. _RFC1421: http://www.ietf.org/rfc/rfc1421.txt - .. _RFC1423: http://www.ietf.org/rfc/rfc1423.txt - .. _RFC5915: http://www.ietf.org/rfc/rfc5915.txt - .. _`PKCS#8`: http://www.ietf.org/rfc/rfc5208.txt - .. _`OpenSSH 6.5+`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf + .. _RFC1421: https://datatracker.ietf.org/doc/html/rfc1421 + .. _RFC1423: https://datatracker.ietf.org/doc/html/rfc1423 + .. _RFC5915: https://datatracker.ietf.org/doc/html/rfc5915 + .. _RFC5656: https://datatracker.ietf.org/doc/html/rfc5656 + .. _RFC8709: https://datatracker.ietf.org/doc/html/rfc8709 + .. _RFC5958: https://datatracker.ietf.org/doc/html/rfc5958 + .. _`PKCS#8`: https://datatracker.ietf.org/doc/html/rfc5208 + .. _`OpenSSH 6.5`: https://flak.tedunangst.com/post/new-openssh-key-format-and-bcrypt-pbkdf + .. _SEC1: https://www.secg.org/sec1-v2.pdf """ from Cryptodome.IO import PEM @@ -1135,12 +1764,11 @@ def import_key(encoded, passphrase=None): # Remove any EC PARAMETERS section # Ignore its content because the curve type must be already given in the key - if sys.version_info[:2] != (2, 6): - ecparams_start = "-----BEGIN EC PARAMETERS-----" - ecparams_end = "-----END EC PARAMETERS-----" - text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "", - text_encoded, - flags=re.DOTALL) + ecparams_start = "-----BEGIN EC PARAMETERS-----" + ecparams_end = "-----END EC PARAMETERS-----" + text_encoded = re.sub(ecparams_start + ".*?" + ecparams_end, "", + text_encoded, + flags=re.DOTALL) der_encoded, marker, enc_flag = PEM.decode(text_encoded, passphrase) if enc_flag: @@ -1154,13 +1782,19 @@ def import_key(encoded, passphrase=None): return result # OpenSSH - if encoded.startswith(b'ecdsa-sha2-'): + if encoded.startswith((b'ecdsa-sha2-', b'ssh-ed25519')): return _import_openssh_public(encoded) # DER if len(encoded) > 0 and bord(encoded[0]) == 0x30: return _import_der(encoded, passphrase) + # SEC1 + if len(encoded) > 0 and bord(encoded[0]) in (0x02, 0x03, 0x04): + if curve_name is None: + raise ValueError("No curve name was provided") + return _import_public_der(encoded, curve_name=curve_name) + raise ValueError("ECC key format is not supported") diff --git a/frozen_deps/Cryptodome/PublicKey/ECC.pyi b/frozen_deps/Cryptodome/PublicKey/ECC.pyi index b38b337..e3c4ed5 100644 --- a/frozen_deps/Cryptodome/PublicKey/ECC.pyi +++ b/frozen_deps/Cryptodome/PublicKey/ECC.pyi @@ -1,12 +1,24 @@ -from typing import Union, Callable, Optional, NamedTuple, List, Tuple, Dict, NamedTuple, Any +from __future__ import annotations + +from typing import Union, Callable, Optional, Tuple, Dict, NamedTuple, Any, overload, Literal +from typing_extensions import TypedDict, Unpack, NotRequired from Cryptodome.Math.Numbers import Integer +from Cryptodome.IO._PBES import ProtParams RNG = Callable[[int], bytes] -class UnsupportedEccFeature(ValueError): ... + +class UnsupportedEccFeature(ValueError): + ... + + class EccPoint(object): - def __init__(self, x: Union[int, Integer], y: Union[int, Integer], curve: Optional[str] = ...) -> None: ... + def __init__(self, + x: Union[int, Integer], + y: Union[int, Integer], + curve: Optional[str] = ...) -> None: ... + def set(self, point: EccPoint) -> EccPoint: ... def __eq__(self, point: object) -> bool: ... def __neg__(self) -> EccPoint: ... @@ -27,6 +39,15 @@ class EccPoint(object): def __imul__(self, scalar: int) -> EccPoint: ... def __mul__(self, scalar: int) -> EccPoint: ... + +class ExportParams(TypedDict): + passphrase: NotRequired[Union[bytes, str]] + use_pkcs8: NotRequired[bool] + protection: NotRequired[str] + compress: NotRequired[bool] + prot_params: NotRequired[ProtParams] + + class EccKey(object): curve: str def __init__(self, *, curve: str = ..., d: int = ..., point: EccPoint = ...) -> None: ... @@ -38,7 +59,18 @@ class EccKey(object): @property def pointQ(self) -> EccPoint: ... def public_key(self) -> EccKey: ... - def export_key(self, **kwargs: Union[str, bytes, bool]) -> str: ... + + @overload + def export_key(self, + *, + format: Literal['PEM', 'OpenSSH'], + **kwargs: Unpack[ExportParams]) -> str: ... + + @overload + def export_key(self, + *, + format: Literal['DER', 'SEC1', 'raw'], + **kwargs: Unpack[ExportParams]) -> bytes: ... _Curve = NamedTuple("_Curve", [('p', Integer), @@ -51,12 +83,20 @@ _Curve = NamedTuple("_Curve", [('p', Integer), ('oid', str), ('context', Any), ('desc', str), - ('openssh', str), + ('openssh', Union[str, None]), ]) -_curves : Dict[str, _Curve] +_curves: Dict[str, _Curve] def generate(**kwargs: Union[str, RNG]) -> EccKey: ... def construct(**kwargs: Union[str, int]) -> EccKey: ... -def import_key(encoded: Union[bytes, str], passphrase: Optional[str]=None) -> EccKey: ... + + +def import_key(encoded: Union[bytes, str], + passphrase: Optional[str] = None, + curve_name: Optional[str] = None) -> EccKey: ... + + +def _import_ed25519_public_key(encoded: bytes) -> EccKey: ... +def _import_ed448_public_key(encoded: bytes) -> EccKey: ... diff --git a/frozen_deps/Cryptodome/PublicKey/RSA.py b/frozen_deps/Cryptodome/PublicKey/RSA.py index 27331ca..9a27c36 100644 --- a/frozen_deps/Cryptodome/PublicKey/RSA.py +++ b/frozen_deps/Cryptodome/PublicKey/RSA.py @@ -37,7 +37,8 @@ import struct from Cryptodome import Random from Cryptodome.Util.py3compat import tobytes, bord, tostr -from Cryptodome.Util.asn1 import DerSequence +from Cryptodome.Util.asn1 import DerSequence, DerNull +from Cryptodome.Util.number import bytes_to_long from Cryptodome.Math.Numbers import Integer from Cryptodome.Math.Primality import (test_probable_prime, @@ -49,7 +50,7 @@ from Cryptodome.PublicKey import (_expand_subject_public_key_info, class RsaKey(object): - r"""Class defining an actual RSA key. + r"""Class defining an RSA key, private or public. Do not instantiate directly. Use :func:`generate`, :func:`construct` or :func:`import_key` instead. @@ -68,8 +69,14 @@ class RsaKey(object): :ivar q: Second factor of the RSA modulus :vartype q: integer - :ivar u: Chinese remainder component (:math:`p^{-1} \text{mod } q`) - :vartype q: integer + :ivar invp: Chinese remainder component (:math:`p^{-1} \text{mod } q`) + :vartype invp: integer + + :ivar invq: Chinese remainder component (:math:`q^{-1} \text{mod } p`) + :vartype invq: integer + + :ivar u: Same as ``invp`` + :vartype u: integer """ def __init__(self, **kwargs): @@ -101,6 +108,7 @@ class RsaKey(object): if input_set == private_set: self._dp = self._d % (self._p - 1) # = (e⁻¹) mod (p-1) self._dq = self._d % (self._q - 1) # = (e⁻¹) mod (q-1) + self._invq = None # will be computed on demand @property def n(self): @@ -129,6 +137,30 @@ class RsaKey(object): return int(self._q) @property + def dp(self): + if not self.has_private(): + raise AttributeError("No CRT component 'dp' available for public keys") + return int(self._dp) + + @property + def dq(self): + if not self.has_private(): + raise AttributeError("No CRT component 'dq' available for public keys") + return int(self._dq) + + @property + def invq(self): + if not self.has_private(): + raise AttributeError("No CRT component 'invq' available for public keys") + if self._invq is None: + self._invq = self._q.inverse(self._p) + return int(self._invq) + + @property + def invp(self): + return self.u + + @property def u(self): if not self.has_private(): raise AttributeError("No CRT component 'u' available for public keys") @@ -147,7 +179,7 @@ class RsaKey(object): raise ValueError("Plaintext too large") return int(pow(Integer(plaintext), self._e, self._n)) - def _decrypt(self, ciphertext): + def _decrypt_to_bytes(self, ciphertext): if not 0 <= ciphertext < self._n: raise ValueError("Ciphertext too large") if not self.has_private(): @@ -164,13 +196,19 @@ class RsaKey(object): m2 = pow(cp, self._dq, self._q) h = ((m2 - m1) * self._u) % self._q mp = h * self._p + m1 - # Step 4: Compute m = m**(r-1) mod n - result = (r.inverse(self._n) * mp) % self._n - # Verify no faults occurred - if ciphertext != pow(result, self._e, self._n): - raise ValueError("Fault detected in RSA decryption") + # Step 4: Compute m = m' * (r**(-1)) mod n + # then encode into a big endian byte string + result = Integer._mult_modulo_bytes( + r.inverse(self._n), + mp, + self._n) return result + def _decrypt(self, ciphertext): + """Legacy private method""" + + return bytes_to_long(self._decrypt_to_bytes(ciphertext)) + def has_private(self): """Whether this is an RSA private key""" @@ -182,7 +220,7 @@ class RsaKey(object): def can_sign(self): # legacy return True - def publickey(self): + def public_key(self): """A matching RSA public key. Returns: @@ -223,67 +261,76 @@ class RsaKey(object): return "%s RSA key at 0x%X" % (key_type, id(self)) def export_key(self, format='PEM', passphrase=None, pkcs=1, - protection=None, randfunc=None): + protection=None, randfunc=None, prot_params=None): """Export this RSA key. - Args: + Keyword Args: format (string): - The format to use for wrapping the key: + The desired output format: - - *'PEM'*. (*Default*) Text encoding, done according to `RFC1421`_/`RFC1423`_. - - *'DER'*. Binary encoding. - - *'OpenSSH'*. Textual encoding, done according to OpenSSH specification. + - ``'PEM'``. (default) Text output, according to `RFC1421`_/`RFC1423`_. + - ``'DER'``. Binary output. + - ``'OpenSSH'``. Text output, according to the OpenSSH specification. Only suitable for public keys (not private keys). - passphrase (string): - (*For private keys only*) The pass phrase used for protecting the output. + Note that PEM contains a DER structure. + + passphrase (bytes or string): + (*Private keys only*) The passphrase to protect the + private key. pkcs (integer): - (*For private keys only*) The ASN.1 structure to use for - serializing the key. Note that even in case of PEM - encoding, there is an inner ASN.1 DER structure. + (*Private keys only*) The standard to use for + serializing the key: PKCS#1 or PKCS#8. - With ``pkcs=1`` (*default*), the private key is encoded in a - simple `PKCS#1`_ structure (``RSAPrivateKey``). + With ``pkcs=1`` (*default*), the private key is encoded with a + simple `PKCS#1`_ structure (``RSAPrivateKey``). The key cannot be + securely encrypted. - With ``pkcs=8``, the private key is encoded in a `PKCS#8`_ structure - (``PrivateKeyInfo``). + With ``pkcs=8``, the private key is encoded with a `PKCS#8`_ structure + (``PrivateKeyInfo``). PKCS#8 offers the best ways to securely + encrypt the key. .. note:: This parameter is ignored for a public key. - For DER and PEM, an ASN.1 DER ``SubjectPublicKeyInfo`` - structure is always used. + For DER and PEM, the output is always an + ASN.1 DER ``SubjectPublicKeyInfo`` structure. protection (string): (*For private keys only*) - The encryption scheme to use for protecting the private key. + The encryption scheme to use for protecting the private key + using the passphrase. - If ``None`` (default), the behavior depends on :attr:`format`: + You can only specify a value if ``pkcs=8``. + For all possible protection schemes, + refer to :ref:`the encryption parameters of PKCS#8<enc_params>`. + The recommended value is + ``'PBKDF2WithHMAC-SHA512AndAES256-CBC'``. - - For *'DER'*, the *PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC* - scheme is used. The following operations are performed: + If ``None`` (default), the behavior depends on :attr:`format`: - 1. A 16 byte Triple DES key is derived from the passphrase - using :func:`Cryptodome.Protocol.KDF.PBKDF2` with 8 bytes salt, - and 1 000 iterations of :mod:`Cryptodome.Hash.HMAC`. - 2. The private key is encrypted using CBC. - 3. The encrypted key is encoded according to PKCS#8. + - if ``format='PEM'``, the obsolete PEM encryption scheme is used. + It is based on MD5 for key derivation, and 3DES for encryption. - - For *'PEM'*, the obsolete PEM encryption scheme is used. - It is based on MD5 for key derivation, and Triple DES for encryption. + - if ``format='DER'``, the ``'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'`` + scheme is used. - Specifying a value for :attr:`protection` is only meaningful for PKCS#8 - (that is, ``pkcs=8``) and only if a pass phrase is present too. + prot_params (dict): + (*For private keys only*) - The supported schemes for PKCS#8 are listed in the - :mod:`Cryptodome.IO.PKCS8` module (see :attr:`wrap_algo` parameter). + The parameters to use to derive the encryption key + from the passphrase. ``'protection'`` must be also specified. + For all possible values, + refer to :ref:`the encryption parameters of PKCS#8<enc_params>`. + The recommendation is to use ``{'iteration_count':21000}`` for PBKDF2, + and ``{'iteration_count':131072}`` for scrypt. randfunc (callable): A function that provides random bytes. Only used for PEM encoding. The default is :func:`Cryptodome.Random.get_random_bytes`. Returns: - byte string: the encoded key + bytes: the encoded key Raises: ValueError:when the format is unknown or when you try to encrypt a private @@ -337,19 +384,25 @@ class RsaKey(object): if format == 'PEM' and protection is None: key_type = 'PRIVATE KEY' - binary_key = PKCS8.wrap(binary_key, oid, None) + binary_key = PKCS8.wrap(binary_key, oid, None, + key_params=DerNull()) else: key_type = 'ENCRYPTED PRIVATE KEY' if not protection: + if prot_params: + raise ValueError("'protection' parameter must be set") protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC' binary_key = PKCS8.wrap(binary_key, oid, - passphrase, protection) + passphrase, protection, + prot_params=prot_params, + key_params=DerNull()) passphrase = None else: key_type = "PUBLIC KEY" binary_key = _create_subject_public_key_info(oid, DerSequence([self.n, - self.e]) + self.e]), + DerNull() ) if format == 'DER': @@ -363,28 +416,41 @@ class RsaKey(object): raise ValueError("Unknown key format '%s'. Cannot export the RSA key." % format) # Backward compatibility - exportKey = export_key + def exportKey(self, *args, **kwargs): + """:meta private:""" + return self.export_key(*args, **kwargs) + + def publickey(self): + """:meta private:""" + return self.public_key() # Methods defined in PyCryptodome that we don't support anymore def sign(self, M, K): + """:meta private:""" raise NotImplementedError("Use module Cryptodome.Signature.pkcs1_15 instead") def verify(self, M, signature): + """:meta private:""" raise NotImplementedError("Use module Cryptodome.Signature.pkcs1_15 instead") def encrypt(self, plaintext, K): + """:meta private:""" raise NotImplementedError("Use module Cryptodome.Cipher.PKCS1_OAEP instead") def decrypt(self, ciphertext): + """:meta private:""" raise NotImplementedError("Use module Cryptodome.Cipher.PKCS1_OAEP instead") def blind(self, M, B): + """:meta private:""" raise NotImplementedError def unblind(self, M, B): + """:meta private:""" raise NotImplementedError def size(self): + """:meta private:""" raise NotImplementedError @@ -402,6 +468,7 @@ def generate(bits, randfunc=None, e=65537): Key length, or size (in bits) of the RSA modulus. It must be at least 1024, but **2048 is recommended.** The FIPS standard only defines 1024, 2048 and 3072. + Keyword Args: randfunc (callable): Function that returns random bytes. The default is :func:`Cryptodome.Random.get_random_bytes`. @@ -499,6 +566,7 @@ def construct(rsa_components, consistency_check=True): 5. Second factor of *n* (*q*). Optional. 6. CRT coefficient *q*, that is :math:`p^{-1} \text{mod }q`. Optional. + Keyword Args: consistency_check (boolean): If ``True``, the library will verify that the provided components fulfil the main RSA properties. diff --git a/frozen_deps/Cryptodome/PublicKey/RSA.pyi b/frozen_deps/Cryptodome/PublicKey/RSA.pyi index e4d0369..85f6c4a 100644 --- a/frozen_deps/Cryptodome/PublicKey/RSA.pyi +++ b/frozen_deps/Cryptodome/PublicKey/RSA.pyi @@ -1,4 +1,7 @@ -from typing import Callable, Union, Tuple, Optional +from typing import Callable, Union, Tuple, Optional, overload, Literal + +from Cryptodome.Math.Numbers import Integer +from Cryptodome.IO._PBES import ProtParams __all__ = ['generate', 'construct', 'import_key', 'RsaKey', 'oid'] @@ -7,6 +10,7 @@ RNG = Callable[[int], bytes] class RsaKey(object): def __init__(self, **kwargs: int) -> None: ... + @property def n(self) -> int: ... @property @@ -19,28 +23,52 @@ class RsaKey(object): def q(self) -> int: ... @property def u(self) -> int: ... + @property + def invp(self) -> int: ... + @property + def invq(self) -> int: ... + def size_in_bits(self) -> int: ... def size_in_bytes(self) -> int: ... def has_private(self) -> bool: ... def can_encrypt(self) -> bool: ... # legacy def can_sign(self) -> bool:... # legacy - def publickey(self) -> RsaKey: ... + def public_key(self) -> RsaKey: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, other: object) -> bool: ... def __getstate__(self) -> None: ... def __repr__(self) -> str: ... def __str__(self) -> str: ... - def export_key(self, format: Optional[str]="PEM", passphrase: Optional[str]=None, pkcs: Optional[int]=1, - protection: Optional[str]=None, randfunc: Optional[RNG]=None) -> bytes: ... + + @overload + def export_key(self, + format: Optional[str]="PEM", + passphrase: Optional[str]=None, + pkcs: Optional[int]=1, + protection: Optional[str]=None, + randfunc: Optional[RNG]=None + ) -> bytes: ... + @overload + def export_key(self, *, + format: Optional[str]="PEM", + passphrase: str, + pkcs: Literal[8], + protection: str, + randfunc: Optional[RNG]=None, + prot_params: ProtParams, + ) -> bytes: ... # Backward compatibility exportKey = export_key + publickey = public_key + +Int = Union[int, Integer] def generate(bits: int, randfunc: Optional[RNG]=None, e: Optional[int]=65537) -> RsaKey: ... -def construct(rsa_components: Union[Tuple[int, int], # n, e - Tuple[int, int, int], # n, e, d - Tuple[int, int, int, int, int], # n, e, d, p, q - Tuple[int, int, int, int, int, int]], # n, e, d, p, q, crt_q +def construct(rsa_components: Union[Tuple[Int, Int], # n, e + Tuple[Int, Int, Int], # n, e, d + Tuple[Int, Int, Int, Int, Int], # n, e, d, p, q + Tuple[Int, Int, Int, Int, Int, Int]], # n, e, d, p, q, crt_q consistency_check: Optional[bool]=True) -> RsaKey: ... def import_key(extern_key: Union[str, bytes], passphrase: Optional[str]=None) -> RsaKey: ... diff --git a/frozen_deps/Cryptodome/PublicKey/__init__.py b/frozen_deps/Cryptodome/PublicKey/__init__.py index 4d019bf..99b67a4 100644 --- a/frozen_deps/Cryptodome/PublicKey/__init__.py +++ b/frozen_deps/Cryptodome/PublicKey/__init__.py @@ -60,17 +60,16 @@ def _expand_subject_public_key_info(encoded): return algo_oid.value, spk, algo_params -def _create_subject_public_key_info(algo_oid, secret_key, params=None): +def _create_subject_public_key_info(algo_oid, public_key, params): if params is None: - params = DerNull() - - spki = DerSequence([ - DerSequence([ - DerObjectId(algo_oid), - params]), - DerBitString(secret_key) - ]) + algorithm = DerSequence([DerObjectId(algo_oid)]) + else: + algorithm = DerSequence([DerObjectId(algo_oid), params]) + + spki = DerSequence([algorithm, + DerBitString(public_key) + ]) return spki.encode() diff --git a/frozen_deps/Cryptodome/PublicKey/_ec_ws.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/PublicKey/_ec_ws.abi3.so Binary files differindex fba01e8..b1272d2 100755 --- a/frozen_deps/Cryptodome/PublicKey/_ec_ws.cpython-38-x86_64-linux-gnu.so +++ b/frozen_deps/Cryptodome/PublicKey/_ec_ws.abi3.so diff --git a/frozen_deps/Cryptodome/PublicKey/_ed25519.abi3.so b/frozen_deps/Cryptodome/PublicKey/_ed25519.abi3.so Binary files differnew file mode 100755 index 0000000..e047bcb --- /dev/null +++ b/frozen_deps/Cryptodome/PublicKey/_ed25519.abi3.so diff --git a/frozen_deps/Cryptodome/PublicKey/_ed448.abi3.so b/frozen_deps/Cryptodome/PublicKey/_ed448.abi3.so Binary files differnew file mode 100755 index 0000000..da7209a --- /dev/null +++ b/frozen_deps/Cryptodome/PublicKey/_ed448.abi3.so diff --git a/frozen_deps/Cryptodome/PublicKey/_x25519.abi3.so b/frozen_deps/Cryptodome/PublicKey/_x25519.abi3.so Binary files differnew file mode 100755 index 0000000..dbb00d5 --- /dev/null +++ b/frozen_deps/Cryptodome/PublicKey/_x25519.abi3.so diff --git a/frozen_deps/Cryptodome/Random/random.pyi b/frozen_deps/Cryptodome/Random/random.pyi index f873c4a..9b7cf7e 100644 --- a/frozen_deps/Cryptodome/Random/random.pyi +++ b/frozen_deps/Cryptodome/Random/random.pyi @@ -1,13 +1,15 @@ -from typing import Callable, Tuple, Union, Sequence, Any, Optional +from typing import Callable, Tuple, Union, Sequence, Any, Optional, TypeVar __all__ = ['StrongRandom', 'getrandbits', 'randrange', 'randint', 'choice', 'shuffle', 'sample'] +T = TypeVar('T') + class StrongRandom(object): def __init__(self, rng: Optional[Any]=None, randfunc: Optional[Callable]=None) -> None: ... # TODO What is rng? def getrandbits(self, k: int) -> int: ... def randrange(self, start: int, stop: int = ..., step: int = ...) -> int: ... def randint(self, a: int, b: int) -> int: ... - def choice(self, seq: Sequence) -> object: ... + def choice(self, seq: Sequence[T]) -> T: ... def shuffle(self, x: Sequence) -> None: ... def sample(self, population: Sequence, k: int) -> list: ... diff --git a/frozen_deps/Cryptodome/Signature/DSS.py b/frozen_deps/Cryptodome/Signature/DSS.py index 3dcbeb4..67f23ac 100644 --- a/frozen_deps/Cryptodome/Signature/DSS.py +++ b/frozen_deps/Cryptodome/Signature/DSS.py @@ -31,15 +31,15 @@ # POSSIBILITY OF SUCH DAMAGE. # =================================================================== -__all__ = ['new'] - - from Cryptodome.Util.asn1 import DerSequence from Cryptodome.Util.number import long_to_bytes from Cryptodome.Math.Numbers import Integer from Cryptodome.Hash import HMAC from Cryptodome.PublicKey.ECC import EccKey +from Cryptodome.PublicKey.DSA import DsaKey + +__all__ = ['DssSigScheme', 'new'] class DssSigScheme(object): @@ -75,24 +75,23 @@ class DssSigScheme(object): raise NotImplementedError("To be provided by subclasses") def sign(self, msg_hash): - """Produce the DSA/ECDSA signature of a message. + """Compute the DSA/ECDSA signature of a message. - :parameter msg_hash: + Args: + msg_hash (hash object): The hash that was carried out over the message. The object belongs to the :mod:`Cryptodome.Hash` package. + Under mode ``'fips-186-3'``, the hash must be a FIPS + approved secure hash (SHA-2 or SHA-3). - Under mode *'fips-186-3'*, the hash must be a FIPS - approved secure hash (SHA-1 or a member of the SHA-2 family), - of cryptographic strength appropriate for the DSA key. - For instance, a 3072/256 DSA key can only be used - in combination with SHA-512. - :type msg_hash: hash object - - :return: The signature as a *byte string* + :return: The signature as ``bytes`` :raise ValueError: if the hash algorithm is incompatible to the (EC)DSA key :raise TypeError: if the (EC)DSA key has no private half """ + if not self._key.has_private(): + raise TypeError("Private key is needed to sign") + if not self._valid_hash(msg_hash): raise ValueError("Hash is not sufficiently strong") @@ -106,7 +105,7 @@ class DssSigScheme(object): # Encode the signature into a single byte string if self._encoding == 'binary': output = b"".join([long_to_bytes(x, self._order_bytes) - for x in sig_pair]) + for x in sig_pair]) else: # Dss-sig ::= SEQUENCE { # r INTEGER, @@ -123,20 +122,15 @@ class DssSigScheme(object): def verify(self, msg_hash, signature): """Check if a certain (EC)DSA signature is authentic. - :parameter msg_hash: + Args: + msg_hash (hash object): The hash that was carried out over the message. This is an object belonging to the :mod:`Cryptodome.Hash` module. + Under mode ``'fips-186-3'``, the hash must be a FIPS + approved secure hash (SHA-2 or SHA-3). - Under mode *'fips-186-3'*, the hash must be a FIPS - approved secure hash (SHA-1 or a member of the SHA-2 family), - of cryptographic strength appropriate for the DSA key. - For instance, a 3072/256 DSA key can only be used in - combination with SHA-512. - :type msg_hash: hash object - - :parameter signature: - The signature that needs to be validated - :type signature: byte string + signature (``bytes``): + The signature that needs to be validated. :raise ValueError: if the signature is not authentic """ @@ -294,85 +288,77 @@ class FipsEcDsaSigScheme(DssSigScheme): randfunc=self._randfunc) def _valid_hash(self, msg_hash): - """Verify that SHA-[23] (256|384|512) bits are used to - match the security of P-256 (128 bits), P-384 (192 bits) - or P-521 (256 bits)""" + """Verify that the strength of the hash matches or exceeds + the strength of the EC. We fail if the hash is too weak.""" modulus_bits = self._key.pointQ.size_in_bits() - sha256 = ( "2.16.840.1.101.3.4.2.1", "2.16.840.1.101.3.4.2.8" ) - sha384 = ( "2.16.840.1.101.3.4.2.2", "2.16.840.1.101.3.4.2.9" ) - sha512 = ( "2.16.840.1.101.3.4.2.3", "2.16.840.1.101.3.4.2.10") - - if msg_hash.oid in sha256: - return modulus_bits <= 256 - elif msg_hash.oid in sha384: - return modulus_bits <= 384 - else: - return msg_hash.oid in sha512 + # SHS: SHA-2, SHA-3, truncated SHA-512 + sha224 = ("2.16.840.1.101.3.4.2.4", "2.16.840.1.101.3.4.2.7", "2.16.840.1.101.3.4.2.5") + sha256 = ("2.16.840.1.101.3.4.2.1", "2.16.840.1.101.3.4.2.8", "2.16.840.1.101.3.4.2.6") + sha384 = ("2.16.840.1.101.3.4.2.2", "2.16.840.1.101.3.4.2.9") + sha512 = ("2.16.840.1.101.3.4.2.3", "2.16.840.1.101.3.4.2.10") + shs = sha224 + sha256 + sha384 + sha512 + + try: + result = msg_hash.oid in shs + except AttributeError: + result = False + return result def new(key, mode, encoding='binary', randfunc=None): - """Create a signature object :class:`DSS_SigScheme` that + """Create a signature object :class:`DssSigScheme` that can perform (EC)DSA signature or verification. .. note:: Refer to `NIST SP 800 Part 1 Rev 4`_ (or newer release) for an overview of the recommended key lengths. - :parameter key: - The key to use for computing the signature (*private* keys only) - or verifying one: it must be either - :class:`Cryptodome.PublicKey.DSA` or :class:`Cryptodome.PublicKey.ECC`. - - For DSA keys, let ``L`` and ``N`` be the bit lengths of the modulus ``p`` - and of ``q``: the pair ``(L,N)`` must appear in the following list, - in compliance to section 4.2 of `FIPS 186-4`_: - - - (1024, 160) *legacy only; do not create new signatures with this* - - (2048, 224) *deprecated; do not create new signatures with this* - - (2048, 256) - - (3072, 256) + Args: + key (:class:`Cryptodome.PublicKey.DSA` or :class:`Cryptodome.PublicKey.ECC`): + The key to use for computing the signature (*private* keys only) + or for verifying one. + For DSA keys, let ``L`` and ``N`` be the bit lengths of the modulus ``p`` + and of ``q``: the pair ``(L,N)`` must appear in the following list, + in compliance to section 4.2 of `FIPS 186-4`_: - For ECC, only keys over P-256, P384, and P-521 are accepted. - :type key: - a key object + - (1024, 160) *legacy only; do not create new signatures with this* + - (2048, 224) *deprecated; do not create new signatures with this* + - (2048, 256) + - (3072, 256) - :parameter mode: - The parameter can take these values: + For ECC, only keys over P-224, P-256, P-384, and P-521 are accepted. - - *'fips-186-3'*. The signature generation is randomized and carried out - according to `FIPS 186-3`_: the nonce ``k`` is taken from the RNG. - - *'deterministic-rfc6979'*. The signature generation is not - randomized. See RFC6979_. - :type mode: - string + mode (string): + The parameter can take these values: - :parameter encoding: - How the signature is encoded. This value determines the output of - :meth:`sign` and the input to :meth:`verify`. + - ``'fips-186-3'``. The signature generation is randomized and carried out + according to `FIPS 186-3`_: the nonce ``k`` is taken from the RNG. + - ``'deterministic-rfc6979'``. The signature generation is not + randomized. See RFC6979_. - The following values are accepted: + encoding (string): + How the signature is encoded. This value determines the output of + :meth:`sign` and the input to :meth:`verify`. - - *'binary'* (default), the signature is the raw concatenation - of ``r`` and ``s``. It is defined in the IEEE P.1363 standard. + The following values are accepted: - For DSA, the size in bytes of the signature is ``N/4`` bytes - (e.g. 64 for ``N=256``). + - ``'binary'`` (default), the signature is the raw concatenation + of ``r`` and ``s``. It is defined in the IEEE P.1363 standard. + For DSA, the size in bytes of the signature is ``N/4`` bytes + (e.g. 64 for ``N=256``). + For ECDSA, the signature is always twice the length of a point + coordinate (e.g. 64 bytes for P-256). - For ECDSA, the signature is always twice the length of a point - coordinate (e.g. 64 bytes for P-256). + - ``'der'``, the signature is a ASN.1 DER SEQUENCE + with two INTEGERs (``r`` and ``s``). It is defined in RFC3279_. + The size of the signature is variable. - - *'der'*, the signature is a ASN.1 DER SEQUENCE - with two INTEGERs (``r`` and ``s``). It is defined in RFC3279_. - The size of the signature is variable. - :type encoding: string - - :parameter randfunc: - A function that returns random *byte strings*, of a given length. - If omitted, the internal RNG is used. - Only applicable for the *'fips-186-3'* mode. - :type randfunc: callable + randfunc (callable): + A function that returns random ``bytes``, of a given length. + If omitted, the internal RNG is used. + Only applicable for the *'fips-186-3'* mode. .. _FIPS 186-3: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf @@ -393,9 +379,13 @@ def new(key, mode, encoding='binary', randfunc=None): if isinstance(key, EccKey): order = key._curve.order private_key_attr = 'd' - else: + if key._curve.name == "ed25519": + raise ValueError("ECC key is not on a NIST P curve") + elif isinstance(key, DsaKey): order = Integer(key.q) private_key_attr = 'x' + else: + raise ValueError("Unsupported key type " + str(type(key))) if key.has_private(): private_key = getattr(key, private_key_attr) diff --git a/frozen_deps/Cryptodome/Signature/PKCS1_PSS.pyi b/frozen_deps/Cryptodome/Signature/PKCS1_PSS.pyi index 7ed68e6..e7424f5 100644 --- a/frozen_deps/Cryptodome/Signature/PKCS1_PSS.pyi +++ b/frozen_deps/Cryptodome/Signature/PKCS1_PSS.pyi @@ -1,7 +1,28 @@ -from typing import Optional, Callable +from typing import Union, Callable, Optional +from typing_extensions import Protocol from Cryptodome.PublicKey.RSA import RsaKey -from Cryptodome.Signature.pss import PSS_SigScheme -def new(rsa_key: RsaKey, mgfunc: Optional[Callable]=None, saltLen: Optional[int]=None, randfunc: Optional[Callable]=None) -> PSS_SigScheme: ... +class Hash(Protocol): + def digest(self) -> bytes: ... + def update(self, bytes) -> None: ... + + +class HashModule(Protocol): + @staticmethod + def new(data: Optional[bytes]) -> Hash: ... + + +MaskFunction = Callable[[bytes, int, Union[Hash, HashModule]], bytes] +RndFunction = Callable[[int], bytes] + +class PSS_SigScheme: + def __init__(self, key: RsaKey, mgfunc: MaskFunction, saltLen: int, randfunc: RndFunction) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_hash: Hash) -> bytes: ... + def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... + + + +def new(rsa_key: RsaKey, mgfunc: Optional[MaskFunction]=None, saltLen: Optional[int]=None, randfunc: Optional[RndFunction]=None) -> PSS_SigScheme: ... diff --git a/frozen_deps/Cryptodome/Signature/PKCS1_v1_5.pyi b/frozen_deps/Cryptodome/Signature/PKCS1_v1_5.pyi index 5851e5b..d02555c 100644 --- a/frozen_deps/Cryptodome/Signature/PKCS1_v1_5.pyi +++ b/frozen_deps/Cryptodome/Signature/PKCS1_v1_5.pyi @@ -1,6 +1,16 @@ +from typing import Optional +from typing_extensions import Protocol + from Cryptodome.PublicKey.RSA import RsaKey -from Cryptodome.Signature.pkcs1_15 import PKCS115_SigScheme +class Hash(Protocol): + def digest(self) -> bytes: ... + +class PKCS115_SigScheme: + def __init__(self, rsa_key: RsaKey) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_hash: Hash) -> bytes: ... + def verify(self, msg_hash: Hash, signature: bytes) -> bool: ... -def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ...
\ No newline at end of file +def new(rsa_key: RsaKey) -> PKCS115_SigScheme: ... diff --git a/frozen_deps/Cryptodome/Signature/__init__.py b/frozen_deps/Cryptodome/Signature/__init__.py index da028a5..11ca64c 100644 --- a/frozen_deps/Cryptodome/Signature/__init__.py +++ b/frozen_deps/Cryptodome/Signature/__init__.py @@ -33,4 +33,4 @@ A collection of standardized protocols to carry out digital signatures. """ -__all__ = ['PKCS1_v1_5', 'PKCS1_PSS', 'DSS', 'pkcs1_15', 'pss'] +__all__ = ['PKCS1_v1_5', 'PKCS1_PSS', 'DSS', 'pkcs1_15', 'pss', 'eddsa'] diff --git a/frozen_deps/Cryptodome/Signature/eddsa.py b/frozen_deps/Cryptodome/Signature/eddsa.py new file mode 100644 index 0000000..638b96b --- /dev/null +++ b/frozen_deps/Cryptodome/Signature/eddsa.py @@ -0,0 +1,343 @@ +# =================================================================== +# +# Copyright (c) 2022, Legrandin <helderijs@gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# =================================================================== + +from Cryptodome.Math.Numbers import Integer + +from Cryptodome.Hash import SHA512, SHAKE256 +from Cryptodome.Util.py3compat import bchr, is_bytes +from Cryptodome.PublicKey.ECC import (EccKey, + construct, + _import_ed25519_public_key, + _import_ed448_public_key) + + +def import_public_key(encoded): + """Create a new Ed25519 or Ed448 public key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC8032. + + Args: + encoded (bytes): + The EdDSA public key to import. + It must be 32 bytes for Ed25519, and 57 bytes for Ed448. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + if len(encoded) == 32: + x, y = _import_ed25519_public_key(encoded) + curve_name = "Ed25519" + elif len(encoded) == 57: + x, y = _import_ed448_public_key(encoded) + curve_name = "Ed448" + else: + raise ValueError("Not an EdDSA key (%d bytes)" % len(encoded)) + return construct(curve=curve_name, point_x=x, point_y=y) + + +def import_private_key(encoded): + """Create a new Ed25519 or Ed448 private key object, + starting from the key encoded as raw ``bytes``, + in the format described in RFC8032. + + Args: + encoded (bytes): + The EdDSA private key to import. + It must be 32 bytes for Ed25519, and 57 bytes for Ed448. + + Returns: + :class:`Cryptodome.PublicKey.EccKey` : a new ECC key object. + + Raises: + ValueError: when the given key cannot be parsed. + """ + + if len(encoded) == 32: + curve_name = "ed25519" + elif len(encoded) == 57: + curve_name = "ed448" + else: + raise ValueError("Incorrect length. Only EdDSA private keys are supported.") + + # Note that the private key is truly a sequence of random bytes, + # so we cannot check its correctness in any way. + + return construct(seed=encoded, curve=curve_name) + + +class EdDSASigScheme(object): + """An EdDSA signature object. + Do not instantiate directly. + Use :func:`Cryptodome.Signature.eddsa.new`. + """ + + def __init__(self, key, context): + """Create a new EdDSA object. + + Do not instantiate this object directly, + use `Cryptodome.Signature.DSS.new` instead. + """ + + self._key = key + self._context = context + self._A = key._export_eddsa() + self._order = key._curve.order + + def can_sign(self): + """Return ``True`` if this signature object can be used + for signing messages.""" + + return self._key.has_private() + + def sign(self, msg_or_hash): + """Compute the EdDSA signature of a message. + + Args: + msg_or_hash (bytes or a hash object): + The message to sign (``bytes``, in case of *PureEdDSA*) or + the hash that was carried out over the message (hash object, for *HashEdDSA*). + + The hash object must be :class:`Cryptodome.Hash.SHA512` for Ed25519, + and :class:`Cryptodome.Hash.SHAKE256` object for Ed448. + + :return: The signature as ``bytes``. It is always 64 bytes for Ed25519, and 114 bytes for Ed448. + :raise TypeError: if the EdDSA key has no private half + """ + + if not self._key.has_private(): + raise TypeError("Private key is needed to sign") + + if self._key._curve.name == "ed25519": + ph = isinstance(msg_or_hash, SHA512.SHA512Hash) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash") + eddsa_sign_method = self._sign_ed25519 + + elif self._key._curve.name == "ed448": + ph = isinstance(msg_or_hash, SHAKE256.SHAKE256_XOF) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHAKE256 hash") + eddsa_sign_method = self._sign_ed448 + + else: + raise ValueError("Incorrect curve for EdDSA") + + return eddsa_sign_method(msg_or_hash, ph) + + def _sign_ed25519(self, msg_or_hash, ph): + + if self._context or ph: + flag = int(ph) + # dom2(flag, self._context) + dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \ + bchr(len(self._context)) + self._context + else: + dom2 = b'' + + PHM = msg_or_hash.digest() if ph else msg_or_hash + + # See RFC 8032, section 5.1.6 + + # Step 2 + r_hash = SHA512.new(dom2 + self._key._prefix + PHM).digest() + r = Integer.from_bytes(r_hash, 'little') % self._order + # Step 3 + R_pk = EccKey(point=r * self._key._curve.G)._export_eddsa() + # Step 4 + k_hash = SHA512.new(dom2 + R_pk + self._A + PHM).digest() + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 5 + s = (r + k * self._key.d) % self._order + + return R_pk + s.to_bytes(32, 'little') + + def _sign_ed448(self, msg_or_hash, ph): + + flag = int(ph) + # dom4(flag, self._context) + dom4 = b'SigEd448' + bchr(flag) + \ + bchr(len(self._context)) + self._context + + PHM = msg_or_hash.read(64) if ph else msg_or_hash + + # See RFC 8032, section 5.2.6 + + # Step 2 + r_hash = SHAKE256.new(dom4 + self._key._prefix + PHM).read(114) + r = Integer.from_bytes(r_hash, 'little') % self._order + # Step 3 + R_pk = EccKey(point=r * self._key._curve.G)._export_eddsa() + # Step 4 + k_hash = SHAKE256.new(dom4 + R_pk + self._A + PHM).read(114) + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 5 + s = (r + k * self._key.d) % self._order + + return R_pk + s.to_bytes(57, 'little') + + def verify(self, msg_or_hash, signature): + """Check if an EdDSA signature is authentic. + + Args: + msg_or_hash (bytes or a hash object): + The message to verify (``bytes``, in case of *PureEdDSA*) or + the hash that was carried out over the message (hash object, for *HashEdDSA*). + + The hash object must be :class:`Cryptodome.Hash.SHA512` object for Ed25519, + and :class:`Cryptodome.Hash.SHAKE256` for Ed448. + + signature (``bytes``): + The signature that needs to be validated. + It must be 64 bytes for Ed25519, and 114 bytes for Ed448. + + :raise ValueError: if the signature is not authentic + """ + + if self._key._curve.name == "ed25519": + ph = isinstance(msg_or_hash, SHA512.SHA512Hash) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHA-512 hash") + eddsa_verify_method = self._verify_ed25519 + + elif self._key._curve.name == "ed448": + ph = isinstance(msg_or_hash, SHAKE256.SHAKE256_XOF) + if not (ph or is_bytes(msg_or_hash)): + raise TypeError("'msg_or_hash' must be bytes of a SHAKE256 hash") + eddsa_verify_method = self._verify_ed448 + + else: + raise ValueError("Incorrect curve for EdDSA") + + return eddsa_verify_method(msg_or_hash, signature, ph) + + def _verify_ed25519(self, msg_or_hash, signature, ph): + + if len(signature) != 64: + raise ValueError("The signature is not authentic (length)") + + if self._context or ph: + flag = int(ph) + dom2 = b'SigEd25519 no Ed25519 collisions' + bchr(flag) + \ + bchr(len(self._context)) + self._context + else: + dom2 = b'' + + PHM = msg_or_hash.digest() if ph else msg_or_hash + + # Section 5.1.7 + + # Step 1 + try: + R = import_public_key(signature[:32]).pointQ + except ValueError: + raise ValueError("The signature is not authentic (R)") + s = Integer.from_bytes(signature[32:], 'little') + if s > self._order: + raise ValueError("The signature is not authentic (S)") + # Step 2 + k_hash = SHA512.new(dom2 + signature[:32] + self._A + PHM).digest() + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 3 + point1 = s * 8 * self._key._curve.G + # OPTIMIZE: with double-scalar multiplication, with no SCA + # countermeasures because it is public values + point2 = 8 * R + k * 8 * self._key.pointQ + if point1 != point2: + raise ValueError("The signature is not authentic") + + def _verify_ed448(self, msg_or_hash, signature, ph): + + if len(signature) != 114: + raise ValueError("The signature is not authentic (length)") + + flag = int(ph) + # dom4(flag, self._context) + dom4 = b'SigEd448' + bchr(flag) + \ + bchr(len(self._context)) + self._context + + PHM = msg_or_hash.read(64) if ph else msg_or_hash + + # Section 5.2.7 + + # Step 1 + try: + R = import_public_key(signature[:57]).pointQ + except ValueError: + raise ValueError("The signature is not authentic (R)") + s = Integer.from_bytes(signature[57:], 'little') + if s > self._order: + raise ValueError("The signature is not authentic (S)") + # Step 2 + k_hash = SHAKE256.new(dom4 + signature[:57] + self._A + PHM).read(114) + k = Integer.from_bytes(k_hash, 'little') % self._order + # Step 3 + point1 = s * 8 * self._key._curve.G + # OPTIMIZE: with double-scalar multiplication, with no SCA + # countermeasures because it is public values + point2 = 8 * R + k * 8 * self._key.pointQ + if point1 != point2: + raise ValueError("The signature is not authentic") + + +def new(key, mode, context=None): + """Create a signature object :class:`EdDSASigScheme` that + can perform or verify an EdDSA signature. + + Args: + key (:class:`Cryptodome.PublicKey.ECC` object): + The key to use for computing the signature (*private* keys only) + or for verifying one. + The key must be on the curve ``Ed25519`` or ``Ed448``. + + mode (string): + This parameter must be ``'rfc8032'``. + + context (bytes): + Up to 255 bytes of `context <https://datatracker.ietf.org/doc/html/rfc8032#page-41>`_, + which is a constant byte string to segregate different protocols or + different applications of the same key. + """ + + if not isinstance(key, EccKey) or not key._is_eddsa(): + raise ValueError("EdDSA can only be used with EdDSA keys") + + if mode != 'rfc8032': + raise ValueError("Mode must be 'rfc8032'") + + if context is None: + context = b'' + elif len(context) > 255: + raise ValueError("Context for EdDSA must not be longer than 255 bytes") + + return EdDSASigScheme(key, context) diff --git a/frozen_deps/Cryptodome/Signature/eddsa.pyi b/frozen_deps/Cryptodome/Signature/eddsa.pyi new file mode 100644 index 0000000..809a7ad --- /dev/null +++ b/frozen_deps/Cryptodome/Signature/eddsa.pyi @@ -0,0 +1,21 @@ +from typing import Union, Optional +from typing_extensions import Protocol +from Cryptodome.PublicKey.ECC import EccKey + +class Hash(Protocol): + def digest(self) -> bytes: ... + +class XOF(Protocol): + def read(self, len: int) -> bytes: ... + +def import_public_key(encoded: bytes) -> EccKey: ... +def import_private_key(encoded: bytes) -> EccKey: ... + +class EdDSASigScheme(object): + + def __init__(self, key: EccKey, context: bytes) -> None: ... + def can_sign(self) -> bool: ... + def sign(self, msg_or_hash: Union[bytes, Hash, XOF]) -> bytes: ... + def verify(self, msg_or_hash: Union[bytes, Hash, XOF], signature: bytes) -> None: ... + +def new(key: EccKey, mode: str, context: Optional[bytes]=None) -> EdDSASigScheme: ... diff --git a/frozen_deps/Cryptodome/Signature/pkcs1_15.py b/frozen_deps/Cryptodome/Signature/pkcs1_15.py index f572f85..bdde78a 100644 --- a/frozen_deps/Cryptodome/Signature/pkcs1_15.py +++ b/frozen_deps/Cryptodome/Signature/pkcs1_15.py @@ -77,10 +77,11 @@ class PKCS115_SigScheme: em = _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k) # Step 2a (OS2IP) em_int = bytes_to_long(em) - # Step 2b (RSASP1) - m_int = self._key._decrypt(em_int) - # Step 2c (I2OSP) - signature = long_to_bytes(m_int, k) + # Step 2b (RSASP1) and Step 2c (I2OSP) + signature = self._key._decrypt_to_bytes(em_int) + # Verify no faults occurred + if em_int != pow(bytes_to_long(signature), self._key.e, self._key.n): + raise ValueError("Fault detected in RSA private key operation") return signature def verify(self, msg_hash, signature): @@ -202,7 +203,7 @@ def _EMSA_PKCS1_V1_5_ENCODE(msg_hash, emLen, with_hash_parameters=True): # We need at least 11 bytes for the remaining data: 3 fixed bytes and # at least 8 bytes of padding). if emLen<len(digestInfo)+11: - raise TypeError("Selected hash algorith has a too long digest (%d bytes)." % len(digest)) + raise TypeError("DigestInfo is too long for this RSA key (%d bytes)." % len(digestInfo)) PS = b'\xFF' * (emLen - len(digestInfo) - 3) return b'\x00\x01' + PS + b'\x00' + digestInfo diff --git a/frozen_deps/Cryptodome/Signature/pss.py b/frozen_deps/Cryptodome/Signature/pss.py index 0b05ed2..b929e26 100644 --- a/frozen_deps/Cryptodome/Signature/pss.py +++ b/frozen_deps/Cryptodome/Signature/pss.py @@ -107,10 +107,11 @@ class PSS_SigScheme: em = _EMSA_PSS_ENCODE(msg_hash, modBits-1, self._randfunc, mgf, sLen) # Step 2a (OS2IP) em_int = bytes_to_long(em) - # Step 2b (RSASP1) - m_int = self._key._decrypt(em_int) - # Step 2c (I2OSP) - signature = long_to_bytes(m_int, k) + # Step 2b (RSASP1) and Step 2c (I2OSP) + signature = self._key._decrypt_to_bytes(em_int) + # Verify no faults occurred + if em_int != pow(bytes_to_long(signature), self._key.e, self._key.n): + raise ValueError("Fault detected in RSA private key operation") return signature def verify(self, msg_hash, signature): @@ -178,7 +179,7 @@ def MGF1(mgfSeed, maskLen, hash_gen): :return: the mask, as a *byte string* """ - + T = b"" for counter in iter_range(ceil_div(maskLen, hash_gen.digest_size)): c = long_to_bytes(counter, 4) diff --git a/frozen_deps/Cryptodome/Signature/pss.pyi b/frozen_deps/Cryptodome/Signature/pss.pyi index 9ca19ea..84a960e 100644 --- a/frozen_deps/Cryptodome/Signature/pss.pyi +++ b/frozen_deps/Cryptodome/Signature/pss.pyi @@ -18,7 +18,7 @@ MaskFunction = Callable[[bytes, int, Union[Hash, HashModule]], bytes] RndFunction = Callable[[int], bytes] class PSS_SigScheme: - def __init__(self, key: RsaKey, mgfunc: RndFunction, saltLen: int, randfunc: RndFunction) -> None: ... + def __init__(self, key: RsaKey, mgfunc: MaskFunction, saltLen: int, randfunc: RndFunction) -> None: ... def can_sign(self) -> bool: ... def sign(self, msg_hash: Hash) -> bytes: ... def verify(self, msg_hash: Hash, signature: bytes) -> None: ... diff --git a/frozen_deps/Cryptodome/Util/Counter.py b/frozen_deps/Cryptodome/Util/Counter.py index 423f91f..269b5a7 100644 --- a/frozen_deps/Cryptodome/Util/Counter.py +++ b/frozen_deps/Cryptodome/Util/Counter.py @@ -45,11 +45,14 @@ def new(nbits, prefix=b"", suffix=b"", initial_value=1, little_endian=False, all used. initial_value (integer): The initial value of the counter. Default value is 1. + Its length in bits must not exceed the argument ``nbits``. little_endian (boolean): If ``True``, the counter number will be encoded in little endian format. If ``False`` (default), in big endian format. allow_wraparound (boolean): This parameter is ignored. + An ``OverflowError`` exception is always raised when the counter wraps + around to zero. Returns: An object that can be passed with the :data:`counter` parameter to a CTR mode cipher. @@ -61,6 +64,12 @@ def new(nbits, prefix=b"", suffix=b"", initial_value=1, little_endian=False, all if (nbits % 8) != 0: raise ValueError("'nbits' must be a multiple of 8") + iv_bl = initial_value.bit_length() + if iv_bl > nbits: + raise ValueError("Initial value takes %d bits but it is longer than " + "the counter (%d bits)" % + (iv_bl, nbits)) + # Ignore wraparound return {"counter_len": nbits // 8, "prefix": prefix, diff --git a/frozen_deps/Cryptodome/Util/Padding.py b/frozen_deps/Cryptodome/Util/Padding.py index 1c353d1..b525475 100644 --- a/frozen_deps/Cryptodome/Util/Padding.py +++ b/frozen_deps/Cryptodome/Util/Padding.py @@ -82,6 +82,8 @@ def unpad(padded_data, block_size, style='pkcs7'): """ pdata_len = len(padded_data) + if pdata_len == 0: + raise ValueError("Zero-length input cannot be unpadded") if pdata_len % block_size: raise ValueError("Input data is not padded") if style in ('pkcs7', 'x923'): diff --git a/frozen_deps/Cryptodome/Util/_cpuid_c.abi3.so b/frozen_deps/Cryptodome/Util/_cpuid_c.abi3.so Binary files differnew file mode 100755 index 0000000..51e31b7 --- /dev/null +++ b/frozen_deps/Cryptodome/Util/_cpuid_c.abi3.so diff --git a/frozen_deps/Cryptodome/Util/_cpuid_c.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Util/_cpuid_c.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index a555959..0000000 --- a/frozen_deps/Cryptodome/Util/_cpuid_c.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Util/_raw_api.py b/frozen_deps/Cryptodome/Util/_raw_api.py index 9423738..cd64ac8 100644 --- a/frozen_deps/Cryptodome/Util/_raw_api.py +++ b/frozen_deps/Cryptodome/Util/_raw_api.py @@ -28,6 +28,7 @@ # POSSIBILITY OF SUCH DAMAGE. # =================================================================== +import os import abc import sys from Cryptodome.Util.py3compat import byte_string @@ -50,10 +51,7 @@ else: extension_suffixes = machinery.EXTENSION_SUFFIXES # Which types with buffer interface we support (apart from byte strings) -if sys.version_info[0] == 2 and sys.version_info[1] < 7: - _buffer_type = (bytearray) -else: - _buffer_type = (bytearray, memoryview) +_buffer_type = (bytearray, memoryview) class _VoidPointer(object): @@ -69,9 +67,6 @@ class _VoidPointer(object): try: - if sys.version_info[0] == 2 and sys.version_info[1] < 7: - raise ImportError("CFFI is only supported with Python 2.7+") - # Starting from v2.18, pycparser (used by cffi for in-line ABI mode) # stops working correctly when PYOPTIMIZE==2 or the parameter -OO is # passed. In that case, we fall back to ctypes. @@ -81,6 +76,12 @@ try: if '__pypy__' not in sys.builtin_module_names and sys.flags.optimize == 2: raise ImportError("CFFI with optimize=2 fails due to pycparser bug.") + # cffi still uses PyUnicode_GetSize, which was removed in Python 3.12 + # thus leading to a crash on cffi.dlopen() + # See https://groups.google.com/u/1/g/python-cffi/c/oZkOIZ_zi5k + if sys.version_info >= (3, 12) and os.name == "nt": + raise ImportError("CFFI is not compatible with Python 3.12 on Windows") + from cffi import FFI ffi = FFI() @@ -98,7 +99,10 @@ try: @cdecl, the C function declarations. """ - lib = ffi.dlopen(name) + if hasattr(ffi, "RTLD_DEEPBIND") and not os.getenv('PYCRYPTODOME_DISABLE_DEEPBIND'): + lib = ffi.dlopen(name, ffi.RTLD_DEEPBIND) + else: + lib = ffi.dlopen(name) ffi.cdef(cdecl) return lib @@ -108,6 +112,7 @@ try: c_ulonglong = c_ulong c_uint = c_ulong + c_ubyte = c_ulong def c_size_t(x): """Convert a Python integer to size_t""" @@ -171,6 +176,11 @@ except ImportError: null_pointer = None cached_architecture = [] + def c_ubyte(c): + if not (0 <= c < 256): + raise OverflowError() + return ctypes.c_ubyte(c) + def load_lib(name, cdecl): if not cached_architecture: # platform.architecture() creates a subprocess, so caching the @@ -193,12 +203,7 @@ except ImportError: # ---- Get raw pointer --- - if sys.version_info[0] == 2 and sys.version_info[1] == 6: - # ctypes in 2.6 does not define c_ssize_t. Replacing it - # with c_size_t keeps the structure correctely laid out - _c_ssize_t = c_size_t - else: - _c_ssize_t = ctypes.c_ssize_t + _c_ssize_t = ctypes.c_ssize_t _PyBUF_SIMPLE = 0 _PyObject_GetBuffer = ctypes.pythonapi.PyObject_GetBuffer @@ -207,7 +212,7 @@ except ImportError: _c_ssize_p = ctypes.POINTER(_c_ssize_t) # See Include/object.h for CPython - # and https://github.com/pallets/click/blob/master/click/_winconsole.py + # and https://github.com/pallets/click/blob/master/src/click/_winconsole.py class _Py_buffer(ctypes.Structure): _fields_ = [ ('buf', c_void_p), @@ -235,7 +240,7 @@ except ImportError: buf = _Py_buffer() _PyObject_GetBuffer(obj, byref(buf), _PyBUF_SIMPLE) try: - buffer_type = c_ubyte * buf.len + buffer_type = ctypes.c_ubyte * buf.len return buffer_type.from_address(buf.buf) finally: _PyBuffer_Release(byref(buf)) @@ -260,7 +265,6 @@ except ImportError: return VoidPointer_ctypes() backend = "ctypes" - del ctypes class SmartPointer(object): @@ -301,27 +305,21 @@ def load_pycryptodome_raw_lib(name, cdecl): for ext in extension_suffixes: try: filename = basename + ext - return load_lib(pycryptodome_filename(dir_comps, filename), - cdecl) + full_name = pycryptodome_filename(dir_comps, filename) + if not os.path.isfile(full_name): + attempts.append("Not found '%s'" % filename) + continue + return load_lib(full_name, cdecl) except OSError as exp: - attempts.append("Trying '%s': %s" % (filename, str(exp))) + attempts.append("Cannot load '%s': %s" % (filename, str(exp))) raise OSError("Cannot load native module '%s': %s" % (name, ", ".join(attempts))) -if sys.version_info[:2] != (2, 6): - - def is_buffer(x): - """Return True if object x supports the buffer interface""" - return isinstance(x, (bytes, bytearray, memoryview)) - - def is_writeable_buffer(x): - return (isinstance(x, bytearray) or - (isinstance(x, memoryview) and not x.readonly)) - -else: +def is_buffer(x): + """Return True if object x supports the buffer interface""" + return isinstance(x, (bytes, bytearray, memoryview)) - def is_buffer(x): - return isinstance(x, (bytes, bytearray)) - def is_writeable_buffer(x): - return isinstance(x, bytearray) +def is_writeable_buffer(x): + return (isinstance(x, bytearray) or + (isinstance(x, memoryview) and not x.readonly)) diff --git a/frozen_deps/Cryptodome/Util/_strxor.abi3.so b/frozen_deps/Cryptodome/Util/_strxor.abi3.so Binary files differnew file mode 100755 index 0000000..f0f3784 --- /dev/null +++ b/frozen_deps/Cryptodome/Util/_strxor.abi3.so diff --git a/frozen_deps/Cryptodome/Util/_strxor.cpython-38-x86_64-linux-gnu.so b/frozen_deps/Cryptodome/Util/_strxor.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index ea7566c..0000000 --- a/frozen_deps/Cryptodome/Util/_strxor.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/Cryptodome/Util/asn1.py b/frozen_deps/Cryptodome/Util/asn1.py index 18e080c..36f2d72 100644 --- a/frozen_deps/Cryptodome/Util/asn1.py +++ b/frozen_deps/Cryptodome/Util/asn1.py @@ -22,13 +22,20 @@ import struct -from Cryptodome.Util.py3compat import byte_string, b, bchr, bord +from Cryptodome.Util.py3compat import byte_string, bchr, bord from Cryptodome.Util.number import long_to_bytes, bytes_to_long -__all__ = ['DerObject', 'DerInteger', 'DerOctetString', 'DerNull', - 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf'] +__all__ = ['DerObject', 'DerInteger', 'DerBoolean', 'DerOctetString', + 'DerNull', 'DerSequence', 'DerObjectId', 'DerBitString', 'DerSetOf'] +# Useful references: +# - https://luca.ntop.org/Teaching/Appunti/asn1.html +# - https://letsencrypt.org/docs/a-warm-welcome-to-asn1-and-der/ +# - https://www.zytrax.com/tech/survival/asn1.html +# - https://www.oss.com/asn1/resources/books-whitepapers-pubs/larmouth-asn1-book.pdf +# - https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf +# - https://misc.daniel-marschall.de/asn.1/oid-converter/online.php def _is_number(x, only_non_negative=False): test = 0 @@ -46,7 +53,7 @@ class BytesIO_EOF(object): def __init__(self, initial_bytes): self._buffer = initial_bytes self._index = 0 - self._bookmark = None + self._bookmark = None def set_bookmark(self): self._bookmark = self._index @@ -82,7 +89,7 @@ class DerObject(object): """Initialize the DER object according to a specific ASN.1 type. :Parameters: - asn1Id : integer + asn1Id : integer or byte The universal DER tag number for this object (e.g. 0x10 for a SEQUENCE). If None, the tag is not known yet. @@ -92,16 +99,20 @@ class DerObject(object): the content octets). If not specified, the payload is empty. - implicit : integer - The IMPLICIT tag number to use for the encoded object. + implicit : integer or byte + The IMPLICIT tag number (< 0x1F) to use for the encoded object. It overrides the universal tag *asn1Id*. + It cannot be combined with the ``explicit`` parameter. + By default, there is no IMPLICIT tag. constructed : bool True when the ASN.1 type is *constructed*. - False when it is *primitive*. + False when it is *primitive* (default). - explicit : integer - The EXPLICIT tag number to use for the encoded object. + explicit : integer or byte + The EXPLICIT tag number (< 0x1F) to use for the encoded object. + It cannot be combined with the ``implicit`` parameter. + By default, there is no EXPLICIT tag. """ if asn1Id is None: @@ -125,23 +136,26 @@ class DerObject(object): # context-spec | 1 0 (default for IMPLICIT/EXPLICIT) # private | 1 1 # + + constructed_bit = 0x20 if constructed else 0x00 + if None not in (explicit, implicit): raise ValueError("Explicit and implicit tags are" " mutually exclusive") if implicit is not None: - self._tag_octet = 0x80 | 0x20 * constructed | self._convertTag(implicit) - return - - if explicit is not None: - self._tag_octet = 0xA0 | self._convertTag(explicit) - self._inner_tag_octet = 0x20 * constructed | asn1Id - return - - self._tag_octet = 0x20 * constructed | asn1Id + # IMPLICIT tag overrides asn1Id + self._tag_octet = 0x80 | constructed_bit | self._convertTag(implicit) + elif explicit is not None: + # 'constructed bit' is always asserted for an EXPLICIT tag + self._tag_octet = 0x80 | 0x20 | self._convertTag(explicit) + self._inner_tag_octet = constructed_bit | asn1Id + else: + # Neither IMPLICIT nor EXPLICIT + self._tag_octet = constructed_bit | asn1Id def _convertTag(self, tag): - """Check if *tag* is a real DER tag. + """Check if *tag* is a real DER tag (5 bits). Convert it from a character to number if necessary. """ if not _is_number(tag): @@ -306,7 +320,7 @@ class DerInteger(DerObject): return DerObject.encode(self) def decode(self, der_encoded, strict=False): - """Decode a complete DER INTEGER DER, and re-initializes this + """Decode a DER-encoded INTEGER, and re-initializes this object with it. Args: @@ -341,6 +355,89 @@ class DerInteger(DerObject): self.value -= bits +class DerBoolean(DerObject): + """Class to model a DER-encoded BOOLEAN. + + An example of encoding is:: + + >>> from Cryptodome.Util.asn1 import DerBoolean + >>> bool_der = DerBoolean(True) + >>> print(bool_der.encode().hex()) + + which will show ``0101ff``, the DER encoding of True. + + And for decoding:: + + >>> s = bytes.fromhex('0101ff') + >>> try: + >>> bool_der = DerBoolean() + >>> bool_der.decode(s) + >>> print(bool_der.value) + >>> except ValueError: + >>> print "Not a valid DER BOOLEAN" + + the output will be ``True``. + + :ivar value: The boolean value + :vartype value: boolean + """ + def __init__(self, value=False, implicit=None, explicit=None): + """Initialize the DER object as a BOOLEAN. + + Args: + value (boolean): + The value of the boolean. Default is False. + + implicit (integer or byte): + The IMPLICIT tag number (< 0x1F) to use for the encoded object. + It overrides the universal tag for BOOLEAN (1). + It cannot be combined with the ``explicit`` parameter. + By default, there is no IMPLICIT tag. + + explicit (integer or byte): + The EXPLICIT tag number (< 0x1F) to use for the encoded object. + It cannot be combined with the ``implicit`` parameter. + By default, there is no EXPLICIT tag. + """ + + DerObject.__init__(self, 0x01, b'', implicit, False, explicit) + self.value = value # The boolean value + + def encode(self): + """Return the DER BOOLEAN, fully encoded as a binary string.""" + + self.payload = b'\xFF' if self.value else b'\x00' + return DerObject.encode(self) + + def decode(self, der_encoded, strict=False): + """Decode a DER-encoded BOOLEAN, and re-initializes this object with it. + + Args: + der_encoded (byte string): A DER-encoded BOOLEAN. + + Raises: + ValueError: in case of parsing errors. + """ + + return DerObject.decode(self, der_encoded, strict) + + def _decodeFromStream(self, s, strict): + """Decode a DER-encoded BOOLEAN from a file.""" + + # Fill up self.payload + DerObject._decodeFromStream(self, s, strict) + + if len(self.payload) != 1: + raise ValueError("Invalid encoding for DER BOOLEAN: payload is not 1 byte") + + if bord(self.payload[0]) == 0: + self.value = False + elif bord(self.payload[0]) == 0xFF: + self.value = True + else: + raise ValueError("Invalid payload for DER BOOLEAN") + + class DerSequence(DerObject): """Class to model a DER SEQUENCE. @@ -384,7 +481,7 @@ class DerSequence(DerObject): """ - def __init__(self, startSeq=None, implicit=None): + def __init__(self, startSeq=None, implicit=None, explicit=None): """Initialize the DER object as a SEQUENCE. :Parameters: @@ -392,12 +489,19 @@ class DerSequence(DerObject): A sequence whose element are either integers or other DER objects. - implicit : integer - The IMPLICIT tag to use for the encoded object. + implicit : integer or byte + The IMPLICIT tag number (< 0x1F) to use for the encoded object. It overrides the universal tag for SEQUENCE (16). + It cannot be combined with the ``explicit`` parameter. + By default, there is no IMPLICIT tag. + + explicit : integer or byte + The EXPLICIT tag number (< 0x1F) to use for the encoded object. + It cannot be combined with the ``implicit`` parameter. + By default, there is no EXPLICIT tag. """ - DerObject.__init__(self, 0x10, b'', implicit, True) + DerObject.__init__(self, 0x10, b'', implicit, True, explicit) if startSeq is None: self._seq = [] else: @@ -434,6 +538,10 @@ class DerSequence(DerObject): self._seq.append(item) return self + def insert(self, index, item): + self._seq.insert(index, item) + return self + def hasInts(self, only_non_negative=True): """Return the number of items in this sequence that are integers. @@ -442,7 +550,7 @@ class DerSequence(DerObject): only_non_negative (boolean): If ``True``, negative integers are not counted in. """ - + items = [x for x in self._seq if _is_number(x, only_non_negative)] return len(items) @@ -527,7 +635,6 @@ class DerSequence(DerObject): self._seq.append(p.data_since_bookmark()) else: derInt = DerInteger() - #import pdb; pdb.set_trace() data = p.data_since_bookmark() derInt.decode(data, strict=strict) self._seq.append(derInt.value) @@ -648,19 +755,25 @@ class DerObjectId(DerObject): binary string.""" comps = [int(x) for x in self.value.split(".")] + if len(comps) < 2: raise ValueError("Not a valid Object Identifier string") - self.payload = bchr(40*comps[0]+comps[1]) - for v in comps[2:]: - if v == 0: - enc = [0] - else: - enc = [] - while v: - enc.insert(0, (v & 0x7F) | 0x80) - v >>= 7 - enc[-1] &= 0x7F - self.payload += b''.join([bchr(x) for x in enc]) + if comps[0] > 2: + raise ValueError("First component must be 0, 1 or 2") + if comps[0] < 2 and comps[1] > 39: + raise ValueError("Second component must be 39 at most") + + subcomps = [40 * comps[0] + comps[1]] + comps[2:] + + encoding = [] + for v in reversed(subcomps): + encoding.append(v & 0x7F) + v >>= 7 + while v: + encoding.append((v & 0x7F) | 0x80) + v >>= 7 + + self.payload = b''.join([bchr(x) for x in reversed(encoding)]) return DerObject.encode(self) def decode(self, der_encoded, strict=False): @@ -687,15 +800,27 @@ class DerObjectId(DerObject): # Derive self.value from self.payload p = BytesIO_EOF(self.payload) - comps = [str(x) for x in divmod(p.read_byte(), 40)] + + subcomps = [] v = 0 while p.remaining_data(): c = p.read_byte() - v = v*128 + (c & 0x7F) + v = (v << 7) + (c & 0x7F) if not (c & 0x80): - comps.append(str(v)) + subcomps.append(v) v = 0 - self.value = '.'.join(comps) + + if len(subcomps) == 0: + raise ValueError("Empty payload") + + if subcomps[0] < 40: + subcomps[:1] = [0, subcomps[0]] + elif subcomps[0] < 80: + subcomps[:1] = [1, subcomps[0] - 40] + else: + subcomps[:1] = [2, subcomps[0] - 80] + + self.value = ".".join([str(x) for x in subcomps]) class DerBitString(DerObject): @@ -704,21 +829,20 @@ class DerBitString(DerObject): An example of encoding is: >>> from Cryptodome.Util.asn1 import DerBitString - >>> from binascii import hexlify, unhexlify - >>> bs_der = DerBitString(b'\\xaa') - >>> bs_der.value += b'\\xbb' - >>> print hexlify(bs_der.encode()) + >>> bs_der = DerBitString(b'\\xAA') + >>> bs_der.value += b'\\xBB' + >>> print(bs_der.encode().hex()) - which will show ``040300aabb``, the DER encoding for the bit string + which will show ``030300aabb``, the DER encoding for the bit string ``b'\\xAA\\xBB'``. For decoding: - >>> s = unhexlify(b'040300aabb') + >>> s = bytes.fromhex('030300aabb') >>> try: >>> bs_der = DerBitString() >>> bs_der.decode(s) - >>> print hexlify(bs_der.value) + >>> print(bs_der.value.hex()) >>> except ValueError: >>> print "Not a valid DER BIT STRING" @@ -737,7 +861,7 @@ class DerBitString(DerObject): If not specified, the bit string is empty. implicit : integer The IMPLICIT tag to use for the encoded object. - It overrides the universal tag for OCTET STRING (3). + It overrides the universal tag for BIT STRING (3). explicit : integer The EXPLICIT tag to use for the encoded object. """ @@ -751,7 +875,7 @@ class DerBitString(DerObject): def encode(self): """Return the DER BIT STRING, fully encoded as a - binary string.""" + byte string.""" # Add padding count byte self.payload = b'\x00' + self.value diff --git a/frozen_deps/Cryptodome/Util/asn1.pyi b/frozen_deps/Cryptodome/Util/asn1.pyi index dac023b..ee4891c 100644 --- a/frozen_deps/Cryptodome/Util/asn1.pyi +++ b/frozen_deps/Cryptodome/Util/asn1.pyi @@ -19,13 +19,19 @@ class DerObject: def __init__(self, asn1Id: Optional[int]=None, payload: Optional[bytes]=..., implicit: Optional[int]=None, constructed: Optional[bool]=False, explicit: Optional[int]=None) -> None: ... def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerObject: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerObject: ... class DerInteger(DerObject): value: int def __init__(self, value: Optional[int]= 0, implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerInteger: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerInteger: ... + +class DerBoolean(DerObject): + value: bool + def __init__(self, value: bool=..., implicit: Optional[Union[int, bytes]]=..., explicit: Optional[Union[int, bytes]]=...) -> None: ... + def encode(self) -> bytes: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerBoolean: ... class DerSequence(DerObject): def __init__(self, startSeq: Optional[Sequence[Union[int, DerInteger, DerObject]]]=None, implicit: Optional[int]=None) -> None: ... @@ -41,7 +47,7 @@ class DerSequence(DerObject): def hasInts(self, only_non_negative: Optional[bool]=True) -> int: ... def hasOnlyInts(self, only_non_negative: Optional[bool]=True) -> bool: ... def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False, nr_elements: Optional[int]=None, only_ints_expected: Optional[bool]=False) -> DerSequence: ... + def decode(self, der_encoded: bytes, strict: bool=..., nr_elements: Optional[int]=None, only_ints_expected: Optional[bool]=False) -> DerSequence: ... class DerOctetString(DerObject): payload: bytes @@ -54,13 +60,13 @@ class DerObjectId(DerObject): value: str def __init__(self, value: Optional[str]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerObjectId: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerObjectId: ... class DerBitString(DerObject): value: bytes def __init__(self, value: Optional[bytes]=..., implicit: Optional[int]=None, explicit: Optional[int]=None) -> None: ... def encode(self) -> bytes: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerBitString: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerBitString: ... DerSetElement = Union[bytes, int] @@ -70,5 +76,5 @@ class DerSetOf(DerObject): def __iter__(self) -> Iterable: ... def __len__(self) -> int: ... def add(self, elem: DerSetElement) -> None: ... - def decode(self, der_encoded: bytes, strict: Optional[bool]=False) -> DerObject: ... + def decode(self, der_encoded: bytes, strict: bool=...) -> DerObject: ... def encode(self) -> bytes: ... diff --git a/frozen_deps/Cryptodome/Util/number.py b/frozen_deps/Cryptodome/Util/number.py index 0367fdc..6d59fd9 100644 --- a/frozen_deps/Cryptodome/Util/number.py +++ b/frozen_deps/Cryptodome/Util/number.py @@ -28,7 +28,7 @@ import math import sys import struct from Cryptodome import Random -from Cryptodome.Util.py3compat import _memoryview, iter_range +from Cryptodome.Util.py3compat import iter_range # Backward compatibility _fastmath = None @@ -51,12 +51,8 @@ def size (N): """Returns the size of the number N in bits.""" if N < 0: - raise ValueError("Size in bits only avialable for non-negative numbers") - - bits = 0 - while N >> bits: - bits += 1 - return bits + raise ValueError("Size in bits only available for non-negative numbers") + return N.bit_length() def getRandomInteger(N, randfunc=None): @@ -113,27 +109,56 @@ def getRandomNBitInteger(N, randfunc=None): assert size(value) >= N return value -def GCD(x,y): - """Greatest Common Denominator of :data:`x` and :data:`y`. - """ - x = abs(x) ; y = abs(y) - while x > 0: - x, y = y % x, x - return y +if sys.version_info[:2] >= (3, 5): + + GCD = math.gcd + +else: + + def GCD(x,y): + """Greatest Common Denominator of :data:`x` and :data:`y`. + """ + + x = abs(x) ; y = abs(y) + while x > 0: + x, y = y % x, x + return y + -def inverse(u, v): - """The inverse of :data:`u` *mod* :data:`v`.""" +if sys.version_info[:2] >= (3, 8): - u3, v3 = u, v - u1, v1 = 1, 0 - while v3 > 0: - q = u3 // v3 - u1, v1 = v1, u1 - v1*q - u3, v3 = v3, u3 - v3*q - while u1<0: - u1 = u1 + v - return u1 + def inverse(u, v): + """The inverse of :data:`u` *mod* :data:`v`.""" + + if v == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if v < 0: + raise ValueError("Modulus cannot be negative") + + return pow(u, -1, v) + +else: + + def inverse(u, v): + """The inverse of :data:`u` *mod* :data:`v`.""" + + if v == 0: + raise ZeroDivisionError("Modulus cannot be zero") + if v < 0: + raise ValueError("Modulus cannot be negative") + + u3, v3 = u, v + u1, v1 = 1, 0 + while v3 > 0: + q = u3 // v3 + u1, v1 = v1, u1 - v1*q + u3, v3 = v3, u3 - v3*q + if u3 != 1: + raise ValueError("No inverse value can be computed") + while u1<0: + u1 = u1 + v + return u1 # Given a number of bits to generate and a random generation function, # find a prime number of the appropriate size. @@ -141,14 +166,19 @@ def inverse(u, v): def getPrime(N, randfunc=None): """Return a random N-bit prime number. + N must be an integer larger than 1. If randfunc is omitted, then :meth:`Random.get_random_bytes` is used. """ if randfunc is None: randfunc = Random.get_random_bytes - number=getRandomNBitInteger(N, randfunc) | 1 - while (not isPrime(number, randfunc=randfunc)): - number=number+2 + if N < 2: + raise ValueError("N must be larger than 1") + + while True: + number = getRandomNBitInteger(N, randfunc) | 1 + if isPrime(number, randfunc=randfunc): + break return number @@ -254,7 +284,7 @@ def getStrongPrime(N, e=0, false_positive_prob=1e-6, randfunc=None): # calculate range for X # lower_bound = sqrt(2) * 2^{511 + 128*x} # upper_bound = 2^{512 + 128*x} - 1 - x = (N - 512) >> 7; + x = (N - 512) >> 7 # We need to approximate the sqrt(2) in the lower_bound by an integer # expression because floating point math overflows with these numbers lower_bound = (14142135623730950489 * (2 ** (511 + 128*x))) // 10000000000000000000 @@ -361,12 +391,12 @@ def isPrime(N, false_positive_prob=1e-6, randfunc=None): return N == 2 for p in sieve_base: if N == p: - return 1 + return True if N % p == 0: - return 0 + return False rounds = int(math.ceil(-math.log(false_positive_prob)/math.log(4))) - return _rabinMillerTest(N, rounds, randfunc) + return bool(_rabinMillerTest(N, rounds, randfunc)) # Improved conversion functions contributed by Barry Warsaw, after @@ -375,46 +405,72 @@ def isPrime(N, false_positive_prob=1e-6, randfunc=None): import struct def long_to_bytes(n, blocksize=0): - """Convert an integer to a byte string. + """Convert a positive integer to a byte string using big endian encoding. - In Python 3.2+, use the native method instead:: + If :data:`blocksize` is absent or zero, the byte string will + be of minimal length. - >>> n.to_bytes(blocksize, 'big') + Otherwise, the length of the byte string is guaranteed to be a multiple + of :data:`blocksize`. If necessary, zeroes (``\\x00``) are added at the left. - For instance:: + .. note:: + In Python 3, if you are sure that :data:`n` can fit into + :data:`blocksize` bytes, you can simply use the native method instead:: - >>> n = 80 - >>> n.to_bytes(2, 'big') - b'\x00P' + >>> n.to_bytes(blocksize, 'big') - If the optional :data:`blocksize` is provided and greater than zero, - the byte string is padded with binary zeros (on the front) so that - the total length of the output is a multiple of blocksize. + For instance:: - If :data:`blocksize` is zero or not provided, the byte string will - be of minimal length. + >>> n = 80 + >>> n.to_bytes(2, 'big') + b'\\x00P' + + However, and unlike this ``long_to_bytes()`` function, + an ``OverflowError`` exception is raised if :data:`n` does not fit. """ - # after much testing, this algorithm was deemed to be the fastest - s = b'' - n = int(n) + + if n < 0 or blocksize < 0: + raise ValueError("Values must be non-negative") + + result = [] pack = struct.pack - while n > 0: - s = pack('>I', n & 0xffffffff) + s + + # Fill the first block independently from the value of n + bsr = blocksize + while bsr >= 8: + result.insert(0, pack('>Q', n & 0xFFFFFFFFFFFFFFFF)) + n = n >> 64 + bsr -= 8 + + while bsr >= 4: + result.insert(0, pack('>I', n & 0xFFFFFFFF)) n = n >> 32 - # strip off leading zeros - for i in range(len(s)): - if s[i] != b'\x00'[0]: - break + bsr -= 4 + + while bsr > 0: + result.insert(0, pack('>B', n & 0xFF)) + n = n >> 8 + bsr -= 1 + + if n == 0: + if len(result) == 0: + bresult = b'\x00' + else: + bresult = b''.join(result) else: - # only happens when n == 0 - s = b'\x00' - i = 0 - s = s[i:] - # add back some pad bytes. this could be done more efficiently w.r.t. the - # de-padding being done above, but sigh... - if blocksize > 0 and len(s) % blocksize: - s = (blocksize - len(s) % blocksize) * b'\x00' + s - return s + # The encoded number exceeds the block size + while n > 0: + result.insert(0, pack('>Q', n & 0xFFFFFFFFFFFFFFFF)) + n = n >> 64 + result[0] = result[0].lstrip(b'\x00') + bresult = b''.join(result) + # bresult has minimum length here + if blocksize > 0: + target_len = ((len(bresult) - 1) // blocksize + 1) * blocksize + bresult = b'\x00' * (target_len - len(bresult)) + bresult + + return bresult + def bytes_to_long(s): """Convert a byte string to a long integer (big endian). @@ -439,7 +495,7 @@ def bytes_to_long(s): if sys.version_info[0:3] < (2, 7, 4): if isinstance(s, bytearray): s = bytes(s) - elif isinstance(s, _memoryview): + elif isinstance(s, memoryview): s = s.tobytes() length = len(s) diff --git a/frozen_deps/Cryptodome/Util/py3compat.py b/frozen_deps/Cryptodome/Util/py3compat.py index 40ef752..3294b66 100644 --- a/frozen_deps/Cryptodome/Util/py3compat.py +++ b/frozen_deps/Cryptodome/Util/py3compat.py @@ -78,6 +78,8 @@ if sys.version_info[0] == 2: return s elif isinstance(s, bytearray): return bytes(s) + elif isinstance(s, memoryview): + return s.tobytes() else: return ''.join(s) def tostr(bs): @@ -85,17 +87,19 @@ if sys.version_info[0] == 2: def byte_string(s): return isinstance(s, str) - # In Pyton 2.x, StringIO is a stand-alone module - from StringIO import StringIO as BytesIO + # In Python 2, a memoryview does not support concatenation + def concat_buffers(a, b): + if isinstance(a, memoryview): + a = a.tobytes() + if isinstance(b, memoryview): + b = b.tobytes() + return a + b + + from StringIO import StringIO + BytesIO = StringIO from sys import maxint - if sys.version_info[1] < 7: - import types - _memoryview = types.NoneType - else: - _memoryview = memoryview - iter_range = xrange def is_native_int(x): @@ -104,8 +108,15 @@ if sys.version_info[0] == 2: def is_string(x): return isinstance(x, basestring) + def is_bytes(x): + return isinstance(x, str) or \ + isinstance(x, bytearray) or \ + isinstance(x, memoryview) + ABC = abc.ABCMeta('ABC', (object,), {'__slots__': ()}) + FileNotFoundError = IOError + else: def b(s): return s.encode("latin-1") # utf-8 would cause some side-effects we don't want @@ -125,6 +136,8 @@ else: return bytes(s) elif isinstance(s,str): return s.encode(encoding) + elif isinstance(s, memoryview): + return s.tobytes() else: return bytes([s]) def tostr(bs): @@ -132,12 +145,13 @@ else: def byte_string(s): return isinstance(s, bytes) - # In Python 3.x, StringIO is a sub-module of io + def concat_buffers(a, b): + return a + b + from io import BytesIO + from io import StringIO from sys import maxsize as maxint - _memoryview = memoryview - iter_range = range def is_native_int(x): @@ -146,14 +160,21 @@ else: def is_string(x): return isinstance(x, str) + def is_bytes(x): + return isinstance(x, bytes) or \ + isinstance(x, bytearray) or \ + isinstance(x, memoryview) + from abc import ABC + FileNotFoundError = FileNotFoundError + def _copy_bytes(start, end, seq): """Return an immutable copy of a sequence (byte string, byte array, memoryview) in a certain interval [start:seq]""" - if isinstance(seq, _memoryview): + if isinstance(seq, memoryview): return seq[start:end].tobytes() elif isinstance(seq, bytearray): return bytes(seq[start:end]) diff --git a/frozen_deps/Cryptodome/Util/py3compat.pyi b/frozen_deps/Cryptodome/Util/py3compat.pyi index 3297dc0..74e04a2 100644 --- a/frozen_deps/Cryptodome/Util/py3compat.pyi +++ b/frozen_deps/Cryptodome/Util/py3compat.pyi @@ -13,23 +13,21 @@ def bytestring(x: Any) -> bool: ... def is_native_int(s: Any) -> bool: ... def is_string(x: Any) -> bool: ... +def is_bytes(x: Any) -> bool: ... def BytesIO(b: bytes) -> IO[bytes]: ... +def StringIO(s: str) -> IO[str]: ... if sys.version_info[0] == 2: from sys import maxint iter_range = xrange - if sys.version_info[1] < 7: - import types - _memoryview = types.NoneType - else: - _memoryview = memoryview - else: from sys import maxsize as maxint iter_range = range - _memoryview = memoryview +class FileNotFoundError: + def __init__(self, err: int, msg: str, filename: str) -> None: + pass def _copy_bytes(start: Optional[int], end: Optional[int], seq: Buffer) -> bytes: ... diff --git a/frozen_deps/Cryptodome/Util/strxor.py b/frozen_deps/Cryptodome/Util/strxor.py index 91fb4c9..6b16155 100644 --- a/frozen_deps/Cryptodome/Util/strxor.py +++ b/frozen_deps/Cryptodome/Util/strxor.py @@ -32,7 +32,8 @@ from Cryptodome.Util._raw_api import (load_pycryptodome_raw_lib, c_size_t, create_string_buffer, get_raw_buffer, c_uint8_ptr, is_writeable_buffer) -_raw_strxor = load_pycryptodome_raw_lib("Cryptodome.Util._strxor", +_raw_strxor = load_pycryptodome_raw_lib( + "Cryptodome.Util._strxor", """ void strxor(const uint8_t *in1, const uint8_t *in2, @@ -45,33 +46,38 @@ _raw_strxor = load_pycryptodome_raw_lib("Cryptodome.Util._strxor", def strxor(term1, term2, output=None): - """XOR two byte strings. - + """From two byte strings of equal length, + create a third one which is the byte-by-byte XOR of the two. + Args: term1 (bytes/bytearray/memoryview): - The first term of the XOR operation. + The first byte string to XOR. term2 (bytes/bytearray/memoryview): - The second term of the XOR operation. + The second byte string to XOR. output (bytearray/memoryview): - The location where the result must be written to. + The location where the result will be written to. + It must have the same length as ``term1`` and ``term2``. If ``None``, the result is returned. :Return: - If ``output`` is ``None``, a new ``bytes`` string with the result. + If ``output`` is ``None``, a new byte string with the result. Otherwise ``None``. + + .. note:: + ``term1`` and ``term2`` must have the same length. """ if len(term1) != len(term2): raise ValueError("Only byte strings of equal length can be xored") - + if output is None: result = create_string_buffer(len(term1)) else: # Note: output may overlap with either input result = output - + if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(term1) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(term1)) @@ -88,15 +94,19 @@ def strxor(term1, term2, output=None): def strxor_c(term, c, output=None): - """XOR a byte string with a repeated sequence of characters. + """From a byte string, create a second one of equal length + where each byte is XOR-red with the same value. Args: - term(bytes/bytearray/memoryview): - The first term of the XOR operation. - c (bytes): - The byte that makes up the second term of the XOR operation. - output (None or bytearray/memoryview): - If not ``None``, the location where the result is stored into. + term(bytes/bytearray/memoryview): + The byte string to XOR. + c (int): + Every byte in the string will be XOR-ed with this value. + It must be between 0 and 255 (included). + output (None or bytearray/memoryview): + The location where the result will be written to. + It must have the same length as ``term``. + If ``None``, the result is returned. Return: If ``output`` is ``None``, a new ``bytes`` string with the result. @@ -105,16 +115,16 @@ def strxor_c(term, c, output=None): if not 0 <= c < 256: raise ValueError("c must be in range(256)") - + if output is None: result = create_string_buffer(len(term)) else: # Note: output may overlap with either input result = output - + if not is_writeable_buffer(output): raise TypeError("output must be a bytearray or a writeable memoryview") - + if len(term) != len(output): raise ValueError("output must have the same length as the input" " (%d bytes)" % len(term)) @@ -134,4 +144,3 @@ def strxor_c(term, c, output=None): def _strxor_direct(term1, term2, result): """Very fast XOR - check conditions!""" _raw_strxor.strxor(term1, term2, result, c_size_t(len(term1))) - diff --git a/frozen_deps/Cryptodome/__init__.py b/frozen_deps/Cryptodome/__init__.py index bb08e39..c33481e 100644 --- a/frozen_deps/Cryptodome/__init__.py +++ b/frozen_deps/Cryptodome/__init__.py @@ -1,6 +1,6 @@ __all__ = ['Cipher', 'Hash', 'Protocol', 'PublicKey', 'Util', 'Signature', 'IO', 'Math'] -version_info = (3, 9, '9') +version_info = (3, 20, '0') __version__ = ".".join([str(x) for x in version_info]) |