diff options
284 files changed, 12466 insertions, 5473 deletions
diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml new file mode 100644 index 0000000..02d034e --- /dev/null +++ b/AppImageBuilder.yml @@ -0,0 +1,50 @@ +version: 1 +script: + - rm -rf AppDir | true + - mkdir -p AppDir/usr/src + - cp mnemonic.py AppDir/usr/src + - cp bech32.py AppDir/usr/src + - cp shamir.py AppDir/usr/src + - cp keytree.py AppDir/usr/src + - cp setup.py AppDir/usr/src + - python3.10 -m pip install -t AppDir/usr/src/frozen_deps AppDir/usr/src + - cp -r wordlist/ AppDir/usr/src/frozen_deps + - rm -rf AppDir/usr/src/frozen_deps/Cryptodome/SelfTest + + +AppDir: + path: ./AppDir + + app_info: + id: org.ted.keytree + name: keytree + icon: utilities-terminal + version: 0.1.9 + exec: usr/bin/python3.10 + exec_args: $APPDIR/usr/src/keytree.py $@ + + apt: + arch: amd64 + sources: + - sourceline: 'deb [arch=amd64] http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse' + key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3b4fe6acc0b21f32' + - sourceline: 'deb [arch=amd64] http://ppa.launchpad.net/deadsnakes/ppa/ubuntu focal main' + key_url: 'http://keyserver.ubuntu.com/pks/lookup?op=get&search=0xBA6932366A755776' + include: + - python3.10 + exclude: [] + + runtime: + env: + PATH: '${APPDIR}/usr/bin:${PATH}' + # Set python home + # See https://docs.python.org/3/using/cmdline.html#envvar-PYTHONHOME + PYTHONHOME: '${APPDIR}/usr' + # Path to the site-packages dir or other modules dirs + # See https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH + PYTHONPATH: '${APPDIR}/usr/lib/python3.10/site-packages' + +AppImage: + update-information: 'gh-releases-zsync|AppImageCrafters|keytree|latest|python-appimage-*x86_64.AppImage.zsync' + sign-key: None + arch: x86_64 @@ -1,18 +1,22 @@ keytree.py ========== -- Make sure you have Python >= 3.7 +- Make sure you have Python = 3.10 - CD into the cloned repo Examples -------- - Derive 10 keys from a given mnemonic: ``./keytree.py --end-idx 10`` -- Generate a new mnemonic, print 10 derived addresses from it, then also save the mnemonic to an encrypted keystore file: ``./keytree.py --end-idx 10 --gen-mnemonic --save-keystore mykeystore.json`` -- Load the mnemonic from an existing keystore file: ``./keytree.py --load-keystore mykeystore.json`` +- Generate a new mnemonic, print 10 derived addresses from it, then also save the mnemonic to an encrypted keystore file: ``./keytree.py --end-idx 10 --gen-mnemonic --save mykeystore.json`` +- Load the mnemonic from an existing keystore file: ``./keytree.py --load mykeystore.json`` - To see all private keys and the mnemonic phrase, use ``--show-private`` (only use it after you look around and ensure there is no one else looking at your screen) -- Use arbitrary UTF-8 string as your mnemonic ``./keytree.py --custom-words --save-keystore mykeystore.json`` +- Use arbitrary UTF-8 string as your mnemonic ``./keytree.py --custom --save mykeystore.json`` +- Show Fuji testnet address format ``./keytree.py <your options> --hrp fuji`` +- Generate a new mnemonic and also use a 2/3 Shamir's secret sharing (3 shares, recoverable with any 2 of them): ``./keytree.py --gen-mnemonic --gen-shamir --shamir-threshold 2 --shamir-num 3`` +- Recover a new mnemonic from the previous example and save it to a keystore file: ``./keytree.py --recover-shamir 1,2 --save mykeystore.json`` + Caveat ------ @@ -21,3 +25,28 @@ shipped in this repo (more secure, recommended, only works on x86-64 Linux). If you instead do a normal pip install (``pip3 install --user .``) and use ``keytree.py`` (without ``./`` prefix), it will use the latest deps fetched by pip. + +Security +-------- + +- The script was written with minimalist design (short, easy to check the code) + . But you should use at your own risk and on an OS/platform/machine that you + can trust. There is NO side-channel attack prevention or special treatment of + the memory. + +- The dependencies should be safe (but do your own check!) because the part under ``frozen_deps/`` only contains: + + - Some standard AES encryption and Keccak-256 hashing provided by ``Cryptodome`` + - Curve manipulation provided by ``ecdsa`` + - Base58 encoding provided by ``base58`` + + Whereas web3-specific modules are pretty short: + + - ``mnemonic.py``: 284 lines, to generate/manipulate mnemonics + - ``bech32.py``: 123 lines, to Bech32-format addresses (for AVAX addresses) + - ``shamir.py``: 80 lines, to implement a minimalist Shamir's secret sharing that's compatible with Ava Labs' implementation (https://github.com/ava-labs/mnemonic-shamir-secret-sharing-cli) + +Portable Binary +--------------- + +Use ``./keytree-0.1.8-x86_64.AppImage`` in place of ``./keytree.py``. 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]) diff --git a/frozen_deps/_pysha3.cpython-38-x86_64-linux-gnu.so b/frozen_deps/_pysha3.cpython-38-x86_64-linux-gnu.so Binary files differdeleted file mode 100755 index 0d09638..0000000 --- a/frozen_deps/_pysha3.cpython-38-x86_64-linux-gnu.so +++ /dev/null diff --git a/frozen_deps/base58-2.0.1.dist-info/COPYING b/frozen_deps/base58-2.0.1.dist-info/COPYING deleted file mode 100644 index 342bd62..0000000 --- a/frozen_deps/base58-2.0.1.dist-info/COPYING +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015 David Keijser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/frozen_deps/base58-2.0.1.dist-info/INSTALLER b/frozen_deps/base58-2.0.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/frozen_deps/base58-2.0.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/frozen_deps/base58-2.0.1.dist-info/METADATA b/frozen_deps/base58-2.0.1.dist-info/METADATA deleted file mode 100644 index 22a37ad..0000000 --- a/frozen_deps/base58-2.0.1.dist-info/METADATA +++ /dev/null @@ -1,20 +0,0 @@ -Metadata-Version: 2.1 -Name: base58 -Version: 2.0.1 -Summary: Base58 and Base58Check implementation -Home-page: https://github.com/keis/base58 -Author: David Keijser -Author-email: keijser@gmail.com -License: MIT -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Requires-Python: >=3.5 - -UNKNOWN - - diff --git a/frozen_deps/base58-2.0.1.dist-info/RECORD b/frozen_deps/base58-2.0.1.dist-info/RECORD deleted file mode 100644 index d20c1c2..0000000 --- a/frozen_deps/base58-2.0.1.dist-info/RECORD +++ /dev/null @@ -1,13 +0,0 @@ -../../bin/base58,sha256=WWCKVkDRfe64OQtfsxf-b0PQGIclDIn84xO8gkjjWcY,213
-base58-2.0.1.dist-info/COPYING,sha256=z0aU8EC3oxzY7D280LWDpgHA1MN94Ba-eqCgbjpqOlQ,1057
-base58-2.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-base58-2.0.1.dist-info/METADATA,sha256=r4yScmUS3A8Yx7mmsSyaqfMSINg6FAIQK2ocWJO1tJw,540
-base58-2.0.1.dist-info/RECORD,,
-base58-2.0.1.dist-info/WHEEL,sha256=p46_5Uhzqz6AzeSosiOnxK-zmFja1i22CrQCjmYe8ec,92
-base58-2.0.1.dist-info/entry_points.txt,sha256=7WwcggBSeBwcC22-LkpqMOCaPdey0nOG3QEaKok403Y,49
-base58-2.0.1.dist-info/top_level.txt,sha256=BVSonMPECDcX_2XqQ7iILRqitlshZNNEmLCEWlpvUvI,7
-base58/__init__.py,sha256=ccX9CZMek4UC0edA_cHs71MgC4YqJCPBhvycuzhbucc,3085
-base58/__main__.py,sha256=OiE3DXq4vwYyAVYC3SM9Y0AQbMuS2IA0v2mvzwv96pk,1080
-base58/__pycache__/__init__.cpython-38.pyc,,
-base58/__pycache__/__main__.cpython-38.pyc,,
-base58/py.typed,sha256=dcrsqJrcYfTX-ckLFJMTaj6mD8aDe2u0tkQG-ZYxnEg,26
diff --git a/frozen_deps/base58-2.0.1.dist-info/WHEEL b/frozen_deps/base58-2.0.1.dist-info/WHEEL deleted file mode 100644 index 3b5c403..0000000 --- a/frozen_deps/base58-2.0.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.33.6) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/frozen_deps/base58-2.0.1.dist-info/entry_points.txt b/frozen_deps/base58-2.0.1.dist-info/entry_points.txt deleted file mode 100644 index dc6d6a2..0000000 --- a/frozen_deps/base58-2.0.1.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -base58 = base58.__main__:main - diff --git a/frozen_deps/base58-2.0.1.dist-info/top_level.txt b/frozen_deps/base58-2.0.1.dist-info/top_level.txt deleted file mode 100644 index b4c9d71..0000000 --- a/frozen_deps/base58-2.0.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -base58 diff --git a/frozen_deps/base58/__init__.py b/frozen_deps/base58/__init__.py index ff2fa18..929014f 100644 --- a/frozen_deps/base58/__init__.py +++ b/frozen_deps/base58/__init__.py @@ -9,15 +9,17 @@ with the bitcoin network. # forum post by Gavin Andresen, so direct your praise to him. # This module adds shiny packaging and support for python3. +from functools import lru_cache from hashlib import sha256 -from typing import Union +from typing import Mapping, Union -__version__ = '2.0.1' +__version__ = '2.1.1' # 58 character alphabet used BITCOIN_ALPHABET = \ b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' RIPPLE_ALPHABET = b'rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz' +XRP_ALPHABET = RIPPLE_ALPHABET # Retro compatibility alphabet = BITCOIN_ALPHABET @@ -39,8 +41,9 @@ def b58encode_int( if not i and default_one: return alphabet[0:1] string = b"" + base = len(alphabet) while i: - i, idx = divmod(i, 58) + i, idx = divmod(i, base) string = alphabet[idx:idx+1] + string return string @@ -53,35 +56,60 @@ def b58encode( """ v = scrub_input(v) - nPad = len(v) + origlen = len(v) v = v.lstrip(b'\0') - nPad -= len(v) + newlen = len(v) + + acc = int.from_bytes(v, byteorder='big') # first byte is most significant - p, acc = 1, 0 - for c in reversed(v): - acc += p * c - p = p << 8 result = b58encode_int(acc, default_one=False, alphabet=alphabet) - return alphabet[0:1] * nPad + result + return alphabet[0:1] * (origlen - newlen) + result + + +@lru_cache() +def _get_base58_decode_map(alphabet: bytes, + autofix: bool) -> Mapping[int, int]: + invmap = {char: index for index, char in enumerate(alphabet)} + + if autofix: + groups = [b'0Oo', b'Il1'] + for group in groups: + pivots = [c for c in group if c in invmap] + if len(pivots) == 1: + for alternative in group: + invmap[alternative] = invmap[pivots[0]] + + return invmap def b58decode_int( - v: Union[str, bytes], alphabet: bytes = BITCOIN_ALPHABET + v: Union[str, bytes], alphabet: bytes = BITCOIN_ALPHABET, *, + autofix: bool = False ) -> int: """ Decode a Base58 encoded string as an integer """ - v = v.rstrip() + if b' ' not in alphabet: + v = v.rstrip() v = scrub_input(v) + map = _get_base58_decode_map(alphabet, autofix=autofix) + decimal = 0 - for char in v: - decimal = decimal * 58 + alphabet.index(char) + base = len(alphabet) + try: + for char in v: + decimal = decimal * base + map[char] + except KeyError as e: + raise ValueError( + "Invalid character {!r}".format(chr(e.args[0])) + ) from None return decimal def b58decode( - v: Union[str, bytes], alphabet: bytes = BITCOIN_ALPHABET + v: Union[str, bytes], alphabet: bytes = BITCOIN_ALPHABET, *, + autofix: bool = False ) -> bytes: """ Decode a Base58 encoded string @@ -93,7 +121,7 @@ def b58decode( v = v.lstrip(alphabet[0:1]) newlen = len(v) - acc = b58decode_int(v, alphabet=alphabet) + acc = b58decode_int(v, alphabet=alphabet, autofix=autofix) result = [] while acc > 0: @@ -116,11 +144,12 @@ def b58encode_check( def b58decode_check( - v: Union[str, bytes], alphabet: bytes = BITCOIN_ALPHABET + v: Union[str, bytes], alphabet: bytes = BITCOIN_ALPHABET, *, + autofix: bool = False ) -> bytes: '''Decode and verify the checksum of a Base58 encoded string''' - result = b58decode(v, alphabet=alphabet) + result = b58decode(v, alphabet=alphabet, autofix=autofix) result, check = result[:-4], result[-4:] digest = sha256(sha256(result).digest()).digest() diff --git a/frozen_deps/base58/__main__.py b/frozen_deps/base58/__main__.py index b76fdad..3a6f5d2 100644 --- a/frozen_deps/base58/__main__.py +++ b/frozen_deps/base58/__main__.py @@ -1,10 +1,18 @@ import argparse import sys +from typing import Callable, Dict, Tuple from base58 import b58decode, b58decode_check, b58encode, b58encode_check +_fmap = { + (False, False): b58encode, + (False, True): b58encode_check, + (True, False): b58decode, + (True, True): b58decode_check +} # type: Dict[Tuple[bool, bool], Callable[[bytes], bytes]] -def main(): + +def main() -> None: '''Base58 encode or decode FILE, or standard input, to standard output.''' stdout = sys.stdout.buffer @@ -26,12 +34,7 @@ def main(): help='append a checksum before encoding') args = parser.parse_args() - fun = { - (False, False): b58encode, - (False, True): b58encode_check, - (True, False): b58decode, - (True, True): b58decode_check - }[(args.decode, args.check)] + fun = _fmap[(args.decode, args.check)] data = args.file.buffer.read() diff --git a/frozen_deps/bech32.py b/frozen_deps/bech32.py deleted file mode 100644 index d450080..0000000 --- a/frozen_deps/bech32.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (c) 2017 Pieter Wuille -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -"""Reference implementation for Bech32 and segwit addresses.""" - - -CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" - - -def bech32_polymod(values): - """Internal function that computes the Bech32 checksum.""" - generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3] - chk = 1 - for value in values: - top = chk >> 25 - chk = (chk & 0x1ffffff) << 5 ^ value - for i in range(5): - chk ^= generator[i] if ((top >> i) & 1) else 0 - return chk - - -def bech32_hrp_expand(hrp): - """Expand the HRP into values for checksum computation.""" - return [ord(x) >> 5 for x in hrp] + [0] + [ord(x) & 31 for x in hrp] - - -def bech32_verify_checksum(hrp, data): - """Verify a checksum given HRP and converted data characters.""" - return bech32_polymod(bech32_hrp_expand(hrp) + data) == 1 - - -def bech32_create_checksum(hrp, data): - """Compute the checksum values given HRP and data.""" - values = bech32_hrp_expand(hrp) + data - polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ 1 - return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)] - - -def bech32_encode(hrp, data): - """Compute a Bech32 string given HRP and data values.""" - combined = data + bech32_create_checksum(hrp, data) - return hrp + '1' + ''.join([CHARSET[d] for d in combined]) - - -def bech32_decode(bech): - """Validate a Bech32 string, and determine HRP and data.""" - if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or - (bech.lower() != bech and bech.upper() != bech)): - return (None, None) - bech = bech.lower() - pos = bech.rfind('1') - if pos < 1 or pos + 7 > len(bech) or len(bech) > 90: - return (None, None) - if not all(x in CHARSET for x in bech[pos+1:]): - return (None, None) - hrp = bech[:pos] - data = [CHARSET.find(x) for x in bech[pos+1:]] - if not bech32_verify_checksum(hrp, data): - return (None, None) - return (hrp, data[:-6]) - - -def convertbits(data, frombits, tobits, pad=True): - """General power-of-2 base conversion.""" - acc = 0 - bits = 0 - ret = [] - maxv = (1 << tobits) - 1 - max_acc = (1 << (frombits + tobits - 1)) - 1 - for value in data: - if value < 0 or (value >> frombits): - return None - acc = ((acc << frombits) | value) & max_acc - bits += frombits - while bits >= tobits: - bits -= tobits - ret.append((acc >> bits) & maxv) - if pad: - if bits: - ret.append((acc << (tobits - bits)) & maxv) - elif bits >= frombits or ((acc << (tobits - bits)) & maxv): - return None - return ret - - -def decode(hrp, addr): - """Decode a segwit address.""" - hrpgot, data = bech32_decode(addr) - if hrpgot != hrp: - return (None, None) - decoded = convertbits(data[1:], 5, 8, False) - if decoded is None or len(decoded) < 2 or len(decoded) > 40: - return (None, None) - if data[0] > 16: - return (None, None) - if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32: - return (None, None) - return (data[0], decoded) - - -def encode(hrp, witver, witprog): - """Encode a segwit address.""" - ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5)) - if decode(hrp, ret) == (None, None): - return None - return ret diff --git a/frozen_deps/bin/base58 b/frozen_deps/bin/base58 deleted file mode 100755 index 1e291f0..0000000 --- a/frozen_deps/bin/base58 +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -import re -import sys -from base58.__main__ import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/frozen_deps/bin/keytree.py b/frozen_deps/bin/keytree.py deleted file mode 100755 index 0b09eaf..0000000 --- a/frozen_deps/bin/keytree.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/python -# MIT License -# -# Copyright (c) 2020 Ted Yin <tederminant@gmail.com> -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# -# -# This little script offers decryption and verification of the existing -# Ethereum wallets, as well as generation of a new wallet. You can use any -# utf-8 string as the password, which could provide with better security -# against the brute-force attack. - -# Use at your own risk. -# -# Example: -# python3 ./keytree.py - -import os -import sys -if sys.version_info[1] < 7: - sys.write("Python should be >= 3.7") - sys.exit(1) -basedir = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, basedir + "/frozen_deps") - -import re -import argparse -import hashlib -import hmac -import unicodedata -import json -from getpass import getpass - -import bech32 -import mnemonic -from ecdsa import SigningKey, VerifyingKey, SECP256k1 -from ecdsa.ecdsa import generator_secp256k1 -from ecdsa.ellipticcurve import INFINITY -from base58 import b58encode, b58decode -from sha3 import keccak_256 -from Crypto.Cipher import AES - - -def sha256(data): - h = hashlib.sha256() - h.update(data) - return h.digest() - - -def ripemd160(data): - h = hashlib.new('ripemd160') - h.update(data) - return h.digest() - - -class KeytreeError(Exception): - pass - - -class BIP32Error(KeytreeError): - pass - - -# point(p): returns the coordinate pair resulting from EC point multiplication -# (repeated application of the EC group operation) of the secp256k1 base point -# with the integer p. -def point(p): - return generator_secp256k1 * p - - -# ser32(i): serialize a 32-bit unsigned integer i as a 4-byte sequence, most -# significant byte first. -def ser32(i): - return i.to_bytes(4, byteorder='big') - - -# ser256(p): serializes the integer p as a 32-byte sequence, most significant -# byte first. -def ser256(p): - return p.to_bytes(32, byteorder='big') - - -# serP(P): serializes the coordinate pair P = (x,y) as a byte sequence using -# SEC1's compressed form: (0x02 or 0x03) || ser256(x), where the header byte -# depends on the parity of the omitted y coordinate. -def serP(P): - if P.y() & 1 == 0: - parity = b'\x02' - else: - parity = b'\x03' - return parity + ser256(P.x()) - - -def is_infinity(P): - return P == INFINITY - - -# parse256(p): interprets a 32-byte sequence as a 256-bit number, most -# significant byte first. -def parse256(p): - assert(len(p) == 32) - return int.from_bytes(p, byteorder='big') - - -def iH(x): - return x + (1 << 31) - - -n = generator_secp256k1.order() -rformat = re.compile(r"^[0-9]+'?$") - - -def ckd_pub(K_par, c_par, i): - if i >= 1 << 31: - raise BIP32Error("the child is a hardended key") - I = hmac.digest( - c_par, serP(K_par) + ser32(i), 'sha512') - I_L, I_R = I[:32], I[32:] - K_i = point(parse256(I_L)) + K_par - c_i = I_R - if parse256(I_L) >= n or is_infinity(K_i): - raise BIP32Error("invalid i") - return K_i, c_i - -def ckd_prv(k_par, c_par, i): - if i >= 1 << 31: - I = hmac.digest( - c_par, b'\x00' + ser256(k_par) + ser32(i), 'sha512') - else: - I = hmac.digest( - c_par, serP(point(k_par)) + ser32(i), 'sha512') - I_L, I_R = I[:32], I[32:] - k_i = (parse256(I_L) + k_par) % n - c_i = I_R - if parse256(I_L) >= n or k_i == 0: - raise BIP32Error("invalid i") - return k_i, c_i - -class BIP32: - path_error = BIP32Error("unsupported BIP32 path format") - - def __init__(self, seed, key="Bitcoin seed"): - I = hmac.digest(b"Bitcoin seed", seed, 'sha512') - I_L, I_R = I[:32], I[32:] - self.m = parse256(I_L) - self.M = SigningKey.from_string(I_L, curve=SECP256k1) \ - .get_verifying_key().pubkey.point - self.c = I_R - - def derive(self, path="m"): - tokens = path.split('/') - if tokens[0] == "m": - k = self.m - c = self.c - for r in tokens[1:]: - if not rformat.match(r): - raise self.path_error - if r[-1] == "'": - i = iH(int(r[:-1])) - else: - i = int(r) - k, c = ckd_prv(k, c, i) - return SigningKey.from_string(k.to_bytes(32, byteorder='big'), curve=SECP256k1) - elif tokens[0] == "M": - K = self.M - c = self.c - for r in tokens[1:]: - if not rformat.match(r): - raise self.path_error - if r[-1] == "'": - i = iH(int(r[:-1])) - else: - i = int(r) - K, c = ckd_pub(K, c, i) - return VerifyingKey.from_public_point(K, curve=SECP256k1) - else: - raise self.path_error - -def get_eth_addr(pk): - pub_key = pk.to_string() - m = keccak_256() - m.update(pub_key) - return m.hexdigest()[24:] - -def get_privkey_btc(sk): - priv_key = b'\x80' + sk.to_string() - checksum = sha256(sha256(priv_key))[:4] - return b58encode(priv_key + checksum).decode("utf-8") - -def get_btc_addr(pk): - h = b'\x00' + ripemd160(sha256(b'\x04' + pk.to_string())) - checksum = sha256(sha256(h))[:4] - h += checksum - return b58encode(h).decode("utf-8") - -def load_from_keystore(filename): - try: - with open(filename, "r") as f: - try: - parsed = json.load(f) - ciphertext = b58decode(parsed['keys'][0]['key'])[:-4] - iv = b58decode(parsed['keys'][0]['iv'])[:-4] - salt = b58decode(parsed['salt'])[:-4] - tag = b58decode(parsed['pass_hash'])[:-4] - passwd = getpass('Enter the password to unlock keystore: ').encode('utf-8') - key = hashlib.pbkdf2_hmac( - 'sha256', - sha256(passwd + salt), salt, 200000) - a = AES.new(key, - mode=AES.MODE_GCM, - nonce=iv) - if tag != sha256(passwd + sha256(passwd + salt)): - raise KeytreeError("incorrect keystore password") - return a.decrypt(ciphertext[:-16]).decode('utf-8') - except KeytreeError as e: - raise e - except: - raise KeytreeError("invalid or corrupted keystore file") - except FileNotFoundError: - raise KeytreeError("failed to open file") - - -def cb58encode(raw): - checksum = sha256(raw)[-4:] - return b58encode(raw + checksum) - - -def save_to_keystore(filename, words): - try: - with open(filename, "w") as f: - #try: - passwd = getpass('Enter the password for the keystore (utf-8): ').encode('utf-8') - iv = os.urandom(12) - salt = os.urandom(16) - pass_hash = sha256(passwd + sha256(passwd + salt)) - key = hashlib.pbkdf2_hmac( - 'sha256', - sha256(passwd + salt), salt, 200000) - a = AES.new(key, - mode=AES.MODE_GCM, - nonce=iv).update(salt) - (c, t) = a.encrypt_with_digest(words) - ciphertext = c + t - json.dump({ - 'keys': [ - {'key': cb58encode(ciphertext), 'iv': cb58encode(iv)}], - 'salt': cb58encode(salt), - 'pass_hash': cb58encode(pass_hash) - }, f) - #except: - # raise KeytreeError("invalid or corrupted keystore file") - except FileNotFoundError: - raise KeytreeError("failed to open file") - - -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Derive BIP32 key pairs from BIP39 mnemonic') - parser.add_argument('--load-keystore', type=str, default=None, help='load mnemonic from a keystore file (AVAX Wallet compatible)') - parser.add_argument('--save-keystore', type=str, default=None, help='save mnemonic to a keystore file (AVAX Wallet compatible)') - parser.add_argument('--show-private', action='store_true', default=False, help='also show private keys and the mnemonic') - parser.add_argument('--custom-words', action='store_true', default=False, help='use an arbitrary word combination as mnemonic') - parser.add_argument('--account-path', default="44'/9000'/0'/0", help="path prefix for key deriving (e.g. \"0/1'/2\")") - parser.add_argument('--gen-mnemonic', action='store_true', default=False, help='generate a mnemonic (instead of taking an input)') - parser.add_argument('--lang', type=str, default="english", help='language for mnemonic words') - parser.add_argument('--start-idx', type=int, default=0, help='the start index for keys') - parser.add_argument('--end-idx', type=int, default=1, help='the end index for keys (exclusive)') - parser.add_argument('--hrp', type=str, default="avax", help='HRP (Human Readable Prefix, defined by Bech32)') - - args = parser.parse_args() - - - try: - try: - if args.gen_mnemonic: - mgen = mnemonic.Mnemonic(args.lang) - words = mgen.generate(256) - else: - if args.load_keystore: - words = load_from_keystore(args.load_keystore) - else: - words = getpass('Enter the mnemonic: ').strip() - if not args.custom_words: - mchecker = mnemonic.Mnemonic(args.lang) - if not mchecker.check(words): - raise KeytreeError("invalid mnemonic") - except FileNotFoundError: - raise KeytreeError("invalid language") - if args.show_private or args.gen_mnemonic: - print("KEEP THIS PRIVATE: {}".format(words)) - seed = hashlib.pbkdf2_hmac('sha512', unicodedata.normalize('NFKD', words).encode("utf-8"), b"mnemonic", 2048) - gen = BIP32(seed) - if args.start_idx < 0 or args.end_idx < 0: - raise KeytreeError("invalid start/end index") - for i in range(args.start_idx, args.end_idx): - path = "m/{}/{}".format(args.account_path, i) - priv = gen.derive(path) - pub = priv.get_verifying_key() - cpub = pub.to_string(encoding="compressed") - if args.show_private: - print("{}.priv(raw) {}".format(i, priv.to_string().hex())) - print("{}.priv(BTC) {}".format(i, get_privkey_btc(priv))) - print("{}.addr(AVAX) X-{}".format(i, bech32.bech32_encode(args.hrp, bech32.convertbits(ripemd160(sha256(cpub)), 8, 5)))) - print("{}.addr(BTC) {}".format(i, get_btc_addr(pub))) - print("{}.addr(ETH) {}".format(i, get_eth_addr(pub))) - if args.save_keystore: - save_to_keystore(args.save_keystore, words) - except KeytreeError as e: - sys.stderr.write("error: {}\n".format(str(e))) - sys.exit(1) diff --git a/frozen_deps/ecdsa-0.16.1.dist-info/INSTALLER b/frozen_deps/ecdsa-0.16.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/frozen_deps/ecdsa-0.16.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/frozen_deps/ecdsa-0.16.1.dist-info/LICENSE b/frozen_deps/ecdsa-0.16.1.dist-info/LICENSE deleted file mode 100644 index 474479a..0000000 --- a/frozen_deps/ecdsa-0.16.1.dist-info/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -"python-ecdsa" Copyright (c) 2010 Brian Warner - -Portions written in 2005 by Peter Pearson and placed in the public domain. - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/frozen_deps/ecdsa-0.16.1.dist-info/METADATA b/frozen_deps/ecdsa-0.16.1.dist-info/METADATA deleted file mode 100644 index 983a64a..0000000 --- a/frozen_deps/ecdsa-0.16.1.dist-info/METADATA +++ /dev/null @@ -1,626 +0,0 @@ -Metadata-Version: 2.1 -Name: ecdsa -Version: 0.16.1 -Summary: ECDSA cryptographic signature library (pure python) -Home-page: http://github.com/warner/python-ecdsa -Author: Brian Warner -Author-email: warner@lothar.com -License: MIT -Platform: UNKNOWN -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.* -Description-Content-Type: text/markdown -Requires-Dist: six (>=1.9.0) -Provides-Extra: gmpy -Requires-Dist: gmpy ; extra == 'gmpy' -Provides-Extra: gmpy2 -Requires-Dist: gmpy2 ; extra == 'gmpy2' - -# Pure-Python ECDSA - -[](http://travis-ci.org/warner/python-ecdsa) -[](https://coveralls.io/r/warner/python-ecdsa) -[](https://travis-ci.org/warner/python-ecdsa/jobs/626479178#L776) -[](https://pypi.python.org/pypi/ecdsa/) - - - -This is an easy-to-use implementation of ECDSA cryptography (Elliptic Curve -Digital Signature Algorithm), implemented purely in Python, released under -the MIT license. With this library, you can quickly create keypairs (signing -key and verifying key), sign messages, and verify the signatures. The keys -and signatures are very short, making them easy to handle and incorporate -into other protocols. - -## Features - -This library provides key generation, signing, and verifying, for five -popular NIST "Suite B" GF(p) (_prime field_) curves, with key lengths of 192, -224, 256, 384, and 521 bits. The "short names" for these curves, as known by -the OpenSSL tool (`openssl ecparam -list_curves`), are: `prime192v1`, -`secp224r1`, `prime256v1`, `secp384r1`, and `secp521r1`. It includes the -256-bit curve `secp256k1` used by Bitcoin. There is also support for the -regular (non-twisted) variants of Brainpool curves from 160 to 512 bits. The -"short names" of those curves are: `brainpoolP160r1`, `brainpoolP192r1`, -`brainpoolP224r1`, `brainpoolP256r1`, `brainpoolP320r1`, `brainpoolP384r1`, -`brainpoolP512r1`. -No other curves are included, but it is not too hard to add support for more -curves over prime fields. - -## Dependencies - -This library uses only Python and the 'six' package. It is compatible with -Python 2.6, 2.7 and 3.3+. It also supports execution on the alternative -implementations like pypy and pypy3. - -If `gmpy2` or `gmpy` is installed, they will be used for faster arithmetic. -Either of them can be installed after this library is installed, -`python-ecdsa` will detect their presence on start-up and use them -automatically. - -To run the OpenSSL compatibility tests, the 'openssl' tool must be in your -`PATH`. This release has been tested successfully against OpenSSL 0.9.8o, -1.0.0a, 1.0.2f and 1.1.1d (among others). - - -## Installation - -This library is available on PyPI, it's recommended to install it using `pip`: - -``` -pip install ecdsa -``` - -In case higher performance is wanted and using native code is not a problem, -it's possible to specify installation together with `gmpy2`: - -``` -pip install ecdsa[gmpy2] -``` - -or (slower, legacy option): -``` -pip install ecdsa[gmpy] -``` - -## Speed - -The following table shows how long this library takes to generate keypairs -(`keygen`), to sign data (`sign`), and to verify those signatures (`verify`). -All those values are in seconds. -For convenience, the inverses of those values are also provided: -how many keys per second can be generated (`keygen/s`), how many signatures -can be made per second (`sign/s`) and how many signatures can be verified -per second (`verify/s`). The size of raw signature (generally the smallest -way a signature can be encoded) is also provided in the `siglen` column. -Use `tox -e speed` to generate this table on your own computer. -On an Intel Core i7 4790K @ 4.0GHz I'm getting the following performance: - -``` - siglen keygen keygen/s sign sign/s verify verify/s - NIST192p: 48 0.00035s 2893.02 0.00038s 2620.53 0.00069s 1458.92 - NIST224p: 56 0.00043s 2307.11 0.00048s 2092.00 0.00088s 1131.33 - NIST256p: 64 0.00056s 1793.70 0.00061s 1639.87 0.00113s 883.79 - NIST384p: 96 0.00116s 864.33 0.00124s 806.29 0.00233s 429.87 - NIST521p: 132 0.00221s 452.16 0.00234s 427.31 0.00460s 217.19 - SECP256k1: 64 0.00056s 1772.65 0.00061s 1628.73 0.00110s 912.13 - BRAINPOOLP160r1: 40 0.00026s 3801.86 0.00029s 3401.11 0.00052s 1930.47 - BRAINPOOLP192r1: 48 0.00034s 2925.73 0.00038s 2634.34 0.00070s 1438.06 - BRAINPOOLP224r1: 56 0.00044s 2287.98 0.00048s 2083.87 0.00088s 1137.52 - BRAINPOOLP256r1: 64 0.00056s 1774.11 0.00061s 1628.25 0.00112s 890.71 - BRAINPOOLP320r1: 80 0.00081s 1238.18 0.00087s 1146.71 0.00151s 661.95 - BRAINPOOLP384r1: 96 0.00117s 855.47 0.00124s 804.56 0.00241s 414.83 - BRAINPOOLP512r1: 128 0.00223s 447.99 0.00234s 427.49 0.00437s 229.09 - - ecdh ecdh/s - NIST192p: 0.00110s 910.70 - NIST224p: 0.00143s 701.17 - NIST256p: 0.00178s 560.44 - NIST384p: 0.00383s 261.03 - NIST521p: 0.00745s 134.23 - SECP256k1: 0.00168s 596.23 - BRAINPOOLP160r1: 0.00085s 1174.02 - BRAINPOOLP192r1: 0.00113s 883.47 - BRAINPOOLP224r1: 0.00145s 687.82 - BRAINPOOLP256r1: 0.00195s 514.03 - BRAINPOOLP320r1: 0.00277s 360.80 - BRAINPOOLP384r1: 0.00412s 242.58 - BRAINPOOLP512r1: 0.00787s 127.12 -``` - -To test performance with `gmpy2` loaded, use `tox -e speedgmpy2`. -On the same machine I'm getting the following performance with `gmpy2`: -``` - siglen keygen keygen/s sign sign/s verify verify/s - NIST192p: 48 0.00017s 5945.50 0.00018s 5544.66 0.00033s 3002.54 - NIST224p: 56 0.00021s 4742.14 0.00022s 4463.52 0.00044s 2248.59 - NIST256p: 64 0.00024s 4155.73 0.00025s 3994.28 0.00047s 2105.34 - NIST384p: 96 0.00041s 2415.06 0.00043s 2316.41 0.00085s 1177.18 - NIST521p: 132 0.00072s 1391.14 0.00074s 1359.63 0.00140s 716.31 - SECP256k1: 64 0.00024s 4216.50 0.00025s 3994.52 0.00047s 2120.57 - BRAINPOOLP160r1: 40 0.00014s 7038.99 0.00015s 6501.55 0.00029s 3397.79 - BRAINPOOLP192r1: 48 0.00017s 5983.18 0.00018s 5626.08 0.00035s 2843.62 - BRAINPOOLP224r1: 56 0.00021s 4727.54 0.00022s 4464.86 0.00043s 2326.84 - BRAINPOOLP256r1: 64 0.00024s 4221.00 0.00025s 4010.26 0.00049s 2046.40 - BRAINPOOLP320r1: 80 0.00032s 3142.14 0.00033s 3009.15 0.00061s 1652.88 - BRAINPOOLP384r1: 96 0.00041s 2415.98 0.00043s 2340.35 0.00083s 1198.77 - BRAINPOOLP512r1: 128 0.00064s 1567.27 0.00066s 1526.33 0.00127s 788.51 - - ecdh ecdh/s - NIST192p: 0.00051s 1960.26 - NIST224p: 0.00067s 1502.97 - NIST256p: 0.00073s 1376.12 - NIST384p: 0.00132s 758.68 - NIST521p: 0.00231s 433.23 - SECP256k1: 0.00072s 1387.18 - BRAINPOOLP160r1: 0.00042s 2366.60 - BRAINPOOLP192r1: 0.00049s 2026.80 - BRAINPOOLP224r1: 0.00067s 1486.52 - BRAINPOOLP256r1: 0.00076s 1310.31 - BRAINPOOLP320r1: 0.00101s 986.16 - BRAINPOOLP384r1: 0.00131s 761.35 - BRAINPOOLP512r1: 0.00211s 473.30 -``` - -(there's also `gmpy` version, execute it using `tox -e speedgmpy`) - -For comparison, a highly optimised implementation (including curve-specific -assembly for some curves), like the one in OpenSSL 1.1.1d, provides following -performance numbers on the same machine. -Run `openssl speed ecdsa` and `openssl speed ecdh` to reproduce it: -``` - sign verify sign/s verify/s - 192 bits ecdsa (nistp192) 0.0002s 0.0002s 4785.6 5380.7 - 224 bits ecdsa (nistp224) 0.0000s 0.0001s 22475.6 9822.0 - 256 bits ecdsa (nistp256) 0.0000s 0.0001s 45069.6 14166.6 - 384 bits ecdsa (nistp384) 0.0008s 0.0006s 1265.6 1648.1 - 521 bits ecdsa (nistp521) 0.0003s 0.0005s 3753.1 1819.5 - 256 bits ecdsa (brainpoolP256r1) 0.0003s 0.0003s 2983.5 3333.2 - 384 bits ecdsa (brainpoolP384r1) 0.0008s 0.0007s 1258.8 1528.1 - 512 bits ecdsa (brainpoolP512r1) 0.0015s 0.0012s 675.1 860.1 - - op op/s - 192 bits ecdh (nistp192) 0.0002s 4853.4 - 224 bits ecdh (nistp224) 0.0001s 15252.1 - 256 bits ecdh (nistp256) 0.0001s 18436.3 - 384 bits ecdh (nistp384) 0.0008s 1292.7 - 521 bits ecdh (nistp521) 0.0003s 2884.7 - 256 bits ecdh (brainpoolP256r1) 0.0003s 3066.5 - 384 bits ecdh (brainpoolP384r1) 0.0008s 1298.0 - 512 bits ecdh (brainpoolP512r1) 0.0014s 694.8 -``` - -Keys and signature can be serialized in different ways (see Usage, below). -For a NIST192p key, the three basic representations require strings of the -following lengths (in bytes): - - to_string: signkey= 24, verifykey= 48, signature=48 - compressed: signkey=n/a, verifykey= 25, signature=n/a - DER: signkey=106, verifykey= 80, signature=55 - PEM: signkey=278, verifykey=162, (no support for PEM signatures) - -## History - -In 2006, Peter Pearson announced his pure-python implementation of ECDSA in a -[message to sci.crypt][1], available from his [download site][2]. In 2010, -Brian Warner wrote a wrapper around this code, to make it a bit easier and -safer to use. Hubert Kario then included an implementation of elliptic curve -cryptography that uses Jacobian coordinates internally, improving performance -about 20-fold. You are looking at the README for this wrapper. - -[1]: http://www.derkeiler.com/Newsgroups/sci.crypt/2006-01/msg00651.html -[2]: http://webpages.charter.net/curryfans/peter/downloads.html - -## Testing - -To run the full test suite, do this: - - tox -e coverage - -On an Intel Core i7 4790K @ 4.0GHz, the tests take about 16 seconds to execute. -The test suite uses -[`hypothesis`](https://github.com/HypothesisWorks/hypothesis) so there is some -inherent variability in the test suite execution time. - -One part of `test_pyecdsa.py` checks compatibility with OpenSSL, by -running the "openssl" CLI tool, make sure it's in your `PATH` if you want -to test compatibility with it. - -## Security - -This library was not designed with security in mind. If you are processing -data that needs to be protected we suggest you use a quality wrapper around -OpenSSL. [pyca/cryptography](https://cryptography.io) is one example of such -a wrapper. The primary use-case of this library is as a portable library for -interoperability testing and as a teaching tool. - -**This library does not protect against side channel attacks.** - -Do not allow attackers to measure how long it takes you to generate a keypair -or sign a message. Do not allow attackers to run code on the same physical -machine when keypair generation or signing is taking place (this includes -virtual machines). Do not allow attackers to measure how much power your -computer uses while generating the keypair or signing a message. Do not allow -attackers to measure RF interference coming from your computer while generating -a keypair or signing a message. Note: just loading the private key will cause -keypair generation. Other operations or attack vectors may also be -vulnerable to attacks. **For a sophisticated attacker observing just one -operation with a private key will be sufficient to completely -reconstruct the private key**. - -Please also note that any Pure-python cryptographic library will be vulnerable -to the same side channel attacks. This is because Python does not provide -side-channel secure primitives (with the exception of -[`hmac.compare_digest()`][3]), making side-channel secure programming -impossible. - -This library depends upon a strong source of random numbers. Do not use it on -a system where `os.urandom()` does not provide cryptographically secure -random numbers. - -[3]: https://docs.python.org/3/library/hmac.html#hmac.compare_digest - -## Usage - -You start by creating a `SigningKey`. You can use this to sign data, by passing -in data as a byte string and getting back the signature (also a byte string). -You can also ask a `SigningKey` to give you the corresponding `VerifyingKey`. -The `VerifyingKey` can be used to verify a signature, by passing it both the -data string and the signature byte string: it either returns True or raises -`BadSignatureError`. - -```python -from ecdsa import SigningKey -sk = SigningKey.generate() # uses NIST192p -vk = sk.verifying_key -signature = sk.sign(b"message") -assert vk.verify(signature, b"message") -``` - -Each `SigningKey`/`VerifyingKey` is associated with a specific curve, like -NIST192p (the default one). Longer curves are more secure, but take longer to -use, and result in longer keys and signatures. - -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -signature = sk.sign(b"message") -assert vk.verify(signature, b"message") -``` - -The `SigningKey` can be serialized into several different formats: the shortest -is to call `s=sk.to_string()`, and then re-create it with -`SigningKey.from_string(s, curve)` . This short form does not record the -curve, so you must be sure to pass to `from_string()` the same curve you used -for the original key. The short form of a NIST192p-based signing key is just 24 -bytes long. If a point encoding is invalid or it does not lie on the specified -curve, `from_string()` will raise `MalformedPointError`. - -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -sk_string = sk.to_string() -sk2 = SigningKey.from_string(sk_string, curve=NIST384p) -print(sk_string.hex()) -print(sk2.to_string().hex()) -``` - -Note: while the methods are called `to_string()` the type they return is -actually `bytes`, the "string" part is leftover from Python 2. - -`sk.to_pem()` and `sk.to_der()` will serialize the signing key into the same -formats that OpenSSL uses. The PEM file looks like the familiar ASCII-armored -`"-----BEGIN EC PRIVATE KEY-----"` base64-encoded format, and the DER format -is a shorter binary form of the same data. -`SigningKey.from_pem()/.from_der()` will undo this serialization. These -formats include the curve name, so you do not need to pass in a curve -identifier to the deserializer. In case the file is malformed `from_der()` -and `from_pem()` will raise `UnexpectedDER` or` MalformedPointError`. - -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -sk_pem = sk.to_pem() -sk2 = SigningKey.from_pem(sk_pem) -# sk and sk2 are the same key -``` - -Likewise, the `VerifyingKey` can be serialized in the same way: -`vk.to_string()/VerifyingKey.from_string()`, `to_pem()/from_pem()`, and -`to_der()/from_der()`. The same `curve=` argument is needed for -`VerifyingKey.from_string()`. - -```python -from ecdsa import SigningKey, VerifyingKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -vk_string = vk.to_string() -vk2 = VerifyingKey.from_string(vk_string, curve=NIST384p) -# vk and vk2 are the same key - -from ecdsa import SigningKey, VerifyingKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -vk_pem = vk.to_pem() -vk2 = VerifyingKey.from_pem(vk_pem) -# vk and vk2 are the same key -``` - -There are a couple of different ways to compute a signature. Fundamentally, -ECDSA takes a number that represents the data being signed, and returns a -pair of numbers that represent the signature. The `hashfunc=` argument to -`sk.sign()` and `vk.verify()` is used to turn an arbitrary string into -fixed-length digest, which is then turned into a number that ECDSA can sign, -and both sign and verify must use the same approach. The default value is -`hashlib.sha1`, but if you use NIST256p or a longer curve, you can use -`hashlib.sha256` instead. - -There are also multiple ways to represent a signature. The default -`sk.sign()` and `vk.verify()` methods present it as a short string, for -simplicity and minimal overhead. To use a different scheme, use the -`sk.sign(sigencode=)` and `vk.verify(sigdecode=)` arguments. There are helper -functions in the `ecdsa.util` module that can be useful here. - -It is also possible to create a `SigningKey` from a "seed", which is -deterministic. This can be used in protocols where you want to derive -consistent signing keys from some other secret, for example when you want -three separate keys and only want to store a single master secret. You should -start with a uniformly-distributed unguessable seed with about `curve.baselen` -bytes of entropy, and then use one of the helper functions in `ecdsa.util` to -convert it into an integer in the correct range, and then finally pass it -into `SigningKey.from_secret_exponent()`, like this: - -```python -import os -from ecdsa import NIST384p, SigningKey -from ecdsa.util import randrange_from_seed__trytryagain - -def make_key(seed): - secexp = randrange_from_seed__trytryagain(seed, NIST384p.order) - return SigningKey.from_secret_exponent(secexp, curve=NIST384p) - -seed = os.urandom(NIST384p.baselen) # or other starting point -sk1a = make_key(seed) -sk1b = make_key(seed) -# note: sk1a and sk1b are the same key -assert sk1a.to_string() == sk1b.to_string() -sk2 = make_key(b"2-"+seed) # different key -assert sk1a.to_string() != sk2.to_string() -``` - -In case the application will verify a lot of signatures made with a single -key, it's possible to precompute some of the internal values to make -signature verification significantly faster. The break-even point occurs at -about 100 signatures verified. - -To perform precomputation, you can call the `precompute()` method -on `VerifyingKey` instance: -```python -from ecdsa import SigningKey, NIST384p -sk = SigningKey.generate(curve=NIST384p) -vk = sk.verifying_key -vk.precompute() -signature = sk.sign(b"message") -assert vk.verify(signature, b"message") -``` - -Once `precompute()` was called, all signature verifications with this key will -be faster to execute. - -## OpenSSL Compatibility - -To produce signatures that can be verified by OpenSSL tools, or to verify -signatures that were produced by those tools, use: - -```python -# openssl ecparam -name prime256v1 -genkey -out sk.pem -# openssl ec -in sk.pem -pubout -out vk.pem -# echo "data for signing" > data -# openssl dgst -sha256 -sign sk.pem -out data.sig data -# openssl dgst -sha256 -verify vk.pem -signature data.sig data -# openssl dgst -sha256 -prverify sk.pem -signature data.sig data - -import hashlib -from ecdsa import SigningKey, VerifyingKey -from ecdsa.util import sigencode_der, sigdecode_der - -with open("vk.pem") as f: - vk = VerifyingKey.from_pem(f.read()) - -with open("data", "rb") as f: - data = f.read() - -with open("data.sig", "rb") as f: - signature = f.read() - -assert vk.verify(signature, data, hashlib.sha256, sigdecode=sigdecode_der) - -with open("sk.pem") as f: - sk = SigningKey.from_pem(f.read(), hashlib.sha256) - -new_signature = sk.sign_deterministic(data, sigencode=sigencode_der) - -with open("data.sig2", "wb") as f: - f.write(new_signature) - -# openssl dgst -sha256 -verify vk.pem -signature data.sig2 data -``` - -Note: if compatibility with OpenSSL 1.0.0 or earlier is necessary, the -`sigencode_string` and `sigdecode_string` from `ecdsa.util` can be used for -respectively writing and reading the signatures. - -The keys also can be written in format that openssl can handle: - -```python -from ecdsa import SigningKey, VerifyingKey - -with open("sk.pem") as f: - sk = SigningKey.from_pem(f.read()) -with open("sk.pem", "wb") as f: - f.write(sk.to_pem()) - -with open("vk.pem") as f: - vk = VerifyingKey.from_pem(f.read()) -with open("vk.pem", "wb") as f: - f.write(vk.to_pem()) -``` - -## Entropy - -Creating a signing key with `SigningKey.generate()` requires some form of -entropy (as opposed to -`from_secret_exponent`/`from_string`/`from_der`/`from_pem`, -which are deterministic and do not require an entropy source). The default -source is `os.urandom()`, but you can pass any other function that behaves -like `os.urandom` as the `entropy=` argument to do something different. This -may be useful in unit tests, where you want to achieve repeatable results. The -`ecdsa.util.PRNG` utility is handy here: it takes a seed and produces a strong -pseudo-random stream from it: - -```python -from ecdsa.util import PRNG -from ecdsa import SigningKey -rng1 = PRNG(b"seed") -sk1 = SigningKey.generate(entropy=rng1) -rng2 = PRNG(b"seed") -sk2 = SigningKey.generate(entropy=rng2) -# sk1 and sk2 are the same key -``` - -Likewise, ECDSA signature generation requires a random number, and each -signature must use a different one (using the same number twice will -immediately reveal the private signing key). The `sk.sign()` method takes an -`entropy=` argument which behaves the same as `SigningKey.generate(entropy=)`. - -## Deterministic Signatures - -If you call `SigningKey.sign_deterministic(data)` instead of `.sign(data)`, -the code will generate a deterministic signature instead of a random one. -This uses the algorithm from RFC6979 to safely generate a unique `k` value, -derived from the private key and the message being signed. Each time you sign -the same message with the same key, you will get the same signature (using -the same `k`). - -This may become the default in a future version, as it is not vulnerable to -failures of the entropy source. - -## Examples - -Create a NIST192p keypair and immediately save both to disk: - -```python -from ecdsa import SigningKey -sk = SigningKey.generate() -vk = sk.verifying_key -with open("private.pem", "wb") as f: - f.write(sk.to_pem()) -with open("public.pem", "wb") as f: - f.write(vk.to_pem()) -``` - -Load a signing key from disk, use it to sign a message (using SHA-1), and write -the signature to disk: - -```python -from ecdsa import SigningKey -with open("private.pem") as f: - sk = SigningKey.from_pem(f.read()) -with open("message", "rb") as f: - message = f.read() -sig = sk.sign(message) -with open("signature", "wb") as f: - f.write(sig) -``` - -Load the verifying key, message, and signature from disk, and verify the -signature (assume SHA-1 hash): - -```python -from ecdsa import VerifyingKey, BadSignatureError -vk = VerifyingKey.from_pem(open("public.pem").read()) -with open("message", "rb") as f: - message = f.read() -with open("signature", "rb") as f: - sig = f.read() -try: - vk.verify(sig, message) - print "good signature" -except BadSignatureError: - print "BAD SIGNATURE" -``` - -Create a NIST521p keypair: - -```python -from ecdsa import SigningKey, NIST521p -sk = SigningKey.generate(curve=NIST521p) -vk = sk.verifying_key -``` - -Create three independent signing keys from a master seed: - -```python -from ecdsa import NIST192p, SigningKey -from ecdsa.util import randrange_from_seed__trytryagain - -def make_key_from_seed(seed, curve=NIST192p): - secexp = randrange_from_seed__trytryagain(seed, curve.order) - return SigningKey.from_secret_exponent(secexp, curve) - -sk1 = make_key_from_seed("1:%s" % seed) -sk2 = make_key_from_seed("2:%s" % seed) -sk3 = make_key_from_seed("3:%s" % seed) -``` - -Load a verifying key from disk and print it using hex encoding in -uncompressed and compressed format (defined in X9.62 and SEC1 standards): - -```python -from ecdsa import VerifyingKey - -with open("public.pem") as f: - vk = VerifyingKey.from_pem(f.read()) - -print("uncompressed: {0}".format(vk.to_string("uncompressed").hex())) -print("compressed: {0}".format(vk.to_string("compressed").hex())) -``` - -Load a verifying key from a hex string from compressed format, output -uncompressed: - -```python -from ecdsa import VerifyingKey, NIST256p - -comp_str = '022799c0d0ee09772fdd337d4f28dc155581951d07082fb19a38aa396b67e77759' -vk = VerifyingKey.from_string(bytearray.fromhex(comp_str), curve=NIST256p) -print(vk.to_string("uncompressed").hex()) -``` - -ECDH key exchange with remote party - -```python -from ecdsa import ECDH, NIST256p - -ecdh = ECDH(curve=NIST256p) -ecdh.generate_private_key() -local_public_key = ecdh.get_public_key() -#send `local_public_key` to remote party and receive `remote_public_key` from remote party -with open("remote_public_key.pem") as e: - remote_public_key = e.read() -ecdh.load_received_public_key_pem(remote_public_key) -secret = ecdh.generate_sharedsecret_bytes() -``` - - diff --git a/frozen_deps/ecdsa-0.16.1.dist-info/RECORD b/frozen_deps/ecdsa-0.16.1.dist-info/RECORD deleted file mode 100644 index 4382e84..0000000 --- a/frozen_deps/ecdsa-0.16.1.dist-info/RECORD +++ /dev/null @@ -1,52 +0,0 @@ -ecdsa-0.16.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-ecdsa-0.16.1.dist-info/LICENSE,sha256=PsqYRXc9LluMydjBGdNF8ApIBuS9Zg1KPWzfnA6di7I,1147
-ecdsa-0.16.1.dist-info/METADATA,sha256=cwaWRd_w5Q-Y4wENZxW14D0cpK13fE3AP56XLw-tF50,24993
-ecdsa-0.16.1.dist-info/RECORD,,
-ecdsa-0.16.1.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
-ecdsa-0.16.1.dist-info/top_level.txt,sha256=7ovPHfAPyTou19f8gOSbHm6B9dGjTibWolcCB7Zjovs,6
-ecdsa/__init__.py,sha256=u-_1cu1I_GIwJ0DRYY7LNvkB4pvodv1kHztsAsCX3eA,1325
-ecdsa/__pycache__/__init__.cpython-38.pyc,,
-ecdsa/__pycache__/_compat.cpython-38.pyc,,
-ecdsa/__pycache__/_rwlock.cpython-38.pyc,,
-ecdsa/__pycache__/_version.cpython-38.pyc,,
-ecdsa/__pycache__/curves.cpython-38.pyc,,
-ecdsa/__pycache__/der.cpython-38.pyc,,
-ecdsa/__pycache__/ecdh.cpython-38.pyc,,
-ecdsa/__pycache__/ecdsa.cpython-38.pyc,,
-ecdsa/__pycache__/ellipticcurve.cpython-38.pyc,,
-ecdsa/__pycache__/keys.cpython-38.pyc,,
-ecdsa/__pycache__/numbertheory.cpython-38.pyc,,
-ecdsa/__pycache__/rfc6979.cpython-38.pyc,,
-ecdsa/__pycache__/test_der.cpython-38.pyc,,
-ecdsa/__pycache__/test_ecdh.cpython-38.pyc,,
-ecdsa/__pycache__/test_ecdsa.cpython-38.pyc,,
-ecdsa/__pycache__/test_ellipticcurve.cpython-38.pyc,,
-ecdsa/__pycache__/test_jacobi.cpython-38.pyc,,
-ecdsa/__pycache__/test_keys.cpython-38.pyc,,
-ecdsa/__pycache__/test_malformed_sigs.cpython-38.pyc,,
-ecdsa/__pycache__/test_numbertheory.cpython-38.pyc,,
-ecdsa/__pycache__/test_pyecdsa.cpython-38.pyc,,
-ecdsa/__pycache__/test_rw_lock.cpython-38.pyc,,
-ecdsa/__pycache__/util.cpython-38.pyc,,
-ecdsa/_compat.py,sha256=j_BnKmVOkjucCQbCuLaFsxHSiEUqj_co5sSAPLLWSsk,1659
-ecdsa/_rwlock.py,sha256=CAwHp2V65ksI8B1UqY7EccK9LaUToiv6pDLVzm44eag,2849
-ecdsa/_version.py,sha256=Qncu2Mr06Q_KO_8jvc8zi5RZ4XgaxiWI17VDRqKMrfw,498
-ecdsa/curves.py,sha256=rlAVrS6hwZ6sNnTswdRMJBlC-mryxXYo7zZIEQjYOPE,3735
-ecdsa/der.py,sha256=l528iLGUwqcNokzDkk-2qO3-6_nzL908OfB0GhUhbZ8,14092
-ecdsa/ecdh.py,sha256=K7T-XoiP-Y_bsGcnulcXFsr_7P5LCK2O4wbM-WkopDQ,10631
-ecdsa/ecdsa.py,sha256=5xD8X3qD9By3aZdxVoPOyx_FFDRNVrRUhxtw5j70g0g,21232
-ecdsa/ellipticcurve.py,sha256=l11lgxjqTe2ocyOed9M19FKZR7kNAB3dUfUvjJLAcsk,27437
-ecdsa/keys.py,sha256=1-YQm967hqvOsnF9o7Tw0eHyo21YHkZYzcKOckebfGI,59502
-ecdsa/numbertheory.py,sha256=yLx-P5-esRFT63gDSvKBfoiwOfSyVfjXyFcGF9_SFbM,16764
-ecdsa/rfc6979.py,sha256=x6dCO2l3QlPLHE-w3c456rqthhSBP03dCnTfSweBgBU,2725
-ecdsa/test_der.py,sha256=jifDHof2nEDs2phCEYMOJ-h6oCEuqS-pz8x65rrmm8U,12653
-ecdsa/test_ecdh.py,sha256=PxwESmg9_ckt1N9yXA88yN_0bERwkXDojSP9Oppfub8,13510
-ecdsa/test_ecdsa.py,sha256=csODW8xYt_LhjEvHiWteehEU2UxBLodvkQk21aMNCzs,19696
-ecdsa/test_ellipticcurve.py,sha256=todhFIkd2pyRCqfa7S92o69uOM7DfFp1tkD7LFa2Edw,6112
-ecdsa/test_jacobi.py,sha256=Ie3NocTE1i69oHxfnmnmvwqXJIlQpzVAFAG1rJq3YFU,12178
-ecdsa/test_keys.py,sha256=lT05J0Cu7C0HLu8cicBKBGRzmkuQBIECHQEzBmXYDzQ,14157
-ecdsa/test_malformed_sigs.py,sha256=Sr4RdBG4WWpOdJBME8f4v82uvbqJ_2cKyccL9crsi58,10300
-ecdsa/test_numbertheory.py,sha256=VqEme1ND9gbh2aMKsXXnZXcI4fpSvfkglM1O8DQpxR8,8815
-ecdsa/test_pyecdsa.py,sha256=61c5ASQ9pHKIYg73JWiIZdlCz4wqmkvCqmPJKVBNzn4,73402
-ecdsa/test_rw_lock.py,sha256=pkSoLder1YdsyRPSam8topCvdMytQjV3q-sCqrjx4nE,6959
-ecdsa/util.py,sha256=lHkBmYk4wuUETSUj4V23ssCjL385zCDxFr24jptXxI8,14557
diff --git a/frozen_deps/ecdsa-0.16.1.dist-info/WHEEL b/frozen_deps/ecdsa-0.16.1.dist-info/WHEEL deleted file mode 100644 index 8b701e9..0000000 --- a/frozen_deps/ecdsa-0.16.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.33.6) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/frozen_deps/ecdsa-0.16.1.dist-info/top_level.txt b/frozen_deps/ecdsa-0.16.1.dist-info/top_level.txt deleted file mode 100644 index aa5efdb..0000000 --- a/frozen_deps/ecdsa-0.16.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -ecdsa diff --git a/frozen_deps/ecdsa/__init__.py b/frozen_deps/ecdsa/__init__.py index 4ae0a11..342538e 100644 --- a/frozen_deps/ecdsa/__init__.py +++ b/frozen_deps/ecdsa/__init__.py @@ -1,3 +1,6 @@ +# while we don't use six in this file, we did bundle it for a long time, so +# keep as part of module in a virtual way (through __all__) +import six from .keys import ( SigningKey, VerifyingKey, @@ -19,6 +22,19 @@ from .curves import ( BRAINPOOLP320r1, BRAINPOOLP384r1, BRAINPOOLP512r1, + SECP112r1, + SECP112r2, + SECP128r1, + SECP160r1, + Ed25519, + Ed448, + BRAINPOOLP160t1, + BRAINPOOLP192t1, + BRAINPOOLP224t1, + BRAINPOOLP256t1, + BRAINPOOLP320t1, + BRAINPOOLP384t1, + BRAINPOOLP512t1, ) from .ecdh import ( ECDH, @@ -28,13 +44,9 @@ from .ecdh import ( InvalidSharedSecretError, ) from .der import UnexpectedDER +from . import _version -# This code comes from http://github.com/warner/python-ecdsa -from ._version import get_versions - -__version__ = get_versions()["version"] -del get_versions - +# This code comes from http://github.com/tlsfuzzer/python-ecdsa __all__ = [ "curves", "der", @@ -72,5 +84,21 @@ _hush_pyflakes = [ BRAINPOOLP320r1, BRAINPOOLP384r1, BRAINPOOLP512r1, + SECP112r1, + SECP112r2, + SECP128r1, + SECP160r1, + Ed25519, + Ed448, + six.b(""), + BRAINPOOLP160t1, + BRAINPOOLP192t1, + BRAINPOOLP224t1, + BRAINPOOLP256t1, + BRAINPOOLP320t1, + BRAINPOOLP384t1, + BRAINPOOLP512t1, ] del _hush_pyflakes + +__version__ = _version.get_versions()["version"] diff --git a/frozen_deps/ecdsa/_compat.py b/frozen_deps/ecdsa/_compat.py index 720360b..4558e33 100644 --- a/frozen_deps/ecdsa/_compat.py +++ b/frozen_deps/ecdsa/_compat.py @@ -3,6 +3,7 @@ Common functions for providing cross-python version compatibility. """ import sys import re +import binascii from six import integer_types @@ -14,7 +15,8 @@ def str_idx_as_int(string, index): return ord(val) -if sys.version_info < (3, 0): +if sys.version_info < (3, 0): # pragma: no branch + import platform def normalise_bytes(buffer_object): """Cast the input into array of bytes.""" @@ -24,37 +26,113 @@ if sys.version_info < (3, 0): def hmac_compat(ret): return ret - if sys.version_info < (2, 7) or sys.version_info < (2, 7, 4): + if ( + sys.version_info < (2, 7) + or sys.version_info < (2, 7, 4) + or platform.system() == "Java" + ): # pragma: no branch def remove_whitespace(text): """Removes all whitespace from passed in string""" return re.sub(r"\s+", "", text) + def compat26_str(val): + return str(val) + + def bit_length(val): + if val == 0: + return 0 + return len(bin(val)) - 2 + else: def remove_whitespace(text): """Removes all whitespace from passed in string""" return re.sub(r"\s+", "", text, flags=re.UNICODE) + def compat26_str(val): + return val + + def bit_length(val): + """Return number of bits necessary to represent an integer.""" + return val.bit_length() + + def b2a_hex(val): + return binascii.b2a_hex(compat26_str(val)) + + def a2b_hex(val): + try: + return bytearray(binascii.a2b_hex(val)) + except Exception as e: + raise ValueError("base16 error: %s" % e) + + def bytes_to_int(val, byteorder): + """Convert bytes to an int.""" + if not val: + return 0 + if byteorder == "big": + return int(b2a_hex(val), 16) + if byteorder == "little": + return int(b2a_hex(val[::-1]), 16) + raise ValueError("Only 'big' and 'little' endian supported") + + def int_to_bytes(val, length=None, byteorder="big"): + """Return number converted to bytes""" + if length is None: + length = byte_length(val) + if byteorder == "big": + return bytearray( + (val >> i) & 0xFF for i in reversed(range(0, length * 8, 8)) + ) + if byteorder == "little": + return bytearray( + (val >> i) & 0xFF for i in range(0, length * 8, 8) + ) + raise ValueError("Only 'big' or 'little' endian supported") else: - if sys.version_info < (3, 4): - # on python 3.3 hmac.hmac.update() accepts only bytes, on newer - # versions it does accept memoryview() also - def hmac_compat(data): - if not isinstance(data, bytes): - return bytes(data) - return data - - else: - def hmac_compat(data): - return data + def hmac_compat(data): + return data def normalise_bytes(buffer_object): """Cast the input into array of bytes.""" return memoryview(buffer_object).cast("B") + def compat26_str(val): + return val + def remove_whitespace(text): """Removes all whitespace from passed in string""" return re.sub(r"\s+", "", text, flags=re.UNICODE) + + def a2b_hex(val): + try: + return bytearray(binascii.a2b_hex(bytearray(val, "ascii"))) + except Exception as e: + raise ValueError("base16 error: %s" % e) + + # pylint: disable=invalid-name + # pylint is stupid here and doesn't notice it's a function, not + # constant + bytes_to_int = int.from_bytes + # pylint: enable=invalid-name + + def bit_length(val): + """Return number of bits necessary to represent an integer.""" + return val.bit_length() + + def int_to_bytes(val, length=None, byteorder="big"): + """Convert integer to bytes.""" + if length is None: + length = byte_length(val) + # for gmpy we need to convert back to native int + if not isinstance(val, int): + val = int(val) + return bytearray(val.to_bytes(length=length, byteorder=byteorder)) + + +def byte_length(val): + """Return number of bytes necessary to represent an integer.""" + length = bit_length(val) + return (length + 7) // 8 diff --git a/frozen_deps/ecdsa/_sha3.py b/frozen_deps/ecdsa/_sha3.py new file mode 100644 index 0000000..2db0058 --- /dev/null +++ b/frozen_deps/ecdsa/_sha3.py @@ -0,0 +1,181 @@ +""" +Implementation of the SHAKE-256 algorithm for Ed448 +""" + +try: + import hashlib + + hashlib.new("shake256").digest(64) + + def shake_256(msg, outlen): + return hashlib.new("shake256", msg).digest(outlen) + +except (TypeError, ValueError): + + from ._compat import bytes_to_int, int_to_bytes + + # From little endian. + def _from_le(s): + return bytes_to_int(s, byteorder="little") + + # Rotate a word x by b places to the left. + def _rol(x, b): + return ((x << b) | (x >> (64 - b))) & (2**64 - 1) + + # Do the SHA-3 state transform on state s. + def _sha3_transform(s): + ROTATIONS = [ + 0, + 1, + 62, + 28, + 27, + 36, + 44, + 6, + 55, + 20, + 3, + 10, + 43, + 25, + 39, + 41, + 45, + 15, + 21, + 8, + 18, + 2, + 61, + 56, + 14, + ] + PERMUTATION = [ + 1, + 6, + 9, + 22, + 14, + 20, + 2, + 12, + 13, + 19, + 23, + 15, + 4, + 24, + 21, + 8, + 16, + 5, + 3, + 18, + 17, + 11, + 7, + 10, + ] + RC = [ + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808A, + 0x8000000080008000, + 0x000000000000808B, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008A, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000A, + 0x000000008000808B, + 0x800000000000008B, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800A, + 0x800000008000000A, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, + ] + + for rnd in range(0, 24): + # AddColumnParity (Theta) + c = [0] * 5 + d = [0] * 5 + for i in range(0, 25): + c[i % 5] ^= s[i] + for i in range(0, 5): + d[i] = c[(i + 4) % 5] ^ _rol(c[(i + 1) % 5], 1) + for i in range(0, 25): + s[i] ^= d[i % 5] + # RotateWords (Rho) + for i in range(0, 25): + s[i] = _rol(s[i], ROTATIONS[i]) + # PermuteWords (Pi) + t = s[PERMUTATION[0]] + for i in range(0, len(PERMUTATION) - 1): + s[PERMUTATION[i]] = s[PERMUTATION[i + 1]] + s[PERMUTATION[-1]] = t + # NonlinearMixRows (Chi) + for i in range(0, 25, 5): + t = [ + s[i], + s[i + 1], + s[i + 2], + s[i + 3], + s[i + 4], + s[i], + s[i + 1], + ] + for j in range(0, 5): + s[i + j] = t[j] ^ ((~t[j + 1]) & (t[j + 2])) + # AddRoundConstant (Iota) + s[0] ^= RC[rnd] + + # Reinterpret octet array b to word array and XOR it to state s. + def _reinterpret_to_words_and_xor(s, b): + for j in range(0, len(b) // 8): + s[j] ^= _from_le(b[8 * j : 8 * j + 8]) + + # Reinterpret word array w to octet array and return it. + def _reinterpret_to_octets(w): + mp = bytearray() + for j in range(0, len(w)): + mp += int_to_bytes(w[j], 8, byteorder="little") + return mp + + def _sha3_raw(msg, r_w, o_p, e_b): + """Semi-generic SHA-3 implementation""" + r_b = 8 * r_w + s = [0] * 25 + # Handle whole blocks. + idx = 0 + blocks = len(msg) // r_b + for i in range(0, blocks): + _reinterpret_to_words_and_xor(s, msg[idx : idx + r_b]) + idx += r_b + _sha3_transform(s) + # Handle last block padding. + m = bytearray(msg[idx:]) + m.append(o_p) + while len(m) < r_b: + m.append(0) + m[len(m) - 1] |= 128 + # Handle padded last block. + _reinterpret_to_words_and_xor(s, m) + _sha3_transform(s) + # Output. + out = bytearray() + while len(out) < e_b: + out += _reinterpret_to_octets(s[:r_w]) + _sha3_transform(s) + return out[:e_b] + + def shake_256(msg, outlen): + return _sha3_raw(msg, 17, 31, outlen) diff --git a/frozen_deps/ecdsa/_version.py b/frozen_deps/ecdsa/_version.py index 9a3e5fa..cf329eb 100644 --- a/frozen_deps/ecdsa/_version.py +++ b/frozen_deps/ecdsa/_version.py @@ -1,5 +1,5 @@ -# This file was generated by 'versioneer.py' (0.17) from +# This file was generated by 'versioneer.py' (0.21) from # revision-control system data, or from the parent directory name of an # unpacked source archive. Distribution tarballs contain a pre-generated copy # of this file. @@ -8,11 +8,11 @@ import json version_json = ''' { - "date": "2020-11-12T20:12:49+0100", + "date": "2024-04-08T20:59:55+0200", "dirty": false, "error": null, - "full-revisionid": "9d5a727c766773b8367f6dd0a49bbda21c18dbe7", - "version": "0.16.1" + "full-revisionid": "be70016f8911f79e891a65dcfcb602e5ba866ed3", + "version": "0.19.0" } ''' # END VERSION_JSON diff --git a/frozen_deps/ecdsa/curves.py b/frozen_deps/ecdsa/curves.py index 9a10380..38e3a75 100644 --- a/frozen_deps/ecdsa/curves.py +++ b/frozen_deps/ecdsa/curves.py @@ -1,7 +1,9 @@ from __future__ import division -from . import der, ecdsa -from .util import orderlen +from six import PY2 +from . import der, ecdsa, ellipticcurve, eddsa +from .util import orderlen, number_to_string, string_to_number +from ._compat import normalise_bytes, bit_length # orderlen was defined in this module previously, so keep it in __all__, @@ -10,6 +12,10 @@ __all__ = [ "UnknownCurveError", "orderlen", "Curve", + "SECP112r1", + "SECP112r2", + "SECP128r1", + "SECP160r1", "NIST192p", "NIST224p", "NIST256p", @@ -17,17 +23,33 @@ __all__ = [ "NIST521p", "curves", "find_curve", + "curve_by_name", "SECP256k1", "BRAINPOOLP160r1", + "BRAINPOOLP160t1", "BRAINPOOLP192r1", + "BRAINPOOLP192t1", "BRAINPOOLP224r1", + "BRAINPOOLP224t1", "BRAINPOOLP256r1", + "BRAINPOOLP256t1", "BRAINPOOLP320r1", + "BRAINPOOLP320t1", "BRAINPOOLP384r1", + "BRAINPOOLP384t1", "BRAINPOOLP512r1", + "BRAINPOOLP512t1", + "PRIME_FIELD_OID", + "CHARACTERISTIC_TWO_FIELD_OID", + "Ed25519", + "Ed448", ] +PRIME_FIELD_OID = (1, 2, 840, 10045, 1, 1) +CHARACTERISTIC_TWO_FIELD_OID = (1, 2, 840, 10045, 1, 2) + + class UnknownCurveError(Exception): pass @@ -39,15 +61,262 @@ class Curve: self.curve = curve self.generator = generator self.order = generator.order() - self.baselen = orderlen(self.order) - self.verifying_key_length = 2 * self.baselen + if isinstance(curve, ellipticcurve.CurveEdTw): + # EdDSA keys are special in that both private and public + # are the same size (as it's defined only with compressed points) + + # +1 for the sign bit and then round up + self.baselen = (bit_length(curve.p()) + 1 + 7) // 8 + self.verifying_key_length = self.baselen + else: + self.baselen = orderlen(self.order) + self.verifying_key_length = 2 * orderlen(curve.p()) self.signature_length = 2 * self.baselen self.oid = oid - self.encoded_oid = der.encode_oid(*oid) + if oid: + self.encoded_oid = der.encode_oid(*oid) + + def __eq__(self, other): + if isinstance(other, Curve): + return ( + self.curve == other.curve and self.generator == other.generator + ) + return NotImplemented + + def __ne__(self, other): + return not self == other def __repr__(self): return self.name + def to_der(self, encoding=None, point_encoding="uncompressed"): + """Serialise the curve parameters to binary string. + + :param str encoding: the format to save the curve parameters in. + Default is ``named_curve``, with fallback being the ``explicit`` + if the OID is not set for the curve. + :param str point_encoding: the point encoding of the generator when + explicit curve encoding is used. Ignored for ``named_curve`` + format. + + :return: DER encoded ECParameters structure + :rtype: bytes + """ + if encoding is None: + if self.oid: + encoding = "named_curve" + else: + encoding = "explicit" + + if encoding not in ("named_curve", "explicit"): + raise ValueError( + "Only 'named_curve' and 'explicit' encodings supported" + ) + + if encoding == "named_curve": + if not self.oid: + raise UnknownCurveError( + "Can't encode curve using named_curve encoding without " + "associated curve OID" + ) + return der.encode_oid(*self.oid) + elif isinstance(self.curve, ellipticcurve.CurveEdTw): + assert encoding == "explicit" + raise UnknownCurveError( + "Twisted Edwards curves don't support explicit encoding" + ) + + # encode the ECParameters sequence + curve_p = self.curve.p() + version = der.encode_integer(1) + field_id = der.encode_sequence( + der.encode_oid(*PRIME_FIELD_OID), der.encode_integer(curve_p) + ) + curve = der.encode_sequence( + der.encode_octet_string( + number_to_string(self.curve.a() % curve_p, curve_p) + ), + der.encode_octet_string( + number_to_string(self.curve.b() % curve_p, curve_p) + ), + ) + base = der.encode_octet_string(self.generator.to_bytes(point_encoding)) + order = der.encode_integer(self.generator.order()) + seq_elements = [version, field_id, curve, base, order] + if self.curve.cofactor(): + cofactor = der.encode_integer(self.curve.cofactor()) + seq_elements.append(cofactor) + + return der.encode_sequence(*seq_elements) + + def to_pem(self, encoding=None, point_encoding="uncompressed"): + """ + Serialise the curve parameters to the :term:`PEM` format. + + :param str encoding: the format to save the curve parameters in. + Default is ``named_curve``, with fallback being the ``explicit`` + if the OID is not set for the curve. + :param str point_encoding: the point encoding of the generator when + explicit curve encoding is used. Ignored for ``named_curve`` + format. + + :return: PEM encoded ECParameters structure + :rtype: str + """ + return der.topem( + self.to_der(encoding, point_encoding), "EC PARAMETERS" + ) + + @staticmethod + def from_der(data, valid_encodings=None): + """Decode the curve parameters from DER file. + + :param data: the binary string to decode the parameters from + :type data: :term:`bytes-like object` + :param valid_encodings: set of names of allowed encodings, by default + all (set by passing ``None``), supported ones are ``named_curve`` + and ``explicit`` + :type valid_encodings: :term:`set-like object` + """ + if not valid_encodings: + valid_encodings = set(("named_curve", "explicit")) + if not all(i in ["named_curve", "explicit"] for i in valid_encodings): + raise ValueError( + "Only named_curve and explicit encodings supported" + ) + data = normalise_bytes(data) + if not der.is_sequence(data): + if "named_curve" not in valid_encodings: + raise der.UnexpectedDER( + "named_curve curve parameters not allowed" + ) + oid, empty = der.remove_object(data) + if empty: + raise der.UnexpectedDER("Unexpected data after OID") + return find_curve(oid) + + if "explicit" not in valid_encodings: + raise der.UnexpectedDER("explicit curve parameters not allowed") + + seq, empty = der.remove_sequence(data) + if empty: + raise der.UnexpectedDER( + "Unexpected data after ECParameters structure" + ) + # decode the ECParameters sequence + version, rest = der.remove_integer(seq) + if version != 1: + raise der.UnexpectedDER("Unknown parameter encoding format") + field_id, rest = der.remove_sequence(rest) + curve, rest = der.remove_sequence(rest) + base_bytes, rest = der.remove_octet_string(rest) + order, rest = der.remove_integer(rest) + cofactor = None + if rest: + # the ASN.1 specification of ECParameters allows for future + # extensions of the sequence, so ignore the remaining bytes + cofactor, _ = der.remove_integer(rest) + + # decode the ECParameters.fieldID sequence + field_type, rest = der.remove_object(field_id) + if field_type == CHARACTERISTIC_TWO_FIELD_OID: + raise UnknownCurveError("Characteristic 2 curves unsupported") + if field_type != PRIME_FIELD_OID: + raise UnknownCurveError( + "Unknown field type: {0}".format(field_type) + ) + prime, empty = der.remove_integer(rest) + if empty: + raise der.UnexpectedDER( + "Unexpected data after ECParameters.fieldID.Prime-p element" + ) + + # decode the ECParameters.curve sequence + curve_a_bytes, rest = der.remove_octet_string(curve) + curve_b_bytes, rest = der.remove_octet_string(rest) + # seed can be defined here, but we don't parse it, so ignore `rest` + + curve_a = string_to_number(curve_a_bytes) + curve_b = string_to_number(curve_b_bytes) + + curve_fp = ellipticcurve.CurveFp(prime, curve_a, curve_b, cofactor) + + # decode the ECParameters.base point + + base = ellipticcurve.PointJacobi.from_bytes( + curve_fp, + base_bytes, + valid_encodings=("uncompressed", "compressed", "hybrid"), + order=order, + generator=True, + ) + tmp_curve = Curve("unknown", curve_fp, base, None) + + # if the curve matches one of the well-known ones, use the well-known + # one in preference, as it will have the OID and name associated + for i in curves: + if tmp_curve == i: + return i + return tmp_curve + + @classmethod + def from_pem(cls, string, valid_encodings=None): + """Decode the curve parameters from PEM file. + + :param str string: the text string to decode the parameters from + :param valid_encodings: set of names of allowed encodings, by default + all (set by passing ``None``), supported ones are ``named_curve`` + and ``explicit`` + :type valid_encodings: :term:`set-like object` + """ + if not PY2 and isinstance(string, str): # pragma: no branch + string = string.encode() + + ec_param_index = string.find(b"-----BEGIN EC PARAMETERS-----") + if ec_param_index == -1: + raise der.UnexpectedDER("EC PARAMETERS PEM header not found") + + return cls.from_der( + der.unpem(string[ec_param_index:]), valid_encodings + ) + + +# the SEC curves +SECP112r1 = Curve( + "SECP112r1", + ecdsa.curve_112r1, + ecdsa.generator_112r1, + (1, 3, 132, 0, 6), + "secp112r1", +) + + +SECP112r2 = Curve( + "SECP112r2", + ecdsa.curve_112r2, + ecdsa.generator_112r2, + (1, 3, 132, 0, 7), + "secp112r2", +) + + +SECP128r1 = Curve( + "SECP128r1", + ecdsa.curve_128r1, + ecdsa.generator_128r1, + (1, 3, 132, 0, 28), + "secp128r1", +) + + +SECP160r1 = Curve( + "SECP160r1", + ecdsa.curve_160r1, + ecdsa.generator_160r1, + (1, 3, 132, 0, 8), + "secp160r1", +) + # the NIST curves NIST192p = Curve( @@ -113,6 +382,15 @@ BRAINPOOLP160r1 = Curve( ) +BRAINPOOLP160t1 = Curve( + "BRAINPOOLP160t1", + ecdsa.curve_brainpoolp160t1, + ecdsa.generator_brainpoolp160t1, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 2), + "brainpoolP160t1", +) + + BRAINPOOLP192r1 = Curve( "BRAINPOOLP192r1", ecdsa.curve_brainpoolp192r1, @@ -122,6 +400,15 @@ BRAINPOOLP192r1 = Curve( ) +BRAINPOOLP192t1 = Curve( + "BRAINPOOLP192t1", + ecdsa.curve_brainpoolp192t1, + ecdsa.generator_brainpoolp192t1, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 4), + "brainpoolP192t1", +) + + BRAINPOOLP224r1 = Curve( "BRAINPOOLP224r1", ecdsa.curve_brainpoolp224r1, @@ -131,6 +418,15 @@ BRAINPOOLP224r1 = Curve( ) +BRAINPOOLP224t1 = Curve( + "BRAINPOOLP224t1", + ecdsa.curve_brainpoolp224t1, + ecdsa.generator_brainpoolp224t1, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 6), + "brainpoolP224t1", +) + + BRAINPOOLP256r1 = Curve( "BRAINPOOLP256r1", ecdsa.curve_brainpoolp256r1, @@ -140,6 +436,15 @@ BRAINPOOLP256r1 = Curve( ) +BRAINPOOLP256t1 = Curve( + "BRAINPOOLP256t1", + ecdsa.curve_brainpoolp256t1, + ecdsa.generator_brainpoolp256t1, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 8), + "brainpoolP256t1", +) + + BRAINPOOLP320r1 = Curve( "BRAINPOOLP320r1", ecdsa.curve_brainpoolp320r1, @@ -149,6 +454,15 @@ BRAINPOOLP320r1 = Curve( ) +BRAINPOOLP320t1 = Curve( + "BRAINPOOLP320t1", + ecdsa.curve_brainpoolp320t1, + ecdsa.generator_brainpoolp320t1, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 10), + "brainpoolP320t1", +) + + BRAINPOOLP384r1 = Curve( "BRAINPOOLP384r1", ecdsa.curve_brainpoolp384r1, @@ -158,6 +472,15 @@ BRAINPOOLP384r1 = Curve( ) +BRAINPOOLP384t1 = Curve( + "BRAINPOOLP384t1", + ecdsa.curve_brainpoolp384t1, + ecdsa.generator_brainpoolp384t1, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 12), + "brainpoolP384t1", +) + + BRAINPOOLP512r1 = Curve( "BRAINPOOLP512r1", ecdsa.curve_brainpoolp512r1, @@ -167,6 +490,32 @@ BRAINPOOLP512r1 = Curve( ) +BRAINPOOLP512t1 = Curve( + "BRAINPOOLP512t1", + ecdsa.curve_brainpoolp512t1, + ecdsa.generator_brainpoolp512t1, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 14), + "brainpoolP512t1", +) + + +Ed25519 = Curve( + "Ed25519", + eddsa.curve_ed25519, + eddsa.generator_ed25519, + (1, 3, 101, 112), +) + + +Ed448 = Curve( + "Ed448", + eddsa.curve_ed448, + eddsa.generator_ed448, + (1, 3, 101, 113), +) + + +# no order in particular, but keep previously added curves first curves = [ NIST192p, NIST224p, @@ -181,10 +530,33 @@ curves = [ BRAINPOOLP320r1, BRAINPOOLP384r1, BRAINPOOLP512r1, + SECP112r1, + SECP112r2, + SECP128r1, + SECP160r1, + Ed25519, + Ed448, + BRAINPOOLP160t1, + BRAINPOOLP192t1, + BRAINPOOLP224t1, + BRAINPOOLP256t1, + BRAINPOOLP320t1, + BRAINPOOLP384t1, + BRAINPOOLP512t1, ] def find_curve(oid_curve): + """Select a curve based on its OID + + :param tuple[int,...] oid_curve: ASN.1 Object Identifier of the + curve to return, like ``(1, 2, 840, 10045, 3, 1, 7)`` for ``NIST256p``. + + :raises UnknownCurveError: When the oid doesn't match any of the supported + curves + + :rtype: ~ecdsa.curves.Curve + """ for c in curves: if c.oid == oid_curve: return c @@ -192,3 +564,27 @@ def find_curve(oid_curve): "I don't know about the curve with oid %s." "I only know about these: %s" % (oid_curve, [c.name for c in curves]) ) + + +def curve_by_name(name): + """Select a curve based on its name. + + Returns a :py:class:`~ecdsa.curves.Curve` object with a ``name`` name. + Note that ``name`` is case-sensitve. + + :param str name: Name of the curve to return, like ``NIST256p`` or + ``prime256v1`` + + :raises UnknownCurveError: When the name doesn't match any of the supported + curves + + :rtype: ~ecdsa.curves.Curve + """ + for c in curves: + if name == c.name or (c.openssl_name and name == c.openssl_name): + return c + raise UnknownCurveError( + "Curve with name {0!r} unknown, only curves supported: {1}".format( + name, [c.name for c in curves] + ) + ) diff --git a/frozen_deps/ecdsa/der.py b/frozen_deps/ecdsa/der.py index 8c1de9b..b291485 100644 --- a/frozen_deps/ecdsa/der.py +++ b/frozen_deps/ecdsa/der.py @@ -4,8 +4,8 @@ import binascii import base64 import warnings from itertools import chain -from six import int2byte, b, text_type -from ._compat import str_idx_as_int +from six import int2byte, text_type +from ._compat import compat26_str, str_idx_as_int class UnexpectedDER(Exception): @@ -20,16 +20,16 @@ def encode_integer(r): assert r >= 0 # can't support negative numbers yet h = ("%x" % r).encode() if len(h) % 2: - h = b("0") + h + h = b"0" + h s = binascii.unhexlify(h) num = str_idx_as_int(s, 0) if num <= 0x7F: - return b("\x02") + encode_length(len(s)) + s + return b"\x02" + encode_length(len(s)) + s else: # DER integers are two's complement, so if the first byte is # 0x80-0xff then we need an extra 0x00 byte to prevent it from # looking negative. - return b("\x02") + encode_length(len(s) + 1) + b("\x00") + s + return b"\x02" + encode_length(len(s) + 1) + b"\x00" + s # sentry object to check if an argument was specified (used to detect @@ -87,15 +87,15 @@ def encode_bitstring(s, unused=_sentry): if not s: raise ValueError("unused is non-zero but s is empty") last = str_idx_as_int(s, -1) - if last & (2 ** unused - 1): + if last & (2**unused - 1): raise ValueError("unused bits must be zeros in DER") encoded_unused = int2byte(unused) len_extra = 1 - return b("\x03") + encode_length(len(s) + len_extra) + encoded_unused + s + return b"\x03" + encode_length(len(s) + len_extra) + encoded_unused + s def encode_octet_string(s): - return b("\x04") + encode_length(len(s)) + s + return b"\x04" + encode_length(len(s)) + s def encode_oid(first, second, *pieces): @@ -111,7 +111,7 @@ def encode_oid(first, second, *pieces): def encode_sequence(*encoded_pieces): total_len = sum([len(p) for p in encoded_pieces]) - return b("\x30") + encode_length(total_len) + b("").join(encoded_pieces) + return b"\x30" + encode_length(total_len) + b"".join(encoded_pieces) def encode_number(n): @@ -122,7 +122,7 @@ def encode_number(n): if not b128_digits: b128_digits.append(0) b128_digits[-1] &= 0x7F - return b("").join([int2byte(d) for d in b128_digits]) + return b"".join([int2byte(d) for d in b128_digits]) def is_sequence(string): @@ -254,7 +254,7 @@ def encode_length(l): return int2byte(l) s = ("%x" % l).encode() if len(s) % 2: - s = b("0") + s + s = b"0" + s s = binascii.unhexlify(s) llen = len(s) return int2byte(0x80 | llen) + s @@ -348,7 +348,7 @@ def remove_bitstring(string, expect_unused=_sentry): raise UnexpectedDER("Invalid encoding of empty bit string") last = str_idx_as_int(body, -1) # verify that all the unused bits are set to zero (DER requirement) - if last & (2 ** unused - 1): + if last & (2**unused - 1): raise UnexpectedDER("Non zero padding bits in bit string") if expect_unused is None: body = (body, unused) @@ -386,24 +386,24 @@ def remove_bitstring(string, expect_unused=_sentry): def unpem(pem): - if isinstance(pem, text_type): + if isinstance(pem, text_type): # pragma: no branch pem = pem.encode() - d = b("").join( + d = b"".join( [ l.strip() - for l in pem.split(b("\n")) - if l and not l.startswith(b("-----")) + for l in pem.split(b"\n") + if l and not l.startswith(b"-----") ] ) return base64.b64decode(d) def topem(der, name): - b64 = base64.b64encode(der) + b64 = base64.b64encode(compat26_str(der)) lines = [("-----BEGIN %s-----\n" % name).encode()] lines.extend( - [b64[start : start + 64] + b("\n") for start in range(0, len(b64), 64)] + [b64[start : start + 76] + b"\n" for start in range(0, len(b64), 76)] ) lines.append(("-----END %s-----\n" % name).encode()) - return b("").join(lines) + return b"".join(lines) diff --git a/frozen_deps/ecdsa/ecdh.py b/frozen_deps/ecdsa/ecdh.py index 9173279..7f697d9 100644 --- a/frozen_deps/ecdsa/ecdh.py +++ b/frozen_deps/ecdsa/ecdh.py @@ -116,7 +116,7 @@ class ECDH(object): :raises NoCurveError: Curve must be set before key generation. :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ if not self.curve: raise NoCurveError("Curve must be set prior to key generation.") @@ -135,7 +135,7 @@ class ECDH(object): :raises InvalidCurveError: private_key curve not the same as self.curve :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ if not self.curve: self.curve = private_key.curve @@ -158,7 +158,7 @@ class ECDH(object): :raises NoCurveError: Curve must be set before loading. :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ if not self.curve: raise NoCurveError("Curve must be set prior to key load.") @@ -183,7 +183,7 @@ class ECDH(object): :raises InvalidCurveError: private_key curve not the same as self.curve :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ return self.load_private_key(SigningKey.from_der(private_key_der)) @@ -204,7 +204,7 @@ class ECDH(object): :raises InvalidCurveError: private_key curve not the same as self.curve :return: public (verifying) key from this private key. - :rtype: VerifyingKey object + :rtype: VerifyingKey """ return self.load_private_key(SigningKey.from_pem(private_key_pem)) @@ -215,8 +215,8 @@ class ECDH(object): Needs to be sent to the remote party. :return: public (verifying) key from local private key. - :rtype: VerifyingKey object - """ + :rtype: VerifyingKey + """ return self.private_key.get_verifying_key() def load_received_public_key(self, public_key): @@ -237,7 +237,9 @@ class ECDH(object): raise InvalidCurveError("Curve mismatch.") self.public_key = public_key - def load_received_public_key_bytes(self, public_key_str): + def load_received_public_key_bytes( + self, public_key_str, valid_encodings=None + ): """ Load public key from byte string. @@ -247,9 +249,16 @@ class ECDH(object): :param public_key_str: public key in bytes string format :type public_key_str: :term:`bytes-like object` + :param valid_encodings: list of acceptable point encoding formats, + supported ones are: :term:`uncompressed`, :term:`compressed`, + :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` + name). All formats by default (specified with ``None``). + :type valid_encodings: :term:`set-like object` """ return self.load_received_public_key( - VerifyingKey.from_string(public_key_str, self.curve) + VerifyingKey.from_string( + public_key_str, self.curve, valid_encodings + ) ) def load_received_public_key_der(self, public_key_der): @@ -301,10 +310,10 @@ class ECDH(object): :raises NoKeyError: public_key or private_key is not set :return: shared secret - :rtype: byte string + :rtype: bytes """ return number_to_string( - self.generate_sharedsecret(), self.private_key.curve.order + self.generate_sharedsecret(), self.private_key.curve.curve.p() ) def generate_sharedsecret(self): @@ -314,9 +323,9 @@ class ECDH(object): The objects needs to have both private key and received public key before generation is allowed. - It's the same for local and remote party. - shared secret(local private key, remote public key ) == - shared secret (local public key, remote private key) + It's the same for local and remote party, + shared secret(local private key, remote public key) == + shared secret(local public key, remote private key) :raises InvalidCurveError: public_key curve not the same as self.curve :raises NoKeyError: public_key or private_key is not set diff --git a/frozen_deps/ecdsa/ecdsa.py b/frozen_deps/ecdsa/ecdsa.py index d785a45..9284ace 100644 --- a/frozen_deps/ecdsa/ecdsa.py +++ b/frozen_deps/ecdsa/ecdsa.py @@ -1,59 +1,71 @@ #! /usr/bin/env python """ -Implementation of Elliptic-Curve Digital Signatures. +Low level implementation of Elliptic-Curve Digital Signatures. + +.. note :: + You're most likely looking for the :py:class:`~ecdsa.keys` module. + This is a low-level implementation of the ECDSA that operates on + integers, not byte strings. + +NOTE: This a low level implementation of ECDSA, for normal applications +you should be looking at the keys.py module. Classes and methods for elliptic-curve signatures: private keys, public keys, signatures, -NIST prime-modulus curves with modulus lengths of -192, 224, 256, 384, and 521 bits. +and definitions of prime-modulus curves. Example: - # (In real-life applications, you would probably want to - # protect against defects in SystemRandom.) - from random import SystemRandom - randrange = SystemRandom().randrange +.. code-block:: python - # Generate a public/private key pair using the NIST Curve P-192: + # (In real-life applications, you would probably want to + # protect against defects in SystemRandom.) + from random import SystemRandom + randrange = SystemRandom().randrange - g = generator_192 - n = g.order() - secret = randrange( 1, n ) - pubkey = Public_key( g, g * secret ) - privkey = Private_key( pubkey, secret ) + # Generate a public/private key pair using the NIST Curve P-192: - # Signing a hash value: + g = generator_192 + n = g.order() + secret = randrange( 1, n ) + pubkey = Public_key( g, g * secret ) + privkey = Private_key( pubkey, secret ) - hash = randrange( 1, n ) - signature = privkey.sign( hash, randrange( 1, n ) ) + # Signing a hash value: - # Verifying a signature for a hash value: + hash = randrange( 1, n ) + signature = privkey.sign( hash, randrange( 1, n ) ) - if pubkey.verifies( hash, signature ): - print_("Demo verification succeeded.") - else: - print_("*** Demo verification failed.") + # Verifying a signature for a hash value: - # Verification fails if the hash value is modified: + if pubkey.verifies( hash, signature ): + print_("Demo verification succeeded.") + else: + print_("*** Demo verification failed.") - if pubkey.verifies( hash-1, signature ): - print_("**** Demo verification failed to reject tampered hash.") - else: - print_("Demo verification correctly rejected tampered hash.") + # Verification fails if the hash value is modified: -Version of 2009.05.16. + if pubkey.verifies( hash-1, signature ): + print_("**** Demo verification failed to reject tampered hash.") + else: + print_("Demo verification correctly rejected tampered hash.") Revision history: 2005.12.31 - Initial version. + 2008.11.25 - Substantial revisions introducing new classes. + 2009.05.16 - Warn against using random.randrange in real applications. + 2009.05.17 - Use random.SystemRandom by default. -Written in 2005 by Peter Pearson and placed in the public domain. +Originally written in 2005 by Peter Pearson and placed in the public domain, +modified as part of the python-ecdsa package. """ -from six import int2byte, b +import warnings +from six import int2byte from . import ellipticcurve from . import numbertheory from .util import bit_length @@ -69,16 +81,26 @@ class InvalidPointError(RuntimeError): class Signature(object): - """ECDSA signature.""" + """ + ECDSA signature. + + :ivar int r: the ``r`` element of the ECDSA signature + :ivar int s: the ``s`` element of the ECDSA signature + """ def __init__(self, r, s): self.r = r self.s = s def recover_public_keys(self, hash, generator): - """Returns two public keys for which the signature is valid - hash is signed hash - generator is the used generator of the signature + """ + Returns two public keys for which the signature is valid + + :param int hash: signed hash + :param AbstractPoint generator: is the generator used in creation + of the signature + :rtype: tuple(Public_key, Public_key) + :return: a pair of public keys that can validate the signature """ curve = generator.curve() n = generator.order() @@ -118,7 +140,7 @@ class Public_key(object): :param bool verify: if True check if point is valid point on curve :raises InvalidPointError: if the point parameters are invalid or - point does not lie on the curve + point does not lay on the curve """ self.curve = generator.curve() @@ -131,7 +153,7 @@ class Public_key(object): "The public point has x or y out of range." ) if verify and not self.curve.contains_point(point.x(), point.y()): - raise InvalidPointError("Point does not lie on the curve") + raise InvalidPointError("Point does not lay on the curve") if not n: raise InvalidPointError("Generator point must have order.") # for curve parameters with base point with cofactor 1, all points @@ -145,11 +167,20 @@ class Public_key(object): raise InvalidPointError("Generator point order is bad.") def __eq__(self, other): + """Return True if the keys are identical, False otherwise. + + Note: for comparison, only placement on the same curve and point + equality is considered, use of the same generator point is not + considered. + """ if isinstance(other, Public_key): - """Return True if the points are identical, False otherwise.""" return self.curve == other.curve and self.point == other.point return NotImplemented + def __ne__(self, other): + """Return False if the keys are identical, True otherwise.""" + return not self == other + def verifies(self, hash, signature): """Verify that signature is a valid signature of hash. Return True if the signature is valid. @@ -188,14 +219,18 @@ class Private_key(object): self.secret_multiplier = secret_multiplier def __eq__(self, other): + """Return True if the points are identical, False otherwise.""" if isinstance(other, Private_key): - """Return True if the points are identical, False otherwise.""" return ( self.public_key == other.public_key and self.secret_multiplier == other.secret_multiplier ) return NotImplemented + def __ne__(self, other): + """Return False if the points are identical, True otherwise.""" + return not self == other + def sign(self, hash, random_k): """Return a signature for the provided hash, using the provided random nonce. It is absolutely vital that random_k be an unpredictable @@ -235,11 +270,17 @@ class Private_key(object): return Signature(r, s) -def int_to_string(x): +def int_to_string(x): # pragma: no cover """Convert integer x into a string of bytes, as per X9.62.""" + # deprecated in 0.19 + warnings.warn( + "Function is unused in library code. If you use this code, " + "change to util.string_to_number.", + DeprecationWarning, + ) assert x >= 0 if x == 0: - return b("\0") + return b"\0" result = [] while x: ordinal = x & 0xFF @@ -247,11 +288,17 @@ def int_to_string(x): x >>= 8 result.reverse() - return b("").join(result) + return b"".join(result) -def string_to_int(s): +def string_to_int(s): # pragma: no cover """Convert a string of bytes into an integer, as per X9.62.""" + # deprecated in 0.19 + warnings.warn( + "Function is unused in library code. If you use this code, " + "change to util.number_to_string.", + DeprecationWarning, + ) result = 0 for c in s: if not isinstance(c, int): @@ -260,9 +307,16 @@ def string_to_int(s): return result -def digest_integer(m): +def digest_integer(m): # pragma: no cover """Convert an integer into a string of bytes, compute - its SHA-1 hash, and convert the result to an integer.""" + its SHA-1 hash, and convert the result to an integer.""" + # deprecated in 0.19 + warnings.warn( + "Function is unused in library code. If you use this code, " + "change to a one-liner with util.number_to_string and " + "util.string_to_number methods.", + DeprecationWarning, + ) # # I don't expect this function to be used much. I wrote # it in order to be able to duplicate the examples @@ -294,6 +348,77 @@ def point_is_valid(generator, x, y): return True +# secp112r1 curve +_p = int(remove_whitespace("DB7C 2ABF62E3 5E668076 BEAD208B"), 16) +# s = 00F50B02 8E4D696E 67687561 51752904 72783FB1 +_a = int(remove_whitespace("DB7C 2ABF62E3 5E668076 BEAD2088"), 16) +_b = int(remove_whitespace("659E F8BA0439 16EEDE89 11702B22"), 16) +_Gx = int(remove_whitespace("09487239 995A5EE7 6B55F9C2 F098"), 16) +_Gy = int(remove_whitespace("A89C E5AF8724 C0A23E0E 0FF77500"), 16) +_r = int(remove_whitespace("DB7C 2ABF62E3 5E7628DF AC6561C5"), 16) +_h = 1 +curve_112r1 = ellipticcurve.CurveFp(_p, _a, _b, _h) +generator_112r1 = ellipticcurve.PointJacobi( + curve_112r1, _Gx, _Gy, 1, _r, generator=True +) + + +# secp112r2 curve +_p = int(remove_whitespace("DB7C 2ABF62E3 5E668076 BEAD208B"), 16) +# s = 022757A1 114D69E 67687561 51755316 C05E0BD4 +_a = int(remove_whitespace("6127 C24C05F3 8A0AAAF6 5C0EF02C"), 16) +_b = int(remove_whitespace("51DE F1815DB5 ED74FCC3 4C85D709"), 16) +_Gx = int(remove_whitespace("4BA30AB5 E892B4E1 649DD092 8643"), 16) +_Gy = int(remove_whitespace("ADCD 46F5882E 3747DEF3 6E956E97"), 16) +_r = int(remove_whitespace("36DF 0AAFD8B8 D7597CA1 0520D04B"), 16) +_h = 4 +curve_112r2 = ellipticcurve.CurveFp(_p, _a, _b, _h) +generator_112r2 = ellipticcurve.PointJacobi( + curve_112r2, _Gx, _Gy, 1, _r, generator=True +) + + +# secp128r1 curve +_p = int(remove_whitespace("FFFFFFFD FFFFFFFF FFFFFFFF FFFFFFFF"), 16) +# S = 000E0D4D 69E6768 75615175 0CC03A44 73D03679 +# a and b are mod p, so a is equal to p-3, or simply -3 +# _a = -3 +_b = int(remove_whitespace("E87579C1 1079F43D D824993C 2CEE5ED3"), 16) +_Gx = int(remove_whitespace("161FF752 8B899B2D 0C28607C A52C5B86"), 16) +_Gy = int(remove_whitespace("CF5AC839 5BAFEB13 C02DA292 DDED7A83"), 16) +_r = int(remove_whitespace("FFFFFFFE 00000000 75A30D1B 9038A115"), 16) +_h = 1 +curve_128r1 = ellipticcurve.CurveFp(_p, -3, _b, _h) +generator_128r1 = ellipticcurve.PointJacobi( + curve_128r1, _Gx, _Gy, 1, _r, generator=True +) + + +# secp160r1 +_p = int(remove_whitespace("FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 7FFFFFFF"), 16) +# S = 1053CDE4 2C14D696 E6768756 1517533B F3F83345 +# a and b are mod p, so a is equal to p-3, or simply -3 +# _a = -3 +_b = int(remove_whitespace("1C97BEFC 54BD7A8B 65ACF89F 81D4D4AD C565FA45"), 16) +_Gx = int( + remove_whitespace("4A96B568 8EF57328 46646989 68C38BB9 13CBFC82"), + 16, +) +_Gy = int( + remove_whitespace("23A62855 3168947D 59DCC912 04235137 7AC5FB32"), + 16, +) +_r = int( + remove_whitespace("01 00000000 00000000 0001F4C8 F927AED3 CA752257"), + 16, +) +_h = 1 +curve_160r1 = ellipticcurve.CurveFp(_p, -3, _b, _h) +generator_160r1 = ellipticcurve.PointJacobi( + curve_160r1, _Gx, _Gy, 1, _r, generator=True +) + + # NIST Curve P-192: _p = 6277101735386680763835789423207666416083908700390324961279 _r = 6277101735386680763835789423176059013767194773182842284081 @@ -549,6 +674,18 @@ generator_brainpoolp160r1 = ellipticcurve.PointJacobi( curve_brainpoolp160r1, _Gx, _Gy, 1, _q, generator=True ) +# Brainpool P-160-t1 +_a = 0xE95E4A5F737059DC60DFC7AD95B3D8139515620C +_b = 0x7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380 +# _z = 0x24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B +_Gx = 0xB199B13B9B34EFC1397E64BAEB05ACC265FF2378 +_Gy = 0xADD6718B7C7C1961F0991B842443772152C9E0AD +_q = 0xE95E4A5F737059DC60DF5991D45029409E60FC09 +curve_brainpoolp160t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) +generator_brainpoolp160t1 = ellipticcurve.PointJacobi( + curve_brainpoolp160t1, _Gx, _Gy, 1, _q, generator=True +) + # Brainpool P-192-r1 _a = 0x6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF _b = 0x469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9 @@ -562,6 +699,19 @@ generator_brainpoolp192r1 = ellipticcurve.PointJacobi( curve_brainpoolp192r1, _Gx, _Gy, 1, _q, generator=True ) +# Brainpool P-192-t1 +_a = 0xC302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294 +_b = 0x13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79 +# _z = 0x1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB +_Gx = 0x3AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129 +_Gy = 0x097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9 +_q = 0xC302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1 + +curve_brainpoolp192t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) +generator_brainpoolp192t1 = ellipticcurve.PointJacobi( + curve_brainpoolp192t1, _Gx, _Gy, 1, _q, generator=True +) + # Brainpool P-224-r1 _a = 0x68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43 _b = 0x2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B @@ -575,6 +725,19 @@ generator_brainpoolp224r1 = ellipticcurve.PointJacobi( curve_brainpoolp224r1, _Gx, _Gy, 1, _q, generator=True ) +# Brainpool P-224-t1 +_a = 0xD7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC +_b = 0x4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D +# _z = 0x2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F +_Gx = 0x6AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D580 +_Gy = 0x0374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C +_q = 0xD7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F + +curve_brainpoolp224t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) +generator_brainpoolp224t1 = ellipticcurve.PointJacobi( + curve_brainpoolp224t1, _Gx, _Gy, 1, _q, generator=True +) + # Brainpool P-256-r1 _a = 0x7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9 _b = 0x26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6 @@ -588,6 +751,19 @@ generator_brainpoolp256r1 = ellipticcurve.PointJacobi( curve_brainpoolp256r1, _Gx, _Gy, 1, _q, generator=True ) +# Brainpool P-256-t1 +_a = 0xA9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374 +_b = 0x662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04 +# _z = 0x3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0 +_Gx = 0xA3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4 +_Gy = 0x2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE +_q = 0xA9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7 + +curve_brainpoolp256t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) +generator_brainpoolp256t1 = ellipticcurve.PointJacobi( + curve_brainpoolp256t1, _Gx, _Gy, 1, _q, generator=True +) + # Brainpool P-320-r1 _a = int( remove_whitespace( @@ -643,6 +819,61 @@ generator_brainpoolp320r1 = ellipticcurve.PointJacobi( curve_brainpoolp320r1, _Gx, _Gy, 1, _q, generator=True ) +# Brainpool P-320-t1 +_a = int( + remove_whitespace( + """ + D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC + 28FCD412B1F1B32E24""" + ), + 16, +) +_b = int( + remove_whitespace( + """ + A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547 + CEB5B4FEF422340353""" + ), + 16, +) +# _z = int( +# remove_whitespace( +# """ +# 15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18F +# EFC3E5AB7496F3C7B1""" +# ), +# 16, +# ) +_Gx = int( + remove_whitespace( + """ + 925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136F + FF3357F624A21BED52""" + ), + 16, +) +_Gy = int( + remove_whitespace( + """ + 63BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE7 + 1B1B9BC0455FB0D2C3""" + ), + 16, +) +_q = int( + remove_whitespace( + """ + D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658 + E98691555B44C59311""" + ), + 16, +) + +curve_brainpoolp320t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) +generator_brainpoolp320t1 = ellipticcurve.PointJacobi( + curve_brainpoolp320t1, _Gx, _Gy, 1, _q, generator=True +) + # Brainpool P-384-r1 _a = int( remove_whitespace( @@ -698,6 +929,60 @@ generator_brainpoolp384r1 = ellipticcurve.PointJacobi( curve_brainpoolp384r1, _Gx, _Gy, 1, _q, generator=True ) +_a = int( + remove_whitespace( + """ + 8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB711 + 23ACD3A729901D1A71874700133107EC50""" + ), + 16, +) +_b = int( + remove_whitespace( + """ + 7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE + 1D2074AA263B88805CED70355A33B471EE""" + ), + 16, +) +# _z = int( +# remove_whitespace( +# """ +# 41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE +# 97D2D63DBC87BCCDDCCC5DA39E8589291C""" +# ), +# 16, +# ) +_Gx = int( + remove_whitespace( + """ + 18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AAB + FFC4FF191B946A5F54D8D0AA2F418808CC""" + ), + 16, +) +_Gy = int( + remove_whitespace( + """ + 25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CC + FE469408584DC2B2912675BF5B9E582928""" + ), + 16, +) +_q = int( + remove_whitespace( + """ + 8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425 + A7CF3AB6AF6B7FC3103B883202E9046565""" + ), + 16, +) + +curve_brainpoolp384t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) +generator_brainpoolp384t1 = ellipticcurve.PointJacobi( + curve_brainpoolp384t1, _Gx, _Gy, 1, _q, generator=True +) + # Brainpool P-512-r1 _a = int( remove_whitespace( @@ -752,3 +1037,58 @@ curve_brainpoolp512r1 = ellipticcurve.CurveFp(_p, _a, _b, 1) generator_brainpoolp512r1 = ellipticcurve.PointJacobi( curve_brainpoolp512r1, _Gx, _Gy, 1, _q, generator=True ) + +# Brainpool P-512-t1 +_a = int( + remove_whitespace( + """ + AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308 + 717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0""" + ), + 16, +) +_b = int( + remove_whitespace( + """ + 7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36 + A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E""" + ), + 16, +) +# _z = int( +# remove_whitespace( +# """ +# 12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B +# 64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB""" +# ), +# 16, +# ) +_Gx = int( + remove_whitespace( + """ + 640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C031 + 3D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA""" + ), + 16, +) +_Gy = int( + remove_whitespace( + """ + 5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CE + E9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332""" + ), + 16, +) +_q = int( + remove_whitespace( + """ + AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308 + 70553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069""" + ), + 16, +) + +curve_brainpoolp512t1 = ellipticcurve.CurveFp(_p, _a, _b, 1) +generator_brainpoolp512t1 = ellipticcurve.PointJacobi( + curve_brainpoolp512t1, _Gx, _Gy, 1, _q, generator=True +) diff --git a/frozen_deps/ecdsa/eddsa.py b/frozen_deps/ecdsa/eddsa.py new file mode 100644 index 0000000..9769cfd --- /dev/null +++ b/frozen_deps/ecdsa/eddsa.py @@ -0,0 +1,252 @@ +"""Implementation of Edwards Digital Signature Algorithm.""" + +import hashlib +from ._sha3 import shake_256 +from . import ellipticcurve +from ._compat import ( + remove_whitespace, + bit_length, + bytes_to_int, + int_to_bytes, + compat26_str, +) + +# edwards25519, defined in RFC7748 +_p = 2**255 - 19 +_a = -1 +_d = int( + remove_whitespace( + "370957059346694393431380835087545651895421138798432190163887855330" + "85940283555" + ) +) +_h = 8 + +_Gx = int( + remove_whitespace( + "151122213495354007725011514095885315114540126930418572060461132" + "83949847762202" + ) +) +_Gy = int( + remove_whitespace( + "463168356949264781694283940034751631413079938662562256157830336" + "03165251855960" + ) +) +_r = 2**252 + 0x14DEF9DEA2F79CD65812631A5CF5D3ED + + +def _sha512(data): + return hashlib.new("sha512", compat26_str(data)).digest() + + +curve_ed25519 = ellipticcurve.CurveEdTw(_p, _a, _d, _h, _sha512) +generator_ed25519 = ellipticcurve.PointEdwards( + curve_ed25519, _Gx, _Gy, 1, _Gx * _Gy % _p, _r, generator=True +) + + +# edwards448, defined in RFC7748 +_p = 2**448 - 2**224 - 1 +_a = 1 +_d = -39081 % _p +_h = 4 + +_Gx = int( + remove_whitespace( + "224580040295924300187604334099896036246789641632564134246125461" + "686950415467406032909029192869357953282578032075146446173674602635" + "247710" + ) +) +_Gy = int( + remove_whitespace( + "298819210078481492676017930443930673437544040154080242095928241" + "372331506189835876003536878655418784733982303233503462500531545062" + "832660" + ) +) +_r = 2**446 - 0x8335DC163BB124B65129C96FDE933D8D723A70AADC873D6D54A7BB0D + + +def _shake256(data): + return shake_256(data, 114) + + +curve_ed448 = ellipticcurve.CurveEdTw(_p, _a, _d, _h, _shake256) +generator_ed448 = ellipticcurve.PointEdwards( + curve_ed448, _Gx, _Gy, 1, _Gx * _Gy % _p, _r, generator=True +) + + +class PublicKey(object): + """Public key for the Edwards Digital Signature Algorithm.""" + + def __init__(self, generator, public_key, public_point=None): + self.generator = generator + self.curve = generator.curve() + self.__encoded = public_key + # plus one for the sign bit and round up + self.baselen = (bit_length(self.curve.p()) + 1 + 7) // 8 + if len(public_key) != self.baselen: + raise ValueError( + "Incorrect size of the public key, expected: {0} bytes".format( + self.baselen + ) + ) + if public_point: + self.__point = public_point + else: + self.__point = ellipticcurve.PointEdwards.from_bytes( + self.curve, public_key + ) + + def __eq__(self, other): + if isinstance(other, PublicKey): + return ( + self.curve == other.curve and self.__encoded == other.__encoded + ) + return NotImplemented + + def __ne__(self, other): + return not self == other + + @property + def point(self): + return self.__point + + @point.setter + def point(self, other): + if self.__point != other: + raise ValueError("Can't change the coordinates of the point") + self.__point = other + + def public_point(self): + return self.__point + + def public_key(self): + return self.__encoded + + def verify(self, data, signature): + """Verify a Pure EdDSA signature over data.""" + data = compat26_str(data) + if len(signature) != 2 * self.baselen: + raise ValueError( + "Invalid signature length, expected: {0} bytes".format( + 2 * self.baselen + ) + ) + R = ellipticcurve.PointEdwards.from_bytes( + self.curve, signature[: self.baselen] + ) + S = bytes_to_int(signature[self.baselen :], "little") + if S >= self.generator.order(): + raise ValueError("Invalid signature") + + dom = bytearray() + if self.curve == curve_ed448: + dom = bytearray(b"SigEd448" + b"\x00\x00") + + k = bytes_to_int( + self.curve.hash_func(dom + R.to_bytes() + self.__encoded + data), + "little", + ) + + if self.generator * S != self.__point * k + R: + raise ValueError("Invalid signature") + + return True + + +class PrivateKey(object): + """Private key for the Edwards Digital Signature Algorithm.""" + + def __init__(self, generator, private_key): + self.generator = generator + self.curve = generator.curve() + # plus one for the sign bit and round up + self.baselen = (bit_length(self.curve.p()) + 1 + 7) // 8 + if len(private_key) != self.baselen: + raise ValueError( + "Incorrect size of private key, expected: {0} bytes".format( + self.baselen + ) + ) + self.__private_key = bytes(private_key) + self.__h = bytearray(self.curve.hash_func(private_key)) + self.__public_key = None + + a = self.__h[: self.baselen] + a = self._key_prune(a) + scalar = bytes_to_int(a, "little") + self.__s = scalar + + @property + def private_key(self): + return self.__private_key + + def __eq__(self, other): + if isinstance(other, PrivateKey): + return ( + self.curve == other.curve + and self.__private_key == other.__private_key + ) + return NotImplemented + + def __ne__(self, other): + return not self == other + + def _key_prune(self, key): + # make sure the key is not in a small subgroup + h = self.curve.cofactor() + if h == 4: + h_log = 2 + elif h == 8: + h_log = 3 + else: + raise ValueError("Only cofactor 4 and 8 curves supported") + key[0] &= ~((1 << h_log) - 1) + + # ensure the highest bit is set but no higher + l = bit_length(self.curve.p()) + if l % 8 == 0: + key[-1] = 0 + key[-2] |= 0x80 + else: + key[-1] = key[-1] & (1 << (l % 8)) - 1 | 1 << (l % 8) - 1 + return key + + def public_key(self): + """Generate the public key based on the included private key""" + if self.__public_key: + return self.__public_key + + public_point = self.generator * self.__s + + self.__public_key = PublicKey( + self.generator, public_point.to_bytes(), public_point + ) + + return self.__public_key + + def sign(self, data): + """Perform a Pure EdDSA signature over data.""" + data = compat26_str(data) + A = self.public_key().public_key() + + prefix = self.__h[self.baselen :] + + dom = bytearray() + if self.curve == curve_ed448: + dom = bytearray(b"SigEd448" + b"\x00\x00") + + r = bytes_to_int(self.curve.hash_func(dom + prefix + data), "little") + R = (self.generator * r).to_bytes() + + k = bytes_to_int(self.curve.hash_func(dom + R + A + data), "little") + k %= self.generator.order() + + S = (r + k * self.__s) % self.generator.order() + + return R + int_to_bytes(S, self.baselen, "little") diff --git a/frozen_deps/ecdsa/ellipticcurve.py b/frozen_deps/ecdsa/ellipticcurve.py index 25565df..18816a6 100644 --- a/frozen_deps/ecdsa/ellipticcurve.py +++ b/frozen_deps/ecdsa/ellipticcurve.py @@ -25,13 +25,12 @@ # Signature checking (5.4.2): # - Verify that r and s are in [1,n-1]. # -# Version of 2008.11.25. -# # Revision history: # 2005.12.31 - Initial version. # 2008.11.25 - Change CurveFp.is_on to contains_point. # # Written in 2005 by Peter Pearson and placed in the public domain. +# Modified extensively as part of python-ecdsa. from __future__ import division @@ -39,7 +38,7 @@ try: from gmpy2 import mpz GMPY = True -except ImportError: +except ImportError: # pragma: no branch try: from gmpy import mpz @@ -50,14 +49,19 @@ except ImportError: from six import python_2_unicode_compatible from . import numbertheory -from ._rwlock import RWLock +from ._compat import normalise_bytes, int_to_bytes, bit_length, bytes_to_int +from .errors import MalformedPointError +from .util import orderlen, string_to_number, number_to_string @python_2_unicode_compatible class CurveFp(object): - """Elliptic Curve over the field of integers modulo a prime.""" + """ + :term:`Short Weierstrass Elliptic Curve <short Weierstrass curve>` over a + prime field. + """ - if GMPY: + if GMPY: # pragma: no branch def __init__(self, p, a, b, h=None): """ @@ -75,7 +79,7 @@ class CurveFp(object): # gmpy with it self.__h = h - else: + else: # pragma: no branch def __init__(self, p, a, b, h=None): """ @@ -92,17 +96,25 @@ class CurveFp(object): self.__h = h def __eq__(self, other): + """Return True if other is an identical curve, False otherwise. + + Note: the value of the cofactor of the curve is not taken into account + when comparing curves, as it's derived from the base point and + intrinsic curve characteristic (but it's complex to compute), + only the prime and curve parameters are considered. + """ if isinstance(other, CurveFp): - """Return True if the curves are identical, False otherwise.""" + p = self.__p return ( self.__p == other.__p - and self.__a == other.__a - and self.__b == other.__b + and self.__a % p == other.__a % p + and self.__b % p == other.__b % p ) return NotImplemented def __ne__(self, other): - return not (self == other) + """Return False if other is an identical curve, True otherwise.""" + return not self == other def __hash__(self): return hash((self.__p, self.__a, self.__b)) @@ -124,17 +136,376 @@ class CurveFp(object): return (y * y - ((x * x + self.__a) * x + self.__b)) % self.__p == 0 def __str__(self): - return "CurveFp(p=%d, a=%d, b=%d, h=%d)" % ( + if self.__h is not None: + return "CurveFp(p={0}, a={1}, b={2}, h={3})".format( + self.__p, + self.__a, + self.__b, + self.__h, + ) + return "CurveFp(p={0}, a={1}, b={2})".format( self.__p, self.__a, self.__b, - self.__h, ) -class PointJacobi(object): +class CurveEdTw(object): + """Parameters for a Twisted Edwards Elliptic Curve""" + + if GMPY: # pragma: no branch + + def __init__(self, p, a, d, h=None, hash_func=None): + """ + The curve of points satisfying a*x^2 + y^2 = 1 + d*x^2*y^2 (mod p). + + h is the cofactor of the curve. + hash_func is the hash function associated with the curve + (like SHA-512 for Ed25519) + """ + self.__p = mpz(p) + self.__a = mpz(a) + self.__d = mpz(d) + self.__h = h + self.__hash_func = hash_func + + else: + + def __init__(self, p, a, d, h=None, hash_func=None): + """ + The curve of points satisfying a*x^2 + y^2 = 1 + d*x^2*y^2 (mod p). + + h is the cofactor of the curve. + hash_func is the hash function associated with the curve + (like SHA-512 for Ed25519) + """ + self.__p = p + self.__a = a + self.__d = d + self.__h = h + self.__hash_func = hash_func + + def __eq__(self, other): + """Returns True if other is an identical curve.""" + if isinstance(other, CurveEdTw): + p = self.__p + return ( + self.__p == other.__p + and self.__a % p == other.__a % p + and self.__d % p == other.__d % p + ) + return NotImplemented + + def __ne__(self, other): + """Return False if the other is an identical curve, True otherwise.""" + return not self == other + + def __hash__(self): + return hash((self.__p, self.__a, self.__d)) + + def contains_point(self, x, y): + """Is the point (x, y) on this curve?""" + return ( + self.__a * x * x + y * y - 1 - self.__d * x * x * y * y + ) % self.__p == 0 + + def p(self): + return self.__p + + def a(self): + return self.__a + + def d(self): + return self.__d + + def hash_func(self, data): + return self.__hash_func(data) + + def cofactor(self): + return self.__h + + def __str__(self): + if self.__h is not None: + return "CurveEdTw(p={0}, a={1}, d={2}, h={3})".format( + self.__p, + self.__a, + self.__d, + self.__h, + ) + return "CurveEdTw(p={0}, a={1}, d={2})".format( + self.__p, + self.__a, + self.__d, + ) + + +class AbstractPoint(object): + """Class for common methods of elliptic curve points.""" + + @staticmethod + def _from_raw_encoding(data, raw_encoding_length): + """ + Decode public point from :term:`raw encoding`. + + :term:`raw encoding` is the same as the :term:`uncompressed` encoding, + but without the 0x04 byte at the beginning. + """ + # real assert, from_bytes() should not call us with different length + assert len(data) == raw_encoding_length + xs = data[: raw_encoding_length // 2] + ys = data[raw_encoding_length // 2 :] + # real assert, raw_encoding_length is calculated by multiplying an + # integer by two so it will always be even + assert len(xs) == raw_encoding_length // 2 + assert len(ys) == raw_encoding_length // 2 + coord_x = string_to_number(xs) + coord_y = string_to_number(ys) + + return coord_x, coord_y + + @staticmethod + def _from_compressed(data, curve): + """Decode public point from compressed encoding.""" + if data[:1] not in (b"\x02", b"\x03"): + raise MalformedPointError("Malformed compressed point encoding") + + is_even = data[:1] == b"\x02" + x = string_to_number(data[1:]) + p = curve.p() + alpha = (pow(x, 3, p) + (curve.a() * x) + curve.b()) % p + try: + beta = numbertheory.square_root_mod_prime(alpha, p) + except numbertheory.Error as e: + raise MalformedPointError( + "Encoding does not correspond to a point on curve", e + ) + if is_even == bool(beta & 1): + y = p - beta + else: + y = beta + return x, y + + @classmethod + def _from_hybrid(cls, data, raw_encoding_length, validate_encoding): + """Decode public point from hybrid encoding.""" + # real assert, from_bytes() should not call us with different types + assert data[:1] in (b"\x06", b"\x07") + + # primarily use the uncompressed as it's easiest to handle + x, y = cls._from_raw_encoding(data[1:], raw_encoding_length) + + # but validate if it's self-consistent if we're asked to do that + if validate_encoding and ( + y & 1 + and data[:1] != b"\x07" + or (not y & 1) + and data[:1] != b"\x06" + ): + raise MalformedPointError("Inconsistent hybrid point encoding") + + return x, y + + @classmethod + def _from_edwards(cls, curve, data): + """Decode a point on an Edwards curve.""" + data = bytearray(data) + p = curve.p() + # add 1 for the sign bit and then round up + exp_len = (bit_length(p) + 1 + 7) // 8 + if len(data) != exp_len: + raise MalformedPointError("Point length doesn't match the curve.") + x_0 = (data[-1] & 0x80) >> 7 + + data[-1] &= 0x80 - 1 + + y = bytes_to_int(data, "little") + if GMPY: + y = mpz(y) + + x2 = ( + (y * y - 1) + * numbertheory.inverse_mod(curve.d() * y * y - curve.a(), p) + % p + ) + + try: + x = numbertheory.square_root_mod_prime(x2, p) + except numbertheory.Error as e: + raise MalformedPointError( + "Encoding does not correspond to a point on curve", e + ) + + if x % 2 != x_0: + x = -x % p + + return x, y + + @classmethod + def from_bytes( + cls, curve, data, validate_encoding=True, valid_encodings=None + ): + """ + Initialise the object from byte encoding of a point. + + The method does accept and automatically detect the type of point + encoding used. It supports the :term:`raw encoding`, + :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. + + Note: generally you will want to call the ``from_bytes()`` method of + either a child class, PointJacobi or Point. + + :param data: single point encoding of the public key + :type data: :term:`bytes-like object` + :param curve: the curve on which the public key is expected to lay + :type curve: ~ecdsa.ellipticcurve.CurveFp + :param validate_encoding: whether to verify that the encoding of the + point is self-consistent, defaults to True, has effect only + on ``hybrid`` encoding + :type validate_encoding: bool + :param valid_encodings: list of acceptable point encoding formats, + supported ones are: :term:`uncompressed`, :term:`compressed`, + :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` + name). All formats by default (specified with ``None``). + :type valid_encodings: :term:`set-like object` + + :raises `~ecdsa.errors.MalformedPointError`: if the public point does + not lay on the curve or the encoding is invalid + + :return: x and y coordinates of the encoded point + :rtype: tuple(int, int) + """ + if not valid_encodings: + valid_encodings = set( + ["uncompressed", "compressed", "hybrid", "raw"] + ) + if not all( + i in set(("uncompressed", "compressed", "hybrid", "raw")) + for i in valid_encodings + ): + raise ValueError( + "Only uncompressed, compressed, hybrid or raw encoding " + "supported." + ) + data = normalise_bytes(data) + + if isinstance(curve, CurveEdTw): + return cls._from_edwards(curve, data) + + key_len = len(data) + raw_encoding_length = 2 * orderlen(curve.p()) + if key_len == raw_encoding_length and "raw" in valid_encodings: + coord_x, coord_y = cls._from_raw_encoding( + data, raw_encoding_length + ) + elif key_len == raw_encoding_length + 1 and ( + "hybrid" in valid_encodings or "uncompressed" in valid_encodings + ): + if data[:1] in (b"\x06", b"\x07") and "hybrid" in valid_encodings: + coord_x, coord_y = cls._from_hybrid( + data, raw_encoding_length, validate_encoding + ) + elif data[:1] == b"\x04" and "uncompressed" in valid_encodings: + coord_x, coord_y = cls._from_raw_encoding( + data[1:], raw_encoding_length + ) + else: + raise MalformedPointError( + "Invalid X9.62 encoding of the public point" + ) + elif ( + key_len == raw_encoding_length // 2 + 1 + and "compressed" in valid_encodings + ): + coord_x, coord_y = cls._from_compressed(data, curve) + else: + raise MalformedPointError( + "Length of string does not match lengths of " + "any of the enabled ({0}) encodings of the " + "curve.".format(", ".join(valid_encodings)) + ) + return coord_x, coord_y + + def _raw_encode(self): + """Convert the point to the :term:`raw encoding`.""" + prime = self.curve().p() + x_str = number_to_string(self.x(), prime) + y_str = number_to_string(self.y(), prime) + return x_str + y_str + + def _compressed_encode(self): + """Encode the point into the compressed form.""" + prime = self.curve().p() + x_str = number_to_string(self.x(), prime) + if self.y() & 1: + return b"\x03" + x_str + return b"\x02" + x_str + + def _hybrid_encode(self): + """Encode the point into the hybrid form.""" + raw_enc = self._raw_encode() + if self.y() & 1: + return b"\x07" + raw_enc + return b"\x06" + raw_enc + + def _edwards_encode(self): + """Encode the point according to RFC8032 encoding.""" + self.scale() + x, y, p = self.x(), self.y(), self.curve().p() + + # add 1 for the sign bit and then round up + enc_len = (bit_length(p) + 1 + 7) // 8 + y_str = int_to_bytes(y, enc_len, "little") + if x % 2: + y_str[-1] |= 0x80 + return y_str + + def to_bytes(self, encoding="raw"): + """ + Convert the point to a byte string. + + The method by default uses the :term:`raw encoding` (specified + by `encoding="raw"`. It can also output points in :term:`uncompressed`, + :term:`compressed`, and :term:`hybrid` formats. + + For points on Edwards curves `encoding` is ignored and only the + encoding defined in RFC 8032 is supported. + + :return: :term:`raw encoding` of a public on the curve + :rtype: bytes + """ + assert encoding in ("raw", "uncompressed", "compressed", "hybrid") + curve = self.curve() + if isinstance(curve, CurveEdTw): + return self._edwards_encode() + elif encoding == "raw": + return self._raw_encode() + elif encoding == "uncompressed": + return b"\x04" + self._raw_encode() + elif encoding == "hybrid": + return self._hybrid_encode() + else: + return self._compressed_encode() + + @staticmethod + def _naf(mult): + """Calculate non-adjacent form of number.""" + ret = [] + while mult: + if mult % 2: + nd = mult % 4 + if nd >= 2: + nd -= 4 + ret.append(nd) + mult -= nd + else: + ret.append(0) + mult //= 2 + return ret + + +class PointJacobi(AbstractPoint): """ - Point on an elliptic curve. Uses Jacobi coordinates. + Point on a short Weierstrass elliptic curve. Uses Jacobi coordinates. In Jacobian coordinates, there are three parameters, X, Y and Z. They correspond to affine parameters 'x' and 'y' like so: @@ -158,88 +529,115 @@ class PointJacobi(object): generator=True :param bool generator: the point provided is a curve generator, as such, it will be commonly used with scalar multiplication. This will - cause to precompute multiplication table for it + cause to precompute multiplication table generation for it """ + super(PointJacobi, self).__init__() self.__curve = curve - # since it's generally better (faster) to use scaled points vs unscaled - # ones, use writer-biased RWLock for locking: - self._update_lock = RWLock() - if GMPY: - self.__x = mpz(x) - self.__y = mpz(y) - self.__z = mpz(z) + if GMPY: # pragma: no branch + self.__coords = (mpz(x), mpz(y), mpz(z)) self.__order = order and mpz(order) - else: - self.__x = x - self.__y = y - self.__z = z + else: # pragma: no branch + self.__coords = (x, y, z) self.__order = order self.__generator = generator self.__precompute = [] - def _maybe_precompute(self): - if self.__generator: - # since we lack promotion of read-locks to write-locks, we do a - # "acquire-read-lock, check, acquire-write-lock plus recheck" cycle - try: - self._update_lock.reader_acquire() - if self.__precompute: - return - finally: - self._update_lock.reader_release() - - try: - self._update_lock.writer_acquire() - if self.__precompute: - return - order = self.__order - assert order - i = 1 - order *= 2 - doubler = PointJacobi( - self.__curve, self.__x, self.__y, self.__z, order - ) - order *= 2 - self.__precompute.append((doubler.x(), doubler.y())) + @classmethod + def from_bytes( + cls, + curve, + data, + validate_encoding=True, + valid_encodings=None, + order=None, + generator=False, + ): + """ + Initialise the object from byte encoding of a point. + + The method does accept and automatically detect the type of point + encoding used. It supports the :term:`raw encoding`, + :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. + + :param data: single point encoding of the public key + :type data: :term:`bytes-like object` + :param curve: the curve on which the public key is expected to lay + :type curve: ~ecdsa.ellipticcurve.CurveFp + :param validate_encoding: whether to verify that the encoding of the + point is self-consistent, defaults to True, has effect only + on ``hybrid`` encoding + :type validate_encoding: bool + :param valid_encodings: list of acceptable point encoding formats, + supported ones are: :term:`uncompressed`, :term:`compressed`, + :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` + name). All formats by default (specified with ``None``). + :type valid_encodings: :term:`set-like object` + :param int order: the point order, must be non zero when using + generator=True + :param bool generator: the point provided is a curve generator, as + such, it will be commonly used with scalar multiplication. This + will cause to precompute multiplication table generation for it + + :raises `~ecdsa.errors.MalformedPointError`: if the public point does + not lay on the curve or the encoding is invalid - while i < order: - i *= 2 - doubler = doubler.double().scale() - self.__precompute.append((doubler.x(), doubler.y())) + :return: Point on curve + :rtype: PointJacobi + """ + coord_x, coord_y = super(PointJacobi, cls).from_bytes( + curve, data, validate_encoding, valid_encodings + ) + return PointJacobi(curve, coord_x, coord_y, 1, order, generator) - finally: - self._update_lock.writer_release() + def _maybe_precompute(self): + if not self.__generator or self.__precompute: + return + + # since this code will execute just once, and it's fully deterministic, + # depend on atomicity of the last assignment to switch from empty + # self.__precompute to filled one and just ignore the unlikely + # situation when two threads execute it at the same time (as it won't + # lead to inconsistent __precompute) + order = self.__order + assert order + precompute = [] + i = 1 + order *= 2 + coord_x, coord_y, coord_z = self.__coords + doubler = PointJacobi(self.__curve, coord_x, coord_y, coord_z, order) + order *= 2 + precompute.append((doubler.x(), doubler.y())) + + while i < order: + i *= 2 + doubler = doubler.double().scale() + precompute.append((doubler.x(), doubler.y())) + + self.__precompute = precompute def __getstate__(self): - try: - self._update_lock.reader_acquire() - state = self.__dict__.copy() - finally: - self._update_lock.reader_release() - del state["_update_lock"] + # while this code can execute at the same time as _maybe_precompute() + # is updating the __precompute or scale() is updating the __coords, + # there is no requirement for consistency between __coords and + # __precompute + state = self.__dict__.copy() return state def __setstate__(self, state): self.__dict__.update(state) - self._update_lock = RWLock() def __eq__(self, other): - """Compare two points with each-other.""" - try: - self._update_lock.reader_acquire() - if other is INFINITY: - return not self.__y or not self.__z - x1, y1, z1 = self.__x, self.__y, self.__z - finally: - self._update_lock.reader_release() + """Compare for equality two points with each-other. + + Note: only points that lay on the same curve can be equal. + """ + x1, y1, z1 = self.__coords + if other is INFINITY: + return not y1 or not z1 if isinstance(other, Point): x2, y2, z2 = other.x(), other.y(), 1 elif isinstance(other, PointJacobi): - try: - other._update_lock.reader_acquire() - x2, y2, z2 = other.__x, other.__y, other.__z - finally: - other._update_lock.reader_release() + x2, y2, z2 = other.__coords else: return NotImplemented if self.__curve != other.curve(): @@ -256,6 +654,10 @@ class PointJacobi(object): y1 * zz2 * z2 - y2 * zz1 * z1 ) % p == 0 + def __ne__(self, other): + """Compare for inequality two points with each-other.""" + return not self == other + def order(self): """Return the order of the point. @@ -276,17 +678,12 @@ class PointJacobi(object): call x() and y() on the returned instance. Or call `scale()` and then x() and y() on the returned instance. """ - try: - self._update_lock.reader_acquire() - if self.__z == 1: - return self.__x - x = self.__x - z = self.__z - finally: - self._update_lock.reader_release() + x, _, z = self.__coords + if z == 1: + return x p = self.__curve.p() z = numbertheory.inverse_mod(z, p) - return x * z ** 2 % p + return x * z**2 % p def y(self): """ @@ -297,17 +694,12 @@ class PointJacobi(object): call x() and y() on the returned instance. Or call `scale()` and then x() and y() on the returned instance. """ - try: - self._update_lock.reader_acquire() - if self.__z == 1: - return self.__y - y = self.__y - z = self.__z - finally: - self._update_lock.reader_release() + _, y, z = self.__coords + if z == 1: + return y p = self.__curve.p() z = numbertheory.inverse_mod(z, p) - return y * z ** 3 % p + return y * z**3 % p def scale(self): """ @@ -315,37 +707,28 @@ class PointJacobi(object): Modifies point in place, returns self. """ - try: - self._update_lock.reader_acquire() - if self.__z == 1: - return self - finally: - self._update_lock.reader_release() + x, y, z = self.__coords + if z == 1: + return self - try: - self._update_lock.writer_acquire() - # scaling already scaled point is safe (as inverse of 1 is 1) and - # quick so we don't need to optimise for the unlikely event when - # two threads hit the lock at the same time - p = self.__curve.p() - z_inv = numbertheory.inverse_mod(self.__z, p) - zz_inv = z_inv * z_inv % p - self.__x = self.__x * zz_inv % p - self.__y = self.__y * zz_inv * z_inv % p - # we are setting the z last so that the check above will return - # true only after all values were already updated - self.__z = 1 - finally: - self._update_lock.writer_release() + # scaling is deterministic, so even if two threads execute the below + # code at the same time, they will set __coords to the same value + p = self.__curve.p() + z_inv = numbertheory.inverse_mod(z, p) + zz_inv = z_inv * z_inv % p + x = x * zz_inv % p + y = y * zz_inv * z_inv % p + self.__coords = (x, y, 1) return self def to_affine(self): """Return point in affine form.""" - if not self.__y or not self.__z: + _, y, z = self.__coords + if not y or not z: return INFINITY self.scale() - # after point is scaled, it's immutable, so no need to perform locking - return Point(self.__curve, self.__x, self.__y, self.__order) + x, y, z = self.__coords + return Point(self.__curve, x, y, self.__order) @staticmethod def from_affine(point, generator=False): @@ -359,7 +742,8 @@ class PointJacobi(object): point.curve(), point.x(), point.y(), 1, point.order(), generator ) - # plese note that all the methods that use the equations from hyperelliptic + # please note that all the methods that use the equations from + # hyperelliptic # are formatted in a way to maximise performance. # Things that make code faster: multiplying instead of taking to the power # (`xx = x * x; xxxx = xx * xx % p` is faster than `xxxx = x**4 % p` and @@ -389,7 +773,7 @@ class PointJacobi(object): """Add a point to itself, arbitrary z.""" if Z1 == 1: return self._double_with_z_1(X1, Y1, p, a) - if not Z1: + if not Y1 or not Z1: return 0, 0, 1 # after: # http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl @@ -409,17 +793,13 @@ class PointJacobi(object): def double(self): """Add a point to itself.""" - if not self.__y: + X1, Y1, Z1 = self.__coords + + if not Y1: return INFINITY p, a = self.__curve.p(), self.__curve.a() - try: - self._update_lock.reader_acquire() - X1, Y1, Z1 = self.__x, self.__y, self.__z - finally: - self._update_lock.reader_release() - X3, Y3, Z3 = self._double(X1, Y1, Z1, p, a) if not Y3 or not Z3: @@ -438,7 +818,7 @@ class PointJacobi(object): if not H and not r: return self._double_with_z_1(X1, Y1, p, self.__curve.a()) V = X1 * I - X3 = (r ** 2 - J - 2 * V) % p + X3 = (r**2 - J - 2 * V) % p Y3 = (r * (V - X3) - 2 * Y1 * J) % p Z3 = 2 * H % p return X3, Y3, Z3 @@ -532,16 +912,9 @@ class PointJacobi(object): raise ValueError("The other point is on different curve") p = self.__curve.p() - try: - self._update_lock.reader_acquire() - X1, Y1, Z1 = self.__x, self.__y, self.__z - finally: - self._update_lock.reader_release() - try: - other._update_lock.reader_acquire() - X2, Y2, Z2 = other.__x, other.__y, other.__z - finally: - other._update_lock.reader_release() + X1, Y1, Z1 = self.__coords + X2, Y2, Z2 = other.__coords + X3, Y3, Z3 = self._add(X1, Y1, Z1, X2, Y2, Z2, p) if not Y3 or not Z3: @@ -571,25 +944,9 @@ class PointJacobi(object): return INFINITY return PointJacobi(self.__curve, X3, Y3, Z3, self.__order) - @staticmethod - def _naf(mult): - """Calculate non-adjacent form of number.""" - ret = [] - while mult: - if mult % 2: - nd = mult % 4 - if nd >= 2: - nd = nd - 4 - ret += [nd] - mult -= nd - else: - ret += [0] - mult //= 2 - return ret - def __mul__(self, other): """Multiply point by an integer.""" - if not self.__y or not other: + if not self.__coords[1] or not other: return INFINITY if other == 1: return self @@ -601,8 +958,7 @@ class PointJacobi(object): return self._mul_precompute(other) self = self.scale() - # once scaled, point is immutable, not need to lock - X2, Y2 = self.__x, self.__y + X2, Y2, _ = self.__coords X3, Y3, Z3 = 0, 0, 1 p, a = self.__curve.p(), self.__curve.a() _double = self._double @@ -621,29 +977,20 @@ class PointJacobi(object): return PointJacobi(self.__curve, X3, Y3, Z3, self.__order) - @staticmethod - def _leftmost_bit(x): - """Return integer with the same magnitude as x but only one bit set""" - assert x > 0 - result = 1 - while result <= x: - result = 2 * result - return result // 2 - def mul_add(self, self_mul, other, other_mul): """ Do two multiplications at the same time, add results. calculates self*self_mul + other*other_mul """ - if other is INFINITY or other_mul == 0: + if other == INFINITY or other_mul == 0: return self * self_mul if self_mul == 0: return other * other_mul if not isinstance(other, PointJacobi): other = PointJacobi.from_affine(other) # when the points have precomputed answers, then multiplying them alone - # is faster (as it uses NAF) + # is faster (as it uses NAF and no point doublings) self._maybe_precompute() other._maybe_precompute() if self.__precompute and other.__precompute: @@ -653,32 +1000,75 @@ class PointJacobi(object): self_mul = self_mul % self.__order other_mul = other_mul % self.__order - i = self._leftmost_bit(max(self_mul, other_mul)) * 2 + # (X3, Y3, Z3) is the accumulator X3, Y3, Z3 = 0, 0, 1 p, a = self.__curve.p(), self.__curve.a() - self = self.scale() - # after scaling, point is immutable, no need for locking - X1, Y1 = self.__x, self.__y - other = other.scale() - X2, Y2 = other.__x, other.__y - both = self + other - if both is INFINITY: - X4, Y4 = 0, 0 - else: - both.scale() - X4, Y4 = both.__x, both.__y + + # as we have 6 unique points to work with, we can't scale all of them, + # but do scale the ones that are used most often + self.scale() + X1, Y1, Z1 = self.__coords + other.scale() + X2, Y2, Z2 = other.__coords + _double = self._double _add = self._add - while i > 1: + + # with NAF we have 3 options: no add, subtract, add + # so with 2 points, we have 9 combinations: + # 0, -A, +A, -B, -A-B, +A-B, +B, -A+B, +A+B + # so we need 4 combined points: + mAmB_X, mAmB_Y, mAmB_Z = _add(X1, -Y1, Z1, X2, -Y2, Z2, p) + pAmB_X, pAmB_Y, pAmB_Z = _add(X1, Y1, Z1, X2, -Y2, Z2, p) + mApB_X, mApB_Y, mApB_Z = pAmB_X, -pAmB_Y, pAmB_Z + pApB_X, pApB_Y, pApB_Z = mAmB_X, -mAmB_Y, mAmB_Z + # when the self and other sum to infinity, we need to add them + # one by one to get correct result but as that's very unlikely to + # happen in regular operation, we don't need to optimise this case + if not pApB_Y or not pApB_Z: + return self * self_mul + other * other_mul + + # gmp object creation has cumulatively higher overhead than the + # speedup we get from calculating the NAF using gmp so ensure use + # of int() + self_naf = list(reversed(self._naf(int(self_mul)))) + other_naf = list(reversed(self._naf(int(other_mul)))) + # ensure that the lists are the same length (zip() will truncate + # longer one otherwise) + if len(self_naf) < len(other_naf): + self_naf = [0] * (len(other_naf) - len(self_naf)) + self_naf + elif len(self_naf) > len(other_naf): + other_naf = [0] * (len(self_naf) - len(other_naf)) + other_naf + + for A, B in zip(self_naf, other_naf): X3, Y3, Z3 = _double(X3, Y3, Z3, p, a) - i = i // 2 - if self_mul & i and other_mul & i: - X3, Y3, Z3 = _add(X3, Y3, Z3, X4, Y4, 1, p) - elif self_mul & i: - X3, Y3, Z3 = _add(X3, Y3, Z3, X1, Y1, 1, p) - elif other_mul & i: - X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, 1, p) + # conditions ordered from most to least likely + if A == 0: + if B == 0: + pass + elif B < 0: + X3, Y3, Z3 = _add(X3, Y3, Z3, X2, -Y2, Z2, p) + else: + assert B > 0 + X3, Y3, Z3 = _add(X3, Y3, Z3, X2, Y2, Z2, p) + elif A < 0: + if B == 0: + X3, Y3, Z3 = _add(X3, Y3, Z3, X1, -Y1, Z1, p) + elif B < 0: + X3, Y3, Z3 = _add(X3, Y3, Z3, mAmB_X, mAmB_Y, mAmB_Z, p) + else: + assert B > 0 + X3, Y3, Z3 = _add(X3, Y3, Z3, mApB_X, mApB_Y, mApB_Z, p) + else: + assert A > 0 + if B == 0: + X3, Y3, Z3 = _add(X3, Y3, Z3, X1, Y1, Z1, p) + elif B < 0: + X3, Y3, Z3 = _add(X3, Y3, Z3, pAmB_X, pAmB_Y, pAmB_Z, p) + else: + assert B > 0 + X3, Y3, Z3 = _add(X3, Y3, Z3, pApB_X, pApB_Y, pApB_Z, p) if not Y3 or not Z3: return INFINITY @@ -687,21 +1077,17 @@ class PointJacobi(object): def __neg__(self): """Return negated point.""" - try: - self._update_lock.reader_acquire() - return PointJacobi( - self.__curve, self.__x, -self.__y, self.__z, self.__order - ) - finally: - self._update_lock.reader_release() + x, y, z = self.__coords + return PointJacobi(self.__curve, x, -y, z, self.__order) -class Point(object): - """A point on an elliptic curve. Altering x and y is forbidding, - but they can be read by the x() and y() methods.""" +class Point(AbstractPoint): + """A point on a short Weierstrass elliptic curve. Altering x and y is + forbidden, but they can be read by the x() and y() methods.""" def __init__(self, curve, x, y, order=None): """curve, x, y, order; order (optional) is the order of this point.""" + super(Point, self).__init__() self.__curve = curve if GMPY: self.__x = x and mpz(x) @@ -720,8 +1106,54 @@ class Point(object): if curve and curve.cofactor() != 1 and order: assert self * order == INFINITY + @classmethod + def from_bytes( + cls, + curve, + data, + validate_encoding=True, + valid_encodings=None, + order=None, + ): + """ + Initialise the object from byte encoding of a point. + + The method does accept and automatically detect the type of point + encoding used. It supports the :term:`raw encoding`, + :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. + + :param data: single point encoding of the public key + :type data: :term:`bytes-like object` + :param curve: the curve on which the public key is expected to lay + :type curve: ~ecdsa.ellipticcurve.CurveFp + :param validate_encoding: whether to verify that the encoding of the + point is self-consistent, defaults to True, has effect only + on ``hybrid`` encoding + :type validate_encoding: bool + :param valid_encodings: list of acceptable point encoding formats, + supported ones are: :term:`uncompressed`, :term:`compressed`, + :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` + name). All formats by default (specified with ``None``). + :type valid_encodings: :term:`set-like object` + :param int order: the point order, must be non zero when using + generator=True + + :raises `~ecdsa.errors.MalformedPointError`: if the public point does + not lay on the curve or the encoding is invalid + + :return: Point on curve + :rtype: Point + """ + coord_x, coord_y = super(Point, cls).from_bytes( + curve, data, validate_encoding, valid_encodings + ) + return Point(curve, coord_x, coord_y, order) + def __eq__(self, other): - """Return True if the points are identical, False otherwise.""" + """Return True if the points are identical, False otherwise. + + Note: only points that lay on the same curve can be equal. + """ if isinstance(other, Point): return ( self.__curve == other.__curve @@ -730,6 +1162,10 @@ class Point(object): ) return NotImplemented + def __ne__(self, other): + """Returns False if points are identical, True otherwise.""" + return not self == other + def __neg__(self): return Point(self.__curve, self.__x, self.__curve.p() - self.__y) @@ -843,5 +1279,320 @@ class Point(object): return self.__order +class PointEdwards(AbstractPoint): + """Point on Twisted Edwards curve. + + Internally represents the coordinates on the curve using four parameters, + X, Y, Z, T. They correspond to affine parameters 'x' and 'y' like so: + + x = X / Z + y = Y / Z + x*y = T / Z + """ + + def __init__(self, curve, x, y, z, t, order=None, generator=False): + """ + Initialise a point that uses the extended coordinates internally. + """ + super(PointEdwards, self).__init__() + self.__curve = curve + if GMPY: # pragma: no branch + self.__coords = (mpz(x), mpz(y), mpz(z), mpz(t)) + self.__order = order and mpz(order) + else: # pragma: no branch + self.__coords = (x, y, z, t) + self.__order = order + self.__generator = generator + self.__precompute = [] + + @classmethod + def from_bytes( + cls, + curve, + data, + validate_encoding=None, + valid_encodings=None, + order=None, + generator=False, + ): + """ + Initialise the object from byte encoding of a point. + + `validate_encoding` and `valid_encodings` are provided for + compatibility with Weierstrass curves, they are ignored for Edwards + points. + + :param data: single point encoding of the public key + :type data: :term:`bytes-like object` + :param curve: the curve on which the public key is expected to lay + :type curve: ecdsa.ellipticcurve.CurveEdTw + :param None validate_encoding: Ignored, encoding is always validated + :param None valid_encodings: Ignored, there is just one encoding + supported + :param int order: the point order, must be non zero when using + generator=True + :param bool generator: Flag to mark the point as a curve generator, + this will cause the library to pre-compute some values to + make repeated usages of the point much faster + + :raises `~ecdsa.errors.MalformedPointError`: if the public point does + not lay on the curve or the encoding is invalid + + :return: Initialised point on an Edwards curve + :rtype: PointEdwards + """ + coord_x, coord_y = super(PointEdwards, cls).from_bytes( + curve, data, validate_encoding, valid_encodings + ) + return PointEdwards( + curve, coord_x, coord_y, 1, coord_x * coord_y, order, generator + ) + + def _maybe_precompute(self): + if not self.__generator or self.__precompute: + return self.__precompute + + # since this code will execute just once, and it's fully deterministic, + # depend on atomicity of the last assignment to switch from empty + # self.__precompute to filled one and just ignore the unlikely + # situation when two threads execute it at the same time (as it won't + # lead to inconsistent __precompute) + order = self.__order + assert order + precompute = [] + i = 1 + order *= 2 + coord_x, coord_y, coord_z, coord_t = self.__coords + prime = self.__curve.p() + + doubler = PointEdwards( + self.__curve, coord_x, coord_y, coord_z, coord_t, order + ) + # for "protection" against Minerva we need 1 or 2 more bits depending + # on order bit size, but it's easier to just calculate one + # point more always + order *= 4 + + while i < order: + doubler = doubler.scale() + coord_x, coord_y = doubler.x(), doubler.y() + coord_t = coord_x * coord_y % prime + precompute.append((coord_x, coord_y, coord_t)) + + i *= 2 + doubler = doubler.double() + + self.__precompute = precompute + return self.__precompute + + def x(self): + """Return affine x coordinate.""" + X1, _, Z1, _ = self.__coords + if Z1 == 1: + return X1 + p = self.__curve.p() + z_inv = numbertheory.inverse_mod(Z1, p) + return X1 * z_inv % p + + def y(self): + """Return affine y coordinate.""" + _, Y1, Z1, _ = self.__coords + if Z1 == 1: + return Y1 + p = self.__curve.p() + z_inv = numbertheory.inverse_mod(Z1, p) + return Y1 * z_inv % p + + def curve(self): + """Return the curve of the point.""" + return self.__curve + + def order(self): + return self.__order + + def scale(self): + """ + Return point scaled so that z == 1. + + Modifies point in place, returns self. + """ + X1, Y1, Z1, _ = self.__coords + if Z1 == 1: + return self + + p = self.__curve.p() + z_inv = numbertheory.inverse_mod(Z1, p) + x = X1 * z_inv % p + y = Y1 * z_inv % p + t = x * y % p + self.__coords = (x, y, 1, t) + return self + + def __eq__(self, other): + """Compare for equality two points with each-other. + + Note: only points on the same curve can be equal. + """ + x1, y1, z1, t1 = self.__coords + if other is INFINITY: + return not x1 or not t1 + if isinstance(other, PointEdwards): + x2, y2, z2, t2 = other.__coords + else: + return NotImplemented + if self.__curve != other.curve(): + return False + p = self.__curve.p() + + # cross multiply to eliminate divisions + xn1 = x1 * z2 % p + xn2 = x2 * z1 % p + yn1 = y1 * z2 % p + yn2 = y2 * z1 % p + return xn1 == xn2 and yn1 == yn2 + + def __ne__(self, other): + """Compare for inequality two points with each-other.""" + return not self == other + + def _add(self, X1, Y1, Z1, T1, X2, Y2, Z2, T2, p, a): + """add two points, assume sane parameters.""" + # after add-2008-hwcd-2 + # from https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html + # NOTE: there are more efficient formulas for Z1 or Z2 == 1 + A = X1 * X2 % p + B = Y1 * Y2 % p + C = Z1 * T2 % p + D = T1 * Z2 % p + E = D + C + F = ((X1 - Y1) * (X2 + Y2) + B - A) % p + G = B + a * A + H = D - C + if not H: + return self._double(X1, Y1, Z1, T1, p, a) + X3 = E * F % p + Y3 = G * H % p + T3 = E * H % p + Z3 = F * G % p + + return X3, Y3, Z3, T3 + + def __add__(self, other): + """Add point to another.""" + if other == INFINITY: + return self + if ( + not isinstance(other, PointEdwards) + or self.__curve != other.__curve + ): + raise ValueError("The other point is on a different curve.") + + p, a = self.__curve.p(), self.__curve.a() + X1, Y1, Z1, T1 = self.__coords + X2, Y2, Z2, T2 = other.__coords + + X3, Y3, Z3, T3 = self._add(X1, Y1, Z1, T1, X2, Y2, Z2, T2, p, a) + + if not X3 or not T3: + return INFINITY + return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) + + def __radd__(self, other): + """Add other to self.""" + return self + other + + def _double(self, X1, Y1, Z1, T1, p, a): + """Double the point, assume sane parameters.""" + # after "dbl-2008-hwcd" + # from https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html + # NOTE: there are more efficient formulas for Z1 == 1 + A = X1 * X1 % p + B = Y1 * Y1 % p + C = 2 * Z1 * Z1 % p + D = a * A % p + E = ((X1 + Y1) * (X1 + Y1) - A - B) % p + G = D + B + F = G - C + H = D - B + X3 = E * F % p + Y3 = G * H % p + T3 = E * H % p + Z3 = F * G % p + + return X3, Y3, Z3, T3 + + def double(self): + """Return point added to itself.""" + X1, Y1, Z1, T1 = self.__coords + + if not X1 or not T1: + return INFINITY + + p, a = self.__curve.p(), self.__curve.a() + + X3, Y3, Z3, T3 = self._double(X1, Y1, Z1, T1, p, a) + + # both Ed25519 and Ed448 have prime order, so no point added to + # itself will equal zero + if not X3 or not T3: # pragma: no branch + return INFINITY + return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) + + def __rmul__(self, other): + """Multiply point by an integer.""" + return self * other + + def _mul_precompute(self, other): + """Multiply point by integer with precomputation table.""" + X3, Y3, Z3, T3, p, a = 0, 1, 1, 0, self.__curve.p(), self.__curve.a() + _add = self._add + for X2, Y2, T2 in self.__precompute: + rem = other % 4 + if rem == 0 or rem == 2: + other //= 2 + elif rem == 3: + other = (other + 1) // 2 + X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, -X2, Y2, 1, -T2, p, a) + else: + assert rem == 1 + other = (other - 1) // 2 + X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, X2, Y2, 1, T2, p, a) + + if not X3 or not T3: + return INFINITY + + return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) + + def __mul__(self, other): + """Multiply point by an integer.""" + X2, Y2, Z2, T2 = self.__coords + if not X2 or not T2 or not other: + return INFINITY + if other == 1: + return self + if self.__order: + # order*2 as a "protection" for Minerva + other = other % (self.__order * 2) + if self._maybe_precompute(): + return self._mul_precompute(other) + + X3, Y3, Z3, T3 = 0, 1, 1, 0 # INFINITY in extended coordinates + p, a = self.__curve.p(), self.__curve.a() + _double = self._double + _add = self._add + + for i in reversed(self._naf(other)): + X3, Y3, Z3, T3 = _double(X3, Y3, Z3, T3, p, a) + if i < 0: + X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, -X2, Y2, Z2, -T2, p, a) + elif i > 0: + X3, Y3, Z3, T3 = _add(X3, Y3, Z3, T3, X2, Y2, Z2, T2, p, a) + + if not X3 or not T3: + return INFINITY + + return PointEdwards(self.__curve, X3, Y3, Z3, T3, self.__order) + + # This one point is the Point At Infinity for all purposes: INFINITY = Point(None, None, None) diff --git a/frozen_deps/ecdsa/errors.py b/frozen_deps/ecdsa/errors.py new file mode 100644 index 0000000..0184c05 --- /dev/null +++ b/frozen_deps/ecdsa/errors.py @@ -0,0 +1,4 @@ +class MalformedPointError(AssertionError): + """Raised in case the encoding of private or public key is malformed.""" + + pass diff --git a/frozen_deps/ecdsa/keys.py b/frozen_deps/ecdsa/keys.py index a6fc13f..f74252c 100644 --- a/frozen_deps/ecdsa/keys.py +++ b/frozen_deps/ecdsa/keys.py @@ -1,80 +1,16 @@ """ Primary classes for performing signing and verification operations. - -.. glossary:: - - raw encoding - Conversion of public, private keys and signatures (which in - mathematical sense are integers or pairs of integers) to strings of - bytes that does not use any special tags or encoding rules. - For any given curve, all keys of the same type or signatures will be - encoded to byte strings of the same length. In more formal sense, - the integers are encoded as big-endian, constant length byte strings, - where the string length is determined by the curve order (e.g. - for NIST256p the order is 256 bits long, so the private key will be 32 - bytes long while public key will be 64 bytes long). The encoding of a - single integer is zero-padded on the left if the numerical value is - low. In case of public keys and signatures, which are comprised of two - integers, the integers are simply concatenated. - - uncompressed - The most common formatting specified in PKIX standards. Specified in - X9.62 and SEC1 standards. The only difference between it and - :term:`raw encoding` is the prepending of a 0x04 byte. Thus an - uncompressed NIST256p public key encoding will be 65 bytes long. - - compressed - The public point representation that uses half of bytes of the - :term:`uncompressed` encoding (rounded up). It uses the first byte of - the encoding to specify the sign of the y coordinate and encodes the - x coordinate as-is. The first byte of the encoding is equal to - 0x02 or 0x03. Compressed encoding of NIST256p public key will be 33 - bytes long. - - hybrid - A combination of :term:`uncompressed` and :term:`compressed` encodings. - Both x and y coordinates are stored just as in :term:`compressed` - encoding, but the first byte reflects the sign of the y coordinate. The - first byte of the encoding will be equal to 0x06 or 0x7. Hybrid - encoding of NIST256p public key will be 65 bytes long. - - PEM - The acronym stands for Privacy Enhanced Email, but currently it is used - primarily as the way to encode :term:`DER` objects into text that can - be either easily copy-pasted or transferred over email. - It uses headers like ``-----BEGIN <type of contents>-----`` and footers - like ``-----END <type of contents>-----`` to separate multiple - types of objects in the same file or the object from the surrounding - comments. The actual object stored is base64 encoded. - - DER - Distinguished Encoding Rules, the way to encode :term:`ASN.1` objects - deterministically and uniquely into byte strings. - - ASN.1 - Abstract Syntax Notation 1 is a standard description language for - specifying serialisation and deserialisation of data structures in a - portable and cross-platform way. - - bytes-like object - All the types that implement the buffer protocol. That includes - ``str`` (only on python2), ``bytes``, ``bytesarray``, ``array.array` - and ``memoryview`` of those objects. - Please note that ``array.array` serialisation (converting it to byte - string) is endianess dependant! Signature computed over ``array.array`` - of integers on a big-endian system will not be verified on a - little-endian system and vice-versa. """ import binascii from hashlib import sha1 -from six import PY2, b -from . import ecdsa -from . import der +import os +from six import PY2 +from . import ecdsa, eddsa +from . import der, ssh from . import rfc6979 from . import ellipticcurve -from .curves import NIST192p, find_curve -from .numbertheory import square_root_mod_prime, SquareRootError +from .curves import NIST192p, Curve, Ed25519, Ed448 from .ecdsa import RSZeroError from .util import string_to_number, number_to_string, randrange from .util import sigencode_string, sigdecode_string, bit_length @@ -86,6 +22,8 @@ from .util import ( MalformedSignature, ) from ._compat import normalise_bytes +from .errors import MalformedPointError +from .ellipticcurve import PointJacobi, CurveEdTw __all__ = [ @@ -118,23 +56,49 @@ class BadDigestError(Exception): pass -class MalformedPointError(AssertionError): - """Raised in case the encoding of private or public key is malformed.""" +def _truncate_and_convert_digest(digest, curve, allow_truncate): + """Truncates and converts digest to an integer.""" + if not allow_truncate: + if len(digest) > curve.baselen: + raise BadDigestError( + "this curve ({0}) is too short " + "for the length of your digest ({1})".format( + curve.name, 8 * len(digest) + ) + ) + else: + digest = digest[: curve.baselen] + number = string_to_number(digest) + if allow_truncate: + max_length = bit_length(curve.order) + # we don't use bit_length(number) as that truncates leading zeros + length = len(digest) * 8 + + # See NIST FIPS 186-4: + # + # When the length of the output of the hash function is greater + # than N (i.e., the bit length of q), then the leftmost N bits of + # the hash function output block shall be used in any calculation + # using the hash function output during the generation or + # verification of a digital signature. + # + # as such, we need to shift-out the low-order bits: + number >>= max(0, length - max_length) - pass + return number class VerifyingKey(object): """ Class for handling keys that can verify signatures (public keys). - :ivar ecdsa.curves.Curve curve: The Curve over which all the cryptographic - operations will take place + :ivar `~ecdsa.curves.Curve` ~.curve: The Curve over which all the + cryptographic operations will take place :ivar default_hashfunc: the function that will be used for hashing the data. Should implement the same API as hashlib.sha1 :vartype default_hashfunc: callable :ivar pubkey: the actual public key - :vartype pubkey: ecdsa.ecdsa.Public_key + :vartype pubkey: ~ecdsa.ecdsa.Public_key """ def __init__(self, _error__please_use_generate=None): @@ -149,8 +113,12 @@ class VerifyingKey(object): def __repr__(self): pub_key = self.to_string("compressed") + if self.default_hashfunc: + hash_name = self.default_hashfunc().name + else: + hash_name = "None" return "VerifyingKey.from_string({0!r}, {1!r}, {2})".format( - pub_key, self.curve, self.default_hashfunc().name + pub_key, self.curve, hash_name ) def __eq__(self, other): @@ -159,6 +127,10 @@ class VerifyingKey(object): return self.curve == other.curve and self.pubkey == other.pubkey return NotImplemented + def __ne__(self, other): + """Return False if the points are identical, True otherwise.""" + return not self == other + @classmethod def from_public_point( cls, point, curve=NIST192p, hashfunc=sha1, validate_point=True @@ -169,25 +141,27 @@ class VerifyingKey(object): This is a low-level method, generally you will not want to use it. :param point: The point to wrap around, the actual public key - :type point: ecdsa.ellipticcurve.Point + :type point: ~ecdsa.ellipticcurve.AbstractPoint :param curve: The curve on which the point needs to reside, defaults to NIST192p - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface - as hashlib.sha1 + as :py:class:`hashlib.sha1` :type hashfunc: callable - :type bool validate_point: whether to check if the point lies on curve + :type bool validate_point: whether to check if the point lays on curve should always be used if the public point is not a result of our own calculation - :raises MalformedPointError: if the public point does not lie on the + :raises MalformedPointError: if the public point does not lay on the curve :return: Initialised VerifyingKey object :rtype: VerifyingKey """ self = cls(_error__please_use_generate=True) + if isinstance(curve.curve, CurveEdTw): + raise ValueError("Method incompatible with Edwards curves") if not isinstance(point, ellipticcurve.PointJacobi): point = ellipticcurve.PointJacobi.from_affine(point) self.curve = curve @@ -197,7 +171,7 @@ class VerifyingKey(object): curve.generator, point, validate_point ) except ecdsa.InvalidPointError: - raise MalformedPointError("Point does not lie on the curve") + raise MalformedPointError("Point does not lay on the curve") self.pubkey.order = curve.order return self @@ -220,90 +194,45 @@ class VerifyingKey(object): (if set to False) or if it should be delayed to the time of first use (when set to True) """ - self.pubkey.point = ellipticcurve.PointJacobi.from_affine( - self.pubkey.point, True - ) + if isinstance(self.curve.curve, CurveEdTw): + pt = self.pubkey.point + self.pubkey.point = ellipticcurve.PointEdwards( + pt.curve(), + pt.x(), + pt.y(), + 1, + pt.x() * pt.y(), + self.curve.order, + generator=True, + ) + else: + self.pubkey.point = ellipticcurve.PointJacobi.from_affine( + self.pubkey.point, True + ) # as precomputation in now delayed to the time of first use of the # point and we were asked specifically to precompute now, make # sure the precomputation is performed now to preserve the behaviour if not lazy: self.pubkey.point * 2 - @staticmethod - def _from_raw_encoding(string, curve): - """ - Decode public point from :term:`raw encoding`. - - :term:`raw encoding` is the same as the :term:`uncompressed` encoding, - but without the 0x04 byte at the beginning. - """ - order = curve.order - # real assert, from_string() should not call us with different length - assert len(string) == curve.verifying_key_length - xs = string[: curve.baselen] - ys = string[curve.baselen :] - if len(xs) != curve.baselen: - raise MalformedPointError("Unexpected length of encoded x") - if len(ys) != curve.baselen: - raise MalformedPointError("Unexpected length of encoded y") - x = string_to_number(xs) - y = string_to_number(ys) - - return ellipticcurve.PointJacobi(curve.curve, x, y, 1, order) - - @staticmethod - def _from_compressed(string, curve): - """Decode public point from compressed encoding.""" - if string[:1] not in (b("\x02"), b("\x03")): - raise MalformedPointError("Malformed compressed point encoding") - - is_even = string[:1] == b("\x02") - x = string_to_number(string[1:]) - order = curve.order - p = curve.curve.p() - alpha = (pow(x, 3, p) + (curve.curve.a() * x) + curve.curve.b()) % p - try: - beta = square_root_mod_prime(alpha, p) - except SquareRootError as e: - raise MalformedPointError( - "Encoding does not correspond to a point on curve", e - ) - if is_even == bool(beta & 1): - y = p - beta - else: - y = beta - return ellipticcurve.PointJacobi(curve.curve, x, y, 1, order) - - @classmethod - def _from_hybrid(cls, string, curve, validate_point): - """Decode public point from hybrid encoding.""" - # real assert, from_string() should not call us with different types - assert string[:1] in (b("\x06"), b("\x07")) - - # primarily use the uncompressed as it's easiest to handle - point = cls._from_raw_encoding(string[1:], curve) - - # but validate if it's self-consistent if we're asked to do that - if validate_point and ( - point.y() & 1 - and string[:1] != b("\x07") - or (not point.y() & 1) - and string[:1] != b("\x06") - ): - raise MalformedPointError("Inconsistent hybrid point encoding") - - return point - @classmethod def from_string( - cls, string, curve=NIST192p, hashfunc=sha1, validate_point=True + cls, + string, + curve=NIST192p, + hashfunc=sha1, + validate_point=True, + valid_encodings=None, ): """ Initialise the object from byte encoding of public key. The method does accept and automatically detect the type of point encoding used. It supports the :term:`raw encoding`, - :term:`uncompressed`, :term:`compressed` and :term:`hybrid` encodings. + :term:`uncompressed`, :term:`compressed`, and :term:`hybrid` encodings. + It also works with the native encoding of Ed25519 and Ed448 public + keys (technically those are compressed, but encoded differently than + in other signature systems). Note, while the method is named "from_string" it's a misnomer from Python 2 days when there were no binary strings. In Python 3 the @@ -311,46 +240,54 @@ class VerifyingKey(object): :param string: single point encoding of the public key :type string: :term:`bytes-like object` - :param curve: the curve on which the public key is expected to lie - :type curve: ecdsa.curves.Curve + :param curve: the curve on which the public key is expected to lay + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for - verification, needs to implement the same interface as hashlib.sha1 + verification, needs to implement the same interface as + hashlib.sha1. Ignored for EdDSA. :type hashfunc: callable - :param validate_point: whether to verify that the point lies on the - provided curve or not, defaults to True + :param validate_point: whether to verify that the point lays on the + provided curve or not, defaults to True. Ignored for EdDSA. :type validate_point: bool - - :raises MalformedPointError: if the public point does not lie on the + :param valid_encodings: list of acceptable point encoding formats, + supported ones are: :term:`uncompressed`, :term:`compressed`, + :term:`hybrid`, and :term:`raw encoding` (specified with ``raw`` + name). All formats by default (specified with ``None``). + Ignored for EdDSA. + :type valid_encodings: :term:`set-like object` + + :raises MalformedPointError: if the public point does not lay on the curve or the encoding is invalid :return: Initialised VerifyingKey object :rtype: VerifyingKey """ - string = normalise_bytes(string) - sig_len = len(string) - if sig_len == curve.verifying_key_length: - point = cls._from_raw_encoding(string, curve) - elif sig_len == curve.verifying_key_length + 1: - if string[:1] in (b("\x06"), b("\x07")): - point = cls._from_hybrid(string, curve, validate_point) - elif string[:1] == b("\x04"): - point = cls._from_raw_encoding(string[1:], curve) - else: - raise MalformedPointError( - "Invalid X9.62 encoding of the public point" - ) - elif sig_len == curve.baselen + 1: - point = cls._from_compressed(string, curve) - else: - raise MalformedPointError( - "Length of string does not match lengths of " - "any of the supported encodings of {0} " - "curve.".format(curve.name) - ) + if isinstance(curve.curve, CurveEdTw): + self = cls(_error__please_use_generate=True) + self.curve = curve + self.default_hashfunc = None # ignored for EdDSA + try: + self.pubkey = eddsa.PublicKey(curve.generator, string) + except ValueError: + raise MalformedPointError("Malformed point for the curve") + return self + + point = PointJacobi.from_bytes( + curve.curve, + string, + validate_encoding=validate_point, + valid_encodings=valid_encodings, + ) return cls.from_public_point(point, curve, hashfunc, validate_point) @classmethod - def from_pem(cls, string, hashfunc=sha1): + def from_pem( + cls, + string, + hashfunc=sha1, + valid_encodings=None, + valid_curve_encodings=None, + ): """ Initialise from public key stored in :term:`PEM` format. @@ -359,19 +296,40 @@ class VerifyingKey(object): See the :func:`~VerifyingKey.from_der()` method for details of the format supported. - Note: only a single PEM object encoding is supported in provided + Note: only a single PEM object decoding is supported in provided string. :param string: text with PEM-encoded public ECDSA key :type string: str + :param valid_encodings: list of allowed point encodings. + By default :term:`uncompressed`, :term:`compressed`, and + :term:`hybrid`. To read malformed files, include + :term:`raw encoding` with ``raw`` in the list. + :type valid_encodings: :term:`set-like object` + :param valid_curve_encodings: list of allowed encoding formats + for curve parameters. By default (``None``) all are supported: + ``named_curve`` and ``explicit``. + :type valid_curve_encodings: :term:`set-like object` + :return: Initialised VerifyingKey object :rtype: VerifyingKey """ - return cls.from_der(der.unpem(string), hashfunc=hashfunc) + return cls.from_der( + der.unpem(string), + hashfunc=hashfunc, + valid_encodings=valid_encodings, + valid_curve_encodings=valid_curve_encodings, + ) @classmethod - def from_der(cls, string, hashfunc=sha1): + def from_der( + cls, + string, + hashfunc=sha1, + valid_encodings=None, + valid_curve_encodings=None, + ): """ Initialise the key stored in :term:`DER` format. @@ -396,10 +354,21 @@ class VerifyingKey(object): :param string: binary string with the DER encoding of public ECDSA key :type string: bytes-like object + :param valid_encodings: list of allowed point encodings. + By default :term:`uncompressed`, :term:`compressed`, and + :term:`hybrid`. To read malformed files, include + :term:`raw encoding` with ``raw`` in the list. + :type valid_encodings: :term:`set-like object` + :param valid_curve_encodings: list of allowed encoding formats + for curve parameters. By default (``None``) all are supported: + ``named_curve`` and ``explicit``. + :type valid_curve_encodings: :term:`set-like object` :return: Initialised VerifyingKey object :rtype: VerifyingKey """ + if valid_encodings is None: + valid_encodings = set(["uncompressed", "compressed", "hybrid"]) string = normalise_bytes(string) # [[oid_ecPublicKey,oid_curve], point_str_bitstring] s1, empty = der.remove_sequence(string) @@ -410,18 +379,22 @@ class VerifyingKey(object): s2, point_str_bitstring = der.remove_sequence(s1) # s2 = oid_ecPublicKey,oid_curve oid_pk, rest = der.remove_object(s2) - oid_curve, empty = der.remove_object(rest) - if empty != b"": - raise der.UnexpectedDER( - "trailing junk after DER pubkey objects: %s" - % binascii.hexlify(empty) - ) + if oid_pk in (Ed25519.oid, Ed448.oid): + if oid_pk == Ed25519.oid: + curve = Ed25519 + else: + assert oid_pk == Ed448.oid + curve = Ed448 + point_str, empty = der.remove_bitstring(point_str_bitstring, 0) + if empty: + raise der.UnexpectedDER("trailing junk after public key") + return cls.from_string(point_str, curve, None) if not oid_pk == oid_ecPublicKey: raise der.UnexpectedDER( "Unexpected object identifier in DER " "encoding: {0!r}".format(oid_pk) ) - curve = find_curve(oid_curve) + curve = Curve.from_der(rest, valid_curve_encodings) point_str, empty = der.remove_bitstring(point_str_bitstring, 0) if empty != b"": raise der.UnexpectedDER( @@ -431,11 +404,22 @@ class VerifyingKey(object): # raw encoding of point is invalid in DER files if len(point_str) == curve.verifying_key_length: raise der.UnexpectedDER("Malformed encoding of public point") - return cls.from_string(point_str, curve, hashfunc=hashfunc) + return cls.from_string( + point_str, + curve, + hashfunc=hashfunc, + valid_encodings=valid_encodings, + ) @classmethod def from_public_key_recovery( - cls, signature, data, curve, hashfunc=sha1, sigdecode=sigdecode_string + cls, + signature, + data, + curve, + hashfunc=sha1, + sigdecode=sigdecode_string, + allow_truncate=True, ): """ Return keys that can be used as verifiers of the provided signature. @@ -448,7 +432,7 @@ class VerifyingKey(object): :param data: the data to be hashed for signature verification :type data: bytes-like object :param curve: the curve over which the signature was performed - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1 :type hashfunc: callable @@ -458,15 +442,25 @@ class VerifyingKey(object): a tuple with two integers, "r" as the first one and "s" as the second one. See :func:`ecdsa.util.sigdecode_string` and :func:`ecdsa.util.sigdecode_der` for examples. + :param bool allow_truncate: if True, the provided hashfunc can generate + values larger than the bit size of the order of the curve, the + extra bits (at the end of the digest) will be truncated. :type sigdecode: callable :return: Initialised VerifyingKey objects :rtype: list of VerifyingKey """ + if isinstance(curve.curve, CurveEdTw): + raise ValueError("Method unsupported for Edwards curves") data = normalise_bytes(data) digest = hashfunc(data).digest() return cls.from_public_key_recovery_with_digest( - signature, digest, curve, hashfunc=hashfunc, sigdecode=sigdecode + signature, + digest, + curve, + hashfunc=hashfunc, + sigdecode=sigdecode, + allow_truncate=allow_truncate, ) @classmethod @@ -477,6 +471,7 @@ class VerifyingKey(object): curve, hashfunc=sha1, sigdecode=sigdecode_string, + allow_truncate=False, ): """ Return keys that can be used as verifiers of the provided signature. @@ -489,7 +484,7 @@ class VerifyingKey(object): :param digest: the hash value of the message signed by the signature :type digest: bytes-like object :param curve: the curve over which the signature was performed - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1 :type hashfunc: callable @@ -500,17 +495,24 @@ class VerifyingKey(object): second one. See :func:`ecdsa.util.sigdecode_string` and :func:`ecdsa.util.sigdecode_der` for examples. :type sigdecode: callable - + :param bool allow_truncate: if True, the provided hashfunc can generate + values larger than the bit size of the order of the curve (and + the length of provided `digest`), the extra bits (at the end of the + digest) will be truncated. :return: Initialised VerifyingKey object :rtype: VerifyingKey """ + if isinstance(curve.curve, CurveEdTw): + raise ValueError("Method unsupported for Edwards curves") generator = curve.generator r, s = sigdecode(signature, generator.order()) sig = ecdsa.Signature(r, s) digest = normalise_bytes(digest) - digest_as_number = string_to_number(digest) + digest_as_number = _truncate_and_convert_digest( + digest, curve, allow_truncate + ) pks = sig.recover_public_keys(digest_as_number, generator) # Transforms the ecdsa.Public_key object into a VerifyingKey @@ -519,30 +521,6 @@ class VerifyingKey(object): ] return verifying_keys - def _raw_encode(self): - """Convert the public key to the :term:`raw encoding`.""" - order = self.pubkey.order - x_str = number_to_string(self.pubkey.point.x(), order) - y_str = number_to_string(self.pubkey.point.y(), order) - return x_str + y_str - - def _compressed_encode(self): - """Encode the public point into the compressed form.""" - order = self.pubkey.order - x_str = number_to_string(self.pubkey.point.x(), order) - if self.pubkey.point.y() & 1: - return b("\x03") + x_str - else: - return b("\x02") + x_str - - def _hybrid_encode(self): - """Encode the public point into the hybrid form.""" - raw_enc = self._raw_encode() - if self.pubkey.point.y() & 1: - return b("\x07") + raw_enc - else: - return b("\x06") + raw_enc - def to_string(self, encoding="raw"): """ Convert the public key to a byte string. @@ -564,16 +542,11 @@ class VerifyingKey(object): :rtype: bytes """ assert encoding in ("raw", "uncompressed", "compressed", "hybrid") - if encoding == "raw": - return self._raw_encode() - elif encoding == "uncompressed": - return b("\x04") + self._raw_encode() - elif encoding == "hybrid": - return self._hybrid_encode() - else: - return self._compressed_encode() + return self.pubkey.point.to_bytes(encoding) - def to_pem(self, point_encoding="uncompressed"): + def to_pem( + self, point_encoding="uncompressed", curve_parameters_encoding=None + ): """ Convert the public key to the :term:`PEM` format. @@ -587,6 +560,9 @@ class VerifyingKey(object): of public keys. "uncompressed" is most portable, "compressed" is smallest. "hybrid" is uncommon and unsupported by most implementations, it is as big as "uncompressed". + :param str curve_parameters_encoding: the encoding for curve parameters + to use, by default tries to use ``named_curve`` encoding, + if that is not possible, falls back to ``explicit`` encoding. :return: portable encoding of the public key :rtype: bytes @@ -594,9 +570,14 @@ class VerifyingKey(object): .. warning:: The PEM is encoded to US-ASCII, it needs to be re-encoded if the system is incompatible (e.g. uses UTF-16) """ - return der.topem(self.to_der(point_encoding), "PUBLIC KEY") + return der.topem( + self.to_der(point_encoding, curve_parameters_encoding), + "PUBLIC KEY", + ) - def to_der(self, point_encoding="uncompressed"): + def to_der( + self, point_encoding="uncompressed", curve_parameters_encoding=None + ): """ Convert the public key to the :term:`DER` format. @@ -608,6 +589,9 @@ class VerifyingKey(object): of public keys. "uncompressed" is most portable, "compressed" is smallest. "hybrid" is uncommon and unsupported by most implementations, it is as big as "uncompressed". + :param str curve_parameters_encoding: the encoding for curve parameters + to use, by default tries to use ``named_curve`` encoding, + if that is not possible, falls back to ``explicit`` encoding. :return: DER encoding of the public key :rtype: bytes @@ -615,15 +599,33 @@ class VerifyingKey(object): if point_encoding == "raw": raise ValueError("raw point_encoding not allowed in DER") point_str = self.to_string(point_encoding) + if isinstance(self.curve.curve, CurveEdTw): + return der.encode_sequence( + der.encode_sequence(der.encode_oid(*self.curve.oid)), + der.encode_bitstring(bytes(point_str), 0), + ) return der.encode_sequence( der.encode_sequence( - encoded_oid_ecPublicKey, self.curve.encoded_oid + encoded_oid_ecPublicKey, + self.curve.to_der(curve_parameters_encoding, point_encoding), ), # 0 is the number of unused bits in the # bit string der.encode_bitstring(point_str, 0), ) + def to_ssh(self): + """ + Convert the public key to the SSH format. + + :return: SSH encoding of the public key + :rtype: bytes + """ + return ssh.serialize_public( + self.curve.name, + self.to_string(), + ) + def verify( self, signature, @@ -643,10 +645,10 @@ class VerifyingKey(object): as the `sigdecode` parameter. :param signature: encoding of the signature - :type signature: sigdecode method dependant + :type signature: sigdecode method dependent :param data: data signed by the `signature`, will be hashed using `hashfunc`, if specified, or default hash function - :type data: bytes like object + :type data: :term:`bytes-like object` :param hashfunc: The default hash function that will be used for verification, needs to implement the same interface as hashlib.sha1 :type hashfunc: callable @@ -671,6 +673,12 @@ class VerifyingKey(object): # signature doesn't have to be a bytes-like-object so don't normalise # it, the decoders will do that data = normalise_bytes(data) + if isinstance(self.curve.curve, CurveEdTw): + signature = normalise_bytes(signature) + try: + return self.pubkey.verify(data, signature) + except (ValueError, MalformedPointError) as e: + raise BadSignatureError("Signature verification failed", e) hashfunc = hashfunc or self.default_hashfunc digest = hashfunc(data).digest() @@ -692,9 +700,9 @@ class VerifyingKey(object): as the `sigdecode` parameter. :param signature: encoding of the signature - :type signature: sigdecode method dependant + :type signature: sigdecode method dependent :param digest: raw hash value that the signature authenticates. - :type digest: bytes like object + :type digest: :term:`bytes-like object` :param sigdecode: Callable to define the way the signature needs to be decoded to an object, needs to handle `signature` as the first parameter, the curve order (an int) as the second and return @@ -717,27 +725,11 @@ class VerifyingKey(object): # signature doesn't have to be a bytes-like-object so don't normalise # it, the decoders will do that digest = normalise_bytes(digest) - if not allow_truncate and len(digest) > self.curve.baselen: - raise BadDigestError( - "this curve (%s) is too short " - "for your digest (%d)" % (self.curve.name, 8 * len(digest)) - ) - number = string_to_number(digest) - if allow_truncate: - max_length = bit_length(self.curve.order) - # we don't use bit_length(number) as that truncates leading zeros - length = len(digest) * 8 - - # See NIST FIPS 186-4: - # - # When the length of the output of the hash function is greater - # than N (i.e., the bit length of q), then the leftmost N bits of - # the hash function output block shall be used in any calculation - # using the hash function output during the generation or - # verification of a digital signature. - # - # as such, we need to shift-out the low-order bits: - number >>= max(0, length - max_length) + number = _truncate_and_convert_digest( + digest, + self.curve, + allow_truncate, + ) try: r, s = sigdecode(signature, self.pubkey.order) @@ -753,14 +745,14 @@ class SigningKey(object): """ Class for handling keys that can create signatures (private keys). - :ivar ecdsa.curves.Curve curve: The Curve over which all the cryptographic - operations will take place + :ivar `~ecdsa.curves.Curve` curve: The Curve over which all the + cryptographic operations will take place :ivar default_hashfunc: the function that will be used for hashing the - data. Should implement the same API as hashlib.sha1 + data. Should implement the same API as :py:class:`hashlib.sha1` :ivar int baselen: the length of a :term:`raw encoding` of private key - :ivar ecdsa.keys.VerifyingKey verifying_key: the public key + :ivar `~ecdsa.keys.VerifyingKey` verifying_key: the public key associated with this private key - :ivar ecdsa.ecdsa.Private_key privkey: the actual private key + :ivar `~ecdsa.ecdsa.Private_key` privkey: the actual private key """ def __init__(self, _error__please_use_generate=None): @@ -783,6 +775,37 @@ class SigningKey(object): ) return NotImplemented + def __ne__(self, other): + """Return False if the points are identical, True otherwise.""" + return not self == other + + @classmethod + def _twisted_edwards_keygen(cls, curve, entropy): + """Generate a private key on a Twisted Edwards curve.""" + if not entropy: + entropy = os.urandom + random = entropy(curve.baselen) + private_key = eddsa.PrivateKey(curve.generator, random) + public_key = private_key.public_key() + + verifying_key = VerifyingKey.from_string( + public_key.public_key(), curve + ) + + self = cls(_error__please_use_generate=True) + self.curve = curve + self.default_hashfunc = None + self.baselen = curve.baselen + self.privkey = private_key + self.verifying_key = verifying_key + return self + + @classmethod + def _weierstrass_keygen(cls, curve, entropy, hashfunc): + """Generate a private key on a Weierstrass curve.""" + secexp = randrange(curve.order, entropy) + return cls.from_secret_exponent(secexp, curve, hashfunc) + @classmethod def generate(cls, curve=NIST192p, entropy=None, hashfunc=sha1): """ @@ -790,7 +813,7 @@ class SigningKey(object): :param curve: The curve on which the point needs to reside, defaults to NIST192p - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param entropy: Source of randomness for generating the private keys, should provide cryptographically secure random numbers if the keys need to be secure. Uses os.urandom() by default. @@ -803,8 +826,9 @@ class SigningKey(object): :return: Initialised SigningKey object :rtype: SigningKey """ - secexp = randrange(curve.order, entropy) - return cls.from_secret_exponent(secexp, curve, hashfunc) + if isinstance(curve.curve, CurveEdTw): + return cls._twisted_edwards_keygen(curve, entropy) + return cls._weierstrass_keygen(curve, entropy, hashfunc) @classmethod def from_secret_exponent(cls, secexp, curve=NIST192p, hashfunc=sha1): @@ -817,7 +841,7 @@ class SigningKey(object): :param int secexp: secret multiplier (the actual private key in ECDSA). Needs to be an integer between 1 and the curve order. :param curve: The curve on which the point needs to reside - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for signing, needs to implement the same interface as hashlib.sha1 @@ -831,6 +855,11 @@ class SigningKey(object): :return: Initialised SigningKey object :rtype: SigningKey """ + if isinstance(curve.curve, CurveEdTw): + raise ValueError( + "Edwards keys don't support setting the secret scalar " + "(exponent) directly" + ) self = cls(_error__please_use_generate=True) self.curve = curve self.default_hashfunc = hashfunc @@ -862,9 +891,9 @@ class SigningKey(object): In Python 3, the expected type is `bytes`. :param string: the raw encoding of the private key - :type string: bytes like object + :type string: :term:`bytes-like object` :param curve: The curve on which the point needs to reside - :type curve: ecdsa.curves.Curve + :type curve: ~ecdsa.curves.Curve :param hashfunc: The default hash function that will be used for signing, needs to implement the same interface as hashlib.sha1 @@ -879,16 +908,27 @@ class SigningKey(object): :rtype: SigningKey """ string = normalise_bytes(string) + if len(string) != curve.baselen: raise MalformedPointError( "Invalid length of private key, received {0}, " "expected {1}".format(len(string), curve.baselen) ) + if isinstance(curve.curve, CurveEdTw): + self = cls(_error__please_use_generate=True) + self.curve = curve + self.default_hashfunc = None # Ignored for EdDSA + self.baselen = curve.baselen + self.privkey = eddsa.PrivateKey(curve.generator, string) + self.verifying_key = VerifyingKey.from_string( + self.privkey.public_key().public_key(), curve + ) + return self secexp = string_to_number(string) return cls.from_secret_exponent(secexp, curve, hashfunc) @classmethod - def from_pem(cls, string, hashfunc=sha1): + def from_pem(cls, string, hashfunc=sha1, valid_curve_encodings=None): """ Initialise from key stored in :term:`PEM` format. @@ -908,6 +948,11 @@ class SigningKey(object): :param string: text with PEM-encoded private ECDSA key :type string: str + :param valid_curve_encodings: list of allowed encoding formats + for curve parameters. By default (``None``) all are supported: + ``named_curve`` and ``explicit``. + :type valid_curve_encodings: :term:`set-like object` + :raises MalformedPointError: if the length of encoding doesn't match the provided curve or the encoded values is too large @@ -918,7 +963,7 @@ class SigningKey(object): :return: Initialised SigningKey object :rtype: SigningKey """ - if not PY2 and isinstance(string, str): + if not PY2 and isinstance(string, str): # pragma: no branch string = string.encode() # The privkey pem may have multiple sections, commonly it also has @@ -928,10 +973,14 @@ class SigningKey(object): if private_key_index == -1: private_key_index = string.index(b"-----BEGIN PRIVATE KEY-----") - return cls.from_der(der.unpem(string[private_key_index:]), hashfunc) + return cls.from_der( + der.unpem(string[private_key_index:]), + hashfunc, + valid_curve_encodings, + ) @classmethod - def from_der(cls, string, hashfunc=sha1): + def from_der(cls, string, hashfunc=sha1, valid_curve_encodings=None): """ Initialise from key stored in :term:`DER` format. @@ -952,14 +1001,14 @@ class SigningKey(object): `publicKey` field is ignored completely (errors, if any, in it will be undetected). - The only format supported for the `parameters` field is the named - curve method. Explicit encoding of curve parameters is not supported. + Two formats are supported for the `parameters` field: the named + curve and the explicit encoding of curve parameters. In the legacy ssleay format, this implementation requires the optional `parameters` field to get the curve name. In PKCS #8 format, the curve is part of the PrivateKeyAlgorithmIdentifier. The PKCS #8 format includes an ECPrivateKey object as the `privateKey` - field within a larger structure: + field within a larger structure:: OneAsymmetricKey ::= SEQUENCE { version Version, @@ -975,7 +1024,12 @@ class SigningKey(object): in them will not be detected. :param string: binary string with DER-encoded private ECDSA key - :type string: bytes like object + :type string: :term:`bytes-like object` + :param valid_curve_encodings: list of allowed encoding formats + for curve parameters. By default (``None``) all are supported: + ``named_curve`` and ``explicit``. + Ignored for EdDSA. + :type valid_curve_encodings: :term:`set-like object` :raises MalformedPointError: if the length of encoding doesn't match the provided curve or the encoded values is too large @@ -990,7 +1044,7 @@ class SigningKey(object): curve = None s, empty = der.remove_sequence(s) - if empty != b(""): + if empty != b"": raise der.UnexpectedDER( "trailing junk after DER privkey: %s" % binascii.hexlify(empty) ) @@ -1010,18 +1064,43 @@ class SigningKey(object): sequence, s = der.remove_sequence(s) algorithm_oid, algorithm_identifier = der.remove_object(sequence) - curve_oid, empty = der.remove_object(algorithm_identifier) - curve = find_curve(curve_oid) + + if algorithm_oid in (Ed25519.oid, Ed448.oid): + if algorithm_identifier: + raise der.UnexpectedDER( + "Non NULL parameters for a EdDSA key" + ) + key_str_der, s = der.remove_octet_string(s) + + # As RFC5958 describe, there are may be optional Attributes + # and Publickey. Don't raise error if something after + # Privatekey + + # TODO parse attributes or validate publickey + # if s: + # raise der.UnexpectedDER( + # "trailing junk inside the privateKey" + # ) + key_str, s = der.remove_octet_string(key_str_der) + if s: + raise der.UnexpectedDER( + "trailing junk after the encoded private key" + ) + + if algorithm_oid == Ed25519.oid: + curve = Ed25519 + else: + assert algorithm_oid == Ed448.oid + curve = Ed448 + + return cls.from_string(key_str, curve, None) if algorithm_oid not in (oid_ecPublicKey, oid_ecDH, oid_ecMQV): raise der.UnexpectedDER( "unexpected algorithm identifier '%s'" % (algorithm_oid,) ) - if empty != b"": - raise der.UnexpectedDER( - "unexpected data after algorithm identifier: %s" - % binascii.hexlify(empty) - ) + + curve = Curve.from_der(algorithm_identifier, valid_curve_encodings) # Up next is an octet string containing an ECPrivateKey. Ignore # the optional "attributes" and "publicKey" fields that come after. @@ -1030,7 +1109,7 @@ class SigningKey(object): # Unpack the ECPrivateKey to get to the key data octet string, # and rejoin the ssleay parsing path. s, empty = der.remove_sequence(s) - if empty != b(""): + if empty != b"": raise der.UnexpectedDER( "trailing junk after DER privkey: %s" % binascii.hexlify(empty) @@ -1053,13 +1132,7 @@ class SigningKey(object): raise der.UnexpectedDER( "expected tag 0 in DER privkey, got %d" % tag ) - curve_oid, empty = der.remove_object(curve_oid_str) - if empty != b(""): - raise der.UnexpectedDER( - "trailing junk after DER privkey " - "curve_oid: %s" % binascii.hexlify(empty) - ) - curve = find_curve(curve_oid) + curve = Curve.from_der(curve_oid_str, valid_curve_encodings) # we don't actually care about the following fields # @@ -1076,7 +1149,7 @@ class SigningKey(object): # our from_string method likes fixed-length privkey strings if len(privkey_str) < curve.baselen: privkey_str = ( - b("\x00") * (curve.baselen - len(privkey_str)) + privkey_str + b"\x00" * (curve.baselen - len(privkey_str)) + privkey_str ) return cls.from_string(privkey_str, curve, hashfunc) @@ -1091,11 +1164,18 @@ class SigningKey(object): :return: raw encoding of private key :rtype: bytes """ + if isinstance(self.curve.curve, CurveEdTw): + return bytes(self.privkey.private_key) secexp = self.privkey.secret_multiplier s = number_to_string(secexp, self.privkey.order) return s - def to_pem(self, point_encoding="uncompressed", format="ssleay"): + def to_pem( + self, + point_encoding="uncompressed", + format="ssleay", + curve_parameters_encoding=None, + ): """ Convert the private key to the :term:`PEM` format. @@ -1109,6 +1189,11 @@ class SigningKey(object): :param str point_encoding: format to use for encoding public point :param str format: either ``ssleay`` (default) or ``pkcs8`` + :param str curve_parameters_encoding: format of encoded curve + parameters, default depends on the curve, if the curve has + an associated OID, ``named_curve`` format will be used, + if no OID is associated with the curve, the fallback of + ``explicit`` parameters will be used. :return: PEM encoded private key :rtype: bytes @@ -1119,9 +1204,26 @@ class SigningKey(object): # TODO: "BEGIN ECPARAMETERS" assert format in ("ssleay", "pkcs8") header = "EC PRIVATE KEY" if format == "ssleay" else "PRIVATE KEY" - return der.topem(self.to_der(point_encoding, format), header) + return der.topem( + self.to_der(point_encoding, format, curve_parameters_encoding), + header, + ) - def to_der(self, point_encoding="uncompressed", format="ssleay"): + def _encode_eddsa(self): + """Create a PKCS#8 encoding of EdDSA keys.""" + ec_private_key = der.encode_octet_string(self.to_string()) + return der.encode_sequence( + der.encode_integer(0), + der.encode_sequence(der.encode_oid(*self.curve.oid)), + der.encode_octet_string(ec_private_key), + ) + + def to_der( + self, + point_encoding="uncompressed", + format="ssleay", + curve_parameters_encoding=None, + ): """ Convert the private key to the :term:`DER` format. @@ -1131,7 +1233,15 @@ class SigningKey(object): The public key will be included in the generated string. :param str point_encoding: format to use for encoding public point - :param str format: either ``ssleay`` (default) or ``pkcs8`` + Ignored for EdDSA + :param str format: either ``ssleay`` (default) or ``pkcs8``. + EdDSA keys require ``pkcs8``. + :param str curve_parameters_encoding: format of encoded curve + parameters, default depends on the curve, if the curve has + an associated OID, ``named_curve`` format will be used, + if no OID is associated with the curve, the fallback of + ``explicit`` parameters will be used. + Ignored for EdDSA. :return: DER encoded private key :rtype: bytes @@ -1141,15 +1251,27 @@ class SigningKey(object): if point_encoding == "raw": raise ValueError("raw encoding not allowed in DER") assert format in ("ssleay", "pkcs8") + if isinstance(self.curve.curve, CurveEdTw): + if format != "pkcs8": + raise ValueError("Only PKCS#8 format supported for EdDSA keys") + return self._encode_eddsa() encoded_vk = self.get_verifying_key().to_string(point_encoding) - # the 0 in encode_bitstring specifies the number of unused bits - # in the `encoded_vk` string - ec_private_key = der.encode_sequence( + priv_key_elems = [ der.encode_integer(1), der.encode_octet_string(self.to_string()), - der.encode_constructed(0, self.curve.encoded_oid), - der.encode_constructed(1, der.encode_bitstring(encoded_vk, 0)), + ] + if format == "ssleay": + priv_key_elems.append( + der.encode_constructed( + 0, self.curve.to_der(curve_parameters_encoding) + ) + ) + # the 0 in encode_bitstring specifies the number of unused bits + # in the `encoded_vk` string + priv_key_elems.append( + der.encode_constructed(1, der.encode_bitstring(encoded_vk, 0)) ) + ec_private_key = der.encode_sequence(*priv_key_elems) if format == "ssleay": return ec_private_key @@ -1159,11 +1281,25 @@ class SigningKey(object): # top-level structure. der.encode_integer(1), der.encode_sequence( - der.encode_oid(*oid_ecPublicKey), self.curve.encoded_oid + der.encode_oid(*oid_ecPublicKey), + self.curve.to_der(curve_parameters_encoding), ), der.encode_octet_string(ec_private_key), ) + def to_ssh(self): + """ + Convert the private key to the SSH format. + + :return: SSH encoded private key + :rtype: bytes + """ + return ssh.serialize_private( + self.curve.name, + self.verifying_key.to_string(), + self.to_string(), + ) + def get_verifying_key(self): """ Return the VerifyingKey associated with this private key. @@ -1184,20 +1320,27 @@ class SigningKey(object): extra_entropy=b"", ): """ - Create signature over data using the deterministic RFC6679 algorithm. + Create signature over data. - The data will be hashed using the `hashfunc` function before signing. + For Weierstrass curves it uses the deterministic RFC6979 algorithm. + For Edwards curves it uses the standard EdDSA algorithm. + + For ECDSA the data will be hashed using the `hashfunc` function before + signing. + For EdDSA the data will be hashed with the hash associated with the + curve (SHA-512 for Ed25519 and SHAKE-256 for Ed448). This is the recommended method for performing signatures when hashing of data is necessary. :param data: data to be hashed and computed signature over - :type data: bytes like object + :type data: :term:`bytes-like object` :param hashfunc: hash function to use for computing the signature, if unspecified, the default hash function selected during object initialisation will be used (see `VerifyingKey.default_hashfunc`). The object needs to implement the same interface as hashlib.sha1. + Ignored with EdDSA. :type hashfunc: callable :param sigencode: function used to encode the signature. The function needs to accept three parameters: the two integers @@ -1205,16 +1348,22 @@ class SigningKey(object): signature was computed. It needs to return an encoded signature. See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der` as examples of such functions. + Ignored with EdDSA. :type sigencode: callable :param extra_entropy: additional data that will be fed into the random number generator used in the RFC6979 process. Entirely optional. - :type extra_entropy: bytes like object + Ignored with EdDSA. + :type extra_entropy: :term:`bytes-like object` :return: encoded signature over `data` - :rtype: bytes or sigencode function dependant type + :rtype: bytes or sigencode function dependent type """ hashfunc = hashfunc or self.default_hashfunc data = normalise_bytes(data) + + if isinstance(self.curve.curve, CurveEdTw): + return self.privkey.sign(data) + extra_entropy = normalise_bytes(extra_entropy) digest = hashfunc(data).digest() @@ -1235,7 +1384,7 @@ class SigningKey(object): allow_truncate=False, ): """ - Create signature for digest using the deterministic RFC6679 algorithm. + Create signature for digest using the deterministic RFC6979 algorithm. `digest` should be the output of cryptographically secure hash function like SHA256 or SHA-3-256. @@ -1244,32 +1393,36 @@ class SigningKey(object): hashing of data is necessary. :param digest: hash of data that will be signed - :type digest: bytes like object + :type digest: :term:`bytes-like object` :param hashfunc: hash function to use for computing the random "k" value from RFC6979 process, if unspecified, the default hash function selected during object initialisation will be used (see - `VerifyingKey.default_hashfunc`). The object needs to implement - the same interface as hashlib.sha1. + :attr:`.VerifyingKey.default_hashfunc`). The object needs to + implement + the same interface as :func:`~hashlib.sha1` from :py:mod:`hashlib`. :type hashfunc: callable :param sigencode: function used to encode the signature. The function needs to accept three parameters: the two integers that are the signature and the order of the curve over which the signature was computed. It needs to return an encoded signature. - See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der` + See :func:`~ecdsa.util.sigencode_string` and + :func:`~ecdsa.util.sigencode_der` as examples of such functions. :type sigencode: callable :param extra_entropy: additional data that will be fed into the random number generator used in the RFC6979 process. Entirely optional. - :type extra_entropy: bytes like object + :type extra_entropy: :term:`bytes-like object` :param bool allow_truncate: if True, the provided digest can have bigger bit-size than the order of the curve, the extra bits (at the end of the digest) will be truncated. Use it when signing SHA-384 output using NIST256p or in similar situations. :return: encoded signature for the `digest` hash - :rtype: bytes or sigencode function dependant type + :rtype: bytes or sigencode function dependent type """ + if isinstance(self.curve.curve, CurveEdTw): + raise ValueError("Method unsupported for Edwards curves") secexp = self.privkey.secret_multiplier hashfunc = hashfunc or self.default_hashfunc digest = normalise_bytes(digest) @@ -1311,7 +1464,11 @@ class SigningKey(object): allow_truncate=True, ): """ - Create signature over data using the probabilistic ECDSA algorithm. + Create signature over data. + + Uses the probabilistic ECDSA algorithm for Weierstrass curves + (NIST256p, etc.) and the deterministic EdDSA algorithm for the + Edwards curves (Ed25519, Ed448). This method uses the standard ECDSA algorithm that requires a cryptographically secure random number generator. @@ -1320,46 +1477,62 @@ class SigningKey(object): method instead of this one. :param data: data that will be hashed for signing - :type data: bytes like object - :param callable entropy: randomness source, os.urandom by default - :param hashfunc: hash function to use for hashing the provided `data`. + :type data: :term:`bytes-like object` + :param callable entropy: randomness source, :func:`os.urandom` by + default. Ignored with EdDSA. + :param hashfunc: hash function to use for hashing the provided + ``data``. If unspecified the default hash function selected during object initialisation will be used (see - `VerifyingKey.default_hashfunc`). - Should behave like hashlib.sha1. The output length of the + :attr:`.VerifyingKey.default_hashfunc`). + Should behave like :func:`~hashlib.sha1` from :py:mod:`hashlib`. + The output length of the hash (in bytes) must not be longer than the length of the curve order (rounded up to the nearest byte), so using SHA256 with NIST256p is ok, but SHA256 with NIST192p is not. (In the 2**-96ish unlikely event of a hash output larger than the curve order, the hash will effectively be wrapped mod n). - Use hashfunc=hashlib.sha1 to match openssl's -ecdsa-with-SHA1 mode, - or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256. + If you want to explicitly allow use of large hashes with small + curves set the ``allow_truncate`` to ``True``. + Use ``hashfunc=hashlib.sha1`` to match openssl's + ``-ecdsa-with-SHA1`` mode, + or ``hashfunc=hashlib.sha256`` for openssl-1.0.0's + ``-ecdsa-with-SHA256``. + Ignored for EdDSA :type hashfunc: callable :param sigencode: function used to encode the signature. The function needs to accept three parameters: the two integers that are the signature and the order of the curve over which the signature was computed. It needs to return an encoded signature. - See `ecdsa.util.sigencode_string` and `ecdsa.util.sigencode_der` + See :func:`~ecdsa.util.sigencode_string` and + :func:`~ecdsa.util.sigencode_der` as examples of such functions. + Ignored for EdDSA :type sigencode: callable :param int k: a pre-selected nonce for calculating the signature. In typical use cases, it should be set to None (the default) to allow its generation from an entropy source. - :param bool allow_truncate: if True, the provided digest can have + Ignored for EdDSA. + :param bool allow_truncate: if ``True``, the provided digest can have bigger bit-size than the order of the curve, the extra bits (at the end of the digest) will be truncated. Use it when signing SHA-384 output using NIST256p or in similar situations. True by default. + Ignored for EdDSA. - :raises RSZeroError: in the unlikely event when "r" parameter or - "s" parameter is equal 0 as that would leak the key. Calee should - try a better entropy source or different 'k' in such case. + :raises RSZeroError: in the unlikely event when *r* parameter or + *s* parameter of the created signature is equal 0, as that would + leak the key. Caller should try a better entropy source, retry with + different ``k``, or use the + :func:`~SigningKey.sign_deterministic` in such case. :return: encoded signature of the hash of `data` - :rtype: bytes or sigencode function dependant type + :rtype: bytes or sigencode function dependent type """ hashfunc = hashfunc or self.default_hashfunc data = normalise_bytes(data) + if isinstance(self.curve.curve, CurveEdTw): + return self.sign_deterministic(data) h = hashfunc(data).digest() return self.sign_digest(h, entropy, sigencode, k, allow_truncate) @@ -1384,7 +1557,7 @@ class SigningKey(object): instead of this one. :param digest: hash value that will be signed - :type digest: bytes like object + :type digest: :term:`bytes-like object` :param callable entropy: randomness source, os.urandom by default :param sigencode: function used to encode the signature. The function needs to accept three parameters: the two integers @@ -1402,21 +1575,22 @@ class SigningKey(object): SHA-384 output using NIST256p or in similar situations. :raises RSZeroError: in the unlikely event when "r" parameter or - "s" parameter is equal 0 as that would leak the key. Calee should - try a better entropy source in such case. + "s" parameter of the created signature is equal 0, as that would + leak the key. Caller should try a better entropy source, retry with + different 'k', or use the + :func:`~SigningKey.sign_digest_deterministic` in such case. :return: encoded signature for the `digest` hash - :rtype: bytes or sigencode function dependant type + :rtype: bytes or sigencode function dependent type """ + if isinstance(self.curve.curve, CurveEdTw): + raise ValueError("Method unsupported for Edwards curves") digest = normalise_bytes(digest) - if allow_truncate: - digest = digest[: self.curve.baselen] - if len(digest) > self.curve.baselen: - raise BadDigestError( - "this curve (%s) is too short " - "for your digest (%d)" % (self.curve.name, 8 * len(digest)) - ) - number = string_to_number(digest) + number = _truncate_and_convert_digest( + digest, + self.curve, + allow_truncate, + ) r, s = self.sign_number(number, entropy, k) return sigencode(r, s, self.privkey.order) @@ -1435,12 +1609,16 @@ class SigningKey(object): it will be selected at random using the entropy source. :raises RSZeroError: in the unlikely event when "r" parameter or - "s" parameter is equal 0 as that would leak the key. Calee should - try a different 'k' in such case. + "s" parameter of the created signature is equal 0, as that would + leak the key. Caller should try a better entropy source, retry with + different 'k', or use the + :func:`~SigningKey.sign_digest_deterministic` in such case. :return: the "r" and "s" parameters of the signature :rtype: tuple of ints """ + if isinstance(self.curve.curve, CurveEdTw): + raise ValueError("Method unsupported for Edwards curves") order = self.privkey.order if k is not None: diff --git a/frozen_deps/ecdsa/numbertheory.py b/frozen_deps/ecdsa/numbertheory.py index e5cc888..fe974f8 100644 --- a/frozen_deps/ecdsa/numbertheory.py +++ b/frozen_deps/ecdsa/numbertheory.py @@ -7,10 +7,11 @@ # Written in 2005 and 2006 by Peter Pearson and placed in the public domain. # Revision history: # 2008.11.14: Use pow(base, exponent, modulus) for modular_exp. -# Make gcd and lcm accept arbitrarly many arguments. +# Make gcd and lcm accept arbitrarily many arguments. from __future__ import division +import sys from six import integer_types, PY2 from six.moves import reduce @@ -19,11 +20,11 @@ try: except NameError: xrange = range try: - from gmpy2 import powmod + from gmpy2 import powmod, mpz GMPY2 = True GMPY = False -except ImportError: +except ImportError: # pragma: no branch GMPY2 = False try: from gmpy import mpz @@ -32,8 +33,15 @@ except ImportError: except ImportError: GMPY = False + +if GMPY2 or GMPY: # pragma: no branch + integer_types = tuple(integer_types + (type(mpz(1)),)) + + import math import warnings +import random +from .util import bit_length class Error(Exception): @@ -42,6 +50,10 @@ class Error(Exception): pass +class JacobiError(Error): + pass + + class SquareRootError(Error): pass @@ -153,8 +165,10 @@ def jacobi(a, n): # table printed in HAC, and by extensive use in calculating # modular square roots. - assert n >= 3 - assert n % 2 == 1 + if not n >= 3: + raise JacobiError("n must be larger than 2") + if not n % 2 == 1: + raise JacobiError("n must be odd") a = a % n if a == 0: return 0 @@ -201,66 +215,76 @@ def square_root_mod_prime(a, p): d = pow(a, (p - 1) // 4, p) if d == 1: return pow(a, (p + 3) // 8, p) - if d == p - 1: - return (2 * a * pow(4 * a, (p - 5) // 8, p)) % p - raise RuntimeError("Shouldn't get here.") + assert d == p - 1 + return (2 * a * pow(4 * a, (p - 5) // 8, p)) % p if PY2: # xrange on python2 can take integers representable as C long only range_top = min(0x7FFFFFFF, p) else: range_top = p - for b in xrange(2, range_top): + for b in xrange(2, range_top): # pragma: no branch if jacobi(b * b - 4 * a, p) == -1: f = (a, -b, 1) ff = polynomial_exp_mod((0, 1), (p + 1) // 2, f, p) - assert ff[1] == 0 + if ff[1]: + raise SquareRootError("p is not prime") return ff[0] - raise RuntimeError("No b found.") + # just an assertion + raise RuntimeError("No b found.") # pragma: no cover -if GMPY2: +# because all the inverse_mod code is arch/environment specific, and coveralls +# expects it to execute equal number of times, we need to waive it by +# adding the "no branch" pragma to all branches +if GMPY2: # pragma: no branch def inverse_mod(a, m): """Inverse of a mod m.""" - if a == 0: + if a == 0: # pragma: no branch return 0 return powmod(a, -1, m) - -elif GMPY: +elif GMPY: # pragma: no branch def inverse_mod(a, m): """Inverse of a mod m.""" - # while libgmp likely does support inverses modulo, it is accessible - # only using the native `pow()` function, and `pow()` sanity checks - # the parameters before passing them on to underlying implementation - # on Python2 - if a == 0: + # while libgmp does support inverses modulo, it is accessible + # only using the native `pow()` function, and `pow()` in gmpy sanity + # checks the parameters before passing them on to underlying + # implementation + if a == 0: # pragma: no branch return 0 a = mpz(a) m = mpz(m) lm, hm = mpz(1), mpz(0) low, high = a % m, m - while low > 1: + while low > 1: # pragma: no branch r = high // low lm, low, hm, high = hm - lm * r, high - low * r, lm, low return lm % m +elif sys.version_info >= (3, 8): # pragma: no branch + + def inverse_mod(a, m): + """Inverse of a mod m.""" + if a == 0: # pragma: no branch + return 0 + return pow(a, -1, m) -else: +else: # pragma: no branch def inverse_mod(a, m): """Inverse of a mod m.""" - if a == 0: + if a == 0: # pragma: no branch return 0 lm, hm = 1, 0 low, high = a % m, m - while low > 1: + while low > 1: # pragma: no branch r = high // low lm, low, hm, high = hm - lm * r, high - low * r, lm, low @@ -321,7 +345,6 @@ def factorization(n): return [] result = [] - d = 2 # Test the small primes: @@ -331,7 +354,7 @@ def factorization(n): q, r = divmod(n, d) if r == 0: count = 1 - while d <= n: + while d <= n: # pragma: no branch n = q q, r = divmod(n, d) if r != 0: @@ -355,7 +378,8 @@ def factorization(n): if r == 0: # d divides n. How many times? count = 1 n = q - while d <= n: # As long as d might still divide n, + # As long as d might still divide n, + while d <= n: # pragma: no branch q, r = divmod(n, d) # see if it does. if r != 0: break @@ -374,7 +398,7 @@ def phi(n): # pragma: no cover warnings.warn( "Function is unused by library code. If you use this code, " "please open an issue in " - "https://github.com/warner/python-ecdsa", + "https://github.com/tlsfuzzer/python-ecdsa", DeprecationWarning, ) @@ -404,7 +428,7 @@ def carmichael(n): # pragma: no cover warnings.warn( "Function is unused by library code. If you use this code, " "please open an issue in " - "https://github.com/warner/python-ecdsa", + "https://github.com/tlsfuzzer/python-ecdsa", DeprecationWarning, ) @@ -419,7 +443,7 @@ def carmichael_of_factorized(f_list): # pragma: no cover warnings.warn( "Function is unused by library code. If you use this code, " "please open an issue in " - "https://github.com/warner/python-ecdsa", + "https://github.com/tlsfuzzer/python-ecdsa", DeprecationWarning, ) @@ -439,7 +463,7 @@ def carmichael_of_ppower(pp): # pragma: no cover warnings.warn( "Function is unused by library code. If you use this code, " "please open an issue in " - "https://github.com/warner/python-ecdsa", + "https://github.com/tlsfuzzer/python-ecdsa", DeprecationWarning, ) @@ -456,7 +480,7 @@ def order_mod(x, m): # pragma: no cover warnings.warn( "Function is unused by library code. If you use this code, " "please open an issue in " - "https://github.com/warner/python-ecdsa", + "https://github.com/tlsfuzzer/python-ecdsa", DeprecationWarning, ) @@ -482,7 +506,7 @@ def largest_factor_relatively_prime(a, b): # pragma: no cover warnings.warn( "Function is unused by library code. If you use this code, " "please open an issue in " - "https://github.com/warner/python-ecdsa", + "https://github.com/tlsfuzzer/python-ecdsa", DeprecationWarning, ) @@ -507,7 +531,7 @@ def kinda_order_mod(x, m): # pragma: no cover warnings.warn( "Function is unused by library code. If you use this code, " "please open an issue in " - "https://github.com/warner/python-ecdsa", + "https://github.com/tlsfuzzer/python-ecdsa", DeprecationWarning, ) @@ -540,8 +564,8 @@ def is_prime(n): return True else: return False - - if gcd(n, 2 * 3 * 5 * 7 * 11) != 1: + # 2310 = 2 * 3 * 5 * 7 * 11 + if gcd(n, 2310) != 1: return False # Choose a number of iterations sufficient to reduce the @@ -549,7 +573,8 @@ def is_prime(n): # (from Menezes et al. Table 4.4): t = 40 - n_bits = 1 + int(math.log(n, 2)) + n_bits = 1 + bit_length(n) + assert 11 <= n_bits <= 16384 for k, tt in ( (100, 27), (150, 18), @@ -576,7 +601,7 @@ def is_prime(n): s = s + 1 r = r // 2 for i in xrange(t): - a = smallprimes[i] + a = random.choice(smallprimes) y = pow(a, r, n) if y != 1 and y != n - 1: j = 1 diff --git a/frozen_deps/ecdsa/rfc6979.py b/frozen_deps/ecdsa/rfc6979.py index 1e577c0..0728b5a 100644 --- a/frozen_deps/ecdsa/rfc6979.py +++ b/frozen_deps/ecdsa/rfc6979.py @@ -42,14 +42,17 @@ def bits2octets(data, order): # https://tools.ietf.org/html/rfc6979#section-3.2 def generate_k(order, secexp, hash_func, data, retry_gen=0, extra_entropy=b""): """ - order - order of the DSA generator used in the signature - secexp - secure exponent (private key) in numeric form - hash_func - reference to the same hash function used for generating - hash - data - hash in binary form of the signing data - retry_gen - int - how many good 'k' values to skip before returning - extra_entropy - extra added data in binary form as per section-3.6 of - rfc6979 + Generate the ``k`` value - the nonce for DSA. + + :param int order: order of the DSA generator used in the signature + :param int secexp: secure exponent (private key) in numeric form + :param hash_func: reference to the same hash function used for generating + hash, like :py:class:`hashlib.sha1` + :param bytes data: hash in binary form of the signing data + :param int retry_gen: how many good 'k' values to skip before returning + :param bytes extra_entropy: additional added data in binary form as per + section-3.6 of rfc6979 + :rtype: int """ qlen = bit_length(order) diff --git a/frozen_deps/ecdsa/ssh.py b/frozen_deps/ecdsa/ssh.py new file mode 100644 index 0000000..64e9403 --- /dev/null +++ b/frozen_deps/ecdsa/ssh.py @@ -0,0 +1,83 @@ +import binascii +from . import der +from ._compat import compat26_str, int_to_bytes + +_SSH_ED25519 = b"ssh-ed25519" +_SK_MAGIC = b"openssh-key-v1\0" +_NONE = b"none" + + +def _get_key_type(name): + if name == "Ed25519": + return _SSH_ED25519 + else: + raise ValueError("Unsupported key type") + + +class _Serializer: + def __init__(self): + self.bytes = b"" + + def put_raw(self, val): + self.bytes += val + + def put_u32(self, val): + self.bytes += int_to_bytes(val, length=4, byteorder="big") + + def put_str(self, val): + self.put_u32(len(val)) + self.bytes += val + + def put_pad(self, blklen=8): + padlen = blklen - (len(self.bytes) % blklen) + self.put_raw(bytearray(range(1, 1 + padlen))) + + def encode(self): + return binascii.b2a_base64(compat26_str(self.bytes)) + + def tobytes(self): + return self.bytes + + def topem(self): + return der.topem(self.bytes, "OPENSSH PRIVATE KEY") + + +def serialize_public(name, pub): + serial = _Serializer() + ktype = _get_key_type(name) + serial.put_str(ktype) + serial.put_str(pub) + return b" ".join([ktype, serial.encode()]) + + +def serialize_private(name, pub, priv): + # encode public part + spub = _Serializer() + ktype = _get_key_type(name) + spub.put_str(ktype) + spub.put_str(pub) + + # encode private part + spriv = _Serializer() + checksum = 0 + spriv.put_u32(checksum) + spriv.put_u32(checksum) + spriv.put_raw(spub.tobytes()) + spriv.put_str(priv + pub) + comment = b"" + spriv.put_str(comment) + spriv.put_pad() + + # top-level structure + main = _Serializer() + main.put_raw(_SK_MAGIC) + ciphername = kdfname = _NONE + main.put_str(ciphername) + main.put_str(kdfname) + nokdf = 0 + main.put_u32(nokdf) + nkeys = 1 + main.put_u32(nkeys) + main.put_str(spub.tobytes()) + main.put_str(spriv.tobytes()) + return main.topem() diff --git a/frozen_deps/ecdsa/test_curves.py b/frozen_deps/ecdsa/test_curves.py new file mode 100644 index 0000000..93b6c9b --- /dev/null +++ b/frozen_deps/ecdsa/test_curves.py @@ -0,0 +1,361 @@ +try: + import unittest2 as unittest +except ImportError: + import unittest + +import base64 +import pytest +from .curves import ( + Curve, + NIST256p, + curves, + UnknownCurveError, + PRIME_FIELD_OID, + curve_by_name, +) +from .ellipticcurve import CurveFp, PointJacobi, CurveEdTw +from . import der +from .util import number_to_string + + +class TestParameterEncoding(unittest.TestCase): + @classmethod + def setUpClass(cls): + # minimal, but with cofactor (excludes seed when compared to + # OpenSSL output) + cls.base64_params = ( + "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////" + "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K" + "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd" + "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1" + "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=" + ) + + def test_from_pem(self): + pem_params = ( + "-----BEGIN EC PARAMETERS-----\n" + "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n" + "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n" + "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n" + "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n" + "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n" + "-----END EC PARAMETERS-----\n" + ) + curve = Curve.from_pem(pem_params) + + self.assertIs(curve, NIST256p) + + def test_from_pem_with_explicit_when_explicit_disabled(self): + pem_params = ( + "-----BEGIN EC PARAMETERS-----\n" + "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n" + "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n" + "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n" + "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n" + "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n" + "-----END EC PARAMETERS-----\n" + ) + with self.assertRaises(der.UnexpectedDER) as e: + Curve.from_pem(pem_params, ["named_curve"]) + + self.assertIn("explicit curve parameters not", str(e.exception)) + + def test_from_pem_with_named_curve_with_named_curve_disabled(self): + pem_params = ( + "-----BEGIN EC PARAMETERS-----\n" + "BggqhkjOPQMBBw==\n" + "-----END EC PARAMETERS-----\n" + ) + with self.assertRaises(der.UnexpectedDER) as e: + Curve.from_pem(pem_params, ["explicit"]) + + self.assertIn("named_curve curve parameters not", str(e.exception)) + + def test_from_pem_with_wrong_header(self): + pem_params = ( + "-----BEGIN PARAMETERS-----\n" + "MIHgAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP/////////\n" + "//////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12K\n" + "o6k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEQQRrF9Hy4SxCR/i85uVjpEDyd\n" + "wN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1\n" + "AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQE=\n" + "-----END PARAMETERS-----\n" + ) + with self.assertRaises(der.UnexpectedDER) as e: + Curve.from_pem(pem_params) + + self.assertIn("PARAMETERS PEM header", str(e.exception)) + + def test_to_pem(self): + pem_params = ( + b"-----BEGIN EC PARAMETERS-----\n" + b"BggqhkjOPQMBBw==\n" + b"-----END EC PARAMETERS-----\n" + ) + encoding = NIST256p.to_pem() + + self.assertEqual(pem_params, encoding) + + def test_compare_with_different_object(self): + self.assertNotEqual(NIST256p, 256) + + def test_named_curve_params_der(self): + encoded = NIST256p.to_der() + + # just the encoding of the NIST256p OID (prime256v1) + self.assertEqual(b"\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07", encoded) + + def test_verify_that_default_is_named_curve_der(self): + encoded_default = NIST256p.to_der() + encoded_named = NIST256p.to_der("named_curve") + + self.assertEqual(encoded_default, encoded_named) + + def test_encoding_to_explicit_params(self): + encoded = NIST256p.to_der("explicit") + + self.assertEqual(encoded, bytes(base64.b64decode(self.base64_params))) + + def test_encoding_to_unsupported_type(self): + with self.assertRaises(ValueError) as e: + NIST256p.to_der("unsupported") + + self.assertIn("Only 'named_curve'", str(e.exception)) + + def test_encoding_to_explicit_compressed_params(self): + encoded = NIST256p.to_der("explicit", "compressed") + + compressed_base_point = ( + "MIHAAgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////" + "/////zBEBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6" + "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsEIQNrF9Hy4SxCR/i85uVjpEDydwN9" + "gS3rM6D0oTlF2JjClgIhAP////8AAAAA//////////+85vqtpxeehPO5ysL8YyVR" + "AgEB" + ) + + self.assertEqual( + encoded, bytes(base64.b64decode(compressed_base_point)) + ) + + def test_decoding_explicit_from_openssl(self): + # generated with openssl 1.1.1k using + # openssl ecparam -name P-256 -param_enc explicit -out /tmp/file.pem + p256_explicit = ( + "MIH3AgEBMCwGByqGSM49AQECIQD/////AAAAAQAAAAAAAAAAAAAAAP//////////" + "/////zBbBCD/////AAAAAQAAAAAAAAAAAAAAAP///////////////AQgWsY12Ko6" + "k+ez671VdpiGvGUdBrDMU7D2O848PifSYEsDFQDEnTYIhucEk2pmeOETnSa3gZ9+" + "kARBBGsX0fLhLEJH+Lzm5WOkQPJ3A32BLeszoPShOUXYmMKWT+NC4v4af5uO5+tK" + "fA+eFivOM1drMV7Oy7ZAaDe/UfUCIQD/////AAAAAP//////////vOb6racXnoTz" + "ucrC/GMlUQIBAQ==" + ) + + decoded = Curve.from_der(bytes(base64.b64decode(p256_explicit))) + + self.assertEqual(NIST256p, decoded) + + def test_decoding_well_known_from_explicit_params(self): + curve = Curve.from_der(bytes(base64.b64decode(self.base64_params))) + + self.assertIs(curve, NIST256p) + + def test_decoding_with_incorrect_valid_encodings(self): + with self.assertRaises(ValueError) as e: + Curve.from_der(b"", ["explicitCA"]) + + self.assertIn("Only named_curve", str(e.exception)) + + def test_compare_curves_with_different_generators(self): + curve_fp = CurveFp(23, 1, 7) + base_a = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True) + base_b = PointJacobi(curve_fp, 1, 20, 1, 9, generator=True) + + curve_a = Curve("unknown", curve_fp, base_a, None) + curve_b = Curve("unknown", curve_fp, base_b, None) + + self.assertNotEqual(curve_a, curve_b) + + def test_default_encode_for_custom_curve(self): + curve_fp = CurveFp(23, 1, 7) + base_point = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True) + + curve = Curve("unknown", curve_fp, base_point, None) + + encoded = curve.to_der() + + decoded = Curve.from_der(encoded) + + self.assertEqual(curve, decoded) + + expected = "MCECAQEwDAYHKoZIzj0BAQIBFzAGBAEBBAEHBAMEDQMCAQk=" + + self.assertEqual(encoded, bytes(base64.b64decode(expected))) + + def test_named_curve_encode_for_custom_curve(self): + curve_fp = CurveFp(23, 1, 7) + base_point = PointJacobi(curve_fp, 13, 3, 1, 9, generator=True) + + curve = Curve("unknown", curve_fp, base_point, None) + + with self.assertRaises(UnknownCurveError) as e: + curve.to_der("named_curve") + + self.assertIn("Can't encode curve", str(e.exception)) + + def test_try_decoding_binary_explicit(self): + sect113r1_explicit = ( + "MIGRAgEBMBwGByqGSM49AQIwEQIBcQYJKoZIzj0BAgMCAgEJMDkEDwAwiCUMpufH" + "/mSc6Fgg9wQPAOi+5NPiJgdEGIvg6ccjAxUAEOcjqxTWluZ2h1YVF1b+v4/LSakE" + "HwQAnXNhbzX0qxQH1zViwQ8ApSgwJ3lY7oTRMV7TGIYCDwEAAAAAAAAA2czsijnl" + "bwIBAg==" + ) + + with self.assertRaises(UnknownCurveError) as e: + Curve.from_der(base64.b64decode(sect113r1_explicit)) + + self.assertIn("Characteristic 2 curves unsupported", str(e.exception)) + + def test_decode_malformed_named_curve(self): + bad_der = der.encode_oid(*NIST256p.oid) + der.encode_integer(1) + + with self.assertRaises(der.UnexpectedDER) as e: + Curve.from_der(bad_der) + + self.assertIn("Unexpected data after OID", str(e.exception)) + + def test_decode_malformed_explicit_garbage_after_ECParam(self): + bad_der = bytes( + base64.b64decode(self.base64_params) + ) + der.encode_integer(1) + + with self.assertRaises(der.UnexpectedDER) as e: + Curve.from_der(bad_der) + + self.assertIn("Unexpected data after ECParameters", str(e.exception)) + + def test_decode_malformed_unknown_version_number(self): + bad_der = der.encode_sequence(der.encode_integer(2)) + + with self.assertRaises(der.UnexpectedDER) as e: + Curve.from_der(bad_der) + + self.assertIn("Unknown parameter encoding format", str(e.exception)) + + def test_decode_malformed_unknown_field_type(self): + curve_p = NIST256p.curve.p() + bad_der = der.encode_sequence( + der.encode_integer(1), + der.encode_sequence( + der.encode_oid(1, 2, 3), der.encode_integer(curve_p) + ), + der.encode_sequence( + der.encode_octet_string( + number_to_string(NIST256p.curve.a() % curve_p, curve_p) + ), + der.encode_octet_string( + number_to_string(NIST256p.curve.b(), curve_p) + ), + ), + der.encode_octet_string( + NIST256p.generator.to_bytes("uncompressed") + ), + der.encode_integer(NIST256p.generator.order()), + ) + + with self.assertRaises(UnknownCurveError) as e: + Curve.from_der(bad_der) + + self.assertIn("Unknown field type: (1, 2, 3)", str(e.exception)) + + def test_decode_malformed_garbage_after_prime(self): + curve_p = NIST256p.curve.p() + bad_der = der.encode_sequence( + der.encode_integer(1), + der.encode_sequence( + der.encode_oid(*PRIME_FIELD_OID), + der.encode_integer(curve_p), + der.encode_integer(1), + ), + der.encode_sequence( + der.encode_octet_string( + number_to_string(NIST256p.curve.a() % curve_p, curve_p) + ), + der.encode_octet_string( + number_to_string(NIST256p.curve.b(), curve_p) + ), + ), + der.encode_octet_string( + NIST256p.generator.to_bytes("uncompressed") + ), + der.encode_integer(NIST256p.generator.order()), + ) + + with self.assertRaises(der.UnexpectedDER) as e: + Curve.from_der(bad_der) + + self.assertIn("Prime-p element", str(e.exception)) + + +class TestCurveSearching(unittest.TestCase): + def test_correct_name(self): + c = curve_by_name("NIST256p") + self.assertIs(c, NIST256p) + + def test_openssl_name(self): + c = curve_by_name("prime256v1") + self.assertIs(c, NIST256p) + + def test_unknown_curve(self): + with self.assertRaises(UnknownCurveError) as e: + curve_by_name("foo bar") + + self.assertIn( + "name 'foo bar' unknown, only curves supported: " + "['NIST192p', 'NIST224p'", + str(e.exception), + ) + + def test_with_None_as_parameter(self): + with self.assertRaises(UnknownCurveError) as e: + curve_by_name(None) + + self.assertIn( + "name None unknown, only curves supported: " + "['NIST192p', 'NIST224p'", + str(e.exception), + ) + + +@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) +def test_curve_params_encode_decode_named(curve): + ret = Curve.from_der(curve.to_der("named_curve")) + + assert curve == ret + + +@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) +def test_curve_params_encode_decode_explicit(curve): + if isinstance(curve.curve, CurveEdTw): + with pytest.raises(UnknownCurveError): + curve.to_der("explicit") + else: + ret = Curve.from_der(curve.to_der("explicit")) + + assert curve == ret + + +@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) +def test_curve_params_encode_decode_default(curve): + ret = Curve.from_der(curve.to_der()) + + assert curve == ret + + +@pytest.mark.parametrize("curve", curves, ids=[i.name for i in curves]) +def test_curve_params_encode_decode_explicit_compressed(curve): + if isinstance(curve.curve, CurveEdTw): + with pytest.raises(UnknownCurveError): + curve.to_der("explicit", "compressed") + else: + ret = Curve.from_der(curve.to_der("explicit", "compressed")) + + assert curve == ret diff --git a/frozen_deps/ecdsa/test_der.py b/frozen_deps/ecdsa/test_der.py index 746d927..0c2dc4d 100644 --- a/frozen_deps/ecdsa/test_der.py +++ b/frozen_deps/ecdsa/test_der.py @@ -7,9 +7,9 @@ try: import unittest2 as unittest except ImportError: import unittest -from six import b +import sys import hypothesis.strategies as st -from hypothesis import given, example +from hypothesis import given, settings import pytest from ._compat import str_idx_as_int from .curves import NIST256p, NIST224p @@ -21,6 +21,9 @@ from .der import ( remove_bitstring, remove_object, encode_oid, + remove_constructed, + remove_octet_string, + remove_sequence, ) @@ -29,47 +32,59 @@ class TestRemoveInteger(unittest.TestCase): # interpreted as negative, check if those errors are detected def test_non_minimal_encoding(self): with self.assertRaises(UnexpectedDER): - remove_integer(b("\x02\x02\x00\x01")) + remove_integer(b"\x02\x02\x00\x01") def test_negative_with_high_bit_set(self): with self.assertRaises(UnexpectedDER): - remove_integer(b("\x02\x01\x80")) + remove_integer(b"\x02\x01\x80") def test_minimal_with_high_bit_set(self): - val, rem = remove_integer(b("\x02\x02\x00\x80")) + val, rem = remove_integer(b"\x02\x02\x00\x80") self.assertEqual(val, 0x80) - self.assertFalse(rem) + self.assertEqual(rem, b"") def test_two_zero_bytes_with_high_bit_set(self): with self.assertRaises(UnexpectedDER): - remove_integer(b("\x02\x03\x00\x00\xff")) + remove_integer(b"\x02\x03\x00\x00\xff") def test_zero_length_integer(self): with self.assertRaises(UnexpectedDER): - remove_integer(b("\x02\x00")) + remove_integer(b"\x02\x00") def test_empty_string(self): with self.assertRaises(UnexpectedDER): - remove_integer(b("")) + remove_integer(b"") def test_encoding_of_zero(self): - val, rem = remove_integer(b("\x02\x01\x00")) + val, rem = remove_integer(b"\x02\x01\x00") self.assertEqual(val, 0) - self.assertFalse(rem) + self.assertEqual(rem, b"") def test_encoding_of_127(self): - val, rem = remove_integer(b("\x02\x01\x7f")) + val, rem = remove_integer(b"\x02\x01\x7f") self.assertEqual(val, 127) - self.assertFalse(rem) + self.assertEqual(rem, b"") def test_encoding_of_128(self): - val, rem = remove_integer(b("\x02\x02\x00\x80")) + val, rem = remove_integer(b"\x02\x02\x00\x80") self.assertEqual(val, 128) - self.assertFalse(rem) + self.assertEqual(rem, b"") + + def test_wrong_tag(self): + with self.assertRaises(UnexpectedDER) as e: + remove_integer(b"\x01\x02\x00\x80") + + self.assertIn("wanted type 'integer'", str(e.exception)) + + def test_wrong_length(self): + with self.assertRaises(UnexpectedDER) as e: + remove_integer(b"\x02\x03\x00\x80") + + self.assertIn("Length longer", str(e.exception)) class TestReadLength(unittest.TestCase): @@ -77,37 +92,37 @@ class TestReadLength(unittest.TestCase): # form and lengths above that encoded with minimal number of bytes # necessary def test_zero_length(self): - self.assertEqual((0, 1), read_length(b("\x00"))) + self.assertEqual((0, 1), read_length(b"\x00")) def test_two_byte_zero_length(self): with self.assertRaises(UnexpectedDER): - read_length(b("\x81\x00")) + read_length(b"\x81\x00") def test_two_byte_small_length(self): with self.assertRaises(UnexpectedDER): - read_length(b("\x81\x7f")) + read_length(b"\x81\x7f") def test_long_form_with_zero_length(self): with self.assertRaises(UnexpectedDER): - read_length(b("\x80")) + read_length(b"\x80") def test_smallest_two_byte_length(self): - self.assertEqual((128, 2), read_length(b("\x81\x80"))) + self.assertEqual((128, 2), read_length(b"\x81\x80")) def test_zero_padded_length(self): with self.assertRaises(UnexpectedDER): - read_length(b("\x82\x00\x80")) + read_length(b"\x82\x00\x80") def test_two_three_byte_length(self): self.assertEqual((256, 3), read_length(b"\x82\x01\x00")) def test_empty_string(self): with self.assertRaises(UnexpectedDER): - read_length(b("")) + read_length(b"") def test_length_overflow(self): with self.assertRaises(UnexpectedDER): - read_length(b("\x83\x01\x00")) + read_length(b"\x83\x01\x00") class TestEncodeBitstring(unittest.TestCase): @@ -129,26 +144,22 @@ class TestEncodeBitstring(unittest.TestCase): def test_new_call_convention(self): """This is how it should be called now.""" - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") der = encode_bitstring(b"\xff", 0) - # verify that new call convention doesn't raise Warnings - self.assertEqual(len(warns), 0) - self.assertEqual(der, b"\x03\x02\x00\xff") def test_implicit_unused_bits(self): """ Writing bit string with already included the number of unused bits. """ - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") der = encode_bitstring(b"\x00\xff", None) - # verify that new call convention doesn't raise Warnings - self.assertEqual(len(warns), 0) - self.assertEqual(der, b"\x03\x02\x00\xff") def test_explicit_unused_bits(self): @@ -188,22 +199,20 @@ class TestRemoveBitstring(unittest.TestCase): self.assertEqual(rest, b"") def test_new_call_convention(self): - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") bits, rest = remove_bitstring(b"\x03\x02\x00\xff", 0) - self.assertEqual(len(warns), 0) - self.assertEqual(bits, b"\xff") self.assertEqual(rest, b"") def test_implicit_unexpected_unused(self): - warnings.simplefilter("always") - with pytest.warns(None) as warns: + # make sure no warnings are raised + with warnings.catch_warnings(): + warnings.simplefilter("error") bits, rest = remove_bitstring(b"\x03\x02\x00\xff", None) - self.assertEqual(len(warns), 0) - self.assertEqual(bits, (b"\xff", 0)) self.assertEqual(rest, b"") @@ -260,10 +269,10 @@ class TestStrIdxAsInt(unittest.TestCase): class TestEncodeOid(unittest.TestCase): def test_pub_key_oid(self): oid_ecPublicKey = encode_oid(1, 2, 840, 10045, 2, 1) - self.assertEqual(hexlify(oid_ecPublicKey), b("06072a8648ce3d0201")) + self.assertEqual(hexlify(oid_ecPublicKey), b"06072a8648ce3d0201") def test_nist224p_oid(self): - self.assertEqual(hexlify(NIST224p.encoded_oid), b("06052b81040021")) + self.assertEqual(hexlify(NIST224p.encoded_oid), b"06052b81040021") def test_nist256p_oid(self): self.assertEqual( @@ -368,8 +377,72 @@ class TestRemoveObject(unittest.TestCase): remove_object(b"\x06\x03\x88\x37") +class TestRemoveConstructed(unittest.TestCase): + def test_simple(self): + data = b"\xa1\x02\xff\xaa" + + tag, body, rest = remove_constructed(data) + + self.assertEqual(tag, 0x01) + self.assertEqual(body, b"\xff\xaa") + self.assertEqual(rest, b"") + + def test_with_malformed_tag(self): + data = b"\x01\x02\xff\xaa" + + with self.assertRaises(UnexpectedDER) as e: + remove_constructed(data) + + self.assertIn("constructed tag", str(e.exception)) + + +class TestRemoveOctetString(unittest.TestCase): + def test_simple(self): + data = b"\x04\x03\xaa\xbb\xcc" + body, rest = remove_octet_string(data) + self.assertEqual(body, b"\xaa\xbb\xcc") + self.assertEqual(rest, b"") + + def test_with_malformed_tag(self): + data = b"\x03\x03\xaa\xbb\xcc" + with self.assertRaises(UnexpectedDER) as e: + remove_octet_string(data) + + self.assertIn("octetstring", str(e.exception)) + + +class TestRemoveSequence(unittest.TestCase): + def test_simple(self): + data = b"\x30\x02\xff\xaa" + body, rest = remove_sequence(data) + self.assertEqual(body, b"\xff\xaa") + self.assertEqual(rest, b"") + + def test_with_empty_string(self): + with self.assertRaises(UnexpectedDER) as e: + remove_sequence(b"") + + self.assertIn("Empty string", str(e.exception)) + + def test_with_wrong_tag(self): + data = b"\x20\x02\xff\xaa" + + with self.assertRaises(UnexpectedDER) as e: + remove_sequence(data) + + self.assertIn("wanted type 'sequence'", str(e.exception)) + + def test_with_wrong_length(self): + data = b"\x30\x03\xff\xaa" + + with self.assertRaises(UnexpectedDER) as e: + remove_sequence(data) + + self.assertIn("Length longer", str(e.exception)) + + @st.composite -def st_oid(draw, max_value=2 ** 512, max_size=50): +def st_oid(draw, max_value=2**512, max_size=50): """ Hypothesis strategy that returns valid OBJECT IDENTIFIERs as tuples @@ -389,6 +462,14 @@ def st_oid(draw, max_value=2 ** 512, max_size=50): return (first, second) + tuple(rest) +HYP_SETTINGS = {} + + +if "--fast" in sys.argv: # pragma: no cover + HYP_SETTINGS["max_examples"] = 2 + + +@settings(**HYP_SETTINGS) @given(st_oid()) def test_oids(ids): encoded_oid = encode_oid(*ids) diff --git a/frozen_deps/ecdsa/test_ecdh.py b/frozen_deps/ecdsa/test_ecdh.py index caf6835..cb22580 100644 --- a/frozen_deps/ecdsa/test_ecdh.py +++ b/frozen_deps/ecdsa/test_ecdh.py @@ -1,19 +1,49 @@ import os +import sys import shutil import subprocess import pytest -from binascii import hexlify, unhexlify - -from .curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p +from binascii import unhexlify + +try: + import unittest2 as unittest +except ImportError: + import unittest + +from .curves import ( + NIST192p, + NIST224p, + NIST256p, + NIST384p, + NIST521p, + BRAINPOOLP160r1, + SECP112r2, + SECP128r1, +) from .curves import curves -from .ecdh import ECDH, InvalidCurveError, InvalidSharedSecretError, NoKeyError +from .ecdh import ( + ECDH, + InvalidCurveError, + InvalidSharedSecretError, + NoKeyError, + NoCurveError, +) from .keys import SigningKey, VerifyingKey +from .ellipticcurve import CurveEdTw + + +if "--fast" in sys.argv: # pragma: no cover + curves = [SECP112r2, SECP128r1] @pytest.mark.parametrize( - "vcurve", curves, ids=[curve.name for curve in curves] + "vcurve", + curves, + ids=[curve.name for curve in curves], ) def test_ecdh_each(vcurve): + if isinstance(vcurve.curve, CurveEdTw): + pytest.skip("ECDH is not supported for Edwards curves") ecdh1 = ECDH(curve=vcurve) ecdh2 = ECDH(curve=vcurve) @@ -26,6 +56,19 @@ def test_ecdh_each(vcurve): assert secret1 == secret2 +def test_ecdh_both_keys_present(): + key1 = SigningKey.generate(BRAINPOOLP160r1) + key2 = SigningKey.generate(BRAINPOOLP160r1) + + ecdh1 = ECDH(BRAINPOOLP160r1, key1, key2.verifying_key) + ecdh2 = ECDH(private_key=key2, public_key=key1.verifying_key) + + secret1 = ecdh1.generate_sharedsecret_bytes() + secret2 = ecdh2.generate_sharedsecret_bytes() + + assert secret1 == secret2 + + def test_ecdh_no_public_key(): ecdh1 = ECDH(curve=NIST192p) @@ -38,6 +81,44 @@ def test_ecdh_no_public_key(): ecdh1.generate_sharedsecret_bytes() +class TestECDH(unittest.TestCase): + def test_load_key_from_wrong_curve(self): + ecdh1 = ECDH() + ecdh1.set_curve(NIST192p) + + key1 = SigningKey.generate(BRAINPOOLP160r1) + + with self.assertRaises(InvalidCurveError) as e: + ecdh1.load_private_key(key1) + + self.assertIn("Curve mismatch", str(e.exception)) + + def test_generate_without_curve(self): + ecdh1 = ECDH() + + with self.assertRaises(NoCurveError) as e: + ecdh1.generate_private_key() + + self.assertIn("Curve must be set", str(e.exception)) + + def test_load_bytes_without_curve_set(self): + ecdh1 = ECDH() + + with self.assertRaises(NoCurveError) as e: + ecdh1.load_private_key_bytes(b"\x01" * 32) + + self.assertIn("Curve must be set", str(e.exception)) + + def test_set_curve_from_received_public_key(self): + ecdh1 = ECDH() + + key1 = SigningKey.generate(BRAINPOOLP160r1) + + ecdh1.load_received_public_key(key1.verifying_key) + + self.assertEqual(ecdh1.curve, BRAINPOOLP160r1) + + def test_ecdh_wrong_public_key_curve(): ecdh1 = ECDH(curve=NIST192p) ecdh1.generate_private_key() @@ -292,26 +373,29 @@ OPENSSL_SUPPORTED_CURVES = set( ) +@pytest.mark.slow @pytest.mark.parametrize( - "vcurve", curves, ids=[curve.name for curve in curves] + "vcurve", + curves, + ids=[curve.name for curve in curves], ) def test_ecdh_with_openssl(vcurve): + if isinstance(vcurve.curve, CurveEdTw): + pytest.skip("Edwards curves are not supported for ECDH") + assert vcurve.openssl_name if vcurve.openssl_name not in OPENSSL_SUPPORTED_CURVES: pytest.skip("system openssl does not support " + vcurve.openssl_name) - return try: hlp = run_openssl("pkeyutl -help") - if hlp.find("-derive") == 0: + if hlp.find("-derive") == 0: # pragma: no cover pytest.skip("system openssl does not support `pkeyutl -derive`") - return - except RunOpenSslError: - pytest.skip("system openssl does not support `pkeyutl -derive`") - return + except RunOpenSslError: # pragma: no cover + pytest.skip("system openssl could not be executed") - if os.path.isdir("t"): + if os.path.isdir("t"): # pragma: no branch shutil.rmtree("t") os.mkdir("t") run_openssl( @@ -346,25 +430,20 @@ def test_ecdh_with_openssl(vcurve): assert secret1 == secret2 - try: - run_openssl( - "pkeyutl -derive -inkey t/privkey1.pem -peerkey t/pubkey2.pem -out t/secret1" - ) - run_openssl( - "pkeyutl -derive -inkey t/privkey2.pem -peerkey t/pubkey1.pem -out t/secret2" - ) - except RunOpenSslError: - pytest.skip("system openssl does not support `pkeyutl -derive`") - return + run_openssl( + "pkeyutl -derive -inkey t/privkey1.pem -peerkey t/pubkey2.pem -out t/secret1" + ) + run_openssl( + "pkeyutl -derive -inkey t/privkey2.pem -peerkey t/pubkey1.pem -out t/secret2" + ) with open("t/secret1", "rb") as e: ssl_secret1 = e.read() with open("t/secret1", "rb") as e: ssl_secret2 = e.read() - if len(ssl_secret1) != vk1.curve.baselen: - pytest.skip("system openssl does not support `pkeyutl -derive`") - return + assert len(ssl_secret1) == vk1.curve.verifying_key_length // 2 + assert len(secret1) == vk1.curve.verifying_key_length // 2 assert ssl_secret1 == ssl_secret2 assert secret1 == ssl_secret1 diff --git a/frozen_deps/ecdsa/test_ecdsa.py b/frozen_deps/ecdsa/test_ecdsa.py index e656b88..c1e2582 100644 --- a/frozen_deps/ecdsa/test_ecdsa.py +++ b/frozen_deps/ecdsa/test_ecdsa.py @@ -21,7 +21,13 @@ from .ecdsa import ( generator_384, generator_521, generator_secp256k1, + curve_192, + InvalidPointError, + curve_112r2, + generator_112r2, + int_to_string, ) +from .ellipticcurve import Point HYP_SETTINGS = {} @@ -71,6 +77,19 @@ class TestP192FromX9_62(unittest.TestCase): def test_rejection(self): assert not self.pubk.verifies(self.msg - 1, self.sig) + def test_verification_with_regular_point(self): + pubk = Public_key( + Point( + generator_192.curve(), + generator_192.x(), + generator_192.y(), + generator_192.order(), + ), + self.pubk.point, + ) + + assert pubk.verifies(self.msg, self.sig) + class TestPublicKey(unittest.TestCase): def test_equality_public_keys(self): @@ -96,6 +115,20 @@ class TestPublicKey(unittest.TestCase): pub_key2 = Public_key(gen, point2) self.assertNotEqual(pub_key1, pub_key2) + def test_inequality_different_curves(self): + gen = generator_192 + x1 = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 + y1 = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F + point1 = ellipticcurve.Point(gen.curve(), x1, y1) + + x2 = 0x722BA0FB6B8FC8898A4C6AB49E66 + y2 = 0x2B7344BB57A7ABC8CA0F1A398C7D + point2 = ellipticcurve.Point(generator_112r2.curve(), x2, y2) + + pub_key1 = Public_key(gen, point1) + pub_key2 = Public_key(generator_112r2, point2) + self.assertNotEqual(pub_key1, pub_key2) + def test_inequality_public_key_not_implemented(self): gen = generator_192 x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 @@ -104,6 +137,106 @@ class TestPublicKey(unittest.TestCase): pub_key = Public_key(gen, point) self.assertNotEqual(pub_key, None) + def test_public_key_with_generator_without_order(self): + gen = ellipticcurve.PointJacobi( + generator_192.curve(), generator_192.x(), generator_192.y(), 1 + ) + + x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 + y = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F + point = ellipticcurve.Point(gen.curve(), x, y) + + with self.assertRaises(InvalidPointError) as e: + Public_key(gen, point) + + self.assertIn("Generator point must have order", str(e.exception)) + + def test_public_point_on_curve_not_scalar_multiple_of_base_point(self): + x = 2 + y = 0xBE6AA4938EF7CFE6FE29595B6B00 + # we need a curve with cofactor != 1 + point = ellipticcurve.PointJacobi(curve_112r2, x, y, 1) + + self.assertTrue(curve_112r2.contains_point(x, y)) + + with self.assertRaises(InvalidPointError) as e: + Public_key(generator_112r2, point) + + self.assertIn("Generator point order", str(e.exception)) + + def test_point_is_valid_with_not_scalar_multiple_of_base_point(self): + x = 2 + y = 0xBE6AA4938EF7CFE6FE29595B6B00 + + self.assertFalse(point_is_valid(generator_112r2, x, y)) + + # the tests to verify the extensiveness of tests in ecdsa.ecdsa + # if PointJacobi gets modified to calculate the x and y mod p the tests + # below will need to use a fake/mock object + def test_invalid_point_x_negative(self): + pt = ellipticcurve.PointJacobi(curve_192, -1, 0, 1) + + with self.assertRaises(InvalidPointError) as e: + Public_key(generator_192, pt) + + self.assertIn("The public point has x or y", str(e.exception)) + + def test_invalid_point_x_equal_p(self): + pt = ellipticcurve.PointJacobi(curve_192, curve_192.p(), 0, 1) + + with self.assertRaises(InvalidPointError) as e: + Public_key(generator_192, pt) + + self.assertIn("The public point has x or y", str(e.exception)) + + def test_invalid_point_y_negative(self): + pt = ellipticcurve.PointJacobi(curve_192, 0, -1, 1) + + with self.assertRaises(InvalidPointError) as e: + Public_key(generator_192, pt) + + self.assertIn("The public point has x or y", str(e.exception)) + + def test_invalid_point_y_equal_p(self): + pt = ellipticcurve.PointJacobi(curve_192, 0, curve_192.p(), 1) + + with self.assertRaises(InvalidPointError) as e: + Public_key(generator_192, pt) + + self.assertIn("The public point has x or y", str(e.exception)) + + +class TestPublicKeyVerifies(unittest.TestCase): + # test all the different ways that a signature can be publicly invalid + @classmethod + def setUpClass(cls): + gen = generator_192 + x = 0xC58D61F88D905293BCD4CD0080BCB1B7F811F2FFA41979F6 + y = 0x8804DC7A7C4C7F8B5D437F5156F3312CA7D6DE8A0E11867F + point = ellipticcurve.Point(gen.curve(), x, y) + + cls.pub_key = Public_key(gen, point) + + def test_sig_with_r_zero(self): + sig = Signature(0, 1) + + self.assertFalse(self.pub_key.verifies(1, sig)) + + def test_sig_with_r_order(self): + sig = Signature(generator_192.order(), 1) + + self.assertFalse(self.pub_key.verifies(1, sig)) + + def test_sig_with_s_zero(self): + sig = Signature(1, 0) + + self.assertFalse(self.pub_key.verifies(1, sig)) + + def test_sig_with_s_order(self): + sig = Signature(1, generator_192.order()) + + self.assertFalse(self.pub_key.verifies(1, sig)) + class TestPrivateKey(unittest.TestCase): @classmethod @@ -465,7 +598,13 @@ def test_signature_validity(gen, msg, qx, qy, r, s, expected): elliptic curve of `gen`, `r` and `s` are the signature, and `expected` is True iff the signature is expected to be valid.""" pubk = Public_key(gen, ellipticcurve.Point(gen.curve(), qx, qy)) - assert expected == pubk.verifies(digest_integer(msg), Signature(r, s)) + with pytest.warns(DeprecationWarning) as warns: + msg_dgst = digest_integer(msg) + assert len(warns) == 3 + assert "unused" in warns[0].message.args[0] + assert "unused" in warns[1].message.args[0] + assert "unused" in warns[2].message.args[0] + assert expected == pubk.verifies(msg_dgst, Signature(r, s)) @pytest.mark.parametrize( @@ -474,7 +613,13 @@ def test_signature_validity(gen, msg, qx, qy, r, s, expected): def test_pk_recovery(gen, msg, r, s, qx, qy, expected): del expected sign = Signature(r, s) - pks = sign.recover_public_keys(digest_integer(msg), gen) + with pytest.warns(DeprecationWarning) as warns: + msg_dgst = digest_integer(msg) + assert len(warns) == 3 + assert "unused" in warns[0].message.args[0] + assert "unused" in warns[1].message.args[0] + assert "unused" in warns[2].message.args[0] + pks = sign.recover_public_keys(msg_dgst, gen) assert pks @@ -503,19 +648,22 @@ def st_random_gen_key_msg_nonce(draw): name = draw(st.sampled_from(sorted(name_gen.keys()))) note("Generator used: {0}".format(name)) generator = name_gen[name] - order = int(generator.order()) + order = int(generator.order()) - 1 key = draw(st.integers(min_value=1, max_value=order)) msg = draw(st.integers(min_value=1, max_value=order)) nonce = draw( - st.integers(min_value=1, max_value=order + 1) + st.integers(min_value=1, max_value=order) | st.integers(min_value=order >> 1, max_value=order) ) return generator, key, msg, nonce SIG_VER_SETTINGS = dict(HYP_SETTINGS) -SIG_VER_SETTINGS["max_examples"] = 10 +if "--fast" in sys.argv: # pragma: no cover + SIG_VER_SETTINGS["max_examples"] = 1 +else: + SIG_VER_SETTINGS["max_examples"] = 10 @settings(**SIG_VER_SETTINGS) @@ -536,3 +684,11 @@ def test_sig_verify(args): assert pubkey.verifies(msg, signature) assert not pubkey.verifies(msg - 1, signature) + + +def test_int_to_string_with_zero(): + with pytest.warns(DeprecationWarning) as warns: + assert int_to_string(0) == b"\x00" + + assert len(warns) == 1 + assert "unused" in warns[0].message.args[0] diff --git a/frozen_deps/ecdsa/test_eddsa.py b/frozen_deps/ecdsa/test_eddsa.py new file mode 100644 index 0000000..6821b3b --- /dev/null +++ b/frozen_deps/ecdsa/test_eddsa.py @@ -0,0 +1,1124 @@ +import sys +import pickle +import hashlib +import pytest + +try: + import unittest2 as unittest +except ImportError: + import unittest +from hypothesis import given, settings, example +import hypothesis.strategies as st +from .ellipticcurve import PointEdwards, INFINITY, CurveEdTw +from .eddsa import ( + generator_ed25519, + curve_ed25519, + generator_ed448, + curve_ed448, + PrivateKey, + PublicKey, +) +from .ecdsa import generator_256, curve_256 +from .errors import MalformedPointError +from ._compat import a2b_hex, compat26_str + + +class TestA2B_Hex(unittest.TestCase): + def test_invalid_input(self): + with self.assertRaises(ValueError): + a2b_hex("abcdefghi") + + +def test_ed25519_curve_compare(): + assert curve_ed25519 != curve_256 + + +def test_ed25519_and_ed448_compare(): + assert curve_ed448 != curve_ed25519 + + +def test_ed25519_and_custom_curve_compare(): + a = CurveEdTw(curve_ed25519.p(), -curve_ed25519.a(), 1) + + assert curve_ed25519 != a + + +def test_ed25519_and_almost_exact_curve_compare(): + a = CurveEdTw(curve_ed25519.p(), curve_ed25519.a(), 1) + + assert curve_ed25519 != a + + +def test_ed25519_and_same_curve_params(): + a = CurveEdTw(curve_ed25519.p(), curve_ed25519.a(), curve_ed25519.d()) + + assert curve_ed25519 == a + assert not (curve_ed25519 != a) + + +def test_ed25519_contains_point(): + g = generator_ed25519 + assert curve_ed25519.contains_point(g.x(), g.y()) + + +def test_ed25519_contains_point_bad(): + assert not curve_ed25519.contains_point(1, 1) + + +def test_ed25519_double(): + a = generator_ed25519 + + z = a.double() + + assert isinstance(z, PointEdwards) + + x2 = int( + "24727413235106541002554574571675588834622768167397638456726423" + "682521233608206" + ) + y2 = int( + "15549675580280190176352668710449542251549572066445060580507079" + "593062643049417" + ) + + b = PointEdwards(curve_ed25519, x2, y2, 1, x2 * y2) + + assert z == b + assert a != b + + +def test_ed25519_add_as_double(): + a = generator_ed25519 + + z = a + a + + assert isinstance(z, PointEdwards) + + b = generator_ed25519.double() + + assert z == b + + +def test_ed25519_double_infinity(): + a = PointEdwards(curve_ed25519, 0, 1, 1, 0) + + z = a.double() + + assert z is INFINITY + + +def test_ed25519_double_badly_encoded_infinity(): + # invalid point, mostly to make instrumental happy + a = PointEdwards(curve_ed25519, 1, 1, 1, 0) + + z = a.double() + + assert z is INFINITY + + +def test_ed25519_eq_with_different_z(): + x = generator_ed25519.x() + y = generator_ed25519.y() + p = curve_ed25519.p() + + a = PointEdwards(curve_ed25519, x * 2 % p, y * 2 % p, 2, x * y * 2 % p) + b = PointEdwards(curve_ed25519, x * 3 % p, y * 3 % p, 3, x * y * 3 % p) + + assert a == b + + assert not (a != b) + + +def test_ed25519_eq_against_infinity(): + assert generator_ed25519 != INFINITY + + +def test_ed25519_eq_encoded_infinity_against_infinity(): + a = PointEdwards(curve_ed25519, 0, 1, 1, 0) + assert a == INFINITY + + +def test_ed25519_eq_bad_encode_of_infinity_against_infinity(): + # technically incorrect encoding of the point at infinity, but we check + # both X and T, so verify that just T==0 works + a = PointEdwards(curve_ed25519, 1, 1, 1, 0) + assert a == INFINITY + + +def test_ed25519_eq_against_non_Edwards_point(): + assert generator_ed25519 != generator_256 + + +def test_ed25519_eq_against_negated_point(): + g = generator_ed25519 + neg = PointEdwards(curve_ed25519, -g.x(), g.y(), 1, -g.x() * g.y()) + assert g != neg + + +def test_ed25519_eq_x_different_y(): + # not points on the curve, but __eq__ doesn't care + a = PointEdwards(curve_ed25519, 1, 1, 1, 1) + b = PointEdwards(curve_ed25519, 1, 2, 1, 2) + + assert a != b + + +def test_ed25519_mul_by_order(): + g = PointEdwards( + curve_ed25519, + generator_ed25519.x(), + generator_ed25519.y(), + 1, + generator_ed25519.x() * generator_ed25519.y(), + ) + + assert g * generator_ed25519.order() == INFINITY + + +def test_radd(): + + a = PointEdwards(curve_ed25519, 1, 1, 1, 1) + + p = INFINITY + a + + assert p == a + + +def test_ed25519_test_normalisation_and_scaling(): + x = generator_ed25519.x() + y = generator_ed25519.y() + p = curve_ed25519.p() + + a = PointEdwards(curve_ed25519, x * 11 % p, y * 11 % p, 11, x * y * 11 % p) + + assert a.x() == x + assert a.y() == y + + a.scale() + + assert a.x() == x + assert a.y() == y + + a.scale() # second execution should be a noop + + assert a.x() == x + assert a.y() == y + + +def test_ed25519_add_three_times(): + a = generator_ed25519 + + z = a + a + a + + x3 = int( + "468967334644549386571235445953867877890461982801326656862413" + "21779790909858396" + ) + y3 = int( + "832484377853344397649037712036920113830141722629755531674120" + "2210403726505172" + ) + + b = PointEdwards(curve_ed25519, x3, y3, 1, x3 * y3) + + assert z == b + + +def test_ed25519_add_to_infinity(): + # generator * (order-1) + x1 = int( + "427838232691226969392843410947554224151809796397784248136826" + "78720006717057747" + ) + y1 = int( + "463168356949264781694283940034751631413079938662562256157830" + "33603165251855960" + ) + inf_m_1 = PointEdwards(curve_ed25519, x1, y1, 1, x1 * y1) + + inf = inf_m_1 + generator_ed25519 + + assert inf is INFINITY + + +def test_ed25519_add_and_mul_equivalence(): + g = generator_ed25519 + + assert g + g == g * 2 + assert g + g + g == g * 3 + + +def test_ed25519_add_literal_infinity(): + g = generator_ed25519 + z = g + INFINITY + + assert z == g + + +def test_ed25519_add_infinity(): + inf = PointEdwards(curve_ed25519, 0, 1, 1, 0) + g = generator_ed25519 + z = g + inf + + assert z == g + + z = inf + g + + assert z == g + + +class TestEd25519(unittest.TestCase): + def test_add_wrong_curves(self): + with self.assertRaises(ValueError) as e: + generator_ed25519 + generator_ed448 + + self.assertIn("different curve", str(e.exception)) + + def test_add_wrong_point_type(self): + with self.assertRaises(ValueError) as e: + generator_ed25519 + generator_256 + + self.assertIn("different curve", str(e.exception)) + + +def test_generate_with_point(): + x1 = int( + "427838232691226969392843410947554224151809796397784248136826" + "78720006717057747" + ) + y1 = int( + "463168356949264781694283940034751631413079938662562256157830" + "33603165251855960" + ) + p = PointEdwards(curve_ed25519, x1, y1, 1, x1 * y1) + + pk = PublicKey(generator_ed25519, b"0" * 32, public_point=p) + + assert pk.public_point() == p + + +def test_ed25519_mul_to_order_min_1(): + x1 = int( + "427838232691226969392843410947554224151809796397784248136826" + "78720006717057747" + ) + y1 = int( + "463168356949264781694283940034751631413079938662562256157830" + "33603165251855960" + ) + inf_m_1 = PointEdwards(curve_ed25519, x1, y1, 1, x1 * y1) + + assert generator_ed25519 * (generator_ed25519.order() - 1) == inf_m_1 + + +def test_ed25519_mul_to_infinity(): + assert generator_ed25519 * generator_ed25519.order() == INFINITY + + +def test_ed25519_mul_to_infinity_plus_1(): + g = generator_ed25519 + assert g * (g.order() + 1) == g + + +def test_ed25519_mul_and_add(): + g = generator_ed25519 + a = g * 128 + b = g * 64 + g * 64 + + assert a == b + + +def test_ed25519_mul_and_add_2(): + g = generator_ed25519 + + a = g * 123 + b = g * 120 + g * 3 + + assert a == b + + +def test_ed25519_mul_infinity(): + inf = PointEdwards(curve_ed25519, 0, 1, 1, 0) + + z = inf * 11 + + assert z == INFINITY + + +def test_ed25519_mul_by_zero(): + z = generator_ed25519 * 0 + + assert z == INFINITY + + +def test_ed25519_mul_by_one(): + z = generator_ed25519 * 1 + + assert z == generator_ed25519 + + +def test_ed25519_mul_custom_point(): + # verify that multiplication without order set works + + g = generator_ed25519 + + a = PointEdwards(curve_ed25519, g.x(), g.y(), 1, g.x() * g.y()) + + z = a * 11 + + assert z == g * 11 + + +def test_ed25519_pickle(): + g = generator_ed25519 + assert pickle.loads(pickle.dumps(g)) == g + + +def test_ed448_eq_against_different_curve(): + assert generator_ed25519 != generator_ed448 + + +def test_ed448_double(): + g = generator_ed448 + z = g.double() + + assert isinstance(z, PointEdwards) + + x2 = int( + "4845591495304045936995492052586696895690942404582120401876" + "6013278705691214670908136440114445572635086627683154494739" + "7859048262938744149" + ) + y2 = int( + "4940887598674337276743026725267350893505445523037277237461" + "2648447308771911703729389009346215770388834286503647778745" + "3078312060500281069" + ) + + b = PointEdwards(curve_ed448, x2, y2, 1, x2 * y2) + + assert z == b + assert g != b + + +def test_ed448_add_as_double(): + g = generator_ed448 + z = g + g + + b = g.double() + + assert z == b + + +def test_ed448_mul_as_double(): + g = generator_ed448 + z = g * 2 + b = g.double() + + assert z == b + + +def test_ed448_add_to_infinity(): + # generator * (order - 1) + x1 = int( + "5022586839996825903617194737881084981068517190547539260353" + "6473749366191269932473977736719082931859264751085238669719" + "1187378895383117729" + ) + y1 = int( + "2988192100784814926760179304439306734375440401540802420959" + "2824137233150618983587600353687865541878473398230323350346" + "2500531545062832660" + ) + inf_m_1 = PointEdwards(curve_ed448, x1, y1, 1, x1 * y1) + + inf = inf_m_1 + generator_ed448 + + assert inf is INFINITY + + +def test_ed448_mul_to_infinity(): + g = generator_ed448 + inf = g * g.order() + + assert inf is INFINITY + + +def test_ed448_mul_to_infinity_plus_1(): + g = generator_ed448 + + z = g * (g.order() + 1) + + assert z == g + + +def test_ed448_add_and_mul_equivalence(): + g = generator_ed448 + + assert g + g == g * 2 + assert g + g + g == g * 3 + + +def test_ed25519_encode(): + g = generator_ed25519 + g_bytes = g.to_bytes() + assert len(g_bytes) == 32 + exp_bytes = ( + b"\x58\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + ) + assert g_bytes == exp_bytes + + +def test_ed25519_decode(): + exp_bytes = ( + b"\x58\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + ) + a = PointEdwards.from_bytes(curve_ed25519, exp_bytes) + + assert a == generator_ed25519 + + +class TestEdwardsMalformed(unittest.TestCase): + def test_invalid_point(self): + exp_bytes = ( + b"\x78\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + ) + with self.assertRaises(MalformedPointError): + PointEdwards.from_bytes(curve_ed25519, exp_bytes) + + def test_invalid_length(self): + exp_bytes = ( + b"\x58\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + b"\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66\x66" + b"\x66" + ) + with self.assertRaises(MalformedPointError) as e: + PointEdwards.from_bytes(curve_ed25519, exp_bytes) + + self.assertIn("length", str(e.exception)) + + def test_ed448_invalid(self): + exp_bytes = b"\xff" * 57 + with self.assertRaises(MalformedPointError): + PointEdwards.from_bytes(curve_ed448, exp_bytes) + + +def test_ed448_encode(): + g = generator_ed448 + g_bytes = g.to_bytes() + assert len(g_bytes) == 57 + exp_bytes = ( + b"\x14\xfa\x30\xf2\x5b\x79\x08\x98\xad\xc8\xd7\x4e\x2c\x13\xbd" + b"\xfd\xc4\x39\x7c\xe6\x1c\xff\xd3\x3a\xd7\xc2\xa0\x05\x1e\x9c" + b"\x78\x87\x40\x98\xa3\x6c\x73\x73\xea\x4b\x62\xc7\xc9\x56\x37" + b"\x20\x76\x88\x24\xbc\xb6\x6e\x71\x46\x3f\x69\x00" + ) + assert g_bytes == exp_bytes + + +def test_ed448_decode(): + exp_bytes = ( + b"\x14\xfa\x30\xf2\x5b\x79\x08\x98\xad\xc8\xd7\x4e\x2c\x13\xbd" + b"\xfd\xc4\x39\x7c\xe6\x1c\xff\xd3\x3a\xd7\xc2\xa0\x05\x1e\x9c" + b"\x78\x87\x40\x98\xa3\x6c\x73\x73\xea\x4b\x62\xc7\xc9\x56\x37" + b"\x20\x76\x88\x24\xbc\xb6\x6e\x71\x46\x3f\x69\x00" + ) + + a = PointEdwards.from_bytes(curve_ed448, exp_bytes) + + assert a == generator_ed448 + + +class TestEdDSAEquality(unittest.TestCase): + def test_equal_public_points(self): + key1 = PublicKey(generator_ed25519, b"\x01" * 32) + key2 = PublicKey(generator_ed25519, b"\x01" * 32) + + self.assertEqual(key1, key2) + # verify that `__ne__` works as expected + self.assertFalse(key1 != key2) + + def test_unequal_public_points(self): + key1 = PublicKey(generator_ed25519, b"\x01" * 32) + key2 = PublicKey(generator_ed25519, b"\x03" * 32) + + self.assertNotEqual(key1, key2) + + def test_unequal_to_string(self): + key1 = PublicKey(generator_ed25519, b"\x01" * 32) + key2 = b"\x01" * 32 + + self.assertNotEqual(key1, key2) + + def test_unequal_publickey_curves(self): + key1 = PublicKey(generator_ed25519, b"\x01" * 32) + key2 = PublicKey(generator_ed448, b"\x03" * 56 + b"\x00") + + self.assertNotEqual(key1, key2) + # verify that `__ne__` works as expected + self.assertTrue(key1 != key2) + + def test_equal_private_keys(self): + key1 = PrivateKey(generator_ed25519, b"\x01" * 32) + key2 = PrivateKey(generator_ed25519, b"\x01" * 32) + + self.assertEqual(key1, key2) + # verify that `__ne__` works as expected + self.assertFalse(key1 != key2) + + def test_unequal_private_keys(self): + key1 = PrivateKey(generator_ed25519, b"\x01" * 32) + key2 = PrivateKey(generator_ed25519, b"\x02" * 32) + + self.assertNotEqual(key1, key2) + # verify that `__ne__` works as expected + self.assertTrue(key1 != key2) + + def test_unequal_privatekey_to_string(self): + key1 = PrivateKey(generator_ed25519, b"\x01" * 32) + key2 = b"\x01" * 32 + + self.assertNotEqual(key1, key2) + + def test_unequal_privatekey_curves(self): + key1 = PrivateKey(generator_ed25519, b"\x01" * 32) + key2 = PrivateKey(generator_ed448, b"\x01" * 57) + + self.assertNotEqual(key1, key2) + + +class TestInvalidEdDSAInputs(unittest.TestCase): + def test_wrong_length_of_private_key(self): + with self.assertRaises(ValueError): + PrivateKey(generator_ed25519, b"\x01" * 31) + + def test_wrong_length_of_public_key(self): + with self.assertRaises(ValueError): + PublicKey(generator_ed25519, b"\x01" * 33) + + def test_wrong_cofactor_curve(self): + ed_c = curve_ed25519 + + def _hash(data): + return hashlib.new("sha512", compat26_str(data)).digest() + + curve = CurveEdTw(ed_c.p(), ed_c.a(), ed_c.d(), 1, _hash) + g = generator_ed25519 + fake_gen = PointEdwards(curve, g.x(), g.y(), 1, g.x() * g.y()) + + with self.assertRaises(ValueError) as e: + PrivateKey(fake_gen, g.to_bytes()) + + self.assertIn("cofactor", str(e.exception)) + + def test_invalid_signature_length(self): + key = PublicKey(generator_ed25519, b"\x01" * 32) + + with self.assertRaises(ValueError) as e: + key.verify(b"", b"\x01" * 65) + + self.assertIn("length", str(e.exception)) + + def test_changing_public_key(self): + key = PublicKey(generator_ed25519, b"\x01" * 32) + + g = key.point + + new_g = PointEdwards(curve_ed25519, g.x(), g.y(), 1, g.x() * g.y()) + + key.point = new_g + + self.assertEqual(g, key.point) + + def test_changing_public_key_to_different_point(self): + key = PublicKey(generator_ed25519, b"\x01" * 32) + + with self.assertRaises(ValueError) as e: + key.point = generator_ed25519 + + self.assertIn("coordinates", str(e.exception)) + + def test_invalid_s_value(self): + key = PublicKey( + generator_ed25519, + b"\xd7\x5a\x98\x01\x82\xb1\x0a\xb7\xd5\x4b\xfe\xd3\xc9\x64\x07\x3a" + b"\x0e\xe1\x72\xf3\xda\xa6\x23\x25\xaf\x02\x1a\x68\xf7\x07\x51\x1a", + ) + sig_valid = bytearray( + b"\xe5\x56\x43\x00\xc3\x60\xac\x72\x90\x86\xe2\xcc\x80\x6e\x82\x8a" + b"\x84\x87\x7f\x1e\xb8\xe5\xd9\x74\xd8\x73\xe0\x65\x22\x49\x01\x55" + b"\x5f\xb8\x82\x15\x90\xa3\x3b\xac\xc6\x1e\x39\x70\x1c\xf9\xb4\x6b" + b"\xd2\x5b\xf5\xf0\x59\x5b\xbe\x24\x65\x51\x41\x43\x8e\x7a\x10\x0b" + ) + + self.assertTrue(key.verify(b"", sig_valid)) + + sig_invalid = bytearray(sig_valid) + sig_invalid[-1] = 0xFF + + with self.assertRaises(ValueError): + key.verify(b"", sig_invalid) + + def test_invalid_r_value(self): + key = PublicKey( + generator_ed25519, + b"\xd7\x5a\x98\x01\x82\xb1\x0a\xb7\xd5\x4b\xfe\xd3\xc9\x64\x07\x3a" + b"\x0e\xe1\x72\xf3\xda\xa6\x23\x25\xaf\x02\x1a\x68\xf7\x07\x51\x1a", + ) + sig_valid = bytearray( + b"\xe5\x56\x43\x00\xc3\x60\xac\x72\x90\x86\xe2\xcc\x80\x6e\x82\x8a" + b"\x84\x87\x7f\x1e\xb8\xe5\xd9\x74\xd8\x73\xe0\x65\x22\x49\x01\x55" + b"\x5f\xb8\x82\x15\x90\xa3\x3b\xac\xc6\x1e\x39\x70\x1c\xf9\xb4\x6b" + b"\xd2\x5b\xf5\xf0\x59\x5b\xbe\x24\x65\x51\x41\x43\x8e\x7a\x10\x0b" + ) + + self.assertTrue(key.verify(b"", sig_valid)) + + sig_invalid = bytearray(sig_valid) + sig_invalid[0] = 0xE0 + + with self.assertRaises(ValueError): + key.verify(b"", sig_invalid) + + +HYP_SETTINGS = dict() +if "--fast" in sys.argv: # pragma: no cover + HYP_SETTINGS["max_examples"] = 2 +else: + HYP_SETTINGS["max_examples"] = 10 + + +@settings(**HYP_SETTINGS) +@example(1) +@example(5) # smallest multiple that requires changing sign of x +@given(st.integers(min_value=1, max_value=int(generator_ed25519.order() - 1))) +def test_ed25519_encode_decode(multiple): + a = generator_ed25519 * multiple + + b = PointEdwards.from_bytes(curve_ed25519, a.to_bytes()) + + assert a == b + + +@settings(**HYP_SETTINGS) +@example(1) +@example(2) # smallest multiple that requires changing the sign of x +@given(st.integers(min_value=1, max_value=int(generator_ed448.order() - 1))) +def test_ed448_encode_decode(multiple): + a = generator_ed448 * multiple + + b = PointEdwards.from_bytes(curve_ed448, a.to_bytes()) + + assert a == b + + +@settings(**HYP_SETTINGS) +@example(1) +@example(2) +@given(st.integers(min_value=1, max_value=int(generator_ed25519.order()) - 1)) +def test_ed25519_mul_precompute_vs_naf(multiple): + """Compare multiplication with and without precomputation.""" + g = generator_ed25519 + new_g = PointEdwards(curve_ed25519, g.x(), g.y(), 1, g.x() * g.y()) + + assert g * multiple == multiple * new_g + + +# Test vectors from RFC 8032 +TEST_VECTORS = [ + # TEST 1 + ( + generator_ed25519, + "9d61b19deffd5a60ba844af492ec2cc4" "4449c5697b326919703bac031cae7f60", + "d75a980182b10ab7d54bfed3c964073a" "0ee172f3daa62325af021a68f707511a", + "", + "e5564300c360ac729086e2cc806e828a" + "84877f1eb8e5d974d873e06522490155" + "5fb8821590a33bacc61e39701cf9b46b" + "d25bf5f0595bbe24655141438e7a100b", + ), + # TEST 2 + ( + generator_ed25519, + "4ccd089b28ff96da9db6c346ec114e0f" "5b8a319f35aba624da8cf6ed4fb8a6fb", + "3d4017c3e843895a92b70aa74d1b7ebc" "9c982ccf2ec4968cc0cd55f12af4660c", + "72", + "92a009a9f0d4cab8720e820b5f642540" + "a2b27b5416503f8fb3762223ebdb69da" + "085ac1e43e15996e458f3613d0f11d8c" + "387b2eaeb4302aeeb00d291612bb0c00", + ), + # TEST 3 + ( + generator_ed25519, + "c5aa8df43f9f837bedb7442f31dcb7b1" "66d38535076f094b85ce3a2e0b4458f7", + "fc51cd8e6218a1a38da47ed00230f058" "0816ed13ba3303ac5deb911548908025", + "af82", + "6291d657deec24024827e69c3abe01a3" + "0ce548a284743a445e3680d7db5ac3ac" + "18ff9b538d16f290ae67f760984dc659" + "4a7c15e9716ed28dc027beceea1ec40a", + ), + # TEST 1024 + ( + generator_ed25519, + "f5e5767cf153319517630f226876b86c" "8160cc583bc013744c6bf255f5cc0ee5", + "278117fc144c72340f67d0f2316e8386" "ceffbf2b2428c9c51fef7c597f1d426e", + "08b8b2b733424243760fe426a4b54908" + "632110a66c2f6591eabd3345e3e4eb98" + "fa6e264bf09efe12ee50f8f54e9f77b1" + "e355f6c50544e23fb1433ddf73be84d8" + "79de7c0046dc4996d9e773f4bc9efe57" + "38829adb26c81b37c93a1b270b20329d" + "658675fc6ea534e0810a4432826bf58c" + "941efb65d57a338bbd2e26640f89ffbc" + "1a858efcb8550ee3a5e1998bd177e93a" + "7363c344fe6b199ee5d02e82d522c4fe" + "ba15452f80288a821a579116ec6dad2b" + "3b310da903401aa62100ab5d1a36553e" + "06203b33890cc9b832f79ef80560ccb9" + "a39ce767967ed628c6ad573cb116dbef" + "efd75499da96bd68a8a97b928a8bbc10" + "3b6621fcde2beca1231d206be6cd9ec7" + "aff6f6c94fcd7204ed3455c68c83f4a4" + "1da4af2b74ef5c53f1d8ac70bdcb7ed1" + "85ce81bd84359d44254d95629e9855a9" + "4a7c1958d1f8ada5d0532ed8a5aa3fb2" + "d17ba70eb6248e594e1a2297acbbb39d" + "502f1a8c6eb6f1ce22b3de1a1f40cc24" + "554119a831a9aad6079cad88425de6bd" + "e1a9187ebb6092cf67bf2b13fd65f270" + "88d78b7e883c8759d2c4f5c65adb7553" + "878ad575f9fad878e80a0c9ba63bcbcc" + "2732e69485bbc9c90bfbd62481d9089b" + "eccf80cfe2df16a2cf65bd92dd597b07" + "07e0917af48bbb75fed413d238f5555a" + "7a569d80c3414a8d0859dc65a46128ba" + "b27af87a71314f318c782b23ebfe808b" + "82b0ce26401d2e22f04d83d1255dc51a" + "ddd3b75a2b1ae0784504df543af8969b" + "e3ea7082ff7fc9888c144da2af58429e" + "c96031dbcad3dad9af0dcbaaaf268cb8" + "fcffead94f3c7ca495e056a9b47acdb7" + "51fb73e666c6c655ade8297297d07ad1" + "ba5e43f1bca32301651339e22904cc8c" + "42f58c30c04aafdb038dda0847dd988d" + "cda6f3bfd15c4b4c4525004aa06eeff8" + "ca61783aacec57fb3d1f92b0fe2fd1a8" + "5f6724517b65e614ad6808d6f6ee34df" + "f7310fdc82aebfd904b01e1dc54b2927" + "094b2db68d6f903b68401adebf5a7e08" + "d78ff4ef5d63653a65040cf9bfd4aca7" + "984a74d37145986780fc0b16ac451649" + "de6188a7dbdf191f64b5fc5e2ab47b57" + "f7f7276cd419c17a3ca8e1b939ae49e4" + "88acba6b965610b5480109c8b17b80e1" + "b7b750dfc7598d5d5011fd2dcc5600a3" + "2ef5b52a1ecc820e308aa342721aac09" + "43bf6686b64b2579376504ccc493d97e" + "6aed3fb0f9cd71a43dd497f01f17c0e2" + "cb3797aa2a2f256656168e6c496afc5f" + "b93246f6b1116398a346f1a641f3b041" + "e989f7914f90cc2c7fff357876e506b5" + "0d334ba77c225bc307ba537152f3f161" + "0e4eafe595f6d9d90d11faa933a15ef1" + "369546868a7f3a45a96768d40fd9d034" + "12c091c6315cf4fde7cb68606937380d" + "b2eaaa707b4c4185c32eddcdd306705e" + "4dc1ffc872eeee475a64dfac86aba41c" + "0618983f8741c5ef68d3a101e8a3b8ca" + "c60c905c15fc910840b94c00a0b9d0", + "0aab4c900501b3e24d7cdf4663326a3a" + "87df5e4843b2cbdb67cbf6e460fec350" + "aa5371b1508f9f4528ecea23c436d94b" + "5e8fcd4f681e30a6ac00a9704a188a03", + ), + # TEST SHA(abc) + ( + generator_ed25519, + "833fe62409237b9d62ec77587520911e" "9a759cec1d19755b7da901b96dca3d42", + "ec172b93ad5e563bf4932c70e1245034" "c35467ef2efd4d64ebf819683467e2bf", + "ddaf35a193617abacc417349ae204131" + "12e6fa4e89a97ea20a9eeee64b55d39a" + "2192992a274fc1a836ba3c23a3feebbd" + "454d4423643ce80e2a9ac94fa54ca49f", + "dc2a4459e7369633a52b1bf277839a00" + "201009a3efbf3ecb69bea2186c26b589" + "09351fc9ac90b3ecfdfbc7c66431e030" + "3dca179c138ac17ad9bef1177331a704", + ), + # Blank + ( + generator_ed448, + "6c82a562cb808d10d632be89c8513ebf" + "6c929f34ddfa8c9f63c9960ef6e348a3" + "528c8a3fcc2f044e39a3fc5b94492f8f" + "032e7549a20098f95b", + "5fd7449b59b461fd2ce787ec616ad46a" + "1da1342485a70e1f8a0ea75d80e96778" + "edf124769b46c7061bd6783df1e50f6c" + "d1fa1abeafe8256180", + "", + "533a37f6bbe457251f023c0d88f976ae" + "2dfb504a843e34d2074fd823d41a591f" + "2b233f034f628281f2fd7a22ddd47d78" + "28c59bd0a21bfd3980ff0d2028d4b18a" + "9df63e006c5d1c2d345b925d8dc00b41" + "04852db99ac5c7cdda8530a113a0f4db" + "b61149f05a7363268c71d95808ff2e65" + "2600", + ), + # 1 octet + ( + generator_ed448, + "c4eab05d357007c632f3dbb48489924d" + "552b08fe0c353a0d4a1f00acda2c463a" + "fbea67c5e8d2877c5e3bc397a659949e" + "f8021e954e0a12274e", + "43ba28f430cdff456ae531545f7ecd0a" + "c834a55d9358c0372bfa0c6c6798c086" + "6aea01eb00742802b8438ea4cb82169c" + "235160627b4c3a9480", + "03", + "26b8f91727bd62897af15e41eb43c377" + "efb9c610d48f2335cb0bd0087810f435" + "2541b143c4b981b7e18f62de8ccdf633" + "fc1bf037ab7cd779805e0dbcc0aae1cb" + "cee1afb2e027df36bc04dcecbf154336" + "c19f0af7e0a6472905e799f1953d2a0f" + "f3348ab21aa4adafd1d234441cf807c0" + "3a00", + ), + # 11 octets + ( + generator_ed448, + "cd23d24f714274e744343237b93290f5" + "11f6425f98e64459ff203e8985083ffd" + "f60500553abc0e05cd02184bdb89c4cc" + "d67e187951267eb328", + "dcea9e78f35a1bf3499a831b10b86c90" + "aac01cd84b67a0109b55a36e9328b1e3" + "65fce161d71ce7131a543ea4cb5f7e9f" + "1d8b00696447001400", + "0c3e544074ec63b0265e0c", + "1f0a8888ce25e8d458a21130879b840a" + "9089d999aaba039eaf3e3afa090a09d3" + "89dba82c4ff2ae8ac5cdfb7c55e94d5d" + "961a29fe0109941e00b8dbdeea6d3b05" + "1068df7254c0cdc129cbe62db2dc957d" + "bb47b51fd3f213fb8698f064774250a5" + "028961c9bf8ffd973fe5d5c206492b14" + "0e00", + ), + # 12 octets + ( + generator_ed448, + "258cdd4ada32ed9c9ff54e63756ae582" + "fb8fab2ac721f2c8e676a72768513d93" + "9f63dddb55609133f29adf86ec9929dc" + "cb52c1c5fd2ff7e21b", + "3ba16da0c6f2cc1f30187740756f5e79" + "8d6bc5fc015d7c63cc9510ee3fd44adc" + "24d8e968b6e46e6f94d19b945361726b" + "d75e149ef09817f580", + "64a65f3cdedcdd66811e2915", + "7eeeab7c4e50fb799b418ee5e3197ff6" + "bf15d43a14c34389b59dd1a7b1b85b4a" + "e90438aca634bea45e3a2695f1270f07" + "fdcdf7c62b8efeaf00b45c2c96ba457e" + "b1a8bf075a3db28e5c24f6b923ed4ad7" + "47c3c9e03c7079efb87cb110d3a99861" + "e72003cbae6d6b8b827e4e6c143064ff" + "3c00", + ), + # 13 octets + ( + generator_ed448, + "7ef4e84544236752fbb56b8f31a23a10" + "e42814f5f55ca037cdcc11c64c9a3b29" + "49c1bb60700314611732a6c2fea98eeb" + "c0266a11a93970100e", + "b3da079b0aa493a5772029f0467baebe" + "e5a8112d9d3a22532361da294f7bb381" + "5c5dc59e176b4d9f381ca0938e13c6c0" + "7b174be65dfa578e80", + "64a65f3cdedcdd66811e2915e7", + "6a12066f55331b6c22acd5d5bfc5d712" + "28fbda80ae8dec26bdd306743c5027cb" + "4890810c162c027468675ecf645a8317" + "6c0d7323a2ccde2d80efe5a1268e8aca" + "1d6fbc194d3f77c44986eb4ab4177919" + "ad8bec33eb47bbb5fc6e28196fd1caf5" + "6b4e7e0ba5519234d047155ac727a105" + "3100", + ), + # 64 octets + ( + generator_ed448, + "d65df341ad13e008567688baedda8e9d" + "cdc17dc024974ea5b4227b6530e339bf" + "f21f99e68ca6968f3cca6dfe0fb9f4fa" + "b4fa135d5542ea3f01", + "df9705f58edbab802c7f8363cfe5560a" + "b1c6132c20a9f1dd163483a26f8ac53a" + "39d6808bf4a1dfbd261b099bb03b3fb5" + "0906cb28bd8a081f00", + "bd0f6a3747cd561bdddf4640a332461a" + "4a30a12a434cd0bf40d766d9c6d458e5" + "512204a30c17d1f50b5079631f64eb31" + "12182da3005835461113718d1a5ef944", + "554bc2480860b49eab8532d2a533b7d5" + "78ef473eeb58c98bb2d0e1ce488a98b1" + "8dfde9b9b90775e67f47d4a1c3482058" + "efc9f40d2ca033a0801b63d45b3b722e" + "f552bad3b4ccb667da350192b61c508c" + "f7b6b5adadc2c8d9a446ef003fb05cba" + "5f30e88e36ec2703b349ca229c267083" + "3900", + ), + # 256 octets + ( + generator_ed448, + "2ec5fe3c17045abdb136a5e6a913e32a" + "b75ae68b53d2fc149b77e504132d3756" + "9b7e766ba74a19bd6162343a21c8590a" + "a9cebca9014c636df5", + "79756f014dcfe2079f5dd9e718be4171" + "e2ef2486a08f25186f6bff43a9936b9b" + "fe12402b08ae65798a3d81e22e9ec80e" + "7690862ef3d4ed3a00", + "15777532b0bdd0d1389f636c5f6b9ba7" + "34c90af572877e2d272dd078aa1e567c" + "fa80e12928bb542330e8409f31745041" + "07ecd5efac61ae7504dabe2a602ede89" + "e5cca6257a7c77e27a702b3ae39fc769" + "fc54f2395ae6a1178cab4738e543072f" + "c1c177fe71e92e25bf03e4ecb72f47b6" + "4d0465aaea4c7fad372536c8ba516a60" + "39c3c2a39f0e4d832be432dfa9a706a6" + "e5c7e19f397964ca4258002f7c0541b5" + "90316dbc5622b6b2a6fe7a4abffd9610" + "5eca76ea7b98816af0748c10df048ce0" + "12d901015a51f189f3888145c03650aa" + "23ce894c3bd889e030d565071c59f409" + "a9981b51878fd6fc110624dcbcde0bf7" + "a69ccce38fabdf86f3bef6044819de11", + "c650ddbb0601c19ca11439e1640dd931" + "f43c518ea5bea70d3dcde5f4191fe53f" + "00cf966546b72bcc7d58be2b9badef28" + "743954e3a44a23f880e8d4f1cfce2d7a" + "61452d26da05896f0a50da66a239a8a1" + "88b6d825b3305ad77b73fbac0836ecc6" + "0987fd08527c1a8e80d5823e65cafe2a" + "3d00", + ), + # 1023 octets + ( + generator_ed448, + "872d093780f5d3730df7c212664b37b8" + "a0f24f56810daa8382cd4fa3f77634ec" + "44dc54f1c2ed9bea86fafb7632d8be19" + "9ea165f5ad55dd9ce8", + "a81b2e8a70a5ac94ffdbcc9badfc3feb" + "0801f258578bb114ad44ece1ec0e799d" + "a08effb81c5d685c0c56f64eecaef8cd" + "f11cc38737838cf400", + "6ddf802e1aae4986935f7f981ba3f035" + "1d6273c0a0c22c9c0e8339168e675412" + "a3debfaf435ed651558007db4384b650" + "fcc07e3b586a27a4f7a00ac8a6fec2cd" + "86ae4bf1570c41e6a40c931db27b2faa" + "15a8cedd52cff7362c4e6e23daec0fbc" + "3a79b6806e316efcc7b68119bf46bc76" + "a26067a53f296dafdbdc11c77f7777e9" + "72660cf4b6a9b369a6665f02e0cc9b6e" + "dfad136b4fabe723d2813db3136cfde9" + "b6d044322fee2947952e031b73ab5c60" + "3349b307bdc27bc6cb8b8bbd7bd32321" + "9b8033a581b59eadebb09b3c4f3d2277" + "d4f0343624acc817804728b25ab79717" + "2b4c5c21a22f9c7839d64300232eb66e" + "53f31c723fa37fe387c7d3e50bdf9813" + "a30e5bb12cf4cd930c40cfb4e1fc6225" + "92a49588794494d56d24ea4b40c89fc0" + "596cc9ebb961c8cb10adde976a5d602b" + "1c3f85b9b9a001ed3c6a4d3b1437f520" + "96cd1956d042a597d561a596ecd3d173" + "5a8d570ea0ec27225a2c4aaff26306d1" + "526c1af3ca6d9cf5a2c98f47e1c46db9" + "a33234cfd4d81f2c98538a09ebe76998" + "d0d8fd25997c7d255c6d66ece6fa56f1" + "1144950f027795e653008f4bd7ca2dee" + "85d8e90f3dc315130ce2a00375a318c7" + "c3d97be2c8ce5b6db41a6254ff264fa6" + "155baee3b0773c0f497c573f19bb4f42" + "40281f0b1f4f7be857a4e59d416c06b4" + "c50fa09e1810ddc6b1467baeac5a3668" + "d11b6ecaa901440016f389f80acc4db9" + "77025e7f5924388c7e340a732e554440" + "e76570f8dd71b7d640b3450d1fd5f041" + "0a18f9a3494f707c717b79b4bf75c984" + "00b096b21653b5d217cf3565c9597456" + "f70703497a078763829bc01bb1cbc8fa" + "04eadc9a6e3f6699587a9e75c94e5bab" + "0036e0b2e711392cff0047d0d6b05bd2" + "a588bc109718954259f1d86678a579a3" + "120f19cfb2963f177aeb70f2d4844826" + "262e51b80271272068ef5b3856fa8535" + "aa2a88b2d41f2a0e2fda7624c2850272" + "ac4a2f561f8f2f7a318bfd5caf969614" + "9e4ac824ad3460538fdc25421beec2cc" + "6818162d06bbed0c40a387192349db67" + "a118bada6cd5ab0140ee273204f628aa" + "d1c135f770279a651e24d8c14d75a605" + "9d76b96a6fd857def5e0b354b27ab937" + "a5815d16b5fae407ff18222c6d1ed263" + "be68c95f32d908bd895cd76207ae7264" + "87567f9a67dad79abec316f683b17f2d" + "02bf07e0ac8b5bc6162cf94697b3c27c" + "d1fea49b27f23ba2901871962506520c" + "392da8b6ad0d99f7013fbc06c2c17a56" + "9500c8a7696481c1cd33e9b14e40b82e" + "79a5f5db82571ba97bae3ad3e0479515" + "bb0e2b0f3bfcd1fd33034efc6245eddd" + "7ee2086ddae2600d8ca73e214e8c2b0b" + "db2b047c6a464a562ed77b73d2d841c4" + "b34973551257713b753632efba348169" + "abc90a68f42611a40126d7cb21b58695" + "568186f7e569d2ff0f9e745d0487dd2e" + "b997cafc5abf9dd102e62ff66cba87", + "e301345a41a39a4d72fff8df69c98075" + "a0cc082b802fc9b2b6bc503f926b65bd" + "df7f4c8f1cb49f6396afc8a70abe6d8a" + "ef0db478d4c6b2970076c6a0484fe76d" + "76b3a97625d79f1ce240e7c576750d29" + "5528286f719b413de9ada3e8eb78ed57" + "3603ce30d8bb761785dc30dbc320869e" + "1a00", + ), +] + + +@pytest.mark.parametrize( + "generator,private_key,public_key,message,signature", + TEST_VECTORS, +) +def test_vectors(generator, private_key, public_key, message, signature): + private_key = a2b_hex(private_key) + public_key = a2b_hex(public_key) + message = a2b_hex(message) + signature = a2b_hex(signature) + + sig_key = PrivateKey(generator, private_key) + ver_key = PublicKey(generator, public_key) + + assert sig_key.public_key().public_key() == ver_key.public_key() + + gen_sig = sig_key.sign(message) + + assert gen_sig == signature + + assert ver_key.verify(message, signature) diff --git a/frozen_deps/ecdsa/test_ellipticcurve.py b/frozen_deps/ecdsa/test_ellipticcurve.py index def53b2..9bf0951 100644 --- a/frozen_deps/ecdsa/test_ellipticcurve.py +++ b/frozen_deps/ecdsa/test_ellipticcurve.py @@ -1,5 +1,4 @@ import pytest -from six import print_ try: import unittest2 as unittest @@ -15,7 +14,7 @@ try: except ImportError: # pragma: no cover HC_PRESENT = False from .numbertheory import inverse_mod -from .ellipticcurve import CurveFp, INFINITY, Point +from .ellipticcurve import CurveFp, INFINITY, Point, CurveEdTw HYP_SETTINGS = {} @@ -41,11 +40,11 @@ g_23 = Point(c_23, 13, 7, 7) HYP_SLOW_SETTINGS = dict(HYP_SETTINGS) -HYP_SLOW_SETTINGS["max_examples"] = 10 +HYP_SLOW_SETTINGS["max_examples"] = 2 @settings(**HYP_SLOW_SETTINGS) -@given(st.integers(min_value=1, max_value=r + 1)) +@given(st.integers(min_value=1, max_value=r - 1)) def test_p192_mult_tests(multiple): inv_m = inverse_mod(multiple, r) @@ -96,7 +95,33 @@ class TestCurve(unittest.TestCase): self.assertEqual(len(set((c_23, eq1, eq2, eq3))), 1) self.assertEqual(len(set((c_23, ne1, ne2, ne3))), 4) self.assertDictEqual({c_23: None}, {eq1: None}) - self.assertTrue(eq2 in {eq3: None}) + self.assertIn(eq2, {eq3: None}) + + def test___str__(self): + self.assertEqual(str(self.c_23), "CurveFp(p=23, a=1, b=1)") + + def test___str___with_cofactor(self): + c = CurveFp(23, 1, 1, 4) + self.assertEqual(str(c), "CurveFp(p=23, a=1, b=1, h=4)") + + +class TestCurveEdTw(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.c_23 = CurveEdTw(23, 1, 1) + + def test___str__(self): + self.assertEqual(str(self.c_23), "CurveEdTw(p=23, a=1, d=1)") + + def test___str___with_cofactor(self): + c = CurveEdTw(23, 1, 1, 4) + self.assertEqual(str(c), "CurveEdTw(p=23, a=1, d=1, h=4)") + + def test_usability_in_a_hashed_collection_curves(self): + {self.c_23: None} + + def test_hashability_curves(self): + hash(self.c_23) class TestPoint(unittest.TestCase): @@ -198,3 +223,34 @@ class TestPoint(unittest.TestCase): def test_inequality_points_diff_types(self): c = CurveFp(100, -3, 100) self.assertNotEqual(self.g_23, c) + + def test_to_bytes_from_bytes(self): + p = Point(self.c_23, 3, 10) + + self.assertEqual(p, Point.from_bytes(self.c_23, p.to_bytes())) + + def test_add_to_neg_self(self): + p = Point(self.c_23, 3, 10) + + self.assertEqual(INFINITY, p + (-p)) + + def test_add_to_infinity(self): + p = Point(self.c_23, 3, 10) + + self.assertIs(p, p + INFINITY) + + def test_mul_infinity_by_scalar(self): + self.assertIs(INFINITY, INFINITY * 10) + + def test_mul_by_negative(self): + p = Point(self.c_23, 3, 10) + + self.assertEqual(p * -5, (-p) * 5) + + def test_str_infinity(self): + self.assertEqual(str(INFINITY), "infinity") + + def test_str_point(self): + p = Point(self.c_23, 3, 10) + + self.assertEqual(str(p), "(3,10)") diff --git a/frozen_deps/ecdsa/test_jacobi.py b/frozen_deps/ecdsa/test_jacobi.py index 43ed6c1..9a46afe 100644 --- a/frozen_deps/ecdsa/test_jacobi.py +++ b/frozen_deps/ecdsa/test_jacobi.py @@ -1,22 +1,43 @@ import pickle +import sys try: import unittest2 as unittest except ImportError: import unittest +import os +import signal +import pytest +import threading +import platform import hypothesis.strategies as st from hypothesis import given, assume, settings, example -from .ellipticcurve import CurveFp, Point, PointJacobi, INFINITY +from .ellipticcurve import CurveFp, PointJacobi, INFINITY from .ecdsa import ( generator_256, curve_256, generator_224, generator_brainpoolp160r1, curve_brainpoolp160r1, + generator_112r2, + curve_112r2, ) from .numbertheory import inverse_mod +from .util import randrange + + +NO_OLD_SETTINGS = {} +if sys.version_info > (2, 7): # pragma: no branch + NO_OLD_SETTINGS["deadline"] = 5000 + + +SLOW_SETTINGS = {} +if "--fast" in sys.argv: # pragma: no cover + SLOW_SETTINGS["max_examples"] = 2 +else: + SLOW_SETTINGS["max_examples"] = 10 class TestJacobi(unittest.TestCase): @@ -37,7 +58,7 @@ class TestJacobi(unittest.TestCase): p_a = PointJacobi.from_affine(generator_256) p_b = PointJacobi.from_affine(generator_224) - with self.assertRaises(ValueError): + with self.assertRaises(ValueError): # pragma: no branch p_a + p_b def test_compare_different_curves(self): @@ -186,10 +207,10 @@ class TestJacobi(unittest.TestCase): self.assertEqual(dbl, mlpl) - @settings(max_examples=10) + @settings(**SLOW_SETTINGS) @given( st.integers( - min_value=0, max_value=int(generator_brainpoolp160r1.order()) + min_value=0, max_value=int(generator_brainpoolp160r1.order() - 1) ) ) def test_multiplications(self, mul): @@ -201,16 +222,17 @@ class TestJacobi(unittest.TestCase): self.assertEqual((pj.x(), pj.y()), (pw.x(), pw.y())) self.assertEqual(pj, pw) - @settings(max_examples=10) + @settings(**SLOW_SETTINGS) @given( st.integers( - min_value=0, max_value=int(generator_brainpoolp160r1.order()) + min_value=0, max_value=int(generator_brainpoolp160r1.order() - 1) ) ) @example(0) @example(int(generator_brainpoolp160r1.order())) def test_precompute(self, mul): - precomp = PointJacobi.from_affine(generator_brainpoolp160r1, True) + precomp = generator_brainpoolp160r1 + self.assertTrue(precomp._PointJacobi__precompute) pj = PointJacobi.from_affine(generator_brainpoolp160r1) a = precomp * mul @@ -218,13 +240,13 @@ class TestJacobi(unittest.TestCase): self.assertEqual(a, b) - @settings(max_examples=10) + @settings(**SLOW_SETTINGS) @given( st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), ) @example(3, 3) @@ -237,13 +259,13 @@ class TestJacobi(unittest.TestCase): self.assertEqual(c, j_g * (a_mul + b_mul)) - @settings(max_examples=10) + @settings(**SLOW_SETTINGS) @given( st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)), ) @@ -269,13 +291,14 @@ class TestJacobi(unittest.TestCase): self.assertEqual(c, j_g * (a_mul + b_mul)) - @settings(max_examples=10) + @pytest.mark.slow + @settings(**SLOW_SETTINGS) @given( st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), st.integers(min_value=1, max_value=int(curve_brainpoolp160r1.p() - 1)), ) @@ -311,13 +334,37 @@ class TestJacobi(unittest.TestCase): self.assertEqual(c, j_g * (a_mul + b_mul)) - @settings(max_examples=14) + def test_add_same_scale_points_static(self): + j_g = generator_brainpoolp160r1 + p = curve_brainpoolp160r1.p() + a = j_g * 11 + a.scale() + z1 = 13 + x = PointJacobi( + curve_brainpoolp160r1, + a.x() * z1**2 % p, + a.y() * z1**3 % p, + z1, + ) + y = PointJacobi( + curve_brainpoolp160r1, + a.x() * z1**2 % p, + a.y() * z1**3 % p, + z1, + ) + + c = a + a + + self.assertEqual(c, x + y) + + @pytest.mark.slow + @settings(**SLOW_SETTINGS) @given( st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), st.integers( - min_value=1, max_value=int(generator_brainpoolp160r1.order()) + min_value=1, max_value=int(generator_brainpoolp160r1.order() - 1) ), st.lists( st.integers( @@ -362,11 +409,112 @@ class TestJacobi(unittest.TestCase): self.assertEqual(c, j_g * (a_mul + b_mul)) + def test_add_different_scale_points_static(self): + j_g = generator_brainpoolp160r1 + p = curve_brainpoolp160r1.p() + a = j_g * 11 + a.scale() + z1 = 13 + x = PointJacobi( + curve_brainpoolp160r1, + a.x() * z1**2 % p, + a.y() * z1**3 % p, + z1, + ) + z2 = 29 + y = PointJacobi( + curve_brainpoolp160r1, + a.x() * z2**2 % p, + a.y() * z2**3 % p, + z2, + ) + + c = a + a + + self.assertEqual(c, x + y) + + def test_add_different_points_same_scale_static(self): + j_g = generator_brainpoolp160r1 + p = curve_brainpoolp160r1.p() + a = j_g * 11 + a.scale() + b = j_g * 12 + z = 13 + x = PointJacobi( + curve_brainpoolp160r1, + a.x() * z**2 % p, + a.y() * z**3 % p, + z, + ) + y = PointJacobi( + curve_brainpoolp160r1, + b.x() * z**2 % p, + b.y() * z**3 % p, + z, + ) + + c = a + b + + self.assertEqual(c, x + y) + + def test_add_same_point_different_scale_second_z_1_static(self): + j_g = generator_112r2 + p = curve_112r2.p() + z = 11 + a = j_g * z + a.scale() + + x = PointJacobi( + curve_112r2, + a.x() * z**2 % p, + a.y() * z**3 % p, + z, + ) + y = PointJacobi( + curve_112r2, + a.x(), + a.y(), + 1, + ) + + c = a + a + + self.assertEqual(c, x + y) + + def test_add_to_infinity_static(self): + j_g = generator_112r2 + + z = 11 + a = j_g * z + a.scale() + + b = -a + + x = PointJacobi( + curve_112r2, + a.x(), + a.y(), + 1, + ) + y = PointJacobi( + curve_112r2, + b.x(), + b.y(), + 1, + ) + + self.assertEqual(INFINITY, x + y) + def test_add_point_3_times(self): j_g = PointJacobi.from_affine(generator_256) self.assertEqual(j_g * 3, j_g + j_g + j_g) + def test_mul_without_order(self): + j_g = PointJacobi(curve_256, generator_256.x(), generator_256.y(), 1) + + self.assertEqual(j_g * generator_256.order(), INFINITY) + def test_mul_add_inf(self): j_g = PointJacobi.from_affine(generator_256) @@ -378,7 +526,7 @@ class TestJacobi(unittest.TestCase): self.assertEqual(j_g * 2, j_g.mul_add(1, j_g, 1)) def test_mul_add_precompute(self): - j_g = PointJacobi.from_affine(generator_256, True) + j_g = PointJacobi.from_affine(generator_brainpoolp160r1, True) b = PointJacobi.from_affine(j_g * 255, True) self.assertEqual(j_g * 256, j_g + b) @@ -386,7 +534,7 @@ class TestJacobi(unittest.TestCase): self.assertEqual(j_g * (5 + 255 * 7), j_g.mul_add(5, b, 7)) def test_mul_add_precompute_large(self): - j_g = PointJacobi.from_affine(generator_256, True) + j_g = PointJacobi.from_affine(generator_brainpoolp160r1, True) b = PointJacobi.from_affine(j_g * 255, True) self.assertEqual(j_g * 256, j_g + b) @@ -405,6 +553,21 @@ class TestJacobi(unittest.TestCase): self.assertEqual(a, b) + def test_mul_add_differnt(self): + j_g = PointJacobi.from_affine(generator_256) + + w_a = j_g * 2 + + self.assertEqual(j_g.mul_add(1, w_a, 1), j_g * 3) + + def test_mul_add_slightly_different(self): + j_g = PointJacobi.from_affine(generator_256) + + w_a = j_g * 2 + w_b = j_g * 3 + + self.assertEqual(w_a.mul_add(1, w_b, 3), w_a * 1 + w_b * 3) + def test_mul_add(self): j_g = PointJacobi.from_affine(generator_256) @@ -428,11 +591,163 @@ class TestJacobi(unittest.TestCase): j_g * (0xFF00 + 255 * 0xF0F0), j_g.mul_add(0xFF00, b, 0xF0F0) ) + def test_mul_add_with_infinity_as_result(self): + j_g = PointJacobi.from_affine(generator_256) + + order = generator_256.order() + + b = PointJacobi.from_affine(generator_256 * 256) + + self.assertEqual(j_g.mul_add(order % 256, b, order // 256), INFINITY) + + def test_mul_add_without_order(self): + j_g = PointJacobi(curve_256, generator_256.x(), generator_256.y(), 1) + + order = generator_256.order() + + w_b = generator_256 * 34 + w_b.scale() + + b = PointJacobi(curve_256, w_b.x(), w_b.y(), 1) + + self.assertEqual(j_g.mul_add(order % 34, b, order // 34), INFINITY) + + def test_mul_add_with_doubled_negation_of_itself(self): + j_g = PointJacobi.from_affine(generator_256 * 17) + + dbl_neg = 2 * (-j_g) + + self.assertEqual(j_g.mul_add(4, dbl_neg, 2), INFINITY) + def test_equality(self): pj1 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) pj2 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) self.assertEqual(pj1, pj2) + def test_equality_with_invalid_object(self): + j_g = PointJacobi.from_affine(generator_256) + + self.assertNotEqual(j_g, 12) + + def test_equality_with_wrong_curves(self): + p_a = PointJacobi.from_affine(generator_256) + p_b = PointJacobi.from_affine(generator_224) + + self.assertNotEqual(p_a, p_b) + + def test_add_with_point_at_infinity(self): + pj1 = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) + x, y, z = pj1._add(2, 3, 1, 5, 5, 0, 23) + + self.assertEqual((x, y, z), (2, 3, 1)) + def test_pickle(self): pj = PointJacobi(curve=CurveFp(23, 1, 1, 1), x=2, y=3, z=1, order=1) self.assertEqual(pickle.loads(pickle.dumps(pj)), pj) + + @pytest.mark.slow + @settings(**NO_OLD_SETTINGS) + @pytest.mark.skipif( + platform.python_implementation() == "PyPy", + reason="threading on PyPy breaks coverage", + ) + @given(st.integers(min_value=1, max_value=10)) + def test_multithreading(self, thread_num): # pragma: no cover + # ensure that generator's precomputation table is filled + generator_112r2 * 2 + + # create a fresh point that doesn't have a filled precomputation table + gen = generator_112r2 + gen = PointJacobi(gen.curve(), gen.x(), gen.y(), 1, gen.order(), True) + + self.assertEqual(gen._PointJacobi__precompute, []) + + def runner(generator): + order = generator.order() + for _ in range(10): + generator * randrange(order) + + threads = [] + for _ in range(thread_num): + threads.append(threading.Thread(target=runner, args=(gen,))) + + for t in threads: + t.start() + + runner(gen) + + for t in threads: + t.join() + + self.assertEqual( + gen._PointJacobi__precompute, + generator_112r2._PointJacobi__precompute, + ) + + @pytest.mark.slow + @pytest.mark.skipif( + platform.system() == "Windows" + or platform.python_implementation() == "PyPy", + reason="there are no signals on Windows, and threading breaks coverage" + " on PyPy", + ) + def test_multithreading_with_interrupts(self): # pragma: no cover + thread_num = 10 + # ensure that generator's precomputation table is filled + generator_112r2 * 2 + + # create a fresh point that doesn't have a filled precomputation table + gen = generator_112r2 + gen = PointJacobi(gen.curve(), gen.x(), gen.y(), 1, gen.order(), True) + + self.assertEqual(gen._PointJacobi__precompute, []) + + def runner(generator): + order = generator.order() + for _ in range(50): + generator * randrange(order) + + def interrupter(barrier_start, barrier_end, lock_exit): + # wait until MainThread can handle KeyboardInterrupt + barrier_start.release() + barrier_end.acquire() + os.kill(os.getpid(), signal.SIGINT) + lock_exit.release() + + threads = [] + for _ in range(thread_num): + threads.append(threading.Thread(target=runner, args=(gen,))) + + barrier_start = threading.Lock() + barrier_start.acquire() + barrier_end = threading.Lock() + barrier_end.acquire() + lock_exit = threading.Lock() + lock_exit.acquire() + + threads.append( + threading.Thread( + target=interrupter, + args=(barrier_start, barrier_end, lock_exit), + ) + ) + + for t in threads: + t.start() + + with self.assertRaises(KeyboardInterrupt): + # signal to interrupter that we can now handle the signal + barrier_start.acquire() + barrier_end.release() + runner(gen) + # use the lock to ensure we never go past the scope of + # assertRaises before the os.kill is called + lock_exit.acquire() + + for t in threads: + t.join() + + self.assertEqual( + gen._PointJacobi__precompute, + generator_112r2._PointJacobi__precompute, + ) diff --git a/frozen_deps/ecdsa/test_keys.py b/frozen_deps/ecdsa/test_keys.py index 406a5bf..348475e 100644 --- a/frozen_deps/ecdsa/test_keys.py +++ b/frozen_deps/ecdsa/test_keys.py @@ -8,14 +8,26 @@ try: except NameError: buffer = memoryview +import os import array -import six -import sys import pytest import hashlib -from .keys import VerifyingKey, SigningKey -from .der import unpem +from .keys import ( + VerifyingKey, + SigningKey, + MalformedPointError, + BadSignatureError, +) +from .der import ( + unpem, + UnexpectedDER, + encode_sequence, + encode_oid, + encode_bitstring, + encode_integer, + encode_octet_string, +) from .util import ( sigencode_string, sigencode_der, @@ -24,7 +36,9 @@ from .util import ( sigdecode_der, sigdecode_strings, ) -from .curves import NIST256p +from .curves import NIST256p, Curve, BRAINPOOLP160r1, Ed25519, Ed448 +from .ellipticcurve import Point, PointJacobi, CurveFp, INFINITY +from .ecdsa import generator_brainpoolp160r1 class TestVerifyingKeyFromString(unittest.TestCase): @@ -113,6 +127,10 @@ class TestVerifyingKeyFromString(unittest.TestCase): self.assertEqual(self.vk.to_string(), vk.to_string()) + def test_ed25519_VerifyingKey_from_string_imported(self): + with self.assertRaises(MalformedPointError): + VerifyingKey.from_string(b"AAA", Ed25519) + class TestVerifyingKeyFromDer(unittest.TestCase): """ @@ -150,6 +168,55 @@ class TestVerifyingKeyFromDer(unittest.TestCase): ) cls.vk2 = VerifyingKey.from_pem(key_str) + cls.sk2 = SigningKey.generate(vk.curve) + + def test_load_key_with_explicit_parameters(self): + pub_key_str = ( + "-----BEGIN PUBLIC KEY-----\n" + "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" + "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" + "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" + "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" + "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" + "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABIr1UkgYs5jmbFc7it1/YI2X\n" + "T//IlaEjMNZft1owjqpBYH2ErJHk4U5Pp4WvWq1xmHwIZlsH7Ig4KmefCfR6SmU=\n" + "-----END PUBLIC KEY-----" + ) + pk = VerifyingKey.from_pem(pub_key_str) + + pk_exp = VerifyingKey.from_string( + b"\x04\x8a\xf5\x52\x48\x18\xb3\x98\xe6\x6c\x57\x3b\x8a\xdd\x7f" + b"\x60\x8d\x97\x4f\xff\xc8\x95\xa1\x23\x30\xd6\x5f\xb7\x5a\x30" + b"\x8e\xaa\x41\x60\x7d\x84\xac\x91\xe4\xe1\x4e\x4f\xa7\x85\xaf" + b"\x5a\xad\x71\x98\x7c\x08\x66\x5b\x07\xec\x88\x38\x2a\x67\x9f" + b"\x09\xf4\x7a\x4a\x65", + curve=NIST256p, + ) + self.assertEqual(pk, pk_exp) + + def test_load_key_with_explicit_with_explicit_disabled(self): + pub_key_str = ( + "-----BEGIN PUBLIC KEY-----\n" + "MIIBSzCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAABAAAA\n" + "AAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA////\n" + "///////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMVAMSd\n" + "NgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg9KE5\n" + "RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8AAAAA\n" + "//////////+85vqtpxeehPO5ysL8YyVRAgEBA0IABIr1UkgYs5jmbFc7it1/YI2X\n" + "T//IlaEjMNZft1owjqpBYH2ErJHk4U5Pp4WvWq1xmHwIZlsH7Ig4KmefCfR6SmU=\n" + "-----END PUBLIC KEY-----" + ) + with self.assertRaises(UnexpectedDER): + VerifyingKey.from_pem( + pub_key_str, valid_curve_encodings=["named_curve"] + ) + + def test_load_key_with_disabled_format(self): + with self.assertRaises(MalformedPointError) as e: + VerifyingKey.from_der(self.key_bytes, valid_encodings=["raw"]) + + self.assertIn("enabled (raw) encodings", str(e.exception)) + def test_custom_hashfunc(self): vk = VerifyingKey.from_der(self.key_bytes, hashlib.sha256) @@ -193,13 +260,259 @@ class TestVerifyingKeyFromDer(unittest.TestCase): self.assertEqual(self.vk.to_string(), vk.to_string()) def test_equality_on_verifying_keys(self): - self.assertEqual(self.vk, self.sk.get_verifying_key()) + self.assertTrue(self.vk == self.sk.get_verifying_key()) def test_inequality_on_verifying_keys(self): - self.assertNotEqual(self.vk, self.vk2) + self.assertFalse(self.vk == self.vk2) def test_inequality_on_verifying_keys_not_implemented(self): - self.assertNotEqual(self.vk, None) + self.assertFalse(self.vk == None) + + def test_VerifyingKey_inequality_on_same_curve(self): + self.assertNotEqual(self.vk, self.sk2.verifying_key) + + def test_SigningKey_inequality_on_same_curve(self): + self.assertNotEqual(self.sk, self.sk2) + + def test_inequality_on_wrong_types(self): + self.assertFalse(self.vk == self.sk) + + def test_from_public_point_old(self): + pj = self.vk.pubkey.point + point = Point(pj.curve(), pj.x(), pj.y()) + + vk = VerifyingKey.from_public_point(point, self.vk.curve) + + self.assertTrue(vk == self.vk) + + def test_ed25519_VerifyingKey_repr__(self): + sk = SigningKey.from_string(Ed25519.generator.to_bytes(), Ed25519) + string = repr(sk.verifying_key) + + self.assertEqual( + "VerifyingKey.from_string(" + "bytearray(b'K\\x0c\\xfbZH\\x8e\\x8c\\x8c\\x07\\xee\\xda\\xfb" + "\\xe1\\x97\\xcd\\x90\\x18\\x02\\x15h]\\xfe\\xbe\\xcbB\\xba\\xe6r" + "\\x10\\xae\\xf1P'), Ed25519, None)", + string, + ) + + def test_edwards_from_public_point(self): + point = Ed25519.generator + with self.assertRaises(ValueError) as e: + VerifyingKey.from_public_point(point, Ed25519) + + self.assertIn("incompatible with Edwards", str(e.exception)) + + def test_edwards_precompute_no_side_effect(self): + sk = SigningKey.from_string(Ed25519.generator.to_bytes(), Ed25519) + vk = sk.verifying_key + vk2 = VerifyingKey.from_string(vk.to_string(), Ed25519) + vk.precompute() + + self.assertEqual(vk, vk2) + + def test_parse_malfomed_eddsa_der_pubkey(self): + der_str = encode_sequence( + encode_sequence(encode_oid(*Ed25519.oid)), + encode_bitstring(bytes(Ed25519.generator.to_bytes()), 0), + encode_bitstring(b"\x00", 0), + ) + + with self.assertRaises(UnexpectedDER) as e: + VerifyingKey.from_der(der_str) + + self.assertIn("trailing junk after public key", str(e.exception)) + + def test_edwards_from_public_key_recovery(self): + with self.assertRaises(ValueError) as e: + VerifyingKey.from_public_key_recovery(b"", b"", Ed25519) + + self.assertIn("unsupported for Edwards", str(e.exception)) + + def test_edwards_from_public_key_recovery_with_digest(self): + with self.assertRaises(ValueError) as e: + VerifyingKey.from_public_key_recovery_with_digest( + b"", b"", Ed25519 + ) + + self.assertIn("unsupported for Edwards", str(e.exception)) + + def test_load_ed25519_from_pem(self): + vk_pem = ( + "-----BEGIN PUBLIC KEY-----\n" + "MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" + "-----END PUBLIC KEY-----\n" + ) + + vk = VerifyingKey.from_pem(vk_pem) + + self.assertIsInstance(vk.curve, Curve) + self.assertIs(vk.curve, Ed25519) + + vk_str = ( + b"\x23\x00\x50\xd0\xd6\x64\x22\x28\x8e\xe3\x55\x89\x7e\x6e\x41\x57" + b"\x8d\xae\xde\x44\x26\xee\x56\x27\xbc\x85\xe6\x0b\x2f\x2a\xcb\x65" + ) + + vk_2 = VerifyingKey.from_string(vk_str, Ed25519) + + self.assertEqual(vk, vk_2) + + def test_export_ed255_to_pem(self): + vk_str = ( + b"\x23\x00\x50\xd0\xd6\x64\x22\x28\x8e\xe3\x55\x89\x7e\x6e\x41\x57" + b"\x8d\xae\xde\x44\x26\xee\x56\x27\xbc\x85\xe6\x0b\x2f\x2a\xcb\x65" + ) + + vk = VerifyingKey.from_string(vk_str, Ed25519) + + vk_pem = ( + b"-----BEGIN PUBLIC KEY-----\n" + b"MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" + b"-----END PUBLIC KEY-----\n" + ) + + self.assertEqual(vk_pem, vk.to_pem()) + + def test_export_ed255_to_ssh(self): + vk_str = ( + b"\x23\x00\x50\xd0\xd6\x64\x22\x28\x8e\xe3\x55\x89\x7e\x6e\x41\x57" + b"\x8d\xae\xde\x44\x26\xee\x56\x27\xbc\x85\xe6\x0b\x2f\x2a\xcb\x65" + ) + + vk = VerifyingKey.from_string(vk_str, Ed25519) + + vk_ssh = b"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICMAUNDWZCIojuNViX5uQVeNrt5EJu5WJ7yF5gsvKstl\n" + + self.assertEqual(vk_ssh, vk.to_ssh()) + + def test_ed25519_export_import(self): + sk = SigningKey.generate(Ed25519) + vk = sk.verifying_key + + vk2 = VerifyingKey.from_pem(vk.to_pem()) + + self.assertEqual(vk, vk2) + + def test_ed25519_sig_verify(self): + vk_pem = ( + "-----BEGIN PUBLIC KEY-----\n" + "MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" + "-----END PUBLIC KEY-----\n" + ) + + vk = VerifyingKey.from_pem(vk_pem) + + data = b"data\n" + + # signature created by OpenSSL 3.0.0 beta1 + sig = ( + b"\x64\x47\xab\x6a\x33\xcd\x79\x45\xad\x98\x11\x6c\xb9\xf2\x20\xeb" + b"\x90\xd6\x50\xe3\xc7\x8f\x9f\x60\x10\xec\x75\xe0\x2f\x27\xd3\x96" + b"\xda\xe8\x58\x7f\xe0\xfe\x46\x5c\x81\xef\x50\xec\x29\x9f\xae\xd5" + b"\xad\x46\x3c\x91\x68\x83\x4d\xea\x8d\xa8\x19\x04\x04\x79\x03\x0b" + ) + + self.assertTrue(vk.verify(sig, data)) + + def test_ed25519_sig_verify_malformed(self): + vk_pem = ( + "-----BEGIN PUBLIC KEY-----\n" + "MCowBQYDK2VwAyEAIwBQ0NZkIiiO41WJfm5BV42u3kQm7lYnvIXmCy8qy2U=\n" + "-----END PUBLIC KEY-----\n" + ) + + vk = VerifyingKey.from_pem(vk_pem) + + data = b"data\n" + + # modified signature from test_ed25519_sig_verify + sig = ( + b"\xAA\x47\xab\x6a\x33\xcd\x79\x45\xad\x98\x11\x6c\xb9\xf2\x20\xeb" + b"\x90\xd6\x50\xe3\xc7\x8f\x9f\x60\x10\xec\x75\xe0\x2f\x27\xd3\x96" + b"\xda\xe8\x58\x7f\xe0\xfe\x46\x5c\x81\xef\x50\xec\x29\x9f\xae\xd5" + b"\xad\x46\x3c\x91\x68\x83\x4d\xea\x8d\xa8\x19\x04\x04\x79\x03\x0b" + ) + + with self.assertRaises(BadSignatureError): + vk.verify(sig, data) + + def test_ed448_from_pem(self): + pem_str = ( + "-----BEGIN PUBLIC KEY-----\n" + "MEMwBQYDK2VxAzoAeQtetSu7CMEzE+XWB10Bg47LCA0giNikOxHzdp+tZ/eK/En0\n" + "dTdYD2ll94g58MhSnBiBQB9A1MMA\n" + "-----END PUBLIC KEY-----\n" + ) + + vk = VerifyingKey.from_pem(pem_str) + + self.assertIsInstance(vk.curve, Curve) + self.assertIs(vk.curve, Ed448) + + vk_str = ( + b"\x79\x0b\x5e\xb5\x2b\xbb\x08\xc1\x33\x13\xe5\xd6\x07\x5d\x01\x83" + b"\x8e\xcb\x08\x0d\x20\x88\xd8\xa4\x3b\x11\xf3\x76\x9f\xad\x67\xf7" + b"\x8a\xfc\x49\xf4\x75\x37\x58\x0f\x69\x65\xf7\x88\x39\xf0\xc8\x52" + b"\x9c\x18\x81\x40\x1f\x40\xd4\xc3\x00" + ) + + vk2 = VerifyingKey.from_string(vk_str, Ed448) + + self.assertEqual(vk, vk2) + + def test_ed448_to_pem(self): + vk_str = ( + b"\x79\x0b\x5e\xb5\x2b\xbb\x08\xc1\x33\x13\xe5\xd6\x07\x5d\x01\x83" + b"\x8e\xcb\x08\x0d\x20\x88\xd8\xa4\x3b\x11\xf3\x76\x9f\xad\x67\xf7" + b"\x8a\xfc\x49\xf4\x75\x37\x58\x0f\x69\x65\xf7\x88\x39\xf0\xc8\x52" + b"\x9c\x18\x81\x40\x1f\x40\xd4\xc3\x00" + ) + vk = VerifyingKey.from_string(vk_str, Ed448) + + vk_pem = ( + b"-----BEGIN PUBLIC KEY-----\n" + b"MEMwBQYDK2VxAzoAeQtetSu7CMEzE+XWB10Bg47LCA0giNikOxHzdp+tZ/eK/En0dTdYD2ll94g5\n" + b"8MhSnBiBQB9A1MMA\n" + b"-----END PUBLIC KEY-----\n" + ) + + self.assertEqual(vk_pem, vk.to_pem()) + + def test_ed448_export_import(self): + sk = SigningKey.generate(Ed448) + vk = sk.verifying_key + + vk2 = VerifyingKey.from_pem(vk.to_pem()) + + self.assertEqual(vk, vk2) + + def test_ed448_sig_verify(self): + pem_str = ( + "-----BEGIN PUBLIC KEY-----\n" + "MEMwBQYDK2VxAzoAeQtetSu7CMEzE+XWB10Bg47LCA0giNikOxHzdp+tZ/eK/En0\n" + "dTdYD2ll94g58MhSnBiBQB9A1MMA\n" + "-----END PUBLIC KEY-----\n" + ) + + vk = VerifyingKey.from_pem(pem_str) + + data = b"data\n" + + # signature created by OpenSSL 3.0.0 beta1 + sig = ( + b"\x68\xed\x2c\x70\x35\x22\xca\x1c\x35\x03\xf3\xaa\x51\x33\x3d\x00" + b"\xc0\xae\xb0\x54\xc5\xdc\x7f\x6f\x30\x57\xb4\x1d\xcb\xe9\xec\xfa" + b"\xc8\x45\x3e\x51\xc1\xcb\x60\x02\x6a\xd0\x43\x11\x0b\x5f\x9b\xfa" + b"\x32\x88\xb2\x38\x6b\xed\xac\x09\x00\x78\xb1\x7b\x5d\x7e\xf8\x16" + b"\x31\xdd\x1b\x3f\x98\xa0\xce\x19\xe7\xd8\x1c\x9f\x30\xac\x2f\xd4" + b"\x1e\x55\xbf\x21\x98\xf6\x4c\x8c\xbe\x81\xa5\x2d\x80\x4c\x62\x53" + b"\x91\xd5\xee\x03\x30\xc6\x17\x66\x4b\x9e\x0c\x8d\x40\xd0\xad\xae" + b"\x0a\x00" + ) + + self.assertTrue(vk.verify(sig, data)) class TestSigningKey(unittest.TestCase): @@ -237,6 +550,61 @@ class TestSigningKey(unittest.TestCase): ) cls.sk2 = SigningKey.from_pem(prv_key_str) + def test_to_der_pkcs8(self): + self.assertEqual( + self.sk1.to_der(format="pkcs8"), + b"0o\x02\x01\x010\x13\x06\x07*\x86H\xce=\x02\x01\x06\x08*\x86H" + b"\xce=\x03\x01\x01\x04U0S\x02\x01\x01\x04\x18^\xc8B\x0b\xd6\xef" + b"\x92R\xa9B\xe9\x89\x04<\xa2\x9fV\x1f\xa5%w\x0e\xb1\xc5\xa14\x03" + b"2\x00\x04\xb8\x81w\xd0\x84\xef\x17\xf5\xe4V9@\x80(6\x0f\x9fY" + b"\xb4\xa4\xd7&Nb\xda\x06Q\xdc\xe4z5\xa4\xc5\xb4\\\xf5\x15\x93B:" + b"\x8bU{\x9c \x99\xf3l", + ) + + def test_decoding_explicit_curve_parameters(self): + prv_key_str = ( + "-----BEGIN PRIVATE KEY-----\n" + "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB\n" + "AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA\n" + "///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV\n" + "AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg\n" + "9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A\n" + "AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgIXtREfUmR16r\n" + "ZbmvDGD2lAEFPZa2DLPyz0czSja58yChRANCAASK9VJIGLOY5mxXO4rdf2CNl0//\n" + "yJWhIzDWX7daMI6qQWB9hKyR5OFOT6eFr1qtcZh8CGZbB+yIOCpnnwn0ekpl\n" + "-----END PRIVATE KEY-----\n" + ) + + sk = SigningKey.from_pem(prv_key_str) + + sk2 = SigningKey.from_string( + b"\x21\x7b\x51\x11\xf5\x26\x47\x5e\xab\x65\xb9\xaf\x0c\x60\xf6" + b"\x94\x01\x05\x3d\x96\xb6\x0c\xb3\xf2\xcf\x47\x33\x4a\x36\xb9" + b"\xf3\x20", + curve=NIST256p, + ) + + self.assertEqual(sk, sk2) + + def test_decoding_explicit_curve_parameters_with_explicit_disabled(self): + prv_key_str = ( + "-----BEGIN PRIVATE KEY-----\n" + "MIIBeQIBADCCAQMGByqGSM49AgEwgfcCAQEwLAYHKoZIzj0BAQIhAP////8AAAAB\n" + "AAAAAAAAAAAAAAAA////////////////MFsEIP////8AAAABAAAAAAAAAAAAAAAA\n" + "///////////////8BCBaxjXYqjqT57PrvVV2mIa8ZR0GsMxTsPY7zjw+J9JgSwMV\n" + "AMSdNgiG5wSTamZ44ROdJreBn36QBEEEaxfR8uEsQkf4vOblY6RA8ncDfYEt6zOg\n" + "9KE5RdiYwpZP40Li/hp/m47n60p8D54WK84zV2sxXs7LtkBoN79R9QIhAP////8A\n" + "AAAA//////////+85vqtpxeehPO5ysL8YyVRAgEBBG0wawIBAQQgIXtREfUmR16r\n" + "ZbmvDGD2lAEFPZa2DLPyz0czSja58yChRANCAASK9VJIGLOY5mxXO4rdf2CNl0//\n" + "yJWhIzDWX7daMI6qQWB9hKyR5OFOT6eFr1qtcZh8CGZbB+yIOCpnnwn0ekpl\n" + "-----END PRIVATE KEY-----\n" + ) + + with self.assertRaises(UnexpectedDER): + SigningKey.from_pem( + prv_key_str, valid_curve_encodings=["named_curve"] + ) + def test_equality_on_signing_keys(self): sk = SigningKey.from_secret_exponent( self.sk1.privkey.secret_multiplier, self.sk1.curve @@ -244,6 +612,15 @@ class TestSigningKey(unittest.TestCase): self.assertEqual(self.sk1, sk) self.assertEqual(self.sk1_pkcs8, sk) + def test_verify_with_empty_message(self): + sig = self.sk1.sign(b"") + + self.assertTrue(sig) + + vk = self.sk1.verifying_key + + self.assertTrue(vk.verify(sig, b"")) + def test_verify_with_precompute(self): sig = self.sk1.sign(b"message") @@ -276,6 +653,266 @@ class TestSigningKey(unittest.TestCase): def test_inequality_on_signing_keys_not_implemented(self): self.assertNotEqual(self.sk1, None) + def test_ed25519_from_pem(self): + pem_str = ( + "-----BEGIN PRIVATE KEY-----\n" + "MC4CAQAwBQYDK2VwBCIEIDS6x9FO1PG8T4xIPg8Zd0z8uL6sVGZFEZrX17gHC/XU\n" + "-----END PRIVATE KEY-----\n" + ) + + sk = SigningKey.from_pem(pem_str) + + sk_str = SigningKey.from_string( + b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" + b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", + Ed25519, + ) + + self.assertEqual(sk, sk_str) + + def test_ed25519_from_der_bad_alg_id_params(self): + der_str = encode_sequence( + encode_integer(1), + encode_sequence(encode_oid(*Ed25519.oid), encode_integer(1)), + encode_octet_string(encode_octet_string(b"A" * 32)), + ) + + with self.assertRaises(UnexpectedDER) as e: + SigningKey.from_der(der_str) + + self.assertIn("Non NULL parameters", str(e.exception)) + + def test_ed25519_from_der_junk_after_priv_key(self): + der_str = encode_sequence( + encode_integer(1), + encode_sequence( + encode_oid(*Ed25519.oid), + ), + encode_octet_string(encode_octet_string(b"A" * 32) + b"B"), + ) + + with self.assertRaises(UnexpectedDER) as e: + SigningKey.from_der(der_str) + + self.assertIn( + "trailing junk after the encoded private key", str(e.exception) + ) + + def test_ed25519_sign(self): + sk_str = SigningKey.from_string( + b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" + b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", + Ed25519, + ) + + msg = b"message" + + sig = sk_str.sign(msg, sigencode=sigencode_der) + + self.assertEqual( + sig, + b"\xe1,v\xc9>%\xda\xd2~>\xc3&\na\xf4@|\x9e`X\x11\x13@<\x987\xd4" + b"\r\xb1\xf5\xb3\x15\x7f%i{\xdf}\xdd\xb1\xf3\x02\x7f\x80\x02\xc2" + b'|\xe5\xd6\x06\xc4\n\xa3\xb0\xf6}\xc0\xed)"+E\xaf\x00', + ) + + def test_ed25519_sign_digest_deterministic(self): + sk_str = SigningKey.from_string( + b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" + b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", + Ed25519, + ) + with self.assertRaises(ValueError) as e: + sk_str.sign_digest_deterministic(b"a" * 20) + + self.assertIn("Method unsupported for Edwards", str(e.exception)) + + def test_ed25519_sign_digest(self): + sk_str = SigningKey.from_string( + b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" + b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", + Ed25519, + ) + with self.assertRaises(ValueError) as e: + sk_str.sign_digest(b"a" * 20) + + self.assertIn("Method unsupported for Edwards", str(e.exception)) + + def test_ed25519_sign_number(self): + sk_str = SigningKey.from_string( + b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" + b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", + Ed25519, + ) + with self.assertRaises(ValueError) as e: + sk_str.sign_number(20) + + self.assertIn("Method unsupported for Edwards", str(e.exception)) + + def test_ed25519_to_der_ssleay(self): + pem_str = ( + "-----BEGIN PRIVATE KEY-----\n" + "MC4CAQAwBQYDK2VwBCIEIDS6x9FO1PG8T4xIPg8Zd0z8uL6sVGZFEZrX17gHC/XU\n" + "-----END PRIVATE KEY-----\n" + ) + + sk = SigningKey.from_pem(pem_str) + + with self.assertRaises(ValueError) as e: + sk.to_der(format="ssleay") + + self.assertIn("Only PKCS#8 format", str(e.exception)) + + def test_ed25519_to_pem(self): + sk = SigningKey.from_string( + b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" + b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", + Ed25519, + ) + + pem_str = ( + b"-----BEGIN PRIVATE KEY-----\n" + b"MC4CAQAwBQYDK2VwBCIEIDS6x9FO1PG8T4xIPg8Zd0z8uL6sVGZFEZrX17gHC/XU\n" + b"-----END PRIVATE KEY-----\n" + ) + + self.assertEqual(sk.to_pem(format="pkcs8"), pem_str) + + def test_ed25519_to_ssh(self): + sk = SigningKey.from_string( + b"\x34\xBA\xC7\xD1\x4E\xD4\xF1\xBC\x4F\x8C\x48\x3E\x0F\x19\x77\x4C" + b"\xFC\xB8\xBE\xAC\x54\x66\x45\x11\x9A\xD7\xD7\xB8\x07\x0B\xF5\xD4", + Ed25519, + ) + + ssh_str = ( + b"-----BEGIN OPENSSH PRIVATE KEY-----\n" + b"b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQyNTUx\n" + b"OQAAACAjAFDQ1mQiKI7jVYl+bkFXja7eRCbuVie8heYLLyrLZQAAAIgAAAAAAAAAAAAAAAtzc2gt\n" + b"ZWQyNTUxOQAAACAjAFDQ1mQiKI7jVYl+bkFXja7eRCbuVie8heYLLyrLZQAAAEA0usfRTtTxvE+M\n" + b"SD4PGXdM/Li+rFRmRRGa19e4Bwv11CMAUNDWZCIojuNViX5uQVeNrt5EJu5WJ7yF5gsvKstlAAAA\n" + b"AAECAwQF\n" + b"-----END OPENSSH PRIVATE KEY-----\n" + ) + + self.assertEqual(sk.to_ssh(), ssh_str) + + def test_ed25519_to_and_from_pem(self): + sk = SigningKey.generate(Ed25519) + + decoded = SigningKey.from_pem(sk.to_pem(format="pkcs8")) + + self.assertEqual(sk, decoded) + + def test_ed25519_custom_entropy(self): + sk = SigningKey.generate(Ed25519, entropy=os.urandom) + + self.assertIsNotNone(sk) + + def test_ed25519_from_secret_exponent(self): + with self.assertRaises(ValueError) as e: + SigningKey.from_secret_exponent(1234567890, curve=Ed25519) + + self.assertIn("don't support setting the secret", str(e.exception)) + + def test_ed448_from_pem(self): + pem_str = ( + "-----BEGIN PRIVATE KEY-----\n" + "MEcCAQAwBQYDK2VxBDsEOTyFuXqFLXgJlV8uDqcOw9nG4IqzLiZ/i5NfBDoHPzmP\n" + "OP0JMYaLGlTzwovmvCDJ2zLaezu9NLz9aQ==\n" + "-----END PRIVATE KEY-----\n" + ) + sk = SigningKey.from_pem(pem_str) + + sk_str = SigningKey.from_string( + b"\x3C\x85\xB9\x7A\x85\x2D\x78\x09\x95\x5F\x2E\x0E\xA7\x0E\xC3\xD9" + b"\xC6\xE0\x8A\xB3\x2E\x26\x7F\x8B\x93\x5F\x04\x3A\x07\x3F\x39\x8F" + b"\x38\xFD\x09\x31\x86\x8B\x1A\x54\xF3\xC2\x8B\xE6\xBC\x20\xC9\xDB" + b"\x32\xDA\x7B\x3B\xBD\x34\xBC\xFD\x69", + Ed448, + ) + + self.assertEqual(sk, sk_str) + + def test_ed448_to_pem(self): + sk = SigningKey.from_string( + b"\x3C\x85\xB9\x7A\x85\x2D\x78\x09\x95\x5F\x2E\x0E\xA7\x0E\xC3\xD9" + b"\xC6\xE0\x8A\xB3\x2E\x26\x7F\x8B\x93\x5F\x04\x3A\x07\x3F\x39\x8F" + b"\x38\xFD\x09\x31\x86\x8B\x1A\x54\xF3\xC2\x8B\xE6\xBC\x20\xC9\xDB" + b"\x32\xDA\x7B\x3B\xBD\x34\xBC\xFD\x69", + Ed448, + ) + pem_str = ( + b"-----BEGIN PRIVATE KEY-----\n" + b"MEcCAQAwBQYDK2VxBDsEOTyFuXqFLXgJlV8uDqcOw9nG4IqzLiZ/i5NfBDoHPzmPOP0JMYaLGlTz\n" + b"wovmvCDJ2zLaezu9NLz9aQ==\n" + b"-----END PRIVATE KEY-----\n" + ) + + self.assertEqual(sk.to_pem(format="pkcs8"), pem_str) + + def test_ed448_encode_decode(self): + sk = SigningKey.generate(Ed448) + + decoded = SigningKey.from_pem(sk.to_pem(format="pkcs8")) + + self.assertEqual(decoded, sk) + + +class TestTrivialCurve(unittest.TestCase): + @classmethod + def setUpClass(cls): + # To test what happens with r or s in signing happens to be zero we + # need to find a scalar that creates one of the points on a curve that + # has x coordinate equal to zero. + # Even for secp112r2 curve that's non trivial so use this toy + # curve, for which we can iterate over all points quickly + curve = CurveFp(163, 84, 58) + gen = PointJacobi(curve, 2, 87, 1, 167, generator=True) + + cls.toy_curve = Curve("toy_p8", curve, gen, (1, 2, 0)) + + cls.sk = SigningKey.from_secret_exponent( + 140, + cls.toy_curve, + hashfunc=hashlib.sha1, + ) + + def test_generator_sanity(self): + gen = self.toy_curve.generator + + self.assertEqual(gen * gen.order(), INFINITY) + + def test_public_key_sanity(self): + self.assertEqual(self.sk.verifying_key.to_string(), b"\x98\x1e") + + def test_deterministic_sign(self): + sig = self.sk.sign_deterministic(b"message") + + self.assertEqual(sig, b"-.") + + self.assertTrue(self.sk.verifying_key.verify(sig, b"message")) + + def test_deterministic_sign_random_message(self): + msg = os.urandom(32) + sig = self.sk.sign_deterministic(msg) + self.assertEqual(len(sig), 2) + self.assertTrue(self.sk.verifying_key.verify(sig, msg)) + + def test_deterministic_sign_that_rises_R_zero_error(self): + # the raised RSZeroError is caught and handled internally by + # sign_deterministic methods + msg = b"\x00\x4f" + sig = self.sk.sign_deterministic(msg) + self.assertEqual(sig, b"\x36\x9e") + self.assertTrue(self.sk.verifying_key.verify(sig, msg)) + + def test_deterministic_sign_that_rises_S_zero_error(self): + msg = b"\x01\x6d" + sig = self.sk.sign_deterministic(msg) + self.assertEqual(sig, b"\x49\x6c") + self.assertTrue(self.sk.verifying_key.verify(sig, msg)) + # test VerifyingKey.verify() prv_key_str = ( @@ -311,8 +948,8 @@ assert isinstance(sig_strings[0], bytes) verifiers = [] for modifier, fun in [ ("bytes", lambda x: x), - ("bytes memoryview", lambda x: buffer(x)), - ("bytearray", lambda x: bytearray(x)), + ("bytes memoryview", buffer), + ("bytearray", bytearray), ("bytearray memoryview", lambda x: buffer(bytearray(x))), ("array.array of bytes", lambda x: array.array("B", x)), ("array.array of bytes memoryview", lambda x: buffer(array.array("B", x))), @@ -452,3 +1089,50 @@ def test_SigningKey_with_unlikely_value(): vk = sk.verifying_key sig = sk.sign(b"hello") assert vk.verify(sig, b"hello") + + +def test_SigningKey_with_custom_curve_old_point(): + generator = generator_brainpoolp160r1 + generator = Point( + generator.curve(), + generator.x(), + generator.y(), + generator.order(), + ) + + curve = Curve( + "BRAINPOOLP160r1", + generator.curve(), + generator, + (1, 3, 36, 3, 3, 2, 8, 1, 1, 1), + ) + + sk = SigningKey.from_secret_exponent(12, curve) + + sk2 = SigningKey.from_secret_exponent(12, BRAINPOOLP160r1) + + assert sk.privkey == sk2.privkey + + +def test_VerifyingKey_inequality_with_different_curves(): + sk1 = SigningKey.from_secret_exponent(2, BRAINPOOLP160r1) + sk2 = SigningKey.from_secret_exponent(2, NIST256p) + + assert not (sk1.verifying_key == sk2.verifying_key) + + +def test_VerifyingKey_inequality_with_different_secret_points(): + sk1 = SigningKey.from_secret_exponent(2, BRAINPOOLP160r1) + sk2 = SigningKey.from_secret_exponent(3, BRAINPOOLP160r1) + + assert not (sk1.verifying_key == sk2.verifying_key) + + +def test_SigningKey_from_pem_pkcs8v2_EdDSA(): + pem = """-----BEGIN PRIVATE KEY----- + MFMCAQEwBQYDK2VwBCIEICc2F2ag1n1QP0jY+g9qWx5sDkx0s/HdNi3cSRHw+zsI + oSMDIQA+HQ2xCif8a/LMWR2m5HaCm5I2pKe/cc8OiRANMHxjKQ== + -----END PRIVATE KEY-----""" + + sk = SigningKey.from_pem(pem) + assert sk.curve == Ed25519 diff --git a/frozen_deps/ecdsa/test_malformed_sigs.py b/frozen_deps/ecdsa/test_malformed_sigs.py index 4895cea..e5a87c2 100644 --- a/frozen_deps/ecdsa/test_malformed_sigs.py +++ b/frozen_deps/ecdsa/test_malformed_sigs.py @@ -13,10 +13,17 @@ except ImportError: # pragma: no cover "sha384", "sha512", ] +# skip algorithms broken by change to OpenSSL 3.0 and early versions +# of hashlib that list algorithms that require the legacy provider to work +# https://bugs.python.org/issue38820 +algorithms_available = [ + i + for i in algorithms_available + if i not in ("mdc2", "md2", "md4", "whirlpool", "ripemd160") +] from functools import partial import pytest import sys -from six import binary_type import hypothesis.strategies as st from hypothesis import note, assume, given, settings, example @@ -24,7 +31,7 @@ from .keys import SigningKey from .keys import BadSignatureError from .util import sigencode_der, sigencode_string from .util import sigdecode_der, sigdecode_string -from .curves import curves, NIST256p +from .curves import curves, SECP112r2, SECP128r1 from .der import ( encode_integer, encode_bitstring, @@ -33,6 +40,7 @@ from .der import ( encode_sequence, encode_constructed, ) +from .ellipticcurve import CurveEdTw example_data = b"some data to sign" @@ -47,6 +55,10 @@ Needed for pairing with curves as we don't support hashes bigger than order sizes of curves.""" +if "--fast" in sys.argv: # pragma: no cover + curves = [SECP112r2, SECP128r1] + + keys_and_sigs = [] """Name of the curve+hash combination, VerifyingKey and DER signature.""" @@ -83,7 +95,7 @@ def test_signatures(verifying_key, signature): @st.composite -def st_fuzzed_sig(draw, keys_and_sigs): +def st_fuzzed_sig(draw, keys_and_sigs): # pragma: no cover """ Hypothesis strategy that generates pairs of VerifyingKey and malformed signatures created by fuzzing of a valid signature. @@ -103,6 +115,7 @@ def st_fuzzed_sig(draw, keys_and_sigs): note("Remove bytes: {0}".format(to_remove)) # decide which bytes of the original signature should be changed + xors = None if sig: # pragma: no branch xors = draw( st.dictionaries( @@ -145,12 +158,17 @@ if sys.version_info >= (2, 7): # pragma: no branch HealthCheck.filter_too_much, HealthCheck.too_slow, ] +if "--fast" in sys.argv: # pragma: no cover + params["max_examples"] = 20 slow_params = dict(params) -slow_params["max_examples"] = 10 +if "--fast" in sys.argv: # pragma: no cover + slow_params["max_examples"] = 1 +else: + slow_params["max_examples"] = 10 -@settings(**params) +@settings(**slow_params) @given(st_fuzzed_sig(keys_and_sigs)) def test_fuzzed_der_signatures(args): verifying_key, sig = args @@ -160,7 +178,7 @@ def test_fuzzed_der_signatures(args): @st.composite -def st_random_der_ecdsa_sig_value(draw): +def st_random_der_ecdsa_sig_value(draw): # pragma: no cover """ Hypothesis strategy for selecting random values and encoding them to ECDSA-Sig-Value object:: @@ -174,7 +192,7 @@ def st_random_der_ecdsa_sig_value(draw): note("Configuration: {0}".format(name)) order = int(verifying_key.curve.order) - # the encode_integer doesn't suport negative numbers, would be nice + # the encode_integer doesn't support negative numbers, would be nice # to generate them too, but we have coverage for remove_integer() # verifying that it doesn't accept them, so meh. # Test all numbers around the ones that can show up (around order) @@ -206,7 +224,7 @@ def test_random_der_ecdsa_sig_value(params): verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) -def st_der_integer(*args, **kwargs): +def st_der_integer(*args, **kwargs): # pragma: no cover """ Hypothesis strategy that returns a random positive integer as DER INTEGER. @@ -218,7 +236,7 @@ def st_der_integer(*args, **kwargs): @st.composite -def st_der_bit_string(draw, *args, **kwargs): +def st_der_bit_string(draw, *args, **kwargs): # pragma: no cover """ Hypothesis strategy that returns a random DER BIT STRING. Parameters are passed to hypothesis.strategy.binary. @@ -227,14 +245,14 @@ def st_der_bit_string(draw, *args, **kwargs): if data: unused = draw(st.integers(min_value=0, max_value=7)) data = bytearray(data) - data[-1] &= -(2 ** unused) + data[-1] &= -(2**unused) data = bytes(data) else: unused = 0 return encode_bitstring(data, unused) -def st_der_octet_string(*args, **kwargs): +def st_der_octet_string(*args, **kwargs): # pragma: no cover """ Hypothesis strategy that returns a random DER OCTET STRING object. Parameters are passed to hypothesis.strategy.binary @@ -242,7 +260,7 @@ def st_der_octet_string(*args, **kwargs): return st.builds(encode_octet_string, st.binary(*args, **kwargs)) -def st_der_null(): +def st_der_null(): # pragma: no cover """ Hypothesis strategy that returns DER NULL object. """ @@ -250,7 +268,7 @@ def st_der_null(): @st.composite -def st_der_oid(draw): +def st_der_oid(draw): # pragma: no cover """ Hypothesis strategy that returns DER OBJECT IDENTIFIER objects. """ @@ -258,14 +276,14 @@ def st_der_oid(draw): if first < 2: second = draw(st.integers(min_value=0, max_value=39)) else: - second = draw(st.integers(min_value=0, max_value=2 ** 512)) + second = draw(st.integers(min_value=0, max_value=2**512)) rest = draw( - st.lists(st.integers(min_value=0, max_value=2 ** 512), max_size=50) + st.lists(st.integers(min_value=0, max_value=2**512), max_size=50) ) return encode_oid(first, second, *rest) -def st_der(): +def st_der(): # pragma: no cover """ Hypothesis strategy that returns random DER structures. @@ -273,22 +291,20 @@ def st_der(): of a valid DER structure, sequence of valid DER objects or a constructed encoding of any of the above. """ - return st.recursive( + return st.recursive( # pragma: no branch st.just(b"") - | st_der_integer(max_value=2 ** 4096) - | st_der_bit_string(max_size=1024 ** 2) - | st_der_octet_string(max_size=1024 ** 2) + | st_der_integer(max_value=2**4096) + | st_der_bit_string(max_size=1024**2) + | st_der_octet_string(max_size=1024**2) | st_der_null() | st_der_oid(), - lambda children: st.builds( - lambda x: encode_octet_string(x), st.one_of(children) - ) + lambda children: st.builds(encode_octet_string, st.one_of(children)) | st.builds(lambda x: encode_bitstring(x, 0), st.one_of(children)) | st.builds( lambda x: encode_sequence(*x), st.lists(children, max_size=200) ) | st.builds( - lambda tag, x: encode_constructed(tag, x), + encode_constructed, st.integers(min_value=0, max_value=0x3F), st.one_of(children), ), @@ -296,7 +312,7 @@ def st_der(): ) -@settings(**params) +@settings(**slow_params) @given(st.sampled_from(keys_and_sigs), st_der()) def test_random_der_as_signature(params, der): """Check if random DER structures are rejected as signature""" @@ -306,8 +322,8 @@ def test_random_der_as_signature(params, der): verifying_key.verify(der, example_data, sigdecode=sigdecode_der) -@settings(**params) -@given(st.sampled_from(keys_and_sigs), st.binary(max_size=1024 ** 2)) +@settings(**slow_params) +@given(st.sampled_from(keys_and_sigs), st.binary(max_size=1024**2)) @example( keys_and_sigs[0], encode_sequence(encode_integer(0), encode_integer(0)) ) @@ -334,6 +350,7 @@ keys_and_string_sigs = [ ), ) for name, verifying_key, sig in keys_and_sigs + if not isinstance(verifying_key.curve.curve, CurveEdTw) ] """ Name of the curve+hash combination, VerifyingKey and signature as a @@ -341,7 +358,18 @@ byte string. """ -@settings(**params) +keys_and_string_sigs += [ + ( + name, + verifying_key, + sig, + ) + for name, verifying_key, sig in keys_and_sigs + if isinstance(verifying_key.curve.curve, CurveEdTw) +] + + +@settings(**slow_params) @given(st_fuzzed_sig(keys_and_string_sigs)) def test_fuzzed_string_signatures(params): verifying_key, sig = params diff --git a/frozen_deps/ecdsa/test_numbertheory.py b/frozen_deps/ecdsa/test_numbertheory.py index 4912c57..966eca2 100644 --- a/frozen_deps/ecdsa/test_numbertheory.py +++ b/frozen_deps/ecdsa/test_numbertheory.py @@ -1,7 +1,6 @@ import operator -from six import print_ from functools import reduce -import operator +import sys try: import unittest2 as unittest @@ -19,6 +18,7 @@ except ImportError: # pragma: no cover HC_PRESENT = False from .numbertheory import ( SquareRootError, + JacobiError, factorization, gcd, lcm, @@ -30,6 +30,16 @@ from .numbertheory import ( square_root_mod_prime, ) +try: + from gmpy2 import mpz +except ImportError: + try: + from gmpy import mpz + except ImportError: + + def mpz(x): + return x + BIGPRIMES = ( 999671, @@ -67,6 +77,7 @@ def test_next_prime_with_nums_less_2(val): assert next_prime(val) == 2 +@pytest.mark.slow @pytest.mark.parametrize("prime", smallprimes) def test_square_root_mod_prime_for_small_primes(prime): squares = set() @@ -84,11 +95,61 @@ def test_square_root_mod_prime_for_small_primes(prime): square_root_mod_prime(nonsquare, prime) +def test_square_root_mod_prime_for_2(): + a = square_root_mod_prime(1, 2) + assert a == 1 + + +def test_square_root_mod_prime_for_small_prime(): + root = square_root_mod_prime(98**2 % 101, 101) + assert root * root % 101 == 9 + + +def test_square_root_mod_prime_for_p_congruent_5(): + p = 13 + assert p % 8 == 5 + + root = square_root_mod_prime(3, p) + assert root * root % p == 3 + + +def test_square_root_mod_prime_for_p_congruent_5_large_d(): + p = 29 + assert p % 8 == 5 + + root = square_root_mod_prime(4, p) + assert root * root % p == 4 + + +class TestSquareRootModPrime(unittest.TestCase): + def test_power_of_2_p(self): + with self.assertRaises(JacobiError): + square_root_mod_prime(12, 32) + + def test_no_square(self): + with self.assertRaises(SquareRootError) as e: + square_root_mod_prime(12, 31) + + self.assertIn("no square root", str(e.exception)) + + def test_non_prime(self): + with self.assertRaises(SquareRootError) as e: + square_root_mod_prime(12, 33) + + self.assertIn("p is not prime", str(e.exception)) + + def test_non_prime_with_negative(self): + with self.assertRaises(SquareRootError) as e: + square_root_mod_prime(697 - 1, 697) + + self.assertIn("p is not prime", str(e.exception)) + + @st.composite def st_two_nums_rel_prime(draw): # 521-bit is the biggest curve we operate on, use 1024 for a bit # of breathing space - mod = draw(st.integers(min_value=2, max_value=2 ** 1024)) + mod = draw(st.integers(min_value=2, max_value=2**1024)) num = draw( st.integers(min_value=1, max_value=mod - 1).filter( lambda x: gcd(x, mod) == 1 @@ -110,7 +171,7 @@ def st_primes(draw, *args, **kwargs): @st.composite def st_num_square_prime(draw): - prime = draw(st_primes(max_value=2 ** 1024)) + prime = draw(st_primes(max_value=2**1024)) num = draw(st.integers(min_value=0, max_value=1 + prime // 2)) sq = num * num % prime return sq, prime @@ -122,7 +183,7 @@ def st_comp_with_com_fac(draw): Strategy that returns lists of numbers, all having a common factor. """ primes = draw( - st.lists(st_primes(max_value=2 ** 512), min_size=1, max_size=10) + st.lists(st_primes(max_value=2**512), min_size=1, max_size=10) ) # select random prime(s) that will make the common factor of composites com_fac_primes = draw( @@ -133,7 +194,7 @@ def st_comp_with_com_fac(draw): # select at most 20 lists (returned numbers), # each having at most 30 primes (factors) including none (then the number # will be 1) - comp_primes = draw( + comp_primes = draw( # pragma: no branch st.integers(min_value=1, max_value=20).flatmap( lambda n: st.lists( st.lists(st.sampled_from(primes), max_size=30), @@ -153,7 +214,7 @@ def st_comp_no_com_fac(draw): """ primes = draw( st.lists( - st_primes(max_value=2 ** 512), min_size=2, max_size=10, unique=True + st_primes(max_value=2**512), min_size=2, max_size=10, unique=True ) ) # first select the primes that will create the uncommon factor @@ -176,7 +237,7 @@ def st_comp_no_com_fac(draw): # select at most 20 lists, each having at most 30 primes # selected from the leftover_primes list - number_primes = draw( + number_primes = draw( # pragma: no branch st.integers(min_value=1, max_value=20).flatmap( lambda n: st.lists( st.lists(st.sampled_from(leftover_primes), max_size=30), @@ -202,9 +263,70 @@ if HC_PRESENT: # pragma: no branch # the factorization() sometimes takes a long time to finish HYP_SETTINGS["deadline"] = 5000 +if "--fast" in sys.argv: # pragma: no cover + HYP_SETTINGS["max_examples"] = 20 + HYP_SLOW_SETTINGS = dict(HYP_SETTINGS) -HYP_SLOW_SETTINGS["max_examples"] = 10 +if "--fast" in sys.argv: # pragma: no cover + HYP_SLOW_SETTINGS["max_examples"] = 1 +else: + HYP_SLOW_SETTINGS["max_examples"] = 20 + + +class TestIsPrime(unittest.TestCase): + def test_very_small_prime(self): + assert is_prime(23) + + def test_very_small_composite(self): + assert not is_prime(22) + + def test_small_prime(self): + assert is_prime(123456791) + + def test_special_composite(self): + assert not is_prime(10261) + + def test_medium_prime_1(self): + # nextPrime[2^256] + assert is_prime(2**256 + 0x129) + + def test_medium_prime_2(self): + # nextPrime(2^256+0x129) + assert is_prime(2**256 + 0x12D) + + def test_medium_trivial_composite(self): + assert not is_prime(2**256 + 0x130) + + def test_medium_non_trivial_composite(self): + assert not is_prime(2**256 + 0x12F) + + def test_large_prime(self): + # nextPrime[2^2048] + assert is_prime(mpz(2) ** 2048 + 0x3D5) + + def test_pseudoprime_base_19(self): + assert not is_prime(1543267864443420616877677640751301) + + def test_pseudoprime_base_300(self): + # F. Arnault "Constructing Carmichael Numbers Which Are Strong + # Pseudoprimes to Several Bases". Journal of Symbolic + # Computation. 20 (2): 151-161. doi:10.1006/jsco.1995.1042. + # Section 4.4 Large Example (a pseudoprime to all bases up to + # 300) + p = int( + "29 674 495 668 685 510 550 154 174 642 905 332 730 " + "771 991 799 853 043 350 995 075 531 276 838 753 171 " + "770 199 594 238 596 428 121 188 033 664 754 218 345 " + "562 493 168 782 883".replace(" ", "") + ) + + assert is_prime(p) + for _ in range(10): + if not is_prime(p * (313 * (p - 1) + 1) * (353 * (p - 1) + 1)): + break + else: + assert False, "composite not detected" class TestNumbertheory(unittest.TestCase): @@ -220,6 +342,7 @@ class TestNumbertheory(unittest.TestCase): "case times-out on it", ) @settings(**HYP_SLOW_SETTINGS) + @example([877 * 1151, 877 * 1009]) @given(st_comp_with_com_fac()) def test_gcd_with_com_factor(self, numbers): n = gcd(numbers) @@ -234,14 +357,16 @@ class TestNumbertheory(unittest.TestCase): "case times-out on it", ) @settings(**HYP_SLOW_SETTINGS) + @example([1151, 1069, 1009]) @given(st_comp_no_com_fac()) def test_gcd_with_uncom_factor(self, numbers): n = gcd(numbers) assert n == 1 + @settings(**HYP_SLOW_SETTINGS) @given( st.lists( - st.integers(min_value=1, max_value=2 ** 8192), + st.integers(min_value=1, max_value=2**8192), min_size=1, max_size=20, ) @@ -257,9 +382,10 @@ class TestNumbertheory(unittest.TestCase): assert lcm([3, 5 * 3, 7 * 3]) == 3 * 5 * 7 assert lcm(3) == 3 + @settings(**HYP_SLOW_SETTINGS) @given( st.lists( - st.integers(min_value=1, max_value=2 ** 8192), + st.integers(min_value=1, max_value=2**8192), min_size=1, max_size=20, ) @@ -275,7 +401,7 @@ class TestNumbertheory(unittest.TestCase): "meet requirements (like `is_prime()`), the test " "case times-out on it", ) - @settings(**HYP_SETTINGS) + @settings(**HYP_SLOW_SETTINGS) @given(st_num_square_prime()) def test_square_root_mod_prime(self, vals): square, prime = vals @@ -283,10 +409,11 @@ class TestNumbertheory(unittest.TestCase): calc = square_root_mod_prime(square, prime) assert calc * calc % prime == square - @settings(**HYP_SETTINGS) - @given(st.integers(min_value=1, max_value=10 ** 12)) + @pytest.mark.slow + @settings(**HYP_SLOW_SETTINGS) + @given(st.integers(min_value=1, max_value=10**12)) @example(265399 * 1526929) - @example(373297 ** 2 * 553991) + @example(373297**2 * 553991) def test_factorization(self, num): factors = factorization(num) mult = 1 @@ -294,16 +421,45 @@ class TestNumbertheory(unittest.TestCase): mult *= i[0] ** i[1] assert mult == num - @settings(**HYP_SETTINGS) + def test_factorisation_smallprimes(self): + exp = 101 * 103 + assert 101 in smallprimes + assert 103 in smallprimes + factors = factorization(exp) + mult = 1 + for i in factors: + mult *= i[0] ** i[1] + assert mult == exp + + def test_factorisation_not_smallprimes(self): + exp = 1231 * 1237 + assert 1231 not in smallprimes + assert 1237 not in smallprimes + factors = factorization(exp) + mult = 1 + for i in factors: + mult *= i[0] ** i[1] + assert mult == exp + + def test_jacobi_with_zero(self): + assert jacobi(0, 3) == 0 + + def test_jacobi_with_one(self): + assert jacobi(1, 3) == 1 + + @settings(**HYP_SLOW_SETTINGS) @given(st.integers(min_value=3, max_value=1000).filter(lambda x: x % 2)) def test_jacobi(self, mod): + mod = mpz(mod) if is_prime(mod): squares = set() for root in range(1, mod): + root = mpz(root) assert jacobi(root * root, mod) == 1 squares.add(root * root % mod) for i in range(1, mod): if i not in squares: + i = mpz(i) assert jacobi(i, mod) == -1 else: factors = factorization(mod) @@ -313,6 +469,7 @@ class TestNumbertheory(unittest.TestCase): c *= jacobi(a, i[0]) ** i[1] assert c == jacobi(a, mod) + @settings(**HYP_SLOW_SETTINGS) @given(st_two_nums_rel_prime()) def test_inverse_mod(self, nums): num, mod = nums diff --git a/frozen_deps/ecdsa/test_pyecdsa.py b/frozen_deps/ecdsa/test_pyecdsa.py index 65b6716..20201ba 100644 --- a/frozen_deps/ecdsa/test_pyecdsa.py +++ b/frozen_deps/ecdsa/test_pyecdsa.py @@ -5,27 +5,36 @@ try: except ImportError: import unittest import os -import time import shutil import subprocess import pytest +import sys from binascii import hexlify, unhexlify -from hashlib import sha1, sha256, sha384, sha512 import hashlib from functools import partial -from hypothesis import given +from hypothesis import given, settings import hypothesis.strategies as st from six import b, print_, binary_type from .keys import SigningKey, VerifyingKey from .keys import BadSignatureError, MalformedPointError, BadDigestError from . import util -from .util import sigencode_der, sigencode_strings -from .util import sigdecode_der, sigdecode_strings +from .util import ( + sigencode_der, + sigencode_strings, + sigencode_strings_canonize, + sigencode_string_canonize, + sigencode_der_canonize, +) +from .util import sigdecode_der, sigdecode_strings, sigdecode_string from .util import number_to_string, encoded_oid_ecPublicKey, MalformedSignature from .curves import Curve, UnknownCurveError from .curves import ( + SECP112r1, + SECP112r2, + SECP128r1, + SECP160r1, NIST192p, NIST224p, NIST256p, @@ -39,6 +48,15 @@ from .curves import ( BRAINPOOLP320r1, BRAINPOOLP384r1, BRAINPOOLP512r1, + BRAINPOOLP160t1, + BRAINPOOLP192t1, + BRAINPOOLP224t1, + BRAINPOOLP256t1, + BRAINPOOLP320t1, + BRAINPOOLP384t1, + BRAINPOOLP512t1, + Ed25519, + Ed448, curves, ) from .ecdsa import ( @@ -57,6 +75,13 @@ class SubprocessError(Exception): pass +HYP_SETTINGS = {} + + +if "--fast" in sys.argv: # pragma: no cover + HYP_SETTINGS["max_examples"] = 2 + + def run_openssl(cmd): OPENSSL = "openssl" p = subprocess.Popen( @@ -78,24 +103,29 @@ class ECDSA(unittest.TestCase): priv = SigningKey.generate() pub = priv.get_verifying_key() - data = b("blahblah") + data = b"blahblah" sig = priv.sign(data) self.assertTrue(pub.verify(sig, data)) - self.assertRaises(BadSignatureError, pub.verify, sig, data + b("bad")) + self.assertRaises(BadSignatureError, pub.verify, sig, data + b"bad") pub2 = VerifyingKey.from_string(pub.to_string()) self.assertTrue(pub2.verify(sig, data)) def test_deterministic(self): - data = b("blahblah") + data = b"blahblah" secexp = int("9d0219792467d7d37b4d43298a7d0c05", 16) - priv = SigningKey.from_secret_exponent(secexp, SECP256k1, sha256) + priv = SigningKey.from_secret_exponent( + secexp, SECP256k1, hashlib.sha256 + ) pub = priv.get_verifying_key() k = rfc6979.generate_k( - SECP256k1.generator.order(), secexp, sha256, sha256(data).digest() + SECP256k1.generator.order(), + secexp, + hashlib.sha256, + hashlib.sha256(data).digest(), ) sig1 = priv.sign(data, k=k) @@ -104,7 +134,7 @@ class ECDSA(unittest.TestCase): sig2 = priv.sign(data, k=k) self.assertTrue(pub.verify(sig2, data)) - sig3 = priv.sign_deterministic(data, sha256) + sig3 = priv.sign_deterministic(data, hashlib.sha256) self.assertTrue(pub.verify(sig3, data)) self.assertEqual(sig1, sig2) @@ -115,41 +145,16 @@ class ECDSA(unittest.TestCase): self.assertRaises(TypeError, SigningKey) self.assertRaises(TypeError, VerifyingKey) - def test_lengths(self): + def test_lengths_default(self): default = NIST192p priv = SigningKey.generate() pub = priv.get_verifying_key() self.assertEqual(len(pub.to_string()), default.verifying_key_length) - sig = priv.sign(b("data")) + sig = priv.sign(b"data") self.assertEqual(len(sig), default.signature_length) - for curve in ( - NIST192p, - NIST224p, - NIST256p, - NIST384p, - NIST521p, - BRAINPOOLP160r1, - BRAINPOOLP192r1, - BRAINPOOLP224r1, - BRAINPOOLP256r1, - BRAINPOOLP320r1, - BRAINPOOLP384r1, - BRAINPOOLP512r1, - ): - start = time.time() - priv = SigningKey.generate(curve=curve) - pub1 = priv.get_verifying_key() - keygen_time = time.time() - start - pub2 = VerifyingKey.from_string(pub1.to_string(), curve) - self.assertEqual(pub1.to_string(), pub2.to_string()) - self.assertEqual(len(pub1.to_string()), curve.verifying_key_length) - start = time.time() - sig = priv.sign(b("data")) - sign_time = time.time() - start - self.assertEqual(len(sig), curve.signature_length) def test_serialize(self): - seed = b("secret") + seed = b"secret" curve = NIST192p secexp1 = util.randrange_from_seed__trytryagain(seed, curve.order) secexp2 = util.randrange_from_seed__trytryagain(seed, curve.order) @@ -162,7 +167,7 @@ class ECDSA(unittest.TestCase): self.assertEqual(priv1.to_pem(), priv2.to_pem()) pub1 = priv1.get_verifying_key() pub2 = priv2.get_verifying_key() - data = b("data") + data = b"data" sig1 = priv1.sign(data) sig2 = priv2.sign(data) self.assertTrue(pub1.verify(sig1, data)) @@ -172,7 +177,7 @@ class ECDSA(unittest.TestCase): self.assertEqual(hexlify(pub1.to_string()), hexlify(pub2.to_string())) def test_nonrandom(self): - s = b("all the entropy in the entire world, compressed into one line") + s = b"all the entropy in the entire world, compressed into one line" def not_much_entropy(numbytes): return s[:numbytes] @@ -188,8 +193,8 @@ class ECDSA(unittest.TestCase): # want to do this with keys you care about, because the secrecy of # the private key depends upon using different random numbers for # each signature - sig1 = priv1.sign(b("data"), entropy=not_much_entropy) - sig2 = priv2.sign(b("data"), entropy=not_much_entropy) + sig1 = priv1.sign(b"data", entropy=not_much_entropy) + sig2 = priv2.sign(b"data", entropy=not_much_entropy) self.assertEqual(hexlify(sig1), hexlify(sig2)) def assertTruePrivkeysEqual(self, priv1, priv2): @@ -202,7 +207,7 @@ class ECDSA(unittest.TestCase): ) def test_privkey_creation(self): - s = b("all the entropy in the entire world, compressed into one line") + s = b"all the entropy in the entire world, compressed into one line" def not_much_entropy(numbytes): return s[:numbytes] @@ -237,8 +242,8 @@ class ECDSA(unittest.TestCase): s1 = priv1.to_pem() self.assertEqual(type(s1), binary_type) - self.assertTrue(s1.startswith(b("-----BEGIN EC PRIVATE KEY-----"))) - self.assertTrue(s1.strip().endswith(b("-----END EC PRIVATE KEY-----"))) + self.assertTrue(s1.startswith(b"-----BEGIN EC PRIVATE KEY-----")) + self.assertTrue(s1.strip().endswith(b"-----END EC PRIVATE KEY-----")) priv2 = SigningKey.from_pem(s1) self.assertTruePrivkeysEqual(priv1, priv2) @@ -250,8 +255,8 @@ class ECDSA(unittest.TestCase): priv1 = SigningKey.generate(curve=NIST256p) s1 = priv1.to_pem() self.assertEqual(type(s1), binary_type) - self.assertTrue(s1.startswith(b("-----BEGIN EC PRIVATE KEY-----"))) - self.assertTrue(s1.strip().endswith(b("-----END EC PRIVATE KEY-----"))) + self.assertTrue(s1.startswith(b"-----BEGIN EC PRIVATE KEY-----")) + self.assertTrue(s1.strip().endswith(b"-----END EC PRIVATE KEY-----")) priv2 = SigningKey.from_pem(s1) self.assertTruePrivkeysEqual(priv1, priv2) @@ -264,8 +269,8 @@ class ECDSA(unittest.TestCase): priv1 = SigningKey.generate(curve=BRAINPOOLP512r1) s1 = priv1.to_pem() self.assertEqual(type(s1), binary_type) - self.assertTrue(s1.startswith(b("-----BEGIN EC PRIVATE KEY-----"))) - self.assertTrue(s1.strip().endswith(b("-----END EC PRIVATE KEY-----"))) + self.assertTrue(s1.startswith(b"-----BEGIN EC PRIVATE KEY-----")) + self.assertTrue(s1.strip().endswith(b"-----END EC PRIVATE KEY-----")) priv2 = SigningKey.from_pem(s1) self.assertTruePrivkeysEqual(priv1, priv2) @@ -302,7 +307,7 @@ class ECDSA(unittest.TestCase): self.assertTruePubkeysEqual(pub1, pub2) self.assertRaises( - der.UnexpectedDER, VerifyingKey.from_der, pub1_der + b("junk") + der.UnexpectedDER, VerifyingKey.from_der, pub1_der + b"junk" ) badpub = VerifyingKey.from_der(pub1_der) @@ -310,8 +315,15 @@ class ECDSA(unittest.TestCase): def order(self): return 123456789 + class FakeCurveFp: + def p(self): + return int( + "6525534529039240705020950546962731340" + "4541085228058844382513856749047873406763" + ) + badcurve = Curve( - "unknown", None, FakeGenerator(), (1, 2, 3, 4, 5, 6), None + "unknown", FakeCurveFp(), FakeGenerator(), (1, 2, 3, 4, 5, 6), None ) badpub.curve = badcurve badder = badpub.to_der() @@ -319,10 +331,8 @@ class ECDSA(unittest.TestCase): pem = pub1.to_pem() self.assertEqual(type(pem), binary_type) - self.assertTrue(pem.startswith(b("-----BEGIN PUBLIC KEY-----")), pem) - self.assertTrue( - pem.strip().endswith(b("-----END PUBLIC KEY-----")), pem - ) + self.assertTrue(pem.startswith(b"-----BEGIN PUBLIC KEY-----"), pem) + self.assertTrue(pem.strip().endswith(b"-----END PUBLIC KEY-----"), pem) pub2 = VerifyingKey.from_pem(pem) self.assertTruePubkeysEqual(pub1, pub2) @@ -379,7 +389,7 @@ class ECDSA(unittest.TestCase): type_oid_der = encoded_oid_ecPublicKey curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) enc_type_der = der.encode_sequence(type_oid_der, curve_oid_der) - point_der = der.encode_bitstring(b"\x00\xff", None) + b("garbage") + point_der = der.encode_bitstring(b"\x00\xff", None) + b"garbage" to_decode = der.encode_sequence(enc_type_der, point_der) with self.assertRaises(der.UnexpectedDER): @@ -418,7 +428,7 @@ class ECDSA(unittest.TestCase): def test_signature_strings(self): priv1 = SigningKey.generate() pub1 = priv1.get_verifying_key() - data = b("data") + data = b"data" sig = priv1.sign(data) self.assertEqual(type(sig), binary_type) @@ -438,24 +448,96 @@ class ECDSA(unittest.TestCase): self.assertEqual(type(sig_der), binary_type) self.assertTrue(pub1.verify(sig_der, data, sigdecode=sigdecode_der)) + def test_sigencode_string_canonize_no_change(self): + r = 12 + s = 400 + order = SECP112r1.order + + new_r, new_s = sigdecode_string( + sigencode_string_canonize(r, s, order), order + ) + + self.assertEqual(r, new_r) + self.assertEqual(s, new_s) + + def test_sigencode_string_canonize(self): + r = 12 + order = SECP112r1.order + s = order - 10 + + new_r, new_s = sigdecode_string( + sigencode_string_canonize(r, s, order), order + ) + + self.assertEqual(r, new_r) + self.assertEqual(order - s, new_s) + + def test_sigencode_strings_canonize_no_change(self): + r = 12 + s = 400 + order = SECP112r1.order + + new_r, new_s = sigdecode_strings( + sigencode_strings_canonize(r, s, order), order + ) + + self.assertEqual(r, new_r) + self.assertEqual(s, new_s) + + def test_sigencode_strings_canonize(self): + r = 12 + order = SECP112r1.order + s = order - 10 + + new_r, new_s = sigdecode_strings( + sigencode_strings_canonize(r, s, order), order + ) + + self.assertEqual(r, new_r) + self.assertEqual(order - s, new_s) + + def test_sigencode_der_canonize_no_change(self): + r = 13 + s = 200 + order = SECP112r1.order + + new_r, new_s = sigdecode_der( + sigencode_der_canonize(r, s, order), order + ) + + self.assertEqual(r, new_r) + self.assertEqual(s, new_s) + + def test_sigencode_der_canonize(self): + r = 13 + order = SECP112r1.order + s = order - 14 + + new_r, new_s = sigdecode_der( + sigencode_der_canonize(r, s, order), order + ) + + self.assertEqual(r, new_r) + self.assertEqual(order - s, new_s) + def test_sig_decode_strings_with_invalid_count(self): with self.assertRaises(MalformedSignature): - sigdecode_strings([b("one"), b("two"), b("three")], 0xFF) + sigdecode_strings([b"one", b"two", b"three"], 0xFF) def test_sig_decode_strings_with_wrong_r_len(self): with self.assertRaises(MalformedSignature): - sigdecode_strings([b("one"), b("two")], 0xFF) + sigdecode_strings([b"one", b"two"], 0xFF) def test_sig_decode_strings_with_wrong_s_len(self): with self.assertRaises(MalformedSignature): - sigdecode_strings([b("\xa0"), b("\xb0\xff")], 0xFF) + sigdecode_strings([b"\xa0", b"\xb0\xff"], 0xFF) def test_verify_with_too_long_input(self): sk = SigningKey.generate() vk = sk.verifying_key with self.assertRaises(BadDigestError): - vk.verify_digest(None, b("\x00") * 128) + vk.verify_digest(None, b"\x00" * 128) def test_sk_from_secret_exponent_with_wrong_sec_exponent(self): with self.assertRaises(MalformedPointError): @@ -463,11 +545,11 @@ class ECDSA(unittest.TestCase): def test_sk_from_string_with_wrong_len_string(self): with self.assertRaises(MalformedPointError): - SigningKey.from_string(b("\x01")) + SigningKey.from_string(b"\x01") def test_sk_from_der_with_junk_after_sequence(self): ver_der = der.encode_integer(1) - to_decode = der.encode_sequence(ver_der) + b("garbage") + to_decode = der.encode_sequence(ver_der) + b"garbage" with self.assertRaises(der.UnexpectedDER): SigningKey.from_der(to_decode) @@ -481,7 +563,7 @@ class ECDSA(unittest.TestCase): def test_sk_from_der_invalid_const_tag(self): ver_der = der.encode_integer(1) - privkey_der = der.encode_octet_string(b("\x00\xff")) + privkey_der = der.encode_octet_string(b"\x00\xff") curve_oid_der = der.encode_oid(*(1, 2, 3)) const_der = der.encode_constructed(1, curve_oid_der) to_decode = der.encode_sequence( @@ -493,8 +575,8 @@ class ECDSA(unittest.TestCase): def test_sk_from_der_garbage_after_privkey_oid(self): ver_der = der.encode_integer(1) - privkey_der = der.encode_octet_string(b("\x00\xff")) - curve_oid_der = der.encode_oid(*(1, 2, 3)) + b("garbage") + privkey_der = der.encode_octet_string(b"\x00\xff") + curve_oid_der = der.encode_oid(*(1, 2, 3)) + b"garbage" const_der = der.encode_constructed(0, curve_oid_der) to_decode = der.encode_sequence( ver_der, privkey_der, const_der, curve_oid_der @@ -505,7 +587,7 @@ class ECDSA(unittest.TestCase): def test_sk_from_der_with_short_privkey(self): ver_der = der.encode_integer(1) - privkey_der = der.encode_octet_string(b("\x00\xff")) + privkey_der = der.encode_octet_string(b"\x00\xff") curve_oid_der = der.encode_oid(*(1, 2, 840, 10045, 3, 1, 1)) const_der = der.encode_constructed(0, curve_oid_der) to_decode = der.encode_sequence( @@ -589,40 +671,42 @@ class ECDSA(unittest.TestCase): sk = SigningKey.from_secret_exponent(12) with self.assertRaises(BadDigestError): - sk.sign_digest(b("\xff") * 64) + sk.sign_digest(b"\xff" * 64) def test_hashfunc(self): - sk = SigningKey.generate(curve=NIST256p, hashfunc=sha256) - data = b("security level is 128 bits") + sk = SigningKey.generate(curve=NIST256p, hashfunc=hashlib.sha256) + data = b"security level is 128 bits" sig = sk.sign(data) vk = VerifyingKey.from_string( - sk.get_verifying_key().to_string(), curve=NIST256p, hashfunc=sha256 + sk.get_verifying_key().to_string(), + curve=NIST256p, + hashfunc=hashlib.sha256, ) self.assertTrue(vk.verify(sig, data)) sk2 = SigningKey.generate(curve=NIST256p) - sig2 = sk2.sign(data, hashfunc=sha256) + sig2 = sk2.sign(data, hashfunc=hashlib.sha256) vk2 = VerifyingKey.from_string( sk2.get_verifying_key().to_string(), curve=NIST256p, - hashfunc=sha256, + hashfunc=hashlib.sha256, ) self.assertTrue(vk2.verify(sig2, data)) vk3 = VerifyingKey.from_string( sk.get_verifying_key().to_string(), curve=NIST256p ) - self.assertTrue(vk3.verify(sig, data, hashfunc=sha256)) + self.assertTrue(vk3.verify(sig, data, hashfunc=hashlib.sha256)) def test_public_key_recovery(self): # Create keys - curve = NIST256p + curve = BRAINPOOLP160r1 sk = SigningKey.generate(curve=curve) vk = sk.get_verifying_key() # Sign a message - data = b("blahblah") + data = b"blahblah" signature = sk.sign(data) # Recover verifying keys @@ -642,25 +726,29 @@ class ECDSA(unittest.TestCase): ) # Test if original vk is the list of recovered keys - self.assertTrue( - vk.pubkey.point - in [recovered_vk.pubkey.point for recovered_vk in recovered_vks] + self.assertIn( + vk.pubkey.point, + [recovered_vk.pubkey.point for recovered_vk in recovered_vks], ) def test_public_key_recovery_with_custom_hash(self): # Create keys - curve = NIST256p + curve = BRAINPOOLP160r1 - sk = SigningKey.generate(curve=curve, hashfunc=sha256) + sk = SigningKey.generate(curve=curve, hashfunc=hashlib.sha256) vk = sk.get_verifying_key() # Sign a message - data = b("blahblah") + data = b"blahblah" signature = sk.sign(data) # Recover verifying keys recovered_vks = VerifyingKey.from_public_key_recovery( - signature, data, curve, hashfunc=sha256 + signature, + data, + curve, + hashfunc=hashlib.sha256, + allow_truncate=True, ) # Test if each pk is valid @@ -670,12 +758,12 @@ class ECDSA(unittest.TestCase): # Test if properties are equal self.assertEqual(vk.curve, recovered_vk.curve) - self.assertEqual(sha256, recovered_vk.default_hashfunc) + self.assertEqual(hashlib.sha256, recovered_vk.default_hashfunc) # Test if original vk is the list of recovered keys - self.assertTrue( - vk.pubkey.point - in [recovered_vk.pubkey.point for recovered_vk in recovered_vks] + self.assertIn( + vk.pubkey.point, + [recovered_vk.pubkey.point for recovered_vk in recovered_vks], ) def test_encoding(self): @@ -689,9 +777,9 @@ class ECDSA(unittest.TestCase): ) self.assertEqual(vk.to_string(), exp) self.assertEqual(vk.to_string("raw"), exp) - self.assertEqual(vk.to_string("uncompressed"), b("\x04") + exp) - self.assertEqual(vk.to_string("compressed"), b("\x02") + exp[:24]) - self.assertEqual(vk.to_string("hybrid"), b("\x06") + exp) + self.assertEqual(vk.to_string("uncompressed"), b"\x04" + exp) + self.assertEqual(vk.to_string("compressed"), b"\x02" + exp[:24]) + self.assertEqual(vk.to_string("hybrid"), b"\x06" + exp) def test_decoding(self): sk = SigningKey.from_secret_exponent(123456789) @@ -706,15 +794,80 @@ class ECDSA(unittest.TestCase): from_raw = VerifyingKey.from_string(enc) self.assertEqual(from_raw.pubkey.point, vk.pubkey.point) - from_uncompressed = VerifyingKey.from_string(b("\x04") + enc) + from_uncompressed = VerifyingKey.from_string(b"\x04" + enc) self.assertEqual(from_uncompressed.pubkey.point, vk.pubkey.point) - from_compressed = VerifyingKey.from_string(b("\x02") + enc[:24]) + from_compressed = VerifyingKey.from_string(b"\x02" + enc[:24]) self.assertEqual(from_compressed.pubkey.point, vk.pubkey.point) - from_uncompressed = VerifyingKey.from_string(b("\x06") + enc) + from_uncompressed = VerifyingKey.from_string(b"\x06" + enc) self.assertEqual(from_uncompressed.pubkey.point, vk.pubkey.point) + def test_uncompressed_decoding_as_only_alowed(self): + enc = b( + "\x04" + "\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" + "\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" + "z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" + ) + vk = VerifyingKey.from_string(enc, valid_encodings=("uncompressed",)) + sk = SigningKey.from_secret_exponent(123456789) + + self.assertEqual(vk, sk.verifying_key) + + def test_raw_decoding_with_blocked_format(self): + enc = b( + "\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" + "\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" + "z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" + ) + with self.assertRaises(MalformedPointError) as exp: + VerifyingKey.from_string(enc, valid_encodings=("hybrid",)) + + self.assertIn("hybrid", str(exp.exception)) + + def test_decoding_with_unknown_format(self): + with self.assertRaises(ValueError) as e: + VerifyingKey.from_string(b"", valid_encodings=("raw", "foobar")) + + self.assertIn("Only uncompressed, compressed", str(e.exception)) + + def test_uncompressed_decoding_with_blocked_format(self): + enc = b( + "\x04" + "\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" + "\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" + "z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" + ) + with self.assertRaises(MalformedPointError) as exp: + VerifyingKey.from_string(enc, valid_encodings=("hybrid",)) + + self.assertIn("Invalid X9.62 encoding", str(exp.exception)) + + def test_hybrid_decoding_with_blocked_format(self): + enc = b( + "\x06" + "\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" + "\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" + "z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" + ) + with self.assertRaises(MalformedPointError) as exp: + VerifyingKey.from_string(enc, valid_encodings=("uncompressed",)) + + self.assertIn("Invalid X9.62 encoding", str(exp.exception)) + + def test_compressed_decoding_with_blocked_format(self): + enc = b( + "\x02" + "\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" + "\xfd\xc8\xa0c\xff\xfb\x02\xb9\xc4\x84)\x1a\x0f\x8b\x87\xa4" + "z\x8a#\xb5\x97\xecO\xb6\xa0HQ\x89*" + )[:25] + with self.assertRaises(MalformedPointError) as exp: + VerifyingKey.from_string(enc, valid_encodings=("hybrid", "raw")) + + self.assertIn("(hybrid, raw)", str(exp.exception)) + def test_decoding_with_malformed_uncompressed(self): enc = b( "\x0c\xe0\x1d\xe0d\x1c\x8eS\x8a\xc0\x9eK\xa8x !\xd5\xc2\xc3" @@ -723,7 +876,7 @@ class ECDSA(unittest.TestCase): ) with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b("\x02") + enc) + VerifyingKey.from_string(b"\x02" + enc) def test_decoding_with_malformed_compressed(self): enc = b( @@ -733,7 +886,7 @@ class ECDSA(unittest.TestCase): ) with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b("\x01") + enc[:24]) + VerifyingKey.from_string(b"\x01" + enc[:24]) def test_decoding_with_inconsistent_hybrid(self): enc = b( @@ -743,7 +896,7 @@ class ECDSA(unittest.TestCase): ) with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b("\x07") + enc) + VerifyingKey.from_string(b"\x07" + enc) def test_decoding_with_point_not_on_curve(self): enc = b( @@ -753,18 +906,18 @@ class ECDSA(unittest.TestCase): ) with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(enc[:47] + b("\x00")) + VerifyingKey.from_string(enc[:47] + b"\x00") def test_decoding_with_point_at_infinity(self): # decoding it is unsupported, as it's not necessary to encode it with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b("\x00")) + VerifyingKey.from_string(b"\x00") def test_not_lying_on_curve(self): enc = number_to_string(NIST192p.curve.p(), NIST192p.curve.p() + 1) with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b("\x02") + enc) + VerifyingKey.from_string(b"\x02" + enc) def test_from_string_with_invalid_curve_too_short_ver_key_len(self): # both verifying_key_length and baselen are calculated internally @@ -775,7 +928,7 @@ class ECDSA(unittest.TestCase): curve.baselen = 32 with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b("\x00") * 16, curve) + VerifyingKey.from_string(b"\x00" * 16, curve) def test_from_string_with_invalid_curve_too_long_ver_key_len(self): # both verifying_key_length and baselen are calculated internally @@ -786,7 +939,7 @@ class ECDSA(unittest.TestCase): curve.baselen = 16 with self.assertRaises(MalformedPointError): - VerifyingKey.from_string(b("\x00") * 16, curve) + VerifyingKey.from_string(b"\x00" * 16, curve) @pytest.mark.parametrize( @@ -796,9 +949,9 @@ def test_VerifyingKey_decode_with_small_values(val, even): enc = number_to_string(val, NIST192p.order) if even: - enc = b("\x02") + enc + enc = b"\x02" + enc else: - enc = b("\x03") + enc + enc = b"\x03" + enc # small values can both be actual valid public keys and not, verify that # only expected exceptions are raised if they are not @@ -829,6 +982,24 @@ def test_VerifyingKey_encode_decode(curve, encoding): assert vk.pubkey.point == from_enc.pubkey.point +if "--fast" in sys.argv: # pragma: no cover + params = [NIST192p, BRAINPOOLP160r1] +else: + params = curves + + +@pytest.mark.parametrize("curve", params) +def test_lengths(curve): + priv = SigningKey.generate(curve=curve) + pub1 = priv.get_verifying_key() + pub2 = VerifyingKey.from_string(pub1.to_string(), curve) + assert pub1.to_string() == pub2.to_string() + assert len(pub1.to_string()) == curve.verifying_key_length + sig = priv.sign(b"data") + assert len(sig) == curve.signature_length + + +@pytest.mark.slow class OpenSSL(unittest.TestCase): # test interoperability with OpenSSL tools. Note that openssl's ECDSA # sign/verify arguments changed between 0.9.8 and 1.0.0: the early @@ -865,6 +1036,39 @@ class OpenSSL(unittest.TestCase): # vk: 3:OpenSSL->python 4:python->OpenSSL # sig: 5:OpenSSL->python 6:python->OpenSSL + @pytest.mark.slow + @pytest.mark.skipif( + "secp112r1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp112r1", + ) + def test_from_openssl_secp112r1(self): + return self.do_test_from_openssl(SECP112r1) + + @pytest.mark.slow + @pytest.mark.skipif( + "secp112r2" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp112r2", + ) + def test_from_openssl_secp112r2(self): + return self.do_test_from_openssl(SECP112r2) + + @pytest.mark.slow + @pytest.mark.skipif( + "secp128r1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp128r1", + ) + def test_from_openssl_secp128r1(self): + return self.do_test_from_openssl(SECP128r1) + + @pytest.mark.slow + @pytest.mark.skipif( + "secp160r1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp160r1", + ) + def test_from_openssl_secp160r1(self): + return self.do_test_from_openssl(SECP160r1) + + @pytest.mark.slow @pytest.mark.skipif( "prime192v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime192v1", @@ -872,6 +1076,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist192p(self): return self.do_test_from_openssl(NIST192p) + @pytest.mark.slow @pytest.mark.skipif( "prime192v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime192v1", @@ -879,6 +1084,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist192p_sha256(self): return self.do_test_from_openssl(NIST192p, "SHA256") + @pytest.mark.slow @pytest.mark.skipif( "secp224r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp224r1", @@ -886,6 +1092,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist224p(self): return self.do_test_from_openssl(NIST224p) + @pytest.mark.slow @pytest.mark.skipif( "prime256v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime256v1", @@ -893,6 +1100,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist256p(self): return self.do_test_from_openssl(NIST256p) + @pytest.mark.slow @pytest.mark.skipif( "prime256v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime256v1", @@ -900,6 +1108,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist256p_sha384(self): return self.do_test_from_openssl(NIST256p, "SHA384") + @pytest.mark.slow @pytest.mark.skipif( "prime256v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime256v1", @@ -907,6 +1116,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist256p_sha512(self): return self.do_test_from_openssl(NIST256p, "SHA512") + @pytest.mark.slow @pytest.mark.skipif( "secp384r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp384r1", @@ -914,6 +1124,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist384p(self): return self.do_test_from_openssl(NIST384p) + @pytest.mark.slow @pytest.mark.skipif( "secp521r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp521r1", @@ -921,6 +1132,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_nist521p(self): return self.do_test_from_openssl(NIST521p) + @pytest.mark.slow @pytest.mark.skipif( "secp256k1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp256k1", @@ -928,6 +1140,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_secp256k1(self): return self.do_test_from_openssl(SECP256k1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP160r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP160r1", @@ -935,6 +1148,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_brainpoolp160r1(self): return self.do_test_from_openssl(BRAINPOOLP160r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP192r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP192r1", @@ -942,6 +1156,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_brainpoolp192r1(self): return self.do_test_from_openssl(BRAINPOOLP192r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP224r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP224r1", @@ -949,6 +1164,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_brainpoolp224r1(self): return self.do_test_from_openssl(BRAINPOOLP224r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP256r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP256r1", @@ -956,6 +1172,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_brainpoolp256r1(self): return self.do_test_from_openssl(BRAINPOOLP256r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP320r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP320r1", @@ -963,6 +1180,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_brainpoolp320r1(self): return self.do_test_from_openssl(BRAINPOOLP320r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP384r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP384r1", @@ -970,6 +1188,7 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_brainpoolp384r1(self): return self.do_test_from_openssl(BRAINPOOLP384r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP512r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP512r1", @@ -977,6 +1196,62 @@ class OpenSSL(unittest.TestCase): def test_from_openssl_brainpoolp512r1(self): return self.do_test_from_openssl(BRAINPOOLP512r1) + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP160t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP160t1", + ) + def test_from_openssl_brainpoolp160t1(self): + return self.do_test_from_openssl(BRAINPOOLP160t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP192t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP192t1", + ) + def test_from_openssl_brainpoolp192t1(self): + return self.do_test_from_openssl(BRAINPOOLP192t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP224t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP224t1", + ) + def test_from_openssl_brainpoolp224t1(self): + return self.do_test_from_openssl(BRAINPOOLP224t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP256t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP256t1", + ) + def test_from_openssl_brainpoolp256t1(self): + return self.do_test_from_openssl(BRAINPOOLP256t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP320t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP320t1", + ) + def test_from_openssl_brainpoolp320t1(self): + return self.do_test_from_openssl(BRAINPOOLP320t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP384t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP384t1", + ) + def test_from_openssl_brainpoolp384t1(self): + return self.do_test_from_openssl(BRAINPOOLP384t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP512t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP512t1", + ) + def test_from_openssl_brainpoolp512t1(self): + return self.do_test_from_openssl(BRAINPOOLP512t1) + def do_test_from_openssl(self, curve, hash_name="SHA1"): curvename = curve.openssl_name assert curvename @@ -988,7 +1263,7 @@ class OpenSSL(unittest.TestCase): os.mkdir("t") run_openssl("ecparam -name %s -genkey -out t/privkey.pem" % curvename) run_openssl("ec -in t/privkey.pem -pubout -out t/pubkey.pem") - data = b("data") + data = b"data" with open("t/data.txt", "wb") as e: e.write(data) run_openssl( @@ -1029,6 +1304,39 @@ class OpenSSL(unittest.TestCase): sk_from_p8 = SigningKey.from_pem(privkey_p8_pem) self.assertEqual(sk, sk_from_p8) + @pytest.mark.slow + @pytest.mark.skipif( + "secp112r1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp112r1", + ) + def test_to_openssl_secp112r1(self): + self.do_test_to_openssl(SECP112r1) + + @pytest.mark.slow + @pytest.mark.skipif( + "secp112r2" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp112r2", + ) + def test_to_openssl_secp112r2(self): + self.do_test_to_openssl(SECP112r2) + + @pytest.mark.slow + @pytest.mark.skipif( + "secp128r1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp128r1", + ) + def test_to_openssl_secp128r1(self): + self.do_test_to_openssl(SECP128r1) + + @pytest.mark.slow + @pytest.mark.skipif( + "secp160r1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support secp160r1", + ) + def test_to_openssl_secp160r1(self): + self.do_test_to_openssl(SECP160r1) + + @pytest.mark.slow @pytest.mark.skipif( "prime192v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime192v1", @@ -1036,6 +1344,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist192p(self): self.do_test_to_openssl(NIST192p) + @pytest.mark.slow @pytest.mark.skipif( "prime192v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime192v1", @@ -1043,6 +1352,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist192p_sha256(self): self.do_test_to_openssl(NIST192p, "SHA256") + @pytest.mark.slow @pytest.mark.skipif( "secp224r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp224r1", @@ -1050,6 +1360,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist224p(self): self.do_test_to_openssl(NIST224p) + @pytest.mark.slow @pytest.mark.skipif( "prime256v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime256v1", @@ -1057,6 +1368,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist256p(self): self.do_test_to_openssl(NIST256p) + @pytest.mark.slow @pytest.mark.skipif( "prime256v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime256v1", @@ -1064,6 +1376,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist256p_sha384(self): self.do_test_to_openssl(NIST256p, "SHA384") + @pytest.mark.slow @pytest.mark.skipif( "prime256v1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support prime256v1", @@ -1071,6 +1384,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist256p_sha512(self): self.do_test_to_openssl(NIST256p, "SHA512") + @pytest.mark.slow @pytest.mark.skipif( "secp384r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp384r1", @@ -1078,6 +1392,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist384p(self): self.do_test_to_openssl(NIST384p) + @pytest.mark.slow @pytest.mark.skipif( "secp521r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp521r1", @@ -1085,6 +1400,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_nist521p(self): self.do_test_to_openssl(NIST521p) + @pytest.mark.slow @pytest.mark.skipif( "secp256k1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support secp256k1", @@ -1092,6 +1408,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_secp256k1(self): self.do_test_to_openssl(SECP256k1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP160r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP160r1", @@ -1099,6 +1416,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_brainpoolp160r1(self): self.do_test_to_openssl(BRAINPOOLP160r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP192r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP192r1", @@ -1106,6 +1424,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_brainpoolp192r1(self): self.do_test_to_openssl(BRAINPOOLP192r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP224r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP224r1", @@ -1113,6 +1432,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_brainpoolp224r1(self): self.do_test_to_openssl(BRAINPOOLP224r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP256r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP256r1", @@ -1120,6 +1440,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_brainpoolp256r1(self): self.do_test_to_openssl(BRAINPOOLP256r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP320r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP320r1", @@ -1127,6 +1448,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_brainpoolp320r1(self): self.do_test_to_openssl(BRAINPOOLP320r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP384r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP384r1", @@ -1134,6 +1456,7 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_brainpoolp384r1(self): self.do_test_to_openssl(BRAINPOOLP384r1) + @pytest.mark.slow @pytest.mark.skipif( "brainpoolP512r1" not in OPENSSL_SUPPORTED_CURVES, reason="system openssl does not support brainpoolP512r1", @@ -1141,6 +1464,62 @@ class OpenSSL(unittest.TestCase): def test_to_openssl_brainpoolp512r1(self): self.do_test_to_openssl(BRAINPOOLP512r1) + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP160t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP160t1", + ) + def test_to_openssl_brainpoolp160t1(self): + self.do_test_to_openssl(BRAINPOOLP160t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP192t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP192t1", + ) + def test_to_openssl_brainpoolp192t1(self): + self.do_test_to_openssl(BRAINPOOLP192t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP224t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP224t1", + ) + def test_to_openssl_brainpoolp224t1(self): + self.do_test_to_openssl(BRAINPOOLP224t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP256t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP256t1", + ) + def test_to_openssl_brainpoolp256t1(self): + self.do_test_to_openssl(BRAINPOOLP256t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP320t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP320t1", + ) + def test_to_openssl_brainpoolp320t1(self): + self.do_test_to_openssl(BRAINPOOLP320t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP384t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP384t1", + ) + def test_to_openssl_brainpoolp384t1(self): + self.do_test_to_openssl(BRAINPOOLP384t1) + + @pytest.mark.slow + @pytest.mark.skipif( + "brainpoolP512t1" not in OPENSSL_SUPPORTED_CURVES, + reason="system openssl does not support brainpoolP512t1", + ) + def test_to_openssl_brainpoolp512t1(self): + self.do_test_to_openssl(BRAINPOOLP512t1) + def do_test_to_openssl(self, curve, hash_name="SHA1"): curvename = curve.openssl_name assert curvename @@ -1152,7 +1531,7 @@ class OpenSSL(unittest.TestCase): os.mkdir("t") sk = SigningKey.generate(curve=curve) vk = sk.get_verifying_key() - data = b("data") + data = b"data" with open("t/pubkey.der", "wb") as e: e.write(vk.to_der()) # 4 with open("t/pubkey.pem", "wb") as e: @@ -1168,7 +1547,7 @@ class OpenSSL(unittest.TestCase): with open("t/data.txt", "wb") as e: e.write(data) with open("t/baddata.txt", "wb") as e: - e.write(data + b("corrupt")) + e.write(data + b"corrupt") self.assertRaises( SubprocessError, @@ -1191,6 +1570,17 @@ class OpenSSL(unittest.TestCase): % mdarg ) + with open("t/privkey-explicit.pem", "wb") as e: + e.write(sk.to_pem(curve_parameters_encoding="explicit")) + run_openssl( + "dgst %s -sign t/privkey-explicit.pem -out t/data.sig2 t/data.txt" + % mdarg + ) + run_openssl( + "dgst %s -verify t/pubkey.pem -signature t/data.sig2 t/data.txt" + % mdarg + ) + with open("t/privkey-p8.pem", "wb") as e: e.write(sk.to_pem(format="pkcs8")) run_openssl( @@ -1202,6 +1592,135 @@ class OpenSSL(unittest.TestCase): % mdarg ) + with open("t/privkey-p8-explicit.pem", "wb") as e: + e.write( + sk.to_pem(format="pkcs8", curve_parameters_encoding="explicit") + ) + run_openssl( + "dgst %s -sign t/privkey-p8-explicit.pem -out t/data.sig3 t/data.txt" + % mdarg + ) + run_openssl( + "dgst %s -verify t/pubkey.pem -signature t/data.sig3 t/data.txt" + % mdarg + ) + + OPENSSL_SUPPORTED_TYPES = set() + try: + if "-rawin" in run_openssl("pkeyutl -help"): + OPENSSL_SUPPORTED_TYPES = set( # pragma: no branch + c.lower() + for c in ("ED25519", "ED448") + if c in run_openssl("list -public-key-methods") + ) + except SubprocessError: # pragma: no cover + pass + + def do_eddsa_test_to_openssl(self, curve): + if os.path.isdir("t"): + shutil.rmtree("t") + os.mkdir("t") + + sk = SigningKey.generate(curve=curve) + vk = sk.get_verifying_key() + + data = b"data" + with open("t/pubkey.der", "wb") as e: + e.write(vk.to_der()) + with open("t/pubkey.pem", "wb") as e: + e.write(vk.to_pem()) + + sig = sk.sign(data) + + with open("t/data.sig", "wb") as e: + e.write(sig) + with open("t/data.txt", "wb") as e: + e.write(data) + with open("t/baddata.txt", "wb") as e: + e.write(data + b"corrupt") + + with self.assertRaises(SubprocessError): + run_openssl( + "pkeyutl -verify -pubin -inkey t/pubkey.pem -rawin " + "-in t/baddata.txt -sigfile t/data.sig" + ) + run_openssl( + "pkeyutl -verify -pubin -inkey t/pubkey.pem -rawin " + "-in t/data.txt -sigfile t/data.sig" + ) + + shutil.rmtree("t") + + # in practice at least OpenSSL 3.0.0 is needed to make EdDSA signatures + # earlier versions support EdDSA only in X.509 certificates + @pytest.mark.slow + @pytest.mark.skipif( + "ed25519" not in OPENSSL_SUPPORTED_TYPES, + reason="system openssl does not support signing with Ed25519", + ) + def test_to_openssl_ed25519(self): + return self.do_eddsa_test_to_openssl(Ed25519) + + @pytest.mark.slow + @pytest.mark.skipif( + "ed448" not in OPENSSL_SUPPORTED_TYPES, + reason="system openssl does not support signing with Ed448", + ) + def test_to_openssl_ed448(self): + return self.do_eddsa_test_to_openssl(Ed448) + + def do_eddsa_test_from_openssl(self, curve): + curvename = curve.name + + if os.path.isdir("t"): + shutil.rmtree("t") + os.mkdir("t") + + data = b"data" + + run_openssl( + "genpkey -algorithm {0} -outform PEM -out t/privkey.pem".format( + curvename + ) + ) + run_openssl( + "pkey -outform PEM -pubout -in t/privkey.pem -out t/pubkey.pem" + ) + + with open("t/data.txt", "wb") as e: + e.write(data) + run_openssl( + "pkeyutl -sign -inkey t/privkey.pem " + "-rawin -in t/data.txt -out t/data.sig" + ) + + with open("t/data.sig", "rb") as e: + sig = e.read() + with open("t/pubkey.pem", "rb") as e: + vk = VerifyingKey.from_pem(e.read()) + + self.assertIs(vk.curve, curve) + + vk.verify(sig, data) + + shutil.rmtree("t") + + @pytest.mark.slow + @pytest.mark.skipif( + "ed25519" not in OPENSSL_SUPPORTED_TYPES, + reason="system openssl does not support signing with Ed25519", + ) + def test_from_openssl_ed25519(self): + return self.do_eddsa_test_from_openssl(Ed25519) + + @pytest.mark.slow + @pytest.mark.skipif( + "ed448" not in OPENSSL_SUPPORTED_TYPES, + reason="system openssl does not support signing with Ed448", + ) + def test_from_openssl_ed448(self): + return self.do_eddsa_test_from_openssl(Ed448) + class TooSmallCurve(unittest.TestCase): OPENSSL_SUPPORTED_CURVES = set( @@ -1215,8 +1734,7 @@ class TooSmallCurve(unittest.TestCase): ) def test_sign_too_small_curve_dont_allow_truncate_raises(self): sk = SigningKey.generate(curve=NIST192p) - vk = sk.get_verifying_key() - data = b("data") + data = b"data" with self.assertRaises(BadDigestError): sk.sign( data, @@ -1232,7 +1750,7 @@ class TooSmallCurve(unittest.TestCase): def test_verify_too_small_curve_dont_allow_truncate_raises(self): sk = SigningKey.generate(curve=NIST192p) vk = sk.get_verifying_key() - data = b("data") + data = b"data" sig_der = sk.sign( data, hashfunc=partial(hashlib.new, "SHA256"), @@ -1251,108 +1769,121 @@ class TooSmallCurve(unittest.TestCase): class DER(unittest.TestCase): def test_integer(self): - self.assertEqual(der.encode_integer(0), b("\x02\x01\x00")) - self.assertEqual(der.encode_integer(1), b("\x02\x01\x01")) - self.assertEqual(der.encode_integer(127), b("\x02\x01\x7f")) - self.assertEqual(der.encode_integer(128), b("\x02\x02\x00\x80")) - self.assertEqual(der.encode_integer(256), b("\x02\x02\x01\x00")) - # self.assertEqual(der.encode_integer(-1), b("\x02\x01\xff")) + self.assertEqual(der.encode_integer(0), b"\x02\x01\x00") + self.assertEqual(der.encode_integer(1), b"\x02\x01\x01") + self.assertEqual(der.encode_integer(127), b"\x02\x01\x7f") + self.assertEqual(der.encode_integer(128), b"\x02\x02\x00\x80") + self.assertEqual(der.encode_integer(256), b"\x02\x02\x01\x00") + # self.assertEqual(der.encode_integer(-1), b"\x02\x01\xff") def s(n): - return der.remove_integer(der.encode_integer(n) + b("junk")) + return der.remove_integer(der.encode_integer(n) + b"junk") - self.assertEqual(s(0), (0, b("junk"))) - self.assertEqual(s(1), (1, b("junk"))) - self.assertEqual(s(127), (127, b("junk"))) - self.assertEqual(s(128), (128, b("junk"))) - self.assertEqual(s(256), (256, b("junk"))) + self.assertEqual(s(0), (0, b"junk")) + self.assertEqual(s(1), (1, b"junk")) + self.assertEqual(s(127), (127, b"junk")) + self.assertEqual(s(128), (128, b"junk")) + self.assertEqual(s(256), (256, b"junk")) self.assertEqual( s(1234567890123456789012345678901234567890), - (1234567890123456789012345678901234567890, b("junk")), + (1234567890123456789012345678901234567890, b"junk"), ) def test_number(self): - self.assertEqual(der.encode_number(0), b("\x00")) - self.assertEqual(der.encode_number(127), b("\x7f")) - self.assertEqual(der.encode_number(128), b("\x81\x00")) - self.assertEqual(der.encode_number(3 * 128 + 7), b("\x83\x07")) + self.assertEqual(der.encode_number(0), b"\x00") + self.assertEqual(der.encode_number(127), b"\x7f") + self.assertEqual(der.encode_number(128), b"\x81\x00") + self.assertEqual(der.encode_number(3 * 128 + 7), b"\x83\x07") # self.assertEqual(der.read_number("\x81\x9b" + "more"), (155, 2)) - # self.assertEqual(der.encode_number(155), b("\x81\x9b")) + # self.assertEqual(der.encode_number(155), b"\x81\x9b") for n in (0, 1, 2, 127, 128, 3 * 128 + 7, 840, 10045): # , 155): - x = der.encode_number(n) + b("more") + x = der.encode_number(n) + b"more" n1, llen = der.read_number(x) self.assertEqual(n1, n) - self.assertEqual(x[llen:], b("more")) + self.assertEqual(x[llen:], b"more") def test_length(self): - self.assertEqual(der.encode_length(0), b("\x00")) - self.assertEqual(der.encode_length(127), b("\x7f")) - self.assertEqual(der.encode_length(128), b("\x81\x80")) - self.assertEqual(der.encode_length(255), b("\x81\xff")) - self.assertEqual(der.encode_length(256), b("\x82\x01\x00")) - self.assertEqual(der.encode_length(3 * 256 + 7), b("\x82\x03\x07")) - self.assertEqual(der.read_length(b("\x81\x9b") + b("more")), (155, 2)) - self.assertEqual(der.encode_length(155), b("\x81\x9b")) + self.assertEqual(der.encode_length(0), b"\x00") + self.assertEqual(der.encode_length(127), b"\x7f") + self.assertEqual(der.encode_length(128), b"\x81\x80") + self.assertEqual(der.encode_length(255), b"\x81\xff") + self.assertEqual(der.encode_length(256), b"\x82\x01\x00") + self.assertEqual(der.encode_length(3 * 256 + 7), b"\x82\x03\x07") + self.assertEqual(der.read_length(b"\x81\x9b" + b"more"), (155, 2)) + self.assertEqual(der.encode_length(155), b"\x81\x9b") for n in (0, 1, 2, 127, 128, 255, 256, 3 * 256 + 7, 155): - x = der.encode_length(n) + b("more") + x = der.encode_length(n) + b"more" n1, llen = der.read_length(x) self.assertEqual(n1, n) - self.assertEqual(x[llen:], b("more")) + self.assertEqual(x[llen:], b"more") def test_sequence(self): - x = der.encode_sequence(b("ABC"), b("DEF")) + b("GHI") - self.assertEqual(x, b("\x30\x06ABCDEFGHI")) + x = der.encode_sequence(b"ABC", b"DEF") + b"GHI" + self.assertEqual(x, b"\x30\x06ABCDEFGHI") x1, rest = der.remove_sequence(x) - self.assertEqual(x1, b("ABCDEF")) - self.assertEqual(rest, b("GHI")) + self.assertEqual(x1, b"ABCDEF") + self.assertEqual(rest, b"GHI") def test_constructed(self): x = der.encode_constructed(0, NIST224p.encoded_oid) - self.assertEqual(hexlify(x), b("a007") + b("06052b81040021")) - x = der.encode_constructed(1, unhexlify(b("0102030a0b0c"))) - self.assertEqual(hexlify(x), b("a106") + b("0102030a0b0c")) + self.assertEqual(hexlify(x), b"a007" + b"06052b81040021") + x = der.encode_constructed(1, unhexlify(b"0102030a0b0c")) + self.assertEqual(hexlify(x), b"a106" + b"0102030a0b0c") class Util(unittest.TestCase): + @pytest.mark.slow def test_trytryagain(self): tta = util.randrange_from_seed__trytryagain for i in range(1000): seed = "seed-%d" % i for order in ( - 2 ** 8 - 2, - 2 ** 8 - 1, - 2 ** 8, - 2 ** 8 + 1, - 2 ** 8 + 2, - 2 ** 16 - 1, - 2 ** 16 + 1, + 2**8 - 2, + 2**8 - 1, + 2**8, + 2**8 + 1, + 2**8 + 2, + 2**16 - 1, + 2**16 + 1, ): n = tta(seed, order) self.assertTrue(1 <= n < order, (1, n, order)) # this trytryagain *does* provide long-term stability self.assertEqual( ("%x" % (tta("seed", NIST224p.order))).encode(), - b("6fa59d73bf0446ae8743cf748fc5ac11d5585a90356417e97155c3bc"), + b"6fa59d73bf0446ae8743cf748fc5ac11d5585a90356417e97155c3bc", ) - @given(st.integers(min_value=0, max_value=10 ** 200)) + def test_trytryagain_single(self): + tta = util.randrange_from_seed__trytryagain + order = 2**8 - 2 + seed = b"text" + n = tta(seed, order) + # known issue: https://github.com/warner/python-ecdsa/issues/221 + if sys.version_info < (3, 0): # pragma: no branch + self.assertEqual(n, 228) + else: # pragma: no branch + self.assertEqual(n, 18) + + @settings(**HYP_SETTINGS) + @given(st.integers(min_value=0, max_value=10**200)) def test_randrange(self, i): # util.randrange does not provide long-term stability: we might # change the algorithm in the future. entropy = util.PRNG("seed-%d" % i) for order in ( - 2 ** 8 - 2, - 2 ** 8 - 1, - 2 ** 8, - 2 ** 16 - 1, - 2 ** 16 + 1, + 2**8 - 2, + 2**8 - 1, + 2**8, + 2**16 - 1, + 2**16 + 1, ): # that oddball 2**16+1 takes half our runtime n = util.randrange(order, entropy=entropy) self.assertTrue(1 <= n < order, (1, n, order)) def OFF_test_prove_uniformity(self): # pragma: no cover - order = 2 ** 8 - 2 + order = 2**8 - 2 counts = dict([(i, 0) for i in range(1, order)]) assert 0 not in counts assert order not in counts @@ -1378,8 +1909,8 @@ class RFC6979(unittest.TestCase): self._do( generator=SECP256k1.generator, secexp=int("9d0219792467d7d37b4d43298a7d0c05", 16), - hsh=sha256(b("sample")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"sample").digest(), + hash_func=hashlib.sha256, expected=int( "8fa1f95d514760e498f28957b824ee6ec39ed64826ff4fecc2b5739ec45b91cd", 16, @@ -1393,8 +1924,8 @@ class RFC6979(unittest.TestCase): "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", 16, ), - hsh=sha256(b("sample")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"sample").digest(), + hash_func=hashlib.sha256, expected=int( "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", 16, @@ -1405,8 +1936,8 @@ class RFC6979(unittest.TestCase): self._do( generator=SECP256k1.generator, secexp=0x1, - hsh=sha256(b("Satoshi Nakamoto")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"Satoshi Nakamoto").digest(), + hash_func=hashlib.sha256, expected=0x8F8A276C19F4149656B280621E358CCE24F5F52542772691EE69063B74F15D15, ) @@ -1414,12 +1945,10 @@ class RFC6979(unittest.TestCase): self._do( generator=SECP256k1.generator, secexp=0x1, - hsh=sha256( - b( - "All those moments will be lost in time, like tears in rain. Time to die..." - ) + hsh=hashlib.sha256( + b"All those moments will be lost in time, like tears in rain. Time to die..." ).digest(), - hash_func=sha256, + hash_func=hashlib.sha256, expected=0x38AA22D72376B4DBC472E06C3BA403EE0A394DA63FC58D88686C611ABA98D6B3, ) @@ -1427,8 +1956,8 @@ class RFC6979(unittest.TestCase): self._do( generator=SECP256k1.generator, secexp=0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364140, - hsh=sha256(b("Satoshi Nakamoto")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"Satoshi Nakamoto").digest(), + hash_func=hashlib.sha256, expected=0x33A19B60E25FB6F4435AF53A3D42D493644827367E6453928554F43E49AA6F90, ) @@ -1436,8 +1965,8 @@ class RFC6979(unittest.TestCase): self._do( generator=SECP256k1.generator, secexp=0xF8B8AF8CE3C7CCA5E300D33939540C10D45CE001B8F252BFBC57BA0342904181, - hsh=sha256(b("Alan Turing")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"Alan Turing").digest(), + hash_func=hashlib.sha256, expected=0x525A82B70E67874398067543FD84C83D30C175FDC45FDEEE082FE13B1D7CFDF1, ) @@ -1456,7 +1985,7 @@ class RFC6979(unittest.TestCase): "AF2BDBE1AA9B6EC1E2ADE1D694F41FC71A831D0268E9891562113D8A62ADD1BF" ) ), - hash_func=sha256, + hash_func=hashlib.sha256, expected=int("23AF4074C90A02B3FE61D286D5C87F425E6BDD81B", 16), ) @@ -1464,8 +1993,8 @@ class RFC6979(unittest.TestCase): self._do( generator=NIST192p.generator, secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=sha1(b("sample")).digest(), - hash_func=sha1, + hsh=hashlib.sha1(b"sample").digest(), + hash_func=hashlib.sha1, expected=int( "37D7CA00D2C7B0E5E412AC03BD44BA837FDD5B28CD3B0021", 16 ), @@ -1475,8 +2004,8 @@ class RFC6979(unittest.TestCase): self._do( generator=NIST192p.generator, secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=sha256(b("sample")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"sample").digest(), + hash_func=hashlib.sha256, expected=int( "32B1B6D7D42A05CB449065727A84804FB1A3E34D8F261496", 16 ), @@ -1486,8 +2015,8 @@ class RFC6979(unittest.TestCase): self._do( generator=NIST192p.generator, secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=sha512(b("sample")).digest(), - hash_func=sha512, + hsh=hashlib.sha512(b"sample").digest(), + hash_func=hashlib.sha512, expected=int( "A2AC7AB055E4F20692D49209544C203A7D1F2C0BFBC75DB1", 16 ), @@ -1497,8 +2026,8 @@ class RFC6979(unittest.TestCase): self._do( generator=NIST192p.generator, secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=sha1(b("test")).digest(), - hash_func=sha1, + hsh=hashlib.sha1(b"test").digest(), + hash_func=hashlib.sha1, expected=int( "D9CF9C3D3297D3260773A1DA7418DB5537AB8DD93DE7FA25", 16 ), @@ -1508,8 +2037,8 @@ class RFC6979(unittest.TestCase): self._do( generator=NIST192p.generator, secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=sha256(b("test")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"test").digest(), + hash_func=hashlib.sha256, expected=int( "5C4CE89CF56D9E7C77C8585339B006B97B5F0680B4306C6C", 16 ), @@ -1519,8 +2048,8 @@ class RFC6979(unittest.TestCase): self._do( generator=NIST192p.generator, secexp=int("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), - hsh=sha512(b("test")).digest(), - hash_func=sha512, + hsh=hashlib.sha512(b"test").digest(), + hash_func=hashlib.sha512, expected=int( "0758753A5254759C7CFBAD2E2D9B0792EEE44136C9480527", 16 ), @@ -1533,8 +2062,8 @@ class RFC6979(unittest.TestCase): "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", 16, ), - hsh=sha1(b("sample")).digest(), - hash_func=sha1, + hsh=hashlib.sha1(b"sample").digest(), + hash_func=hashlib.sha1, expected=int( "089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9", 16, @@ -1548,8 +2077,8 @@ class RFC6979(unittest.TestCase): "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", 16, ), - hsh=sha256(b("sample")).digest(), - hash_func=sha256, + hsh=hashlib.sha256(b"sample").digest(), + hash_func=hashlib.sha256, expected=int( "0EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0", 16, @@ -1563,8 +2092,8 @@ class RFC6979(unittest.TestCase): "0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538", 16, ), - hsh=sha512(b("test")).digest(), - hash_func=sha512, + hsh=hashlib.sha512(b"test").digest(), + hash_func=hashlib.sha512, expected=int( "16200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D", 16, @@ -1667,6 +2196,7 @@ class RFC6932(ECDH): ), ) + @pytest.mark.slow def test_brainpoolP384r1(self): self._do( curve=curve_brainpoolp384r1, @@ -1713,6 +2243,7 @@ class RFC6932(ECDH): ), ) + @pytest.mark.slow def test_brainpoolP512r1(self): self._do( curve=curve_brainpoolp512r1, @@ -1817,6 +2348,7 @@ class RFC7027(ECDH): ), ) + @pytest.mark.slow def test_brainpoolP384r1(self): self._do( curve=curve_brainpoolp384r1, @@ -1863,6 +2395,7 @@ class RFC7027(ECDH): ), ) + @pytest.mark.slow def test_brainpoolP512r1(self): self._do( curve=curve_brainpoolp512r1, @@ -1928,7 +2461,7 @@ class RFC7027(ECDH): "6FC98BD7E50211A4A27102FA3549DF79EBCB4BF246B80945CDDFE7D509BBFD7D", "9E56F509196784D963D1C0A401510EE7ADA3DCC5DEE04B154BF61AF1D5A6DECE", b"abc", - sha256, + hashlib.sha256, "CB28E0999B9C7715FD0A80D8E47A77079716CBBF917DD72E97566EA1C066957C", "86FA3BB4E26CAD5BF90B7F81899256CE7594BB1EA0C89212748BFF3B3D5B0315", NIST256p, @@ -1944,7 +2477,7 @@ class RFC7027(ECDH): "B4B74E44D71A13D568003D7489908D564C7761E229C58CBFA18950096EB7463B" "854D7FA992F934D927376285E63414FA", b"abc", - sha384, + hashlib.sha384, "FB017B914E29149432D8BAC29A514640B46F53DDAB2C69948084E2930F1C8F7E" "08E07C9C63F2D21A07DCB56A6AF56EB3", "B263A1305E057F984D38726A1B46874109F417BCA112674C528262A40A629AF1" @@ -1966,7 +2499,7 @@ class RFC7027(ECDH): "373778F9DE6B6497B1EF825FF24F42F9B4A4BD7382CFC3378A540B1B7F0C1B95" "6C2F", b"abc", - sha512, + hashlib.sha512, "0154FD3836AF92D0DCA57DD5341D3053988534FDE8318FC6AAAAB68E2E6F4339" "B19F2F281A7E0B22C269D93CF8794A9278880ED7DBB8D9362CAEACEE54432055" "2251", diff --git a/frozen_deps/ecdsa/test_rw_lock.py b/frozen_deps/ecdsa/test_rw_lock.py index d360482..0a84b9c 100644 --- a/frozen_deps/ecdsa/test_rw_lock.py +++ b/frozen_deps/ecdsa/test_rw_lock.py @@ -2,7 +2,10 @@ # https://code.activestate.com/recipes/577803-reader-writer-lock-with-priority-for-writers/ # released under the MIT licence -import unittest +try: + import unittest2 as unittest +except ImportError: + import unittest import threading import time import copy diff --git a/frozen_deps/ecdsa/test_sha3.py b/frozen_deps/ecdsa/test_sha3.py new file mode 100644 index 0000000..d30381d --- /dev/null +++ b/frozen_deps/ecdsa/test_sha3.py @@ -0,0 +1,111 @@ +try: + import unittest2 as unittest +except ImportError: + import unittest +import pytest + +try: + from gmpy2 import mpz + + GMPY = True +except ImportError: # pragma: no cover + try: + from gmpy import mpz + + GMPY = True + except ImportError: + GMPY = False + +from ._sha3 import shake_256 +from ._compat import bytes_to_int, int_to_bytes + +B2I_VECTORS = [ + (b"\x00\x01", "big", 1), + (b"\x00\x01", "little", 0x0100), + (b"", "big", 0), + (b"\x00", "little", 0), +] + + +@pytest.mark.parametrize("bytes_in,endian,int_out", B2I_VECTORS) +def test_bytes_to_int(bytes_in, endian, int_out): + out = bytes_to_int(bytes_in, endian) + assert out == int_out + + +class TestBytesToInt(unittest.TestCase): + def test_bytes_to_int_wrong_endian(self): + with self.assertRaises(ValueError): + bytes_to_int(b"\x00", "middle") + + def test_int_to_bytes_wrong_endian(self): + with self.assertRaises(ValueError): + int_to_bytes(0, byteorder="middle") + + +@pytest.mark.skipif(GMPY == False, reason="requires gmpy or gmpy2") +def test_int_to_bytes_with_gmpy(): + assert int_to_bytes(mpz(1)) == b"\x01" + + +I2B_VECTORS = [ + (0, None, "big", b""), + (0, 1, "big", b"\x00"), + (1, None, "big", b"\x01"), + (0x0100, None, "little", b"\x00\x01"), + (0x0100, 4, "little", b"\x00\x01\x00\x00"), + (1, 4, "big", b"\x00\x00\x00\x01"), +] + + +@pytest.mark.parametrize("int_in,length,endian,bytes_out", I2B_VECTORS) +def test_int_to_bytes(int_in, length, endian, bytes_out): + out = int_to_bytes(int_in, length, endian) + assert out == bytes_out + + +SHAKE_256_VECTORS = [ + ( + b"Message.", + 32, + b"\x78\xa1\x37\xbb\x33\xae\xe2\x72\xb1\x02\x4f\x39\x43\xe5\xcf\x0c" + b"\x4e\x9c\x72\x76\x2e\x34\x4c\xf8\xf9\xc3\x25\x9d\x4f\x91\x2c\x3a", + ), + ( + b"", + 32, + b"\x46\xb9\xdd\x2b\x0b\xa8\x8d\x13\x23\x3b\x3f\xeb\x74\x3e\xeb\x24" + b"\x3f\xcd\x52\xea\x62\xb8\x1b\x82\xb5\x0c\x27\x64\x6e\xd5\x76\x2f", + ), + ( + b"message", + 32, + b"\x86\x16\xe1\xe4\xcf\xd8\xb5\xf7\xd9\x2d\x43\xd8\x6e\x1b\x14\x51" + b"\xa2\xa6\x5a\xf8\x64\xfc\xb1\x26\xc2\x66\x0a\xb3\x46\x51\xb1\x75", + ), + ( + b"message", + 16, + b"\x86\x16\xe1\xe4\xcf\xd8\xb5\xf7\xd9\x2d\x43\xd8\x6e\x1b\x14\x51", + ), + ( + b"message", + 64, + b"\x86\x16\xe1\xe4\xcf\xd8\xb5\xf7\xd9\x2d\x43\xd8\x6e\x1b\x14\x51" + b"\xa2\xa6\x5a\xf8\x64\xfc\xb1\x26\xc2\x66\x0a\xb3\x46\x51\xb1\x75" + b"\x30\xd6\xba\x2a\x46\x65\xf1\x9d\xf0\x62\x25\xb1\x26\xd1\x3e\xed" + b"\x91\xd5\x0d\xe7\xb9\xcb\x65\xf3\x3a\x46\xae\xd3\x6c\x7d\xc5\xe8", + ), + ( + b"A" * 1024, + 32, + b"\xa5\xef\x7e\x30\x8b\xe8\x33\x64\xe5\x9c\xf3\xb5\xf3\xba\x20\xa3" + b"\x5a\xe7\x30\xfd\xbc\x33\x11\xbf\x83\x89\x50\x82\xb4\x41\xe9\xb3", + ), +] + + +@pytest.mark.parametrize("msg,olen,ohash", SHAKE_256_VECTORS) +def test_shake_256(msg, olen, ohash): + out = shake_256(msg, olen) + assert out == bytearray(ohash) diff --git a/frozen_deps/ecdsa/util.py b/frozen_deps/ecdsa/util.py index e77d61c..639bc0c 100644 --- a/frozen_deps/ecdsa/util.py +++ b/frozen_deps/ecdsa/util.py @@ -1,3 +1,16 @@ +""" +This module includes some utility functions. + +The methods most typically used are the sigencode and sigdecode functions +to be used with :func:`~ecdsa.keys.SigningKey.sign` and +:func:`~ecdsa.keys.VerifyingKey.verify` +respectively. See the :func:`sigencode_strings`, :func:`sigdecode_string`, +:func:`sigencode_der`, :func:`sigencode_strings_canonize`, +:func:`sigencode_string_canonize`, :func:`sigencode_der_canonize`, +:func:`sigdecode_strings`, :func:`sigdecode_string`, and +:func:`sigdecode_der` functions. +""" + from __future__ import division import os @@ -5,10 +18,11 @@ import math import binascii import sys from hashlib import sha256 -from six import PY2, int2byte, b, next +from six import PY2, int2byte, next from . import der from ._compat import normalise_bytes + # RFC5480: # The "unrestricted" algorithm identifier is: # id-ecPublicKey OBJECT IDENTIFIER ::= { @@ -33,13 +47,12 @@ oid_ecDH = (1, 3, 132, 1, 12) oid_ecMQV = (1, 3, 132, 1, 13) -if sys.version_info >= (3,): +if sys.version_info >= (3,): # pragma: no branch def entropy_to_bits(ent_256): """Convert a bytestring to string of 0's and 1's""" return bin(int.from_bytes(ent_256, "big"))[2:].zfill(len(ent_256) * 8) - else: def entropy_to_bits(ent_256): @@ -47,12 +60,11 @@ else: return "".join(bin(ord(x))[2:].zfill(8) for x in ent_256) -if sys.version_info < (2, 7): +if sys.version_info < (2, 7): # pragma: no branch # Can't add a method to a built-in type so we are stuck with this def bit_length(x): return len(bin(x)) - 2 - else: def bit_length(x): @@ -99,7 +111,7 @@ class PRNG: def __call__(self, numbytes): a = [next(self.generator) for i in range(numbytes)] - if PY2: + if PY2: # pragma: no branch return "".join(a) else: return bytes(a) @@ -190,7 +202,7 @@ def randrange_from_seed__trytryagain(seed, order): bits, bytes, extrabits = bits_and_bytes(order) generate = PRNG(seed) while True: - extrabyte = b("") + extrabyte = b"" if extrabits: extrabyte = int2byte(ord(generate(1)) & lsb_of_ones(extrabits)) guess = string_to_number(extrabyte + generate(bytes)) + 1 @@ -223,12 +235,24 @@ def string_to_number_fixedlen(string, order): return int(binascii.hexlify(string), 16) -# these methods are useful for the sigencode= argument to SK.sign() and the -# sigdecode= argument to VK.verify(), and control how the signature is packed -# or unpacked. +def sigencode_strings(r, s, order): + """ + Encode the signature to a pair of strings in a tuple + Encodes signature into raw encoding (:term:`raw encoding`) with the + ``r`` and ``s`` parts of the signature encoded separately. -def sigencode_strings(r, s, order): + It's expected that this function will be used as a ``sigencode=`` parameter + in :func:`ecdsa.keys.SigningKey.sign` method. + + :param int r: first parameter of the signature + :param int s: second parameter of the signature + :param int order: the order of the curve over which the signature was + computed + + :return: raw encoding of ECDSA signature + :rtype: tuple(bytes, bytes) + """ r_str = number_to_string(r, order) s_str = number_to_string(s, order) return (r_str, s_str) @@ -238,7 +262,7 @@ def sigencode_string(r, s, order): """ Encode the signature to raw format (:term:`raw encoding`) - It's expected that this function will be used as a `sigencode=` parameter + It's expected that this function will be used as a ``sigencode=`` parameter in :func:`ecdsa.keys.SigningKey.sign` method. :param int r: first parameter of the signature @@ -266,7 +290,7 @@ def sigencode_der(r, s, order): s INTEGER } - It's expected that this function will be used as a `sigencode=` parameter + It's expected that this function will be used as a ``sigencode=`` parameter in :func:`ecdsa.keys.SigningKey.sign` method. :param int r: first parameter of the signature @@ -280,23 +304,83 @@ def sigencode_der(r, s, order): return der.encode_sequence(der.encode_integer(r), der.encode_integer(s)) -# canonical versions of sigencode methods -# these enforce low S values, by negating the value (modulo the order) if -# above order/2 see CECKey::Sign() -# https://github.com/bitcoin/bitcoin/blob/master/src/key.cpp#L214 def sigencode_strings_canonize(r, s, order): + """ + Encode the signature to a pair of strings in a tuple + + Encodes signature into raw encoding (:term:`raw encoding`) with the + ``r`` and ``s`` parts of the signature encoded separately. + + Makes sure that the signature is encoded in the canonical format, where + the ``s`` parameter is always smaller than ``order / 2``. + Most commonly used in bitcoin. + + It's expected that this function will be used as a ``sigencode=`` parameter + in :func:`ecdsa.keys.SigningKey.sign` method. + + :param int r: first parameter of the signature + :param int s: second parameter of the signature + :param int order: the order of the curve over which the signature was + computed + + :return: raw encoding of ECDSA signature + :rtype: tuple(bytes, bytes) + """ if s > order / 2: s = order - s return sigencode_strings(r, s, order) def sigencode_string_canonize(r, s, order): + """ + Encode the signature to raw format (:term:`raw encoding`) + + Makes sure that the signature is encoded in the canonical format, where + the ``s`` parameter is always smaller than ``order / 2``. + Most commonly used in bitcoin. + + It's expected that this function will be used as a ``sigencode=`` parameter + in :func:`ecdsa.keys.SigningKey.sign` method. + + :param int r: first parameter of the signature + :param int s: second parameter of the signature + :param int order: the order of the curve over which the signature was + computed + + :return: raw encoding of ECDSA signature + :rtype: bytes + """ if s > order / 2: s = order - s return sigencode_string(r, s, order) def sigencode_der_canonize(r, s, order): + """ + Encode the signature into the ECDSA-Sig-Value structure using :term:`DER`. + + Makes sure that the signature is encoded in the canonical format, where + the ``s`` parameter is always smaller than ``order / 2``. + Most commonly used in bitcoin. + + Encodes the signature to the following :term:`ASN.1` structure:: + + Ecdsa-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER + } + + It's expected that this function will be used as a ``sigencode=`` parameter + in :func:`ecdsa.keys.SigningKey.sign` method. + + :param int r: first parameter of the signature + :param int s: second parameter of the signature + :param int order: the order of the curve over which the signature was + computed + + :return: DER encoding of ECDSA signature + :rtype: bytes + """ if s > order / 2: s = order - s return sigencode_der(r, s, order) @@ -323,7 +407,7 @@ def sigdecode_string(signature, order): the signature, with each encoded using the same amount of bytes depending on curve size/order. - It's expected that this function will be used as the `sigdecode=` + It's expected that this function will be used as the ``sigdecode=`` parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method. :param signature: encoded signature @@ -333,7 +417,7 @@ def sigdecode_string(signature, order): :raises MalformedSignature: when the encoding of the signature is invalid - :return: tuple with decoded 'r' and 's' values of signature + :return: tuple with decoded ``r`` and ``s`` values of signature :rtype: tuple of ints """ signature = normalise_bytes(signature) @@ -352,10 +436,10 @@ def sigdecode_strings(rs_strings, order): """ Decode the signature from two strings. - First string needs to be a big endian encoding of 'r', second needs to - be a big endian encoding of the 's' parameter of an ECDSA signature. + First string needs to be a big endian encoding of ``r``, second needs to + be a big endian encoding of the ``s`` parameter of an ECDSA signature. - It's expected that this function will be used as the `sigdecode=` + It's expected that this function will be used as the ``sigdecode=`` parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method. :param list rs_strings: list of two bytes-like objects, each encoding one @@ -364,7 +448,7 @@ def sigdecode_strings(rs_strings, order): :raises MalformedSignature: when the encoding of the signature is invalid - :return: tuple with decoded 'r' and 's' values of signature + :return: tuple with decoded ``r`` and ``s`` values of signature :rtype: tuple of ints """ if not len(rs_strings) == 2: @@ -406,7 +490,7 @@ def sigdecode_der(sig_der, order): s INTEGER } - It's expected that this function will be used as as the `sigdecode=` + It's expected that this function will be used as as the ``sigdecode=`` parameter to the :func:`ecdsa.keys.VerifyingKey.verify` method. :param sig_der: encoded signature @@ -416,7 +500,7 @@ def sigdecode_der(sig_der, order): :raises UnexpectedDER: when the encoding of signature is invalid - :return: tuple with decoded 'r' and 's' values of signature + :return: tuple with decoded ``r`` and ``s`` values of signature :rtype: tuple of ints """ sig_der = normalise_bytes(sig_der) diff --git a/frozen_deps/keytree.py-0.2.dist-info/INSTALLER b/frozen_deps/keytree.py-0.2.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/frozen_deps/keytree.py-0.2.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/frozen_deps/keytree.py-0.2.dist-info/METADATA b/frozen_deps/keytree.py-0.2.dist-info/METADATA deleted file mode 100644 index 30904eb..0000000 --- a/frozen_deps/keytree.py-0.2.dist-info/METADATA +++ /dev/null @@ -1,18 +0,0 @@ -Metadata-Version: 2.1 -Name: keytree.py -Version: 0.2 -Summary: Derive BIP32 key pairs from BIP39 mnemonic -Home-page: http://github.com/Determinant/keytree.py -Author: Ted Yin -Author-email: tederminant@gmail.com -License: MIT -Platform: UNKNOWN -Requires-Dist: ecdsa -Requires-Dist: base58 -Requires-Dist: pysha3 -Requires-Dist: pycryptodomex -Requires-Dist: mnemonic - -UNKNOWN - - diff --git a/frozen_deps/keytree.py-0.2.dist-info/RECORD b/frozen_deps/keytree.py-0.2.dist-info/RECORD deleted file mode 100644 index 5f7d2f8..0000000 --- a/frozen_deps/keytree.py-0.2.dist-info/RECORD +++ /dev/null @@ -1,10 +0,0 @@ -../../bin/__pycache__/keytree.cpython-38.pyc,,
-../../bin/keytree.py,sha256=XCCc0ThEVf1BRHtz8LefMmWyhGBp9G8LkxzY51JDkj0,11850
-__pycache__/bech32.cpython-38.pyc,,
-bech32.py,sha256=QZdU7nY1UUzeYfV-5ASwhe3PA3YVVnClyGGrtgJIjsE,4376
-keytree.py-0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-keytree.py-0.2.dist-info/METADATA,sha256=bnRg0Bju4Uk768UXWAJ2TAlKIkRFgPP92ClhF1Z2o2w,368
-keytree.py-0.2.dist-info/RECORD,,
-keytree.py-0.2.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
-keytree.py-0.2.dist-info/direct_url.json,sha256=6seyiOxGCRXsnt6lrEcpcJtZGEXuBr-KHa0idXAuZDA,71
-keytree.py-0.2.dist-info/top_level.txt,sha256=oESACl4kH99axdjvTQuJATlgqujLpRc8iCwiqjvbI8M,7
diff --git a/frozen_deps/keytree.py-0.2.dist-info/WHEEL b/frozen_deps/keytree.py-0.2.dist-info/WHEEL deleted file mode 100644 index b552003..0000000 --- a/frozen_deps/keytree.py-0.2.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.34.2) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/frozen_deps/keytree.py-0.2.dist-info/direct_url.json b/frozen_deps/keytree.py-0.2.dist-info/direct_url.json deleted file mode 100644 index 650a846..0000000 --- a/frozen_deps/keytree.py-0.2.dist-info/direct_url.json +++ /dev/null @@ -1 +0,0 @@ -{"dir_info": {}, "url": "file:///home/ymf/work/2020_summer/keytree.py"}
\ No newline at end of file diff --git a/frozen_deps/keytree.py-0.2.dist-info/top_level.txt b/frozen_deps/keytree.py-0.2.dist-info/top_level.txt deleted file mode 100644 index e5e2a6a..0000000 --- a/frozen_deps/keytree.py-0.2.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -bech32 diff --git a/frozen_deps/mnemonic-0.19.dist-info/AUTHORS b/frozen_deps/mnemonic-0.19.dist-info/AUTHORS deleted file mode 100644 index 34ed344..0000000 --- a/frozen_deps/mnemonic-0.19.dist-info/AUTHORS +++ /dev/null @@ -1,2 +0,0 @@ -Marek Palatinus <marek@satoshilabs.com> -Pavol Rusnak <stick@satoshilabs.com> diff --git a/frozen_deps/mnemonic-0.19.dist-info/INSTALLER b/frozen_deps/mnemonic-0.19.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/frozen_deps/mnemonic-0.19.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/frozen_deps/mnemonic-0.19.dist-info/LICENSE b/frozen_deps/mnemonic-0.19.dist-info/LICENSE deleted file mode 100644 index b135744..0000000 --- a/frozen_deps/mnemonic-0.19.dist-info/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-2016 Pavol Rusnak - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/frozen_deps/mnemonic-0.19.dist-info/METADATA b/frozen_deps/mnemonic-0.19.dist-info/METADATA deleted file mode 100644 index ccd2d7e..0000000 --- a/frozen_deps/mnemonic-0.19.dist-info/METADATA +++ /dev/null @@ -1,42 +0,0 @@ -Metadata-Version: 2.1 -Name: mnemonic -Version: 0.19 -Summary: Implementation of Bitcoin BIP-0039 -Home-page: https://github.com/trezor/python-mnemonic -Author: Trezor -Author-email: info@trezor.io -License: UNKNOWN -Platform: UNKNOWN -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 - -python-mnemonic -=============== - -.. image:: https://travis-ci.org/trezor/python-mnemonic.svg?branch=master - :target: https://travis-ci.org/trezor/python-mnemonic - -Reference implementation of BIP-0039: Mnemonic code for generating -deterministic keys - -Abstract --------- - -This BIP describes the implementation of a mnemonic code or mnemonic sentence -- -a group of easy to remember words -- for the generation of deterministic wallets. - -It consists of two parts: generating the mnenomic, and converting it into a -binary seed. This seed can be later used to generate deterministic wallets using -BIP-0032 or similar methods. - -BIP Paper ---------- - -See https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki -for full specification - - diff --git a/frozen_deps/mnemonic-0.19.dist-info/RECORD b/frozen_deps/mnemonic-0.19.dist-info/RECORD deleted file mode 100644 index dea0329..0000000 --- a/frozen_deps/mnemonic-0.19.dist-info/RECORD +++ /dev/null @@ -1,19 +0,0 @@ -mnemonic-0.19.dist-info/AUTHORS,sha256=5ugihxzh5OoFf-6gBQOnJfgaznUQHX5Vv4L9Th9iGFo,77
-mnemonic-0.19.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-mnemonic-0.19.dist-info/LICENSE,sha256=1ePHxiqE6ABzIB4vblEw6eaAT6BfisT4smoTx9OWlpc,1084
-mnemonic-0.19.dist-info/METADATA,sha256=qwLACoQeTvWdaoDuBFWJUNBq0YxKAZ0l1fm06N0OY_w,1260
-mnemonic-0.19.dist-info/RECORD,,
-mnemonic-0.19.dist-info/WHEEL,sha256=HX-v9-noUkyUoxyZ1PMSuS7auUxDAR4VBdoYLqD0xws,110
-mnemonic-0.19.dist-info/top_level.txt,sha256=XlFgB9xaifTc2HXO7w9EXCvIUHFN_x51trUyPQKBSHI,9
-mnemonic/__init__.py,sha256=oASNYH5yS0zFSw4wYRvtw_O42j5Xojt7gZ2ur519DWc,45
-mnemonic/__pycache__/__init__.cpython-38.pyc,,
-mnemonic/__pycache__/mnemonic.cpython-38.pyc,,
-mnemonic/mnemonic.py,sha256=WjWwsSKvpv6cP44mXJXrsWqpJuSR-EN8dSb9GFnPfqs,10532
-mnemonic/wordlist/chinese_simplified.txt,sha256=XFlCeSvYNAy4snzVkvEBXt9WqMWyYnbuGKSCQo58VyY,8192
-mnemonic/wordlist/chinese_traditional.txt,sha256=QXsms9hQCkrj1ZcX1wEZUttvwvuEuAfz-UrHNOicG18,8192
-mnemonic/wordlist/english.txt,sha256=L17tU6Rye0v4iA2PPxme_JDlhQNkbZ_47_Oi7Tsk29o,13116
-mnemonic/wordlist/french.txt,sha256=AQHYifYipgZMqXzbc2iDjdWhPxO7sLOt-nRRFAN1WJg,16779
-mnemonic/wordlist/italian.txt,sha256=05LEn9twCiTNH86yN8H2XcwSj2s0qKrLWLWThLXGSMI,16033
-mnemonic/wordlist/japanese.txt,sha256=Lu0K70kikeBhYz162BF_GisD64CinQ5OMResJSjQX_0,26423
-mnemonic/wordlist/korean.txt,sha256=npX4bBZ96I9FDwqvieh_ZiSlf5c8Z7UW4zjo6LiJf2A,37832
-mnemonic/wordlist/spanish.txt,sha256=RoRqWgE50ePLdyk-UhwoZfe824LETo0KBqLNDsukjAs,13996
diff --git a/frozen_deps/mnemonic-0.19.dist-info/WHEEL b/frozen_deps/mnemonic-0.19.dist-info/WHEEL deleted file mode 100644 index c8240f0..0000000 --- a/frozen_deps/mnemonic-0.19.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.33.1) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/frozen_deps/mnemonic-0.19.dist-info/top_level.txt b/frozen_deps/mnemonic-0.19.dist-info/top_level.txt deleted file mode 100644 index 9015942..0000000 --- a/frozen_deps/mnemonic-0.19.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -mnemonic diff --git a/frozen_deps/mnemonic/__init__.py b/frozen_deps/mnemonic/__init__.py deleted file mode 100644 index 47e293d..0000000 --- a/frozen_deps/mnemonic/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .mnemonic import Mnemonic # noqa: F401 diff --git a/frozen_deps/pycryptodomex-3.9.9.dist-info/AUTHORS.rst b/frozen_deps/pycryptodomex-3.9.9.dist-info/AUTHORS.rst deleted file mode 100644 index bdafc82..0000000 --- a/frozen_deps/pycryptodomex-3.9.9.dist-info/AUTHORS.rst +++ /dev/null @@ -1,49 +0,0 @@ -Simon Arneaud -Nevins Bartolomeo -Thorsten E. Behrens -Tim Berners-Lee -Frédéric Bertolus -Ian Bicking -Joris Bontje -Antoon Bosselaers -Andrea Bottoni -Jean-Paul Calderone -Sergey Chernov -Geremy Condra -Jan Dittberner -Andrew Eland -Philippe Frycia -Peter Gutmann -Hirendra Hindocha -Nikhil Jhingan -Sebastian Kayser -Ryan Kelly -Andrew M. Kuchling -Piers Lauder -Legrandin -M.-A. Lemburg -Wim Lewis -Darsey C. Litzenberger -Richard Mitchell -Mark Moraes -Lim Chee Siang -Bryan Olson -Wallace Owen -Colin Plumb -Robey Pointer -Lorenz Quack -Sebastian Ramacher -Jeethu Rao -James P. Rutledge -Matt Schreiner -Peter Simmons -Janne Snabb -Tom St. Denis -Anders Sundman -Paul Swartz -Fabrizio Tarizzo -Kevin M. Turner -Barry A. Warsaw -Eric Young -Hannes van Niekerk -Stefan Seering diff --git a/frozen_deps/pycryptodomex-3.9.9.dist-info/INSTALLER b/frozen_deps/pycryptodomex-3.9.9.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/frozen_deps/pycryptodomex-3.9.9.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/frozen_deps/pycryptodomex-3.9.9.dist-info/LICENSE.rst b/frozen_deps/pycryptodomex-3.9.9.dist-info/LICENSE.rst deleted file mode 100644 index 23f8f33..0000000 --- a/frozen_deps/pycryptodomex-3.9.9.dist-info/LICENSE.rst +++ /dev/null @@ -1,274 +0,0 @@ -The source code in PyCryptodome is partially in the public domain -and partially released under the BSD 2-Clause license. - -In either case, there are minimal if no restrictions on the redistribution, -modification and usage of the software. - -Public domain -============= - -All code originating from PyCrypto is free and unencumbered software -released into the public domain. - -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. - -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - -For more information, please refer to <http://unlicense.org> - -BSD license -=========== - -All direct contributions to PyCryptodome are released under the following -license. The copyright of each piece belongs to the respective author. - -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. - -OCB license -=========== - -The OCB cipher mode is patented in the US under patent numbers 7,949,129 and -8,321,675. The directory Doc/ocb contains three free licenses for implementors -and users. As a general statement, OCB can be freely used for software not meant -for military purposes. Contact your attorney for further information. - -Apache 2.0 license (Wycheproof) -=============================== - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/frozen_deps/pycryptodomex-3.9.9.dist-info/METADATA b/frozen_deps/pycryptodomex-3.9.9.dist-info/METADATA deleted file mode 100644 index c519e01..0000000 --- a/frozen_deps/pycryptodomex-3.9.9.dist-info/METADATA +++ /dev/null @@ -1,84 +0,0 @@ -Metadata-Version: 2.1 -Name: pycryptodomex -Version: 3.9.9 -Summary: Cryptographic library for Python -Home-page: https://www.pycryptodome.org -Author: Helder Eijs -Author-email: helderijs@gmail.com -License: BSD, Public Domain, Apache -Project-URL: Source, https://github.com/Legrandin/pycryptodome/ -Platform: Posix; MacOS X; Windows -Classifier: Development Status :: 5 - Production/Stable -Classifier: License :: OSI Approved :: BSD License -Classifier: License :: OSI Approved :: Apache Software License -Classifier: License :: Public Domain -Classifier: Intended Audience :: Developers -Classifier: Operating System :: Unix -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Topic :: Security :: Cryptography -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 -Classifier: Programming Language :: Python :: 3.8 -Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* - - -PyCryptodome -============ - -PyCryptodome is a self-contained Python package of low-level -cryptographic primitives. - -It supports Python 2.6 and 2.7, Python 3.4 and newer, and PyPy. - -You can install it with:: - - pip install pycryptodomex - -All modules are installed under the ``Cryptodome`` package. - -Check the pycryptodome_ project for the equivalent library that -works under the ``Crypto`` package. - -PyCryptodome is a fork of PyCrypto. It brings several enhancements -with respect to the last official version of PyCrypto (2.6.1), -for instance: - -* Authenticated encryption modes (GCM, CCM, EAX, SIV, OCB) -* Accelerated AES on Intel platforms via AES-NI -* First class support for PyPy -* Elliptic curves cryptography (NIST P-256, P-384 and P-521 curves only) -* Better and more compact API (`nonce` and `iv` attributes for ciphers, - automatic generation of random nonces and IVs, simplified CTR cipher mode, - and more) -* SHA-3 (including SHAKE XOFs) and BLAKE2 hash algorithms -* Salsa20 and ChaCha20 stream ciphers -* scrypt and HKDF -* Deterministic (EC)DSA -* Password-protected PKCS#8 key containers -* Shamir's Secret Sharing scheme -* Random numbers get sourced directly from the OS (and not from a CSPRNG in userspace) -* Simplified install process, including better support for Windows -* Cleaner RSA and DSA key generation (largely based on FIPS 186-4) -* Major clean ups and simplification of the code base - -PyCryptodome is not a wrapper to a separate C library like *OpenSSL*. -To the largest possible extent, algorithms are implemented in pure Python. -Only the pieces that are extremely critical to performance (e.g. block ciphers) -are implemented as C extensions. - -For more information, see the `homepage`_. - -All the code can be downloaded from `GitHub`_. - -.. _pycryptodome: https://pypi.python.org/pypi/pycryptodome -.. _`homepage`: http://www.pycryptodome.org -.. _GitHub: https://github.com/Legrandin/pycryptodome - - diff --git a/frozen_deps/pycryptodomex-3.9.9.dist-info/RECORD b/frozen_deps/pycryptodomex-3.9.9.dist-info/RECORD deleted file mode 100644 index 6cea692..0000000 --- a/frozen_deps/pycryptodomex-3.9.9.dist-info/RECORD +++ /dev/null @@ -1,794 +0,0 @@ -Cryptodome/Cipher/AES.py,sha256=fbD_h8DbAF4NsFKrbhKz5sMFnqKYUza0XqT4k9f1SpE,9569
-Cryptodome/Cipher/AES.pyi,sha256=3ahEn43wmFv37xdmnlibzjWOmRAgSSeiFToFMIoLVUk,1387
-Cryptodome/Cipher/ARC2.py,sha256=NwO42KWBpuTXS5Thx0gsDRmxyrvfiudx7PKed1KR0CI,7026
-Cryptodome/Cipher/ARC2.pyi,sha256=zgMfUY35w1AuEi0apkFuHo_NQOfzsCxuZ9gN1s3oAhg,982
-Cryptodome/Cipher/ARC4.py,sha256=x_8L_KA_pDkoeIOSCQZyVPwhD3na4-xShkPkeNRka58,5168
-Cryptodome/Cipher/ARC4.pyi,sha256=sMw73yZHeonmGx9BhiyA7__4PQJocU04SMRcDjnyJ2Y,431
-Cryptodome/Cipher/Blowfish.py,sha256=K5hF6nb2r8FsHhgLX2irdyUMqg4PCwrAgu68NNhU1ag,5976
-Cryptodome/Cipher/Blowfish.pyi,sha256=kDooazMxY1973SMtPuhNJ9f68PS4cNWynyYa7CoWC48,1018
-Cryptodome/Cipher/CAST.py,sha256=3XDjtVBsia2kPvducB19_FEc3zM7hSK8JKKmK-b8cvU,6087
-Cryptodome/Cipher/CAST.pyi,sha256=XgVk9wOv_V77LbQmm24O2R-PDss8JiHfw11karavKCI,983
-Cryptodome/Cipher/ChaCha20.py,sha256=u7YX0kO9MBwV7Ibt_Dbyz_pHq-TG5POxoRnNOGy9ZPs,10754
-Cryptodome/Cipher/ChaCha20.pyi,sha256=_l1xhtOyBmYEHP7Ftmk8EQZpKegX9p3N5tckC_PPve0,762
-Cryptodome/Cipher/ChaCha20_Poly1305.py,sha256=W0tOmBkoNzfwtwgPG9Tw0dUm3sZ8IVhnehTbAc2jRt4,11561
-Cryptodome/Cipher/ChaCha20_Poly1305.pyi,sha256=h1U5ixODzM9NwLpX9oaIJdeQ0ubYeDeY9m6ur05dKCc,1068
-Cryptodome/Cipher/DES.py,sha256=ebgHOqNGjCYlIoFh3W5KXY17aQnvckjhQC9TPEKqPuY,5963
-Cryptodome/Cipher/DES.pyi,sha256=thNZATxZ0Q-vOh_V7QVZu6J_ESvr9mcA67WlQV_nP1A,963
-Cryptodome/Cipher/DES3.py,sha256=qmIagOLhMGG221sC7BAH9xe5lnxk2iyilbeYoC3it4c,6941
-Cryptodome/Cipher/DES3.pyi,sha256=arv4Uhv7lSgAL36B_Vx5DL-s_18Kc9_TejNxftMp4H4,1033
-Cryptodome/Cipher/PKCS1_OAEP.py,sha256=GtxJWWSmK5PCIc1xFZDkMucGmPrioWBRB3M3T_VeVDY,8880
-Cryptodome/Cipher/PKCS1_OAEP.pyi,sha256=XRZ5_0v8w2LUYD04Gz3Ekey9PxYBZJnUl-0rVv2q_gY,1183
-Cryptodome/Cipher/PKCS1_v1_5.py,sha256=IeTKcgsUJSYzct2EzvL0cPg4d2F7SjUMGjTQ4HjxnUc,7979
-Cryptodome/Cipher/PKCS1_v1_5.pyi,sha256=XzzxTLrPfBUqROLd-hhDua4w6YrzI7xjLmHrQN__Xck,571
-Cryptodome/Cipher/Salsa20.py,sha256=SuzaYhBc_Q7voODDmQ2rCzILndPpmF1n6qitDMmk7no,6369
-Cryptodome/Cipher/Salsa20.pyi,sha256=4vjq_HN8NK7U9VdaaHIgs17-fyW8SRPDZaHy3jKVkto,744
-Cryptodome/Cipher/_ARC4.cpython-38-x86_64-linux-gnu.so,sha256=bFvUKemyW2bXoEsC2HdV35dgQgtR8S7m6eLRNhAXSi4,14354
-Cryptodome/Cipher/_EKSBlowfish.py,sha256=fi6TEeN0bXcznFkyLzsaoLxNmu9iPT-Tmp3CLvJsE0A,5217
-Cryptodome/Cipher/_EKSBlowfish.pyi,sha256=6JhAXsSVbJMYlcudpNwSNEDB9X5NjhfRGPzZvcOc_As,270
-Cryptodome/Cipher/_Salsa20.cpython-38-x86_64-linux-gnu.so,sha256=LyVUPFhUIQoJx0QaXx0FkwZC0nmZGILsrE3uoTXsIw0,21734
-Cryptodome/Cipher/__init__.py,sha256=Cdau3A_ZsmqOFM8yK4Q2C_hFeV2xjd9_fU812_ferXM,2888
-Cryptodome/Cipher/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-Cryptodome/Cipher/__pycache__/AES.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/ARC2.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/ARC4.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/Blowfish.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/CAST.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/ChaCha20.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/ChaCha20_Poly1305.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/DES.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/DES3.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/PKCS1_OAEP.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/PKCS1_v1_5.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/Salsa20.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_EKSBlowfish.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_cbc.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_ccm.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_cfb.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_ctr.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_eax.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_ecb.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_gcm.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_ocb.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_ofb.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_openpgp.cpython-38.pyc,,
-Cryptodome/Cipher/__pycache__/_mode_siv.cpython-38.pyc,,
-Cryptodome/Cipher/_chacha20.cpython-38-x86_64-linux-gnu.so,sha256=xCnihlEf-dEc4-Zq5sOpUBcuHEcYfhw58nJLvkt_n_o,25741
-Cryptodome/Cipher/_mode_cbc.py,sha256=cDaa-zgNIbosLHJhwsDtt7YOTE-jzRUi4ODfj95SBsM,10971
-Cryptodome/Cipher/_mode_cbc.pyi,sha256=qH5pEQNuefabeRV-Xz-6AA953MFd_Z20zGeBTwa6t0s,691
-Cryptodome/Cipher/_mode_ccm.py,sha256=zqq91jARvmdPXs58u0uCP-D8ctzsg65Lf8nW9VQYezs,24476
-Cryptodome/Cipher/_mode_ccm.pyi,sha256=ZSs4SOlivIG_JUxknDjQKs4ZYGmkwAO7K2DKcbz_14M,1600
-Cryptodome/Cipher/_mode_cfb.py,sha256=lfIeHxJmyqmBWk84d4z9030OooTSBX1gfaVIaRqIPyE,10821
-Cryptodome/Cipher/_mode_cfb.pyi,sha256=PM0slBBfWdA4Ec0JjM-OJheiZkCFPWAADvLsvKpDRCY,731
-Cryptodome/Cipher/_mode_ctr.py,sha256=PFiqbWjboWaeLv0M0GnE4o8_vv6h7Aedv5cNq51VNlU,15920
-Cryptodome/Cipher/_mode_ctr.pyi,sha256=UcZ1zOZlVnTSlka9R1yFo7kaDhreiLKCe7AU05AcAuI,804
-Cryptodome/Cipher/_mode_eax.py,sha256=XXOc-GKbZ2hRagr5I5FihKWaGh8hXP1Si2kY3D85-ls,14543
-Cryptodome/Cipher/_mode_eax.pyi,sha256=VHPtTdA-2btCvRE-4npRtGCrApg7rBNWpHSZV1po8J0,1545
-Cryptodome/Cipher/_mode_ecb.py,sha256=h81F3mNQc08dVr__iP3_41ixeul00OsDw9mCI_Bh7I8,8222
-Cryptodome/Cipher/_mode_ecb.pyi,sha256=PgzUPsVY2DRM72wM-h74vCiceNF_yeaBxOA6bt_ZfmA,596
-Cryptodome/Cipher/_mode_gcm.py,sha256=oAOWTQ1qynOv7BfuueXokEF1TghERzKOXEgHKMj50wg,21402
-Cryptodome/Cipher/_mode_gcm.pyi,sha256=5t72QHQS0gDq6wtzYfaVqTxmjBzpUvsQvDaP2DqNvLE,1541
-Cryptodome/Cipher/_mode_ocb.py,sha256=QeHiPunUGWKt4iG8A50xgWV9b3C7qW0uwJPRcta5bC8,19838
-Cryptodome/Cipher/_mode_ocb.pyi,sha256=SXMUa1s1dY-272lktxSOtyOoqLdtPvfNkRXqmXjBE4o,1231
-Cryptodome/Cipher/_mode_ofb.py,sha256=sXdbumASGN-K7ps89z7c-knnMnnYtuO97X7y-VYZvyA,10301
-Cryptodome/Cipher/_mode_ofb.pyi,sha256=mPIZ2e_X-URk-8LBNiZyacfcS3Ei1vgT8YlhyI-0C8k,695
-Cryptodome/Cipher/_mode_openpgp.py,sha256=whIc90qioqxMiL2RCys5-XwfDntDneVYJx4Br6X3zD4,7061
-Cryptodome/Cipher/_mode_openpgp.pyi,sha256=FoLrFqnvxJf0F_npHOgPURfUyGSt6DxyIp2ikoXi-CI,556
-Cryptodome/Cipher/_mode_siv.py,sha256=nRqGJBjqxmKikUpVBLgMN3TGwg2f3boCNtUtGcn9uEU,14094
-Cryptodome/Cipher/_mode_siv.pyi,sha256=syb3kXnyuhoQV6FXvozIjudWCQBCadOb1I2BuV-6Ai0,1261
-Cryptodome/Cipher/_raw_aes.cpython-38-x86_64-linux-gnu.so,sha256=XItknsf2UUYW6JTafj9EiURNPq87iPbpU7MZsxstgvM,54112
-Cryptodome/Cipher/_raw_aesni.cpython-38-x86_64-linux-gnu.so,sha256=9SThqIhzfGdPQ_KGthp7Zf6_HwJ37LKk69bXn1miAlI,52331
-Cryptodome/Cipher/_raw_arc2.cpython-38-x86_64-linux-gnu.so,sha256=P_bLzcdq-ErD_QIP554zqCsKh5T4j6tag0Nr8B-9TOQ,18917
-Cryptodome/Cipher/_raw_blowfish.cpython-38-x86_64-linux-gnu.so,sha256=qpJcyzPSThz-wLRFqvzllniT56b7srYSSJVXFpVpxI8,26938
-Cryptodome/Cipher/_raw_cast.cpython-38-x86_64-linux-gnu.so,sha256=GKXmI8Brnf70GZO4Ewcsfaod5W7C4lGOomlHD8AxoD0,44422
-Cryptodome/Cipher/_raw_cbc.cpython-38-x86_64-linux-gnu.so,sha256=djug00p4Co5fTF90S4DloDEmnOHx94K0aFE57DCb1n0,17215
-Cryptodome/Cipher/_raw_cfb.cpython-38-x86_64-linux-gnu.so,sha256=IH-UyapBP38NwDAGVlG7zU1aVaYG05NFGRp_8z9ZYCQ,22696
-Cryptodome/Cipher/_raw_ctr.cpython-38-x86_64-linux-gnu.so,sha256=MBDwyhkt0HsQFCGnyb-aD5y_YRn78gY02Eik1Dite44,23249
-Cryptodome/Cipher/_raw_des.cpython-38-x86_64-linux-gnu.so,sha256=8RP468xPFfr5eTZHWvuAuft4MIk-BGQ61u4h82b6nZw,62525
-Cryptodome/Cipher/_raw_des3.cpython-38-x86_64-linux-gnu.so,sha256=gVRpZJLUtQJ2FZypbVn-v4vFi6JLT1nQsiERbLT4xK0,63370
-Cryptodome/Cipher/_raw_ecb.cpython-38-x86_64-linux-gnu.so,sha256=DWruIGvT5Yibn7gNdmoCf05Ug03nRkmtSZI5WlG2MRE,10893
-Cryptodome/Cipher/_raw_eksblowfish.cpython-38-x86_64-linux-gnu.so,sha256=0P3HCyU6I1CQoQpqIH37qOVpTzvzAIkglPiM7SpDHyc,58926
-Cryptodome/Cipher/_raw_ocb.cpython-38-x86_64-linux-gnu.so,sha256=SGNBSgyJzNmKRDzt_qxUvQxxwAPRpRTS_HRjqZLv1_8,30281
-Cryptodome/Cipher/_raw_ofb.cpython-38-x86_64-linux-gnu.so,sha256=YjayUPJO7GrvYEn_zHCyA87uDH4hlIvr8XwLX8qiqbE,14743
-Cryptodome/Hash/BLAKE2b.py,sha256=WEV8u2cm18T_j9BwjCDPaSJ6AappqpwO1u7mHG6Sgnk,9440
-Cryptodome/Hash/BLAKE2b.pyi,sha256=9FsubGLHkCf6aPA5xZGVSop8WY4yLCWi3Vq53cGiSNo,877
-Cryptodome/Hash/BLAKE2s.py,sha256=uBxYbWDZleCmsOvSEmVRXPywTS2TM-qq3oyN4FJp68c,9446
-Cryptodome/Hash/BLAKE2s.pyi,sha256=9jsL4jLQq5_Mb8WM99LPurH1D-FL-gLAeZyBf8QiWt0,739
-Cryptodome/Hash/CMAC.py,sha256=06Hyo7r7XAgklKXWp7tttTiZFqKRTGINigxkEgWh6WY,10448
-Cryptodome/Hash/CMAC.pyi,sha256=8gybenApjooarPbVIWZohcOruj0tMyZuW5gJvrK_Vag,797
-Cryptodome/Hash/HMAC.py,sha256=pp450gCQNmw4vUfrQAJyDZ_h1ovwd-8wLvoyqd9t5hU,7062
-Cryptodome/Hash/HMAC.pyi,sha256=fAyHBEf5Ee6LoiYYTZ9PZpmIRvitU6OriKGfjFUM_4c,624
-Cryptodome/Hash/MD2.py,sha256=mfucNRXYIj8iOXGKEXGN4TIwyHHhIglb2ScSowyg5tc,6123
-Cryptodome/Hash/MD2.pyi,sha256=wa7GSYUpzL27so4YgiJEZo0dO201KyHK87Q20Pvm-bM,492
-Cryptodome/Hash/MD4.py,sha256=FSGY7k8rYayR6PE0hNpICRTa1uNiISVxixIpaC28zzg,6598
-Cryptodome/Hash/MD4.pyi,sha256=7ZtZQEgJCwIswneb0NBov_uL0_Toglh9EPMnLVFGqwo,532
-Cryptodome/Hash/MD5.py,sha256=Cd5wtZ4OBW-O7tvebvObsay_jI6tRtoUfIfkbE0aqMQ,6630
-Cryptodome/Hash/MD5.pyi,sha256=c4MCJHvYTi2YL4hmqEu9ivbSvkBJdR-S2ldUqEpzK8s,492
-Cryptodome/Hash/Poly1305.py,sha256=xESe_sBaJg7jBJE88_S3jWU0uIu8l18NaQjmol_uIeA,8106
-Cryptodome/Hash/Poly1305.pyi,sha256=TSGottirLPIRyivSjZucQB7aPaYfhrUkn8oot6OrmmU,665
-Cryptodome/Hash/RIPEMD.py,sha256=0oRaGuKcTUVTfBZXZm5NZLQAvyPbAhjBpgzN5Kf2a6g,1211
-Cryptodome/Hash/RIPEMD.pyi,sha256=-DzZk9OtiAZE-E2_PCyFz4pHQ3RouoLlUo3Neabf3Sc,98
-Cryptodome/Hash/RIPEMD160.py,sha256=GYDiBSw_D7SCOPA80i3l3mjZsPvmmhZSVVENKwkUs_k,6410
-Cryptodome/Hash/RIPEMD160.pyi,sha256=RQ9yXxjH1BSaU3mwhsCn9-67C0a_Bcv3MDdafQCiuPs,516
-Cryptodome/Hash/SHA.py,sha256=1-O3GFKbm1ht2jV7M9pdKu6GpACsCSnARPHllFcFTAo,1156
-Cryptodome/Hash/SHA.pyi,sha256=RJHp4vuV_19StgE4qxlnIfDltgFjx-L9q6H0tjh-Rk0,169
-Cryptodome/Hash/SHA1.py,sha256=oyz9PdGgaVa90S6O1NPhe7OPq7AvDbJIsH6pICDpTN4,6702
-Cryptodome/Hash/SHA1.pyi,sha256=vNtB_b4MytJq8Io1xufdOO6VL-nMBcCnDPIgJQuNPCM,536
-Cryptodome/Hash/SHA224.py,sha256=RQ3ECOkVJsnh2a5fCPL7Aienpi22lcpsuRNUypkWfBs,6913
-Cryptodome/Hash/SHA224.pyi,sha256=8RsbyIwIfO8Fc_fpWw1MnFw04Z4n-qL0G01qCQZwvx8,544
-Cryptodome/Hash/SHA256.py,sha256=2fhVNPGKrifj49B0ExaxrMCubtDTcQiHarrzN0JPVUA,6909
-Cryptodome/Hash/SHA256.pyi,sha256=zndNEjv6DZOWaOpuoUKsA2hTi2J7-oJFgOQ10sSRnXE,612
-Cryptodome/Hash/SHA384.py,sha256=aDu5NdDbICyrSt2sj0N4fIWwGurEu08WYB5mMiqfW7g,6911
-Cryptodome/Hash/SHA384.pyi,sha256=KIWbD-lBbd7lvWgFquIqUAMaisovey0HV0Nmmq-pvOY,544
-Cryptodome/Hash/SHA3_224.py,sha256=eoXfnjBCNjCD8nNxE8-S4vR7XJZBY11Xf6Lk__fNzU8,5302
-Cryptodome/Hash/SHA3_224.pyi,sha256=Dv2Xk6o9Sm1kcUMeo8sbuuP32HqQhEo_dV9p8yAyc0k,504
-Cryptodome/Hash/SHA3_256.py,sha256=z9IiiZvVV_J3Fpbl8c7-mjDMB_q-5Hrdx1tZpNxLy4A,5302
-Cryptodome/Hash/SHA3_256.pyi,sha256=MLvrZYxvRJ0l9TiGq2axjs66_13px5XlUx_lugQTVxM,504
-Cryptodome/Hash/SHA3_384.py,sha256=dGiHZHjbeU-Ul7zjQnpGfQebLWjixnVAtK_kPMNxIFY,5302
-Cryptodome/Hash/SHA3_384.pyi,sha256=pciFn3aMYw23Y3MZhAbf-cqXuyHIlI27qAmDo-6VtJY,504
-Cryptodome/Hash/SHA3_512.py,sha256=etHVIzMn11RfjalnGPGHqE3G_7iXxwffrh3Gh7ja5fo,5304
-Cryptodome/Hash/SHA3_512.pyi,sha256=HxxfMXlsnZ42ZQ_2YxWZU7aBdGhDPEtAT4EIF77kRzU,504
-Cryptodome/Hash/SHA512.py,sha256=rmSnd1Rka2NCImO0e-suLbzAF9EEXrY1ipnnS8RlG-Q,7732
-Cryptodome/Hash/SHA512.pyi,sha256=VfMzHx-0U4efCyZCrgs_aOz17W8t0ZHL_3uR8zaYzCU,622
-Cryptodome/Hash/SHAKE128.py,sha256=wNVbtzVBie6jczEfjiGjtRflEPEeYWji8CgHK5oak5c,4656
-Cryptodome/Hash/SHAKE128.pyi,sha256=wLhV8lh8YYWzi7PkhAB3_JQn_hOZNvkiZYg-JjiPpfs,437
-Cryptodome/Hash/SHAKE256.py,sha256=dBCwFGVqbythJH6Zy7tGVgtZKo5WCXFP9LVZICEvHjg,4656
-Cryptodome/Hash/SHAKE256.pyi,sha256=9Uq_FaeYwDx_6dLv331Wv1snnGxA2UhFcUdELHkwU9U,437
-Cryptodome/Hash/_BLAKE2b.cpython-38-x86_64-linux-gnu.so,sha256=TszE3R0aDpiryAo6AYj6sOyeUCuOV1O_qoWGSxUIOW8,20015
-Cryptodome/Hash/_BLAKE2s.cpython-38-x86_64-linux-gnu.so,sha256=5IuREhBw3LMMax7ws8i3xNwUf9hRhiviNgYsqu1JMFY,20807
-Cryptodome/Hash/_MD2.cpython-38-x86_64-linux-gnu.so,sha256=6JKEXGjwn3jffmux4Syh3LY1gY1vjCF-pa2OE8dHyJE,16919
-Cryptodome/Hash/_MD4.cpython-38-x86_64-linux-gnu.so,sha256=J-t1w8Jf51EpWYC7DUJk22uBCVgdVl1yFgTntYg9Piw,19072
-Cryptodome/Hash/_MD5.cpython-38-x86_64-linux-gnu.so,sha256=-wohxwVJRlUgJoJgtrJdRs0DCtjT67AYObjbtcRjhqc,25434
-Cryptodome/Hash/_RIPEMD160.cpython-38-x86_64-linux-gnu.so,sha256=Xa2c7tVD_7Qn-Zqx5RoWhad9uXkwvtQDFkzGCQNt6cs,27226
-Cryptodome/Hash/_SHA1.cpython-38-x86_64-linux-gnu.so,sha256=xTMo-GOZ7R3XAGVtwYHh3eInH66rJE0erLkToaI24uY,84273
-Cryptodome/Hash/_SHA224.cpython-38-x86_64-linux-gnu.so,sha256=QrWYibmzohwXUyqhfrb7Eb62f0oMXEKAV7NCO-s7uUc,35822
-Cryptodome/Hash/_SHA256.cpython-38-x86_64-linux-gnu.so,sha256=GZg9EMGcEzxNzFddlDMUKih4zZJ8nEwpnWo4gfOk2io,35806
-Cryptodome/Hash/_SHA384.cpython-38-x86_64-linux-gnu.so,sha256=uAbYxVoN7kiMPGtm89lzSomGqeexJ1Vt91JaJCpMUWU,41869
-Cryptodome/Hash/_SHA512.cpython-38-x86_64-linux-gnu.so,sha256=ED19YH2nMlNTNGT5DyWRW1fD3R0ItQMY3qRDEckqtGM,41967
-Cryptodome/Hash/__init__.py,sha256=jxsjQHZzCkphA6DkKfV200k5U6ipBEXf2YI__PQua7s,1119
-Cryptodome/Hash/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-Cryptodome/Hash/__pycache__/BLAKE2b.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/BLAKE2s.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/CMAC.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/HMAC.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/MD2.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/MD4.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/MD5.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/Poly1305.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/RIPEMD.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/RIPEMD160.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA1.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA224.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA256.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA384.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA3_224.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA3_256.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA3_384.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA3_512.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHA512.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHAKE128.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/SHAKE256.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Hash/__pycache__/keccak.cpython-38.pyc,,
-Cryptodome/Hash/_ghash_clmul.cpython-38-x86_64-linux-gnu.so,sha256=jlP-qmQqsu7X0ujoJgm6Jrr7Fm56k4gx3f7I6QMmB00,34203
-Cryptodome/Hash/_ghash_portable.cpython-38-x86_64-linux-gnu.so,sha256=GOThQjY5Ahc4_kVcRAXMWzFKMf1uiKkbqbj_6DZ2dzs,18711
-Cryptodome/Hash/_keccak.cpython-38-x86_64-linux-gnu.so,sha256=F9ha1YMuXWPL9-HEhfyOOuGY6GOkoIyjHSxIh37h9Ig,26749
-Cryptodome/Hash/_poly1305.cpython-38-x86_64-linux-gnu.so,sha256=M0HF762RLGF4PmslwV16dqAp2p8jhLAnhEKg3F7qF0w,25921
-Cryptodome/Hash/keccak.py,sha256=a6uqDYaAveDMk73ZAK4q2D1GkzHyEmnOgE91Fi5BnsA,7118
-Cryptodome/Hash/keccak.pyi,sha256=pXAZaNfayZCXMxB7IDFr2F8Hi06_hwFB3GXjNzY7sBM,741
-Cryptodome/IO/PEM.py,sha256=TPPdUiCHLEauwRAIZ1Y0uxtIGzz5Vz5eF5EZsP3dGRc,6972
-Cryptodome/IO/PEM.pyi,sha256=a1G07RQtZvEtXHlybxdDcoTPM3nqMbdONNjzcz5HGtE,303
-Cryptodome/IO/PKCS8.py,sha256=z-WihBqgcebhhkkK6jcuXE3-4i34RCXJlqefF3qaOg0,8711
-Cryptodome/IO/PKCS8.pyi,sha256=VxlDc05DEKa1DJ6lGPMbyuFC8XHTjm-pvviw90phLpU,474
-Cryptodome/IO/_PBES.py,sha256=ZAoljR3_saaEGvNmv1Zjkcp-Up925t6lH0GHbPAzZP4,16352
-Cryptodome/IO/_PBES.pyi,sha256=QWJLbYh7ywy2wlRWnbUQG_hqlv6zfobF5o6FKh7reWA,489
-Cryptodome/IO/__init__.py,sha256=QUvnoDWlmuOGEjxXh_uXHMoSmoPi_nSeh-Et7MSofeg,1540
-Cryptodome/IO/__pycache__/PEM.cpython-38.pyc,,
-Cryptodome/IO/__pycache__/PKCS8.cpython-38.pyc,,
-Cryptodome/IO/__pycache__/_PBES.cpython-38.pyc,,
-Cryptodome/IO/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Math/Numbers.py,sha256=2fQR0NxDh4r8rxGGrIahadGXQ5ssQb2nNPuhC1O9S0Q,2042
-Cryptodome/Math/Numbers.pyi,sha256=DBEdhel2f5i097pHa5ZTccxyGf0rKfhXtJP4GiNbP_Q,88
-Cryptodome/Math/Primality.py,sha256=dElcPU2SbxTu3E5IGj_S18W4tEXMkI0AJNEz8Xd8f54,11352
-Cryptodome/Math/Primality.pyi,sha256=iXAY0gUmciIS_FvH5VJwhQfK-0tDmaH2vcDLHHFyxIE,823
-Cryptodome/Math/_IntegerBase.py,sha256=4fofn-eRAi5h_RTX4w44_fh-S_r36GISV2nbLtjUJ5w,10486
-Cryptodome/Math/_IntegerBase.pyi,sha256=8robOel28h7YCFIOEWhW-DtJE1GLzdowmDkWyUaWQR8,3417
-Cryptodome/Math/_IntegerCustom.py,sha256=viV3iZBDGkLLqsfBgY0ebmaAyXjTRdEKaMc5fi_J6x8,4016
-Cryptodome/Math/_IntegerCustom.pyi,sha256=s9UZigBEgUvHS4IOdt8jXhsZ33O9j19p7lieob1R-EY,135
-Cryptodome/Math/_IntegerGMP.py,sha256=kWG3VAWTzO1lJO0cpS5rk0Vb3ldplAHNpF3yu4ry69c,25317
-Cryptodome/Math/_IntegerGMP.pyi,sha256=UcJOGMYT1d-G0PjbC5ByShFl5oyorFR8h38fFt0uY9s,78
-Cryptodome/Math/_IntegerNative.py,sha256=j-v3xELayy7C0lOgOlDR4hyUDHc0TzUIguUBh1tJDn8,11076
-Cryptodome/Math/_IntegerNative.pyi,sha256=pZaN1xXnB8u7VfrMgp6jqi_jCaJ4x4t0Ecs7qZ_2x-4,81
-Cryptodome/Math/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-Cryptodome/Math/__pycache__/Numbers.cpython-38.pyc,,
-Cryptodome/Math/__pycache__/Primality.cpython-38.pyc,,
-Cryptodome/Math/__pycache__/_IntegerBase.cpython-38.pyc,,
-Cryptodome/Math/__pycache__/_IntegerCustom.cpython-38.pyc,,
-Cryptodome/Math/__pycache__/_IntegerGMP.cpython-38.pyc,,
-Cryptodome/Math/__pycache__/_IntegerNative.cpython-38.pyc,,
-Cryptodome/Math/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Math/_modexp.cpython-38-x86_64-linux-gnu.so,sha256=UjtwotV2UVN7d8J1re7ErZ75kvBvA1RFffcroyjmjJM,207274
-Cryptodome/Protocol/KDF.py,sha256=nmwDb1qTj5fHNSWZdLVwl_CyjlbOjM6rUDSl8wNLcUM,19897
-Cryptodome/Protocol/KDF.pyi,sha256=OfuAajDDJIDIny-zMuGsfhqCLZr4x8bZnV5Tonbg00E,1383
-Cryptodome/Protocol/SecretSharing.py,sha256=ZNw_YhVs4TYrJ7075g6WwaiiCJRRmy0fpT_LoEMV3Ww,8794
-Cryptodome/Protocol/SecretSharing.pyi,sha256=-lErV2RvaNPuOA0z4c44WmNSu9irCw_DDb7wPgCS2BY,798
-Cryptodome/Protocol/__init__.py,sha256=eXlh5nJVd6NoXfUjJ-mNGgm5oE8r6MYDBOIHXWdzTPw,1548
-Cryptodome/Protocol/__init__.pyi,sha256=RNdrwMgjt9b9LmckdRkaYYC4PCzNV-1Hi2T3B2MHgds,43
-Cryptodome/Protocol/__pycache__/KDF.cpython-38.pyc,,
-Cryptodome/Protocol/__pycache__/SecretSharing.cpython-38.pyc,,
-Cryptodome/Protocol/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Protocol/_scrypt.cpython-38-x86_64-linux-gnu.so,sha256=RAIsDgb0Bgzraim44UGmPeISIJH4VWDCEinZbDAfDg8,16510
-Cryptodome/PublicKey/DSA.py,sha256=r3Vo6fyCWAngyfI8hWsrOms9Srj_lvzIfoHcdlwFMCM,22363
-Cryptodome/PublicKey/DSA.pyi,sha256=Q4s-ZAx5xV8ue2lxfVhOtQQzYuawu3qhDz0O5ThoLdM,1353
-Cryptodome/PublicKey/ECC.py,sha256=62eaTeNl_6VcHjwyaA28vcjmWM-WEKMnFdq-3GOr8Lk,42053
-Cryptodome/PublicKey/ECC.pyi,sha256=KhDMYrqTioBcZa0FWeMdJelJWmN47M2KWfS7y78ILVw,2358
-Cryptodome/PublicKey/ElGamal.py,sha256=qe1JXZRLCnMQO8u892VZA80u92IBXnTq-rV0CcvMKa8,8631
-Cryptodome/PublicKey/ElGamal.pyi,sha256=-s3ty0v_o-8Rq8_nrYh32Vo6ihr8OaSWdc_H7_CVGCo,674
-Cryptodome/PublicKey/RSA.py,sha256=jn4L8zDEPRB1haBoVKikrgUb9cOl5Dg2fU2gYiGx7J0,28834
-Cryptodome/PublicKey/RSA.pyi,sha256=53HgZFdczCzVYl8hVQLay9RA0KqcVBGtyKG0u2r5S-8,1837
-Cryptodome/PublicKey/__init__.py,sha256=2yP0pjkXKBr0C0QA5xS8Jxd9nHz9VT5uoNIS59KC4Kw,3123
-Cryptodome/PublicKey/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-Cryptodome/PublicKey/__pycache__/DSA.cpython-38.pyc,,
-Cryptodome/PublicKey/__pycache__/ECC.cpython-38.pyc,,
-Cryptodome/PublicKey/__pycache__/ElGamal.cpython-38.pyc,,
-Cryptodome/PublicKey/__pycache__/RSA.cpython-38.pyc,,
-Cryptodome/PublicKey/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/PublicKey/__pycache__/_openssh.cpython-38.pyc,,
-Cryptodome/PublicKey/_ec_ws.cpython-38-x86_64-linux-gnu.so,sha256=FAVYikDHr6gC6vLsL4BE-v0mI0olLJ9GbxYXyB3APZ0,1000375
-Cryptodome/PublicKey/_openssh.py,sha256=t8Z8fOJDh64ZXmqpSCqlds-OKb2C5FncQmqCstfGImM,5146
-Cryptodome/PublicKey/_openssh.pyi,sha256=ywCy9UDu2_AQI60ChWxGxyqHiZoYwMKC3TVXJn_ZVIM,324
-Cryptodome/Random/__init__.py,sha256=EJnd9lTXo5ZFvmgrAzv2wHX8b87SNPO3sDGB3UofVe0,1813
-Cryptodome/Random/__init__.pyi,sha256=ieifhoMB2veKusRRBZWQp6igPri5027VrqfddO5b-WU,367
-Cryptodome/Random/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Random/__pycache__/random.cpython-38.pyc,,
-Cryptodome/Random/random.py,sha256=aWcD7vA4eWrRmjIkho-YGxbrVC3anFTzHa_N_7Sds64,5246
-Cryptodome/Random/random.pyi,sha256=Lgo1h6wtyUDhEuroDRyt-eYvPFEgQOo0fxfAE68S2cM,807
-Cryptodome/SelfTest/Cipher/__init__.py,sha256=nI0MW4-BVQHwCwYqgWxa7MhL9OxYmwYSIJcp5qe_n9Y,3708
-Cryptodome/SelfTest/Cipher/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/common.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_AES.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_ARC2.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_ARC4.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_Blowfish.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_CAST.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_CBC.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_CCM.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_CFB.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_CTR.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_ChaCha20_Poly1305.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_DES.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_DES3.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_EAX.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_GCM.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_OCB.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_OFB.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_OpenPGP.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_SIV.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_Salsa20.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_15.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/__pycache__/test_pkcs1_oaep.cpython-38.pyc,,
-Cryptodome/SelfTest/Cipher/common.py,sha256=HpeH9ouK2m5kcrfcb0vRSw2q1LehsuicQfGuT1jnclg,17016
-Cryptodome/SelfTest/Cipher/test_AES.py,sha256=PpAFYq6sGbzd-tFNi--37LLD-hI_A6KCw4J5DB5nlDo,71827
-Cryptodome/SelfTest/Cipher/test_ARC2.py,sha256=gOXQEu0PBG3vD7D_sT7y0AqfrXfAA4U-qsbArNOujBI,6550
-Cryptodome/SelfTest/Cipher/test_ARC4.py,sha256=5YgyIIhAn1_Ca5q3Sh2Cx1yLsQhrZK6t0aQdAVtdCdo,24749
-Cryptodome/SelfTest/Cipher/test_Blowfish.py,sha256=fC6tYqaKzCuo7gIqyenNsoxvS-hSyC8FAkqUIadrv_w,7318
-Cryptodome/SelfTest/Cipher/test_CAST.py,sha256=WjrbmsHybravO0qPALVVyBRskQTlRiemhsh-ud5MvxU,3367
-Cryptodome/SelfTest/Cipher/test_CBC.py,sha256=dr5yzeU-HaLlTFVaJeRjm59uZuJYjdQqFvFAPoWNSDg,20419
-Cryptodome/SelfTest/Cipher/test_CCM.py,sha256=FB0ElwRqrWNUlOmeNup21HC2MVCxRObrRzG_8UJ2WVw,38039
-Cryptodome/SelfTest/Cipher/test_CFB.py,sha256=WNkgDVTR1BacaVPnVDscddLFkfAUENfABdR6enu4CtM,16162
-Cryptodome/SelfTest/Cipher/test_CTR.py,sha256=X2d0y1ZktQd29BxgEmeiC86OIUGgVrl_41dOuxJyHX0,21402
-Cryptodome/SelfTest/Cipher/test_ChaCha20.py,sha256=0Aj4tJWSxW8Lbn5EbXk9PyNbTDB9zIOK4_a4k0-NBYQ,20017
-Cryptodome/SelfTest/Cipher/test_ChaCha20_Poly1305.py,sha256=pKisgjpYWUB6GE-Vj9U_wdWzNGArBIYTF0fXwvKhKXQ,31070
-Cryptodome/SelfTest/Cipher/test_DES.py,sha256=5nGk-NGJg4iap191mOJgiNpLgjZ38Qwq_5oktYz58cs,16027
-Cryptodome/SelfTest/Cipher/test_DES3.py,sha256=DnPIMMsAf2N-yl0j7JILr1GGvJNzAi3A4Qsi3P-3HE4,6724
-Cryptodome/SelfTest/Cipher/test_EAX.py,sha256=b-qiqzx_wpBUDaQ1cgybM5V_Eoh_dJte3TMn4-uFTpc,29491
-Cryptodome/SelfTest/Cipher/test_GCM.py,sha256=p-4TGNvjhCY2EZl1HrVpxU5X0o3cE4BYJP02u3x5-MM,38246
-Cryptodome/SelfTest/Cipher/test_OCB.py,sha256=-lvM3XRSouW29b1m3bhhno4TgKI9TUI2DKxBbfd1dCA,28406
-Cryptodome/SelfTest/Cipher/test_OFB.py,sha256=bKcBCLL39YIz8xr0YEGySWWJxxzQ6pgmRLZv2FxCxUo,9327
-Cryptodome/SelfTest/Cipher/test_OpenPGP.py,sha256=Q4rOCU0axh_z7U4MSUGda39nujktPlBUaqVVfE5kMhs,8497
-Cryptodome/SelfTest/Cipher/test_SIV.py,sha256=h_SPw8YaOZOQ4Bw7BCRms9K7qbfY5byDzLbisDLNtbA,21125
-Cryptodome/SelfTest/Cipher/test_Salsa20.py,sha256=1AuzeYLpnYhuzdqqbdkUguIpZlT7kbbpParNYF220QY,16767
-Cryptodome/SelfTest/Cipher/test_pkcs1_15.py,sha256=s_t7dHvCIKc-QobF8CJHZcRsb1Q4qRUslxEkih19ZVA,10594
-Cryptodome/SelfTest/Cipher/test_pkcs1_oaep.py,sha256=s8-2D2puFnmmUcbRkcXro8h1CE4cAhYO_8_rYjChwV0,22998
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCGFSbox128.rsp,sha256=jU0y_RjZc7Rae4Ra71JZdnuZjOVYRxAp1IGe4aYSabY,2787
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCGFSbox192.rsp,sha256=fjvAZvU59Szb-jHISNXS2eJwyxCNSfUUZtuj4EBBL3k,2609
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCGFSbox256.rsp,sha256=V9hpYePiv0Idf-261mYVpmHGtDFVA10iyd8R-x4dKpc,2367
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCKeySbox128.rsp,sha256=dbpmQvcgZvrPzNBCOxGnqCQuEKuKvLOZWP8ECuNw-V4,7990
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCKeySbox192.rsp,sha256=lr4vtlL_4gVhySVIlxg01kVY351NpTNfhutiXPLENYI,9874
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCKeySbox256.rsp,sha256=JELpUAjt036FZn87hQAiV4bwz3rXlHjR2ZStkB9sM4k,7154
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCMCT128.rsp,sha256=jk8YVL-7jYSPWGHPshIQTfYb1tEUKXiSYArqP7ovJ2Q,37376
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCMCT192.rsp,sha256=LTXLqH_ODWAW53y2Xe_bdALPxDjTOhMtyvAlvtN-9Gs,40576
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCMCT256.rsp,sha256=I7H3lzMhXUSCCp6MTV8y2GKwnyHkCng7DglNkVeVmL0,43776
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCMMT128.rsp,sha256=hgKmNyD7pJJbFBOF9ZC-8z4Q0qYcLJPX8wsLgIzLJ74,9654
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCMMT192.rsp,sha256=kxK_gWyWXZMpsixh-Nfz5zTpwORBDEvDdHh_Wys7bBI,9974
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCMMT256.rsp,sha256=vfQ3mslBnS4ejLIFaGEapETh8rTvfTuUOK-kNqlwBLc,10294
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCVarKey128.rsp,sha256=CG8rZuSGmdaCofMPCRv-RBlW8CymmSNf49_s_HBsr9E,47849
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCVarKey192.rsp,sha256=IK1mvGNLPgnAyNACs3RsXPItkRb4RKcm9ZYQPZkzn1M,77929
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCVarKey256.rsp,sha256=3AyzgBafQ6g8Sv-G7rFG1YYafgJHkIEG-Lb9N5Aul_g,112105
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCVarTxt128.rsp,sha256=NuIPk6FOKn_HyvD0eKbMUEMelNXn203qZkLFhDx4fd0,47849
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCVarTxt192.rsp,sha256=myc4SHgTQ_R0NslkNNBvxIemJm8ycws1mt0fvoPOX3M,51945
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CBCVarTxt256.rsp,sha256=E8WwhsZMgW5D_8ZXtgLP5qcjG-qCl-vJqWsJMtNR8VU,56041
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128GFSbox128.rsp,sha256=PetBa4V9l8tZucoVdmnTcG2yxGmXV5zggGAs6BjyJrM,2790
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128GFSbox192.rsp,sha256=4pLczu5j53_ZEJN3QbGtb9s1BPckiwM-B4Xy9FEmmfc,2612
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128GFSbox256.rsp,sha256=2U8vwvdS2yN5UPGAxKcHq7jHwFymgHfCGbNNyg5nshE,2370
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128KeySbox128.rsp,sha256=o87VaOGVb2A0vBEzf8wxTcgBKdJ7qyv5aTNDJrdbgSk,7993
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128KeySbox192.rsp,sha256=aOrrWPE21kdquhb2-NF7BV__wJh2VfWXyZ2yEoezwGI,9877
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128KeySbox256.rsp,sha256=PM1Kl9FkTLqkBPAXKuk_0hjbi-ktnL21YZ6UZJ4oaKQ,7157
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128MCT128.rsp,sha256=qssStFCa3Xi9-x0RB3Y4hQUXqw1vAwXnH-cc8vuQonI,37379
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128MCT192.rsp,sha256=uvFr2372lGeK9DD4S1ulwwqAXusEkc3Aok7Zbu6-WME,40579
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128MCT256.rsp,sha256=ptLz5OsPykXQx_j4_BxRX1OWRxKbRsdfvGFG0hi6uBo,43779
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128MMT128.rsp,sha256=QysTd7nANa2-aYZZtjeSnvqjfkmsiBasoMN1FqmsRQw,9657
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128MMT192.rsp,sha256=SCubxxY-Xz2uJCsD_N3Gm4PcH0f_Gfrj74Opar0mIJU,9977
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128MMT256.rsp,sha256=C2AkiXUSrDlMAxFKkaPxdDBQH0Codt4YDWAI4To_H34,10297
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128VarKey128.rsp,sha256=lMpe6dc1E2S1BTK1CSJubsXCNUcylc1Juyj0CjZX0v8,47852
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128VarKey192.rsp,sha256=JRwBrwNDy5npksDoi1UwjnL40vGWEeJG7cezM7Ep50w,77932
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128VarKey256.rsp,sha256=rfwz1yvXvU4DN2ZxNkPFE5wajQcREZbO76mvOo_GLsQ,112108
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128VarTxt128.rsp,sha256=UFUNsGaH5PAijmRJ3wli320O0u4smpQMvxKLaTr-aU4,47852
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128VarTxt192.rsp,sha256=a52sEs1Sn_A1CMD16vC-mHDAw_CD2dZcGJolAcFC46U,51948
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB128VarTxt256.rsp,sha256=_FRB9oN5Q-KyVVbNMsnLionMBYFVfx7CX_rSb9Lmg5o,56044
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8GFSbox128.rsp,sha256=hMQY14LzloH3lWaW5Wa_w_xrPmYC_4-mkt5zbjlSyY0,1948
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8GFSbox192.rsp,sha256=PINYd4KRk623-kA7c13ekEWrxbrhidZOTNQVWCZSw9M,1890
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8GFSbox256.rsp,sha256=VUbW4eab0v3SNO5BRdNcd6bGXxaZ4thkxOfq6S7Dw-U,1768
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8KeySbox128.rsp,sha256=lXccJkglpMet2HdG_hVxPHUA5T9ye7w3RNtXbROqz2Y,5471
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8KeySbox192.rsp,sha256=dde2y-QM22fXMMdRL6A8DIofghIZihRBxmC2w3HZMy0,6995
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8KeySbox256.rsp,sha256=41SLZ_y0h0qdyzfHWhYSkzu2e7SDes8nTzHvpvkdd40,5235
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8MCT128.rsp,sha256=D3yf9MGKx78BNoN4GkNnHFwco6enBlY_G0wf07FEPxc,25377
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8MCT192.rsp,sha256=MQumbDtwDZOOVY66sOODkLjiygHMwRF5iwDC1_7RpdM,28577
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8MCT256.rsp,sha256=DxHJ-AmB8z--Ly3Kt_inweIwUVECXWgBXvujaIbD5kY,31777
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8MMT128.rsp,sha256=lP20fsuv0fqhnbdWG-YiHiDp8tNPjdVuIRc3wiE20nE,3055
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8MMT192.rsp,sha256=sBqsFN3TMkQO7Zbl7I_n8sloD52zxeLgiq5zYH4Oyy8,3375
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8MMT256.rsp,sha256=4NOc6LASPWEnD-50boVm5MomaWhYTYbQhzLCPybGddo,3695
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8VarKey128.rsp,sha256=mvHAmSr092Z32a3kveZlNruin3zWe2tIQpqqfWTeXPI,32490
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8VarKey192.rsp,sha256=01L3kHeD-LqSfE--mpFjnGGkeenqOSas8s-I82Vfpw8,54890
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8VarKey256.rsp,sha256=6Aooiamd3pB-ZUOmrBcsCbaXwR7BI-i9QCM5tWY9r40,81386
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8VarTxt128.rsp,sha256=jrHzMizQegT39uay0-m_U_fCYRp2SXSNNb162zb4m9w,32490
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8VarTxt192.rsp,sha256=D3mN2TULDZ9UWIB5GfZo27SlYSUCCpN1pSCOpf9gQvA,36586
-Cryptodome/SelfTest/Cipher/test_vectors/AES/CFB8VarTxt256.rsp,sha256=PMX7Tm87AiMU17lrRB5SBlgUkfCQMurFhZ8U1gXd_DM,40682
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBGFSbox128.rsp,sha256=NqmhVuhGhk3KiDpdoLHj2aStP0mrQ8ltYMAWPf09V7w,2787
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBGFSbox192.rsp,sha256=i8YFQ_bSRpAARg3o0cypWgXVNg4LJQEpaT-MueuBi80,2609
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBGFSbox256.rsp,sha256=QQvrbGgDg13HR6sG9Y4NYJG9Fno1GiDhksD7WsbEnGI,2367
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBKeySbox128.rsp,sha256=zYZzoBHZJywm8-PXGkdh0M92lt69q1Xlez6pT36jXyM,7990
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBKeySbox192.rsp,sha256=LpaZlABRpjAHBI6Wb5FrgtYQCgYiqQJ5pA5LgoS6sv8,9874
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBKeySbox256.rsp,sha256=sJzuWVShDIACWoUw9ZKIfuPG4bBl9dqvZ0_nWV5Ykvg,7154
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBMCT128.rsp,sha256=AW0pmMOE2FdpcJOY0OUT6AluNbIJmY4ymqsTryRBj_E,37376
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBMCT192.rsp,sha256=hff1UxqKGO1wIP9SQ2g6OCWsoBdnivefOw0SrKkX-q4,40576
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBMCT256.rsp,sha256=8ixrgFsp_27dSKskpR0Omy9FE6nQw9Q3ZiwJwadbK_s,43776
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBMMT128.rsp,sha256=aEps11PAOdDX_p5pzR8IrK4oLaGal6NVHYTvimGheV0,9654
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBMMT192.rsp,sha256=UN9R1JN8LPSgp7m-YVbnwrxw5u6wu9_n39T5vQmleMY,9974
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBMMT256.rsp,sha256=ULROQmjB5MnVIhWgp2mY8hNbTzxZsw10EtMDPncNq40,10294
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBVarKey128.rsp,sha256=-wNByOr7EMG_6ZXa3usWmI7DE6SxaYhCJiZHQhrrMQY,47849
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBVarKey192.rsp,sha256=aAE8BEABWnKPgbvs2OtQCb5UAOLVoC3X8gDfZd4mw20,77929
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBVarKey256.rsp,sha256=2Pzwktz9Ff5i7lNCvHqjmD1pYDUCCjpsGoOBDfbhUeQ,112105
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBVarTxt128.rsp,sha256=Jowo6O7I1UKWPGQUBL6lPKOVbSQecaTv4eFJoihGrmA,47849
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBVarTxt192.rsp,sha256=DjaxbJUulI8uZ9Aw_N-f5OZijPScGK-1A62TbI19eag,51945
-Cryptodome/SelfTest/Cipher/test_vectors/AES/OFBVarTxt256.rsp,sha256=bupYeO4v-gv_bLKAgIV4CN6_J4odWn11xE7boL8Qjtc,56041
-Cryptodome/SelfTest/Cipher/test_vectors/AES/README.txt,sha256=60TZ8t3yT6VSsa8Em-WuA3U8b4YZxo5ZacUyGq6G890,360
-Cryptodome/SelfTest/Cipher/test_vectors/AES/gcmDecrypt128.rsp,sha256=DR-Y0Mnhdu3h8-hUhN0T3pLDQ2ypffN47DSB4EwZpzI,2748606
-Cryptodome/SelfTest/Cipher/test_vectors/AES/gcmEncryptExtIV128.rsp,sha256=MBViNvdosNgeWKPlvTvXnOKUz57wugqEz3uGnInr2f0,2930939
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/README.txt,sha256=hDeBnqtd185cf-MlzMsAUHtTQMTQA3AWXlRwieQu_NE,195
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCBCMMT2.rsp,sha256=w9zaXFSlBUkSgOd9EIv-uJjZMd5Kq4CCh1Mw39Ef5SI,6492
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCBCMMT3.rsp,sha256=01k6aw7y1P3YU1O1tMGJxfzU_hQTSv-cu-ZFLwUoO0I,6492
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCBCinvperm.rsp,sha256=_zs_hHhOHk8R0jqalJfZv5W9YLR0JZwouXlUNVb4D70,15890
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCBCpermop.rsp,sha256=Jo3PnThZZS_EbimNgAhLZ_885v2CYFgUSKrLzInKvpc,8020
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCBCsubtab.rsp,sha256=5900Cila5IOo5VpUDtrB8RDRtOIPWsrroTAGsc4oULM,4819
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCBCvarkey.rsp,sha256=2lA8JmREU52Vp9X5pJWQa6rLCMzGYnUDi5VG6Yr5CYA,13915
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCBCvartext.rsp,sha256=6qE0bIigNfJslrVQDGWZV7YkXBG3-hwOgjsuIhzyQrc,15900
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB64MMT2.rsp,sha256=TpBVhZUmX2C4sRoCDROvQDuQv5gVOk0aFxm1pp6bfA4,6494
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB64MMT3.rsp,sha256=mMwx1bCOtw0AcJrsYxrhmBycW4B3VaHvfgPGHrnpHKs,6494
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB64invperm.rsp,sha256=BVMb18Mm1Hin3tgHjnxrfPSb4P4Y2mvfh2B9V5Zy9Xc,15892
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB64permop.rsp,sha256=6ZwOKZ5Ej8ErjfZEnWOBT19WgTx5Uyq6j0bi1Qr6Vu8,8022
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB64subtab.rsp,sha256=RPLhWK13522rsiUgBnbgCk57_yDSEbqtXY1QZy8SRQA,4821
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB64varkey.rsp,sha256=whxavgBPUbeGwSAlDqy1wWgELMtQs9PQE0LUzFzcBsY,13917
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB64vartext.rsp,sha256=DCRrqKJ3cE7sPTd5Nov00szLB3UsZvhhIIlYyXClhjM,15902
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB8MMT2.rsp,sha256=BtKIJNMPMQiuTRUb2GVrFYPfeMkFvGUkpzfQcj9hmKo,3413
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB8MMT3.rsp,sha256=iR2pfe1o2D6uXaWhYIyI104EiwMoSh_xQvlACak2jdc,3413
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB8invperm.rsp,sha256=y1BhaDajhJK6sgi_WoCpivnunEcQz3s_YP6S0cx5cYY,12307
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB8permop.rsp,sha256=UunDHgTlkgu5SX-_rbwru7Cb14r71p_52mGgk1eA4Yg,6229
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB8subtab.rsp,sha256=Pz9gt4Yg56ZhpJaNdWIXm0rrEuFgRDVJE3BSRXRXB4I,3756
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB8varkey.rsp,sha256=OUnAab1XVxlUkcHR0hpZM4WzF4aLnkbPorYPs3LeLlk,10780
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TCFB8vartext.rsp,sha256=4qzDlfCrKSgqizeSaWSSCbdMXu7wWupnWYI2J9Zy0JM,12317
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TECBMMT2.rsp,sha256=iD7ZSuiJkln6dzwrs9CmSXt6nd-rkVK1dOQ7Yvuq-jM,6032
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TECBMMT3.rsp,sha256=4jD9aPnKbr9QvC6bBzzznaFXknd2ryXoUG2UyAXxVz4,6032
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TOFBMMT2.rsp,sha256=90ejMmcQJAAva5oDHZfVFtV8PfJwcCAJ-VZvrvdVP4M,6492
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TOFBMMT3.rsp,sha256=0C3349hXpEGwP8fryw8jAzo2yxlxHUloeMyALrFyxEg,6492
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TOFBinvperm.rsp,sha256=jhBskIqunOstw3z9ECnLPjY3le5CV3GkbsZimghIFik,15890
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TOFBpermop.rsp,sha256=9kwCTwvwrMICoK13_yYU9l8mJk_5N5_91bqMFm56aws,8020
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TOFBsubtab.rsp,sha256=sVfYcy66WOKFcT4vfy_ykavEt8fFP-5TzUNdR0gs5sY,4819
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TOFBvarkey.rsp,sha256=HmcozNR9lqGmiNcyI9QqAI3GasIQfkuWK6LmE52A2Ak,13915
-Cryptodome/SelfTest/Cipher/test_vectors/TDES/TOFBvartext.rsp,sha256=kkrk9qQzO-tzAH0YYR4QtyGQAfyiu_JQ8vIv0-KcvBg,15900
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/aead_aes_siv_cmac_test.json,sha256=pUC3FoitW8wK8OntE4DlwN7iquDH9BLRRf5uBta3kGI,405682
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/aes_ccm_test.json,sha256=zus5i_I7cLNlM2essEx__Ae4NrtPlJ3Wo3AwfTJbpQA,236978
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/aes_eax_test.json,sha256=iYDZEI3B_4j0OXdyfii49rIDQeaWpq-HKBC6J5WND_4,84816
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/aes_gcm_test.json,sha256=xj96NNX0m-Uvjy9aXEd1C0GK8wQmWGn3fNS6y44dL1E,133455
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/aes_siv_cmac_test.json,sha256=weGSoUbwEUmiIjpWUHs6y2XT0rVgxZFcGcxGwLKh4v0,177708
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/chacha20_poly1305_test.json,sha256=S17zmflWIUIn2lScioTZ0JdTjACj0THeV0ithQgQWuw,196184
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha1_mgf1sha1_test.json,sha256=k3KUn7gP3nLejBN_1jsVYlXKn-o2iQQzQ-pZZBFVkLo,35337
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha224_mgf1sha1_test.json,sha256=DB8sKJtW7C6MixB6xl-LGZqUTxGRBYyOFNUAAezkvp4,27669
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha224_mgf1sha224_test.json,sha256=gomskn7LU4tbT0n6z3CqDNgIuGrv_k31OzJcN3gG_e4,32722
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha256_mgf1sha1_test.json,sha256=qn09ZvlxI2FtRB1j6nkjht9PGLV3AuRyVrp9S9fMzbc,27647
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha256_mgf1sha256_test.json,sha256=BjZddqcYpQxuI1WDknKJIDrt8MRt-WUf4l2QqSbf7rU,36411
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha384_mgf1sha1_test.json,sha256=ou0E0xKYvocIgueLOXXGVJqvJm5WRsVoFjVJGE9UoDU,27583
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha384_mgf1sha384_test.json,sha256=ssgZNn8L633XaGD8mBL1lkk7HgZrMNKoY2VkHoUM5Zc,31284
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha512_mgf1sha1_test.json,sha256=pCZoGS3QUPDbRjs5-evo_Yp95r-RJBlZoA_Et8E8IKc,27517
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_2048_sha512_mgf1sha512_test.json,sha256=rof_1bNM5JD2FFAISphMxFD6upRpDo6MZnBNQmKI8y0,29546
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_3072_sha256_mgf1sha1_test.json,sha256=gd8cnYuJlqQP18DopU4aMaOOtp_MQslrdjBtkstmTr0,38507
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_3072_sha256_mgf1sha256_test.json,sha256=zY8aRXZ7ZiyDsuizeprFoRMN2Pmp9FrJzrtqH2vvtwo,49871
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_3072_sha512_mgf1sha1_test.json,sha256=2eh490VoYTgj0dtpM9aFIVrNvtH59sxDonPiQ3SZ60s,37409
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_3072_sha512_mgf1sha512_test.json,sha256=KEr7XjVuzjRdG1qfVjBWVGEdUhY2mg9zD6jf9Q8VPyw,40890
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_4096_sha256_mgf1sha1_test.json,sha256=WNIxqjFQnECM-q0FqGBHMU8UqXffYunrgDtWF3z1Yd8,48665
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_4096_sha256_mgf1sha256_test.json,sha256=W5PFMgMBr7LrftEMF41eUXtk5gOWYTaPdzy0r1y4McQ,63366
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_4096_sha512_mgf1sha1_test.json,sha256=-iuHeAw8VvKt0LGqa6dS16KVvOlbZIftcaKqpkDx1TI,47299
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_4096_sha512_mgf1sha512_test.json,sha256=MgaDMR-MzZxxcCpTuHkJNprvGsQV-gUOzVTDstNREy0,57400
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_oaep_misc_test.json,sha256=jMh3_BLOIzzV1QZUbWxe4mNwVkmHF302u6wJki3SITk,1262220
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_pkcs1_2048_test.json,sha256=UoeSkKnXl60751hJ_G7856k8YhkfMHNH2EAx5eFQsF0,292951
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_pkcs1_3072_test.json,sha256=2DTy-Osluiq2MqrzmAHqxACQ5HK1a2BMQGpXW2ZdP88,423258
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/rsa_pkcs1_4096_test.json,sha256=ZIMdsdGrwxFehQuFZCCKp40l3uZKH5WcvXUstDuxku0,551672
-Cryptodome/SelfTest/Cipher/test_vectors/wycheproof/xchacha20_poly1305_test.json,sha256=F4Kso6XhhcUv1Xa5aGfoEeJKV79II0u59xN0K1MDlOk,181687
-Cryptodome/SelfTest/Hash/__init__.py,sha256=um4TKfVp-bYbGRIbSdPzy2Tal_tEmREk0NiJkCTRwz4,3533
-Cryptodome/SelfTest/Hash/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/common.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_BLAKE2.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_CMAC.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_HMAC.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_MD2.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_MD4.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_MD5.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_Poly1305.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_RIPEMD160.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA1.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA224.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA256.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA384.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_224.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_256.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_384.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA3_512.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHA512.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_SHAKE.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/__pycache__/test_keccak.cpython-38.pyc,,
-Cryptodome/SelfTest/Hash/common.py,sha256=C2jFAjRERl6uCNr12bwRTTighWDRpNiyAbXVfc-iSl8,9964
-Cryptodome/SelfTest/Hash/test_BLAKE2.py,sha256=vpPxSXeaZGIo6iprJCASNjuz4pW8epk1gK3C0ygjgwA,14953
-Cryptodome/SelfTest/Hash/test_CMAC.py,sha256=tj7t9augqONo539ZaxxXuNGMShgPMSs3ZNDj4RJBGHs,13946
-Cryptodome/SelfTest/Hash/test_HMAC.py,sha256=S-oBHJeQ4M8xdSfuq1IjYQB3BVqADGwC4aXpoFAGBc8,13568
-Cryptodome/SelfTest/Hash/test_MD2.py,sha256=ElKzN0tL3U-0TeLVP0e7I8txskHXSA8Ys63aYjLW_BM,2336
-Cryptodome/SelfTest/Hash/test_MD4.py,sha256=9SFHZcbB3M2AhjYtK-Y9w0tWE_cdmeo2QrHvl3f9S4U,2359
-Cryptodome/SelfTest/Hash/test_MD5.py,sha256=Bj6C548u8dz0d-pGxg7JZlezPWuXfD_TBnj7QOJGtxw,3300
-Cryptodome/SelfTest/Hash/test_Poly1305.py,sha256=2_ZTIuatKcaI0ATBGQm0DicKnXMTUqdu1nC7g6rNg10,18406
-Cryptodome/SelfTest/Hash/test_RIPEMD160.py,sha256=V1q7YGF0xKe0DeXZhAmtc4hIbbDKhEpjkNfPsNkB-qE,2675
-Cryptodome/SelfTest/Hash/test_SHA1.py,sha256=CrQWc1iCeKmVauPe5KqrBS4kt2qE2Ocwf365BOThGPM,2960
-Cryptodome/SelfTest/Hash/test_SHA224.py,sha256=Dz7sRLuh-AJZXarIZ7Lza4ZUy9tNNT5pUSsAm5Q6Ax0,2541
-Cryptodome/SelfTest/Hash/test_SHA256.py,sha256=pmV4r5WojFZmtVWAIFAl1uO55GO7wMWXCdE_I2e87J0,3637
-Cryptodome/SelfTest/Hash/test_SHA384.py,sha256=6_hL7uoZdQYAEoC0gT2mYuZQuCELHe9ebxcFhQZd4BM,2722
-Cryptodome/SelfTest/Hash/test_SHA3_224.py,sha256=S3PBL2Jqiby-Fmrj8SfU9OHoIL6ggCkWT8wbBJ69kBo,2874
-Cryptodome/SelfTest/Hash/test_SHA3_256.py,sha256=gQIzg3vguubWE2m3Dg0GiKXrWU_0aEQUvYjO5HE_LjE,2875
-Cryptodome/SelfTest/Hash/test_SHA3_384.py,sha256=iKXhYtyaa85GiNJ5y0C97JSWy2JLAR88bwZEgt-jttY,2874
-Cryptodome/SelfTest/Hash/test_SHA3_512.py,sha256=Z05p5vkxaJFoaxuPtZuFJTZxMyqRfzIFPE3z9SuBZmY,2875
-Cryptodome/SelfTest/Hash/test_SHA512.py,sha256=dGVeICdKxE_4mmpgewgEjnqzxDU0_ZYr5qt4LKMIO9c,5302
-Cryptodome/SelfTest/Hash/test_SHAKE.py,sha256=e5J4G8UNR-h5_ucZL_iqr1GlyWUY0ILyvOgqmYiGz-0,4786
-Cryptodome/SelfTest/Hash/test_keccak.py,sha256=ZdxMKcZf5zTOjcguA2HBnreYFZYWUwKBlsvPqyw6v1E,9160
-Cryptodome/SelfTest/Hash/test_vectors/BLAKE2b/blake2b-test.txt,sha256=6DYRIlZ96-rzmjXAmmoGiEIsAQqnQpIWnJqbDM26AkY,135750
-Cryptodome/SelfTest/Hash/test_vectors/BLAKE2b/tv1.txt,sha256=_fgZKswUlDW4iyAtEb4h0XcjY0edq6M0CyfEE1g0ncQ,4741
-Cryptodome/SelfTest/Hash/test_vectors/BLAKE2b/tv2.txt,sha256=hejftkYHZ5waIFHWX_OacTNfVyfdIwWhuzF0lL1KKps,9060
-Cryptodome/SelfTest/Hash/test_vectors/BLAKE2s/blake2s-test.txt,sha256=nH7O_rr67tH8etckN_qAoRu6BTAi0Oa8EIvyNaVMijs,102983
-Cryptodome/SelfTest/Hash/test_vectors/BLAKE2s/tv1.txt,sha256=sO6d-SWvAMOwzjMuLNZR8K2eb7QLIzOBk6L7omqcg9k,1413
-Cryptodome/SelfTest/Hash/test_vectors/BLAKE2s/tv2.txt,sha256=v6M_7bwZO3a7V4KXowFt93wWHudF1M5A1_2BWHz4OcI,2564
-Cryptodome/SelfTest/Hash/test_vectors/SHA1/SHA1ShortMsg.rsp,sha256=vgmR3cU3KTLVWASxFxPJFA0QQ170sxagdz41Bu7HnNo,8735
-Cryptodome/SelfTest/Hash/test_vectors/SHA2/SHA512ShortMsg.rsp,sha256=5To2wDYJ5aPjzEtuEXpJnbeGTCPsglxs7JlQOkX0B2Q,36800
-Cryptodome/SelfTest/Hash/test_vectors/SHA2/SHA512_224ShortMsg.rsp,sha256=mxH7Jf8I2McI4JiiLQE8XTjAaNHjmOtXPSBVwFO__nU,27536
-Cryptodome/SelfTest/Hash/test_vectors/SHA2/SHA512_256ShortMsg.rsp,sha256=2NUAi3P5DLkqj41NmvdFgJzu9Hr0y-su4kXMaxU_UiM,28568
-Cryptodome/SelfTest/Hash/test_vectors/SHA3/ShortMsgKAT_SHA3-224.txt,sha256=1eLWO-0-QY5KJRsFVYuMsZxZJUqid5fQdoYf62TK0UU,86195
-Cryptodome/SelfTest/Hash/test_vectors/SHA3/ShortMsgKAT_SHA3-256.txt,sha256=RvFAFF5Dz74xTtmOI-6rlwdLm9g3q6ToCZCSdTwWjgA,88243
-Cryptodome/SelfTest/Hash/test_vectors/SHA3/ShortMsgKAT_SHA3-384.txt,sha256=iyqT-Rq0yO5R6eYMQnnlEynzNYvT1fMjEb1TetruOZw,96434
-Cryptodome/SelfTest/Hash/test_vectors/SHA3/ShortMsgKAT_SHA3-512.txt,sha256=pImzhhuDKlqdHvspZxdke4Ovym8Cgfdw-5gQtni4BTI,104627
-Cryptodome/SelfTest/Hash/test_vectors/SHA3/ShortMsgKAT_SHAKE128.txt,sha256=-GOrJL52VikLqOrNLo_dW6vAuoikrIwv_M8yE-cC20c,333928
-Cryptodome/SelfTest/Hash/test_vectors/SHA3/ShortMsgKAT_SHAKE256.txt,sha256=wRVs94lIiWRqphXKojGwqWxi_BjtbNOToZwvLuT0C_4,333928
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ExtremelyLongMsgKAT_224.txt,sha256=Z8BU0nZzRihAAARK2JV-gbZKBkeEPF1meRld4oOyJLU,316
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ExtremelyLongMsgKAT_256.txt,sha256=wDRraKgIR_Bb--u3qjgRDI_4JuDYY3k8CERjWlfXcO0,324
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ExtremelyLongMsgKAT_384.txt,sha256=J1aO_Asi6jHQkLvNqqQX0ct3IjlGSi_X2dKi886PhJw,356
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ExtremelyLongMsgKAT_512.txt,sha256=xCXigswYKQjijTOnSo6YfMKbWNu-p_RnR0-WKdR2zy0,388
-Cryptodome/SelfTest/Hash/test_vectors/keccak/LongMsgKAT_224.txt,sha256=ORAzRQYztzHLW1kiQcKViaDpOFDmxRWlVH55E57axYo,300741
-Cryptodome/SelfTest/Hash/test_vectors/keccak/LongMsgKAT_256.txt,sha256=0GA-RoRMyaobz-mZsxR0FAYaGJax0yDeCMo7AidY6JA,301261
-Cryptodome/SelfTest/Hash/test_vectors/keccak/LongMsgKAT_384.txt,sha256=lcfkQiEcCvCDWCAPxrLtAjVIVtqftH9iUohS38DMlDQ,303341
-Cryptodome/SelfTest/Hash/test_vectors/keccak/LongMsgKAT_512.txt,sha256=Z9a9BYUTLD92OdA2FR15LhIcqStLBnAAZSeJqf6dggo,305421
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ShortMsgKAT_224.txt,sha256=4GBcFh1vLSJXYo7p-TRHHnHvp43NgyPgXjV69KZolzA,85946
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ShortMsgKAT_256.txt,sha256=qo_vZ44ayILxErUnmTwnKwOBndsWRgk9ER9GDh2r2nY,87994
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ShortMsgKAT_384.txt,sha256=TmfukzxIOlEHEFfahvDDuOtrebZhSaGUcNggUv8_ywY,96186
-Cryptodome/SelfTest/Hash/test_vectors/keccak/ShortMsgKAT_512.txt,sha256=3-33JR9udHo5AELPPPFLu12Y4ltAjxkSa6HPgn3s0yI,104378
-Cryptodome/SelfTest/Hash/test_vectors/keccak/readme.txt,sha256=K1q35vq7h6S1aGqUPr8EcZKoJEjtaBgQlaQtya3v-6U,83
-Cryptodome/SelfTest/Hash/test_vectors/wycheproof/aes_cmac_test.json,sha256=4GQcX-EVpdpSANFyweVfnrUS0_qOhnwUFNZQFlBPQzk,90510
-Cryptodome/SelfTest/IO/__init__.py,sha256=62l-NkQk9WPrRYoDAbtWKMOc9LT5yAE6ENws7t7-uzU,2002
-Cryptodome/SelfTest/IO/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/IO/__pycache__/test_PBES.cpython-38.pyc,,
-Cryptodome/SelfTest/IO/__pycache__/test_PKCS8.cpython-38.pyc,,
-Cryptodome/SelfTest/IO/test_PBES.py,sha256=sCOtJYeUCsSYM1NRYpweWzlUgrrc8W4vSHLIdi2s_aE,3469
-Cryptodome/SelfTest/IO/test_PKCS8.py,sha256=RC8LDc5b-7056ZWgoJNMPxaRgN4J8UyzgvQNE7LfoU8,17574
-Cryptodome/SelfTest/Math/__init__.py,sha256=EkOt_fJnPR9-LS36rE0xm0j1nlj-I0Y9CPnQk1KO29E,2113
-Cryptodome/SelfTest/Math/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/Math/__pycache__/test_Numbers.cpython-38.pyc,,
-Cryptodome/SelfTest/Math/__pycache__/test_Primality.cpython-38.pyc,,
-Cryptodome/SelfTest/Math/__pycache__/test_modexp.cpython-38.pyc,,
-Cryptodome/SelfTest/Math/test_Numbers.py,sha256=AwPV2PIK_R51JgX5GxpYUVOxp2eZ1uzhcxvFPpzN3V8,29839
-Cryptodome/SelfTest/Math/test_Primality.py,sha256=0V_gzcBWyk1SFYEBcsEgYVaPfw3-UZtcWl0etV_bgvA,4901
-Cryptodome/SelfTest/Math/test_modexp.py,sha256=rsoK86G8jDUNPiVg5uu3c3S6XVN4wz9dl_ty0oajcwI,8135
-Cryptodome/SelfTest/Protocol/__init__.py,sha256=M2Sh9OvDVzEqup__hYYipuAqXvBwEHSooPPz4meBCyo,1763
-Cryptodome/SelfTest/Protocol/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/Protocol/__pycache__/test_KDF.cpython-38.pyc,,
-Cryptodome/SelfTest/Protocol/__pycache__/test_SecretSharing.cpython-38.pyc,,
-Cryptodome/SelfTest/Protocol/__pycache__/test_rfc1751.cpython-38.pyc,,
-Cryptodome/SelfTest/Protocol/test_KDF.py,sha256=qIDtlD4nJOHL0Rlg-2rAIw-PhBaR3Q96Vbn3kxzq0XI,34529
-Cryptodome/SelfTest/Protocol/test_SecretSharing.py,sha256=B64noTracARMA3qGIUmIuk5Ob-NYyIldndNK-KJVmkg,9701
-Cryptodome/SelfTest/Protocol/test_rfc1751.py,sha256=6QuxUUE-NP8_1tQNj9Macjtc540zk4j85Z7G1Nyy2cI,2220
-Cryptodome/SelfTest/Protocol/test_vectors/wycheproof/hkdf_sha1_test.json,sha256=O9w7X1BkMKkFTU_6LHA-NO1uMTMLKr0IgRSO4SlWCP0,80132
-Cryptodome/SelfTest/Protocol/test_vectors/wycheproof/hkdf_sha256_test.json,sha256=i0ExHY0YXUgtQ6TH9svR3lNezQ0ZHU_mhU_hpj0mf7Q,98622
-Cryptodome/SelfTest/Protocol/test_vectors/wycheproof/hkdf_sha384_test.json,sha256=iCNFhGsEfB3wwhKfOnKjzhBpfry4CaZIlAmg8maC9DA,122104
-Cryptodome/SelfTest/Protocol/test_vectors/wycheproof/hkdf_sha512_test.json,sha256=UzoAknq9V9ZtOoCB48e0C4VoQh4_yXesEH555P8ee-s,147385
-Cryptodome/SelfTest/PublicKey/__init__.py,sha256=aRQ22RfDcpSeNEKu98hfxITqQMIoSOCGwCG1XTQuzVo,2203
-Cryptodome/SelfTest/PublicKey/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/__pycache__/test_DSA.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/__pycache__/test_ECC.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/__pycache__/test_ElGamal.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/__pycache__/test_RSA.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/__pycache__/test_import_DSA.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/__pycache__/test_import_ECC.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/__pycache__/test_import_RSA.cpython-38.pyc,,
-Cryptodome/SelfTest/PublicKey/test_DSA.py,sha256=8V1xuY9LWsMLxFJUfbf0SkJYuy0F1mRIprozyn3kdXU,9552
-Cryptodome/SelfTest/PublicKey/test_ECC.py,sha256=aWwLootkojYrRI6cwttSD1SSYnCEGZ2QiG2uSmp8BX4,31788
-Cryptodome/SelfTest/PublicKey/test_ElGamal.py,sha256=FhcxH3ngmtbPezyLLS2g1JXUb6RreGTVfK6a8RT5y4Q,8671
-Cryptodome/SelfTest/PublicKey/test_RSA.py,sha256=_MlvOivZxIzWVARdyMYx6AKpbZnSYQ_0DfnGBlzNw3Q,12220
-Cryptodome/SelfTest/PublicKey/test_import_DSA.py,sha256=V20ehAYhf5WAcm5mBxurN9YM3Z58vAfTY-irdzE7A_Y,25492
-Cryptodome/SelfTest/PublicKey/test_import_ECC.py,sha256=0fbH06J9fkz1AErgv0uS7dUGSROOjSnxNWmpvyj5_Qg,50208
-Cryptodome/SelfTest/PublicKey/test_import_RSA.py,sha256=cWheO9zbXvoCrHsCticFCqHOmkqmuCyZQWwk2FHrq_c,23778
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256.txt,sha256=wYvstytkYlYw41vRkecS-zFU5jRFvqjck1_FslBiU9s,630
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private.der,sha256=7qlKORodBckn-NEiXjjhvdK33oj615HsiX2lCdn_HHY,121
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private.pem,sha256=yjB0KGJw7cK59wOGC9vav00Hua7O-4y4KmR-ZvfTIFo,227
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_ecparams.pem,sha256=UoWial9kzXR5-vqH-DiiStF9LQuR7HaWVEza1zO6oGM,302
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_enc_aes128.pem,sha256=0wkiqVsPBEzM0xudk3HJ41WKhYIp1XYb5EMid3HIhjk,314
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_enc_aes192.pem,sha256=TJKSWl5XvJu7ir-bBj_YNhqw1zrT2tJpQ0tacLnPswA,314
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_enc_aes256.pem,sha256=yMEDYmgWlztJujMOF9rMS9Iha34GBXyuXYpYgLWxx0k,314
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_enc_aes256_gcm.pem,sha256=GotcdRDvbl91HvWlW1z009iuUYTTSpGy4HrmVJ_sDCk,300
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_enc_des3.pem,sha256=XOwp6KnEADXw239Va5r9ugVpJOWoaZQTQ-iE99Gpyh4,299
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_openssh.pem,sha256=aCxAUluUngRkqklTjXMJ1U-R06vyTtgvAY9HJiyiBM0,525
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_openssh_old.pem,sha256=U2LOqXeFl_KpuBjteuFMVINwpkhySBQHreMsIsmAe8U,241
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_openssh_pwd.pem,sha256=faDeroEuwg_Ix_5F5NPjrcIgL1JsuVTO8ElkT09GgL4,578
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_openssh_pwd_old.pem,sha256=DKlWKgTzq5QEpu7OfnASW2P1CMpsTrHYLFMMzP__SMU,241
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_p8.der,sha256=8Lia3f3O81Fur193lkEPfMuqxxJIRO2UqjqWo_HDHF4,179
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_p8.pem,sha256=XoGTYG5LrjouLTIkIT4eFOxt5N1VH7AYbhBA2aZbzKE,318
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_p8_clear.der,sha256=cnmbIowIW8z6EJ2Nn4eg6jygbK5Fx-TPjIsr9RX50i4,138
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_private_p8_clear.pem,sha256=aQZgvErmx6ZyJ4UtYRukA17Gc4eQO7uaiDsCwBqPF08,241
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_public.der,sha256=fGv8W3UpJMMXYmJ2nPRrmjSPNnyOcE-fI1dgGsA1qWo,91
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_public.pem,sha256=18VbHNZHsikjlu35teZZB5_x_Vimb7NlLu3xTwIMs4U,178
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_public_compressed.der,sha256=wUxc_rRUKSbVuW9Xmr2y-9j6fZoWUyp-f3kMEFnScVU,59
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_public_compressed.pem,sha256=AQ9fW0iXXwb_gAfEgsZOFbv8_F9rHkrO5FWkG6WL5-4,134
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_public_openssh.txt,sha256=lez_62x3FxIN6LUS6NdwuGRn4yZZ0VqVWJIdsyC7jKY,161
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_x509.der,sha256=FbcHrhY7Q7BO0nt-AoCVMWqPPLebvNB7dPNUyBFVHtI,401
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p256_x509.pem,sha256=zTGkUwOeqJpxZz2LcsluZ3A_0f_wHrMPzR7DF3lJ7bw,599
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384.txt,sha256=30cv9scTYhSDTQE7gNXeihp7QVFW3azbBPfSqdIeLBI,848
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private.der,sha256=gdF5yQdMI2w9N1Rz2OZl1kXAS3VjdvvO4eRBNEwci88,167
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private.pem,sha256=lW4F-gHG8plnrEjwXODlNBDR06244E2FqdNW6RrKZ0k,288
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_enc_aes128.pem,sha256=m8h8zR8UR_shztyeCLv2ERdn-Pj0RZPI_lDnA84EzNU,379
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_enc_aes192.pem,sha256=jjDKqZ71CAeoEf9qdFUrm5qMdL9SLBBUSA77aHCdsqY,379
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_enc_aes256.pem,sha256=Okuv8VAz-TjM1INmOx-sfZIAaNYENrkViLhU6Tub5BM,379
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_enc_aes256_gcm.pem,sha256=q7oNkCM9-0ZVdmXMT-I_ubd9BAeUf7FAWw7ax45nUbA,361
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_enc_des3.pem,sha256=zvzq_un0MjYOriaiI2unsjiZyODYLajkEZhKl1M-fIg,352
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_openssh.pem,sha256=YaQ4jzZ_Qk680cHo4D7pSgOuGKL-x1ehVrmNuaP8VpA,634
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_openssh_old.pem,sha256=xtuVGnb35W5TviTFR-VX4UAm27jPw_qaAKT2zGRdN50,306
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_openssh_pwd.pem,sha256=VJGw10-QUR3K012qM5S0xulsxqHMAnLO9kjyZ9AUyAs,687
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_openssh_pwd_old.pem,sha256=HA9CtaFCz82uqaJWF4PbMra_WmBWeGhs_oOUPE4I46k,306
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_p8.der,sha256=v-ba89TMhcrwYb99FwTTSGRjPvHEY_YtAD_uHN9NXfY,288
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_p8.pem,sha256=28va4dDY6o0BQweiABnLzVd2XJHP6Sh1keljdA4vSMI,464
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_p8_clear.der,sha256=iQNdOt70TwEAa8JjslZfU14t9QMuJw4WI4xp9bO1boM,185
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_private_p8_clear.pem,sha256=p9k9kyrlXEdWLTgX77lC-EsRjRyJ_attoLxP_7u9ABo,306
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_public.der,sha256=P_Xu10VVbabmws1UYBe36AAb0r67KopkCpVXrdAZWBk,120
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_public.pem,sha256=DLmI4hGdlkQt8msGAWK8PIGeSwljpsaRPcap48ljUPE,215
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_public_compressed.der,sha256=40gth3gsa-MDzpE3oBbzNUeGT6w2xUHnGJr6MFHPPp0,72
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_public_compressed.pem,sha256=KAd0DNF4lw7LCTEHG-eQ5AlQx61yfbISZ15OoWlImxI,150
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_public_openssh.txt,sha256=lwxYgs4nmrAh3MzAwGXVnpzbGMUuIVtlGUQA6w1kd4g,205
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_x509.der,sha256=ianAVbMC_RUc_qkW56ZveHWNON9UkCtxHzRAKNTgU3Y,465
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p384_x509.pem,sha256=IoS2VsH6MzJFrqkaE7dUNx9zpPZilSOKqwWWTzwd1ss,684
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521.txt,sha256=csPtEBUyVqueAivVBMENIQK6dIW5EeVzOuMm74eEbuw,1102
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private.der,sha256=EgT4zXHC_nUdlpMQPtVNVL6Kd85-UNlFvWpXj3ZKLsU,223
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private.pem,sha256=SzMianLiLMvdM_uoKpuoolMEr149xfjxZs1BMzNk3E4,365
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_enc_aes128.pem,sha256=6Q7QjmOg9HtGgvzbr1Ir8y_s-X0VJiItGIojnGk_188,444
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_enc_aes192.pem,sha256=Usoy3FRZ621Ba_On0UR8iuS8a1dBIliXoNViFedOn5M,444
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_enc_aes256.pem,sha256=V7aiqI6niQFt33j0fRuSjLULlAebLtrzqkStBm-tynI,444
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_enc_aes256_gcm.pem,sha256=p5exiD4JHHDtK0jVlajI0N73pBwVVVmg03O2caZDb-M,438
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_enc_des3.pem,sha256=9ct7Q2bQ4Wqw-S_BCu6TPpRmLoVxuAA5Ui3vNRrcX54,429
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_openssh.pem,sha256=kBOZ_mWsjGkvuY76LoeXCW08zpd6e-vzL-PC2A1kRE8,756
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_openssh_old.pem,sha256=fo2rw0koPqjatPBspOclEYuVLVko-wLgmxTsEqoNJjY,384
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_openssh_pwd.pem,sha256=kVA6BoPYrlOqW1scj0tddmMaeKfn-MT7unIpZClsSIM,801
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_openssh_pwd_old.pem,sha256=uZCxZEF1324xbh8FsyeC-e5xWTuh2JI9THSMYta3nNc,384
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_p8.der,sha256=uBLXLGBOnJHNhsnfxi3_LBzEQt7zZ7dvA8W10XNFBsU,353
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_p8.pem,sha256=IMvxQdmrlUhfItAyms1un1MBUETxXOELdpb7wqg58RM,554
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_p8_clear.der,sha256=bhoyjpfdqhn8txQ02eOmK1uBoz7Y2FTj3qFYvf9er6g,241
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_private_p8_clear.pem,sha256=GvWW9t8Ux6z1-Uu7O6hWAgxdI5vgU2eVsDNcyyS_b18,384
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_public.der,sha256=n8k_4lc8DlJD1jqFzj9QFbIU2uMyJTuZt08BOjEQHaU,158
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_public.pem,sha256=cd0AukbHFnj_d1habRRQaZxss3QEgzs6pkYvFFgMh2A,268
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_public_compressed.der,sha256=35DQpuatGV2E92otSp8JcI4yszBg2A3q3a1TiVoDHzE,90
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_public_compressed.pem,sha256=LYsdWOfaBZtP9eYvu4hktp5HhmuuiGATJPOYQYNmVqw,174
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_public_openssh.txt,sha256=NUTubHKJmFuqIhBPwTy9PSOMoWI511Q_bUUOallD5jY,253
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_x509.der,sha256=T8JHzhTzXC74Bzy2t9JCfpXMi3FgC_RvhqZNK2S47vU,539
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/ecc_p521_x509.pem,sha256=il319QczAtkua27nPwS5gQnwuhPDuVc4U8z8_F5HHgQ,786
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/gen_ecc_p256.sh,sha256=jvhcZKBm51b1N-zcTLjsiquVBtdrQuLHm6c6JagsDCA,2651
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/gen_ecc_p384.sh,sha256=tOY_BeLz7D55rRohOnASfpKU5VISAI_slDKmNuQCxr8,2540
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/gen_ecc_p521.sh,sha256=pr2bzhpJtOMHa9HCIToMctduu9bzKwFhr06kFd9aeIk,2540
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/openssl_version.txt,sha256=TpgzscIqzY_FLk6WH0y1H0klab_iJn2U120v1loK4Gg,31
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/openssl_version_p384.txt,sha256=NEWRNBfUbq4TNQkZuuSOQAp6VeGmnrbIoo-lC-Qe0-M,27
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/openssl_version_p521.txt,sha256=NEWRNBfUbq4TNQkZuuSOQAp6VeGmnrbIoo-lC-Qe0-M,27
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/point-at-infinity.org-P256.txt,sha256=YCL_d9GA0wp_B4jH63gFgglZz97QDipQb3JAGyGk1iQ,9993
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/point-at-infinity.org-P384.txt,sha256=LH3JZPf82mX9kZfLCurwN6KFxAJKe0c7dn_wTkmznTc,14455
-Cryptodome/SelfTest/PublicKey/test_vectors/ECC/point-at-infinity.org-P521.txt,sha256=uXgYPT7uZU4VSE8D4of-9MbgFWVWyTLWekpPwryKWho,19421
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/gen_rsa_2048.sh,sha256=kKh8bTqhBmvzCO-rek3THD8SfhibZXb-5MKAkua6-_0,659
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/openssl_version.txt,sha256=g4a696SFxOtAl9Ta6wEQ7Gk7S2xAOYDW_2owds4QRG0,33
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/rsa2048_private.pem,sha256=p-GqC-XtacpQsChpxqB0UuDzGJz25zDVGc1XLD9QZlw,1675
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/rsa2048_private_openssh.pem,sha256=SscubX5Q_zu193_200rKEEMcDsA8UUNMFl2qwpZD79c,1843
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/rsa2048_private_openssh_old.pem,sha256=z7hNYzNlTHBBD1TgzIeRT1jL6Mz9WFNNbnB1HjihX2s,1704
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/rsa2048_private_openssh_pwd.pem,sha256=d2AQnmOPVvU_FiCA9nPo3QA7TQnRIkCrVKiiBP7Zuy4,1896
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/rsa2048_private_openssh_pwd_old.pem,sha256=akUEWlzHkLQySLriut7c1Lz7_A8Uv6GmID2a_nSrvgA,1708
-Cryptodome/SelfTest/PublicKey/test_vectors/RSA/rsa2048_public_openssh.txt,sha256=Wk5hyMlp7Cb_TAglAhmPEVFejSPMY97cTz9voxhgp4E,381
-Cryptodome/SelfTest/Random/__init__.py,sha256=vWmKA--IXzOIszf150wbGq1-OTAVBTI3sqInjutIBWk,1546
-Cryptodome/SelfTest/Random/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/Random/__pycache__/test_random.cpython-38.pyc,,
-Cryptodome/SelfTest/Random/test_random.py,sha256=VtbtEXdP_6EaxZ_hRL3rP-HrBVBEqb_ANN7l8HfoRFM,7014
-Cryptodome/SelfTest/Signature/__init__.py,sha256=C-5wFBkGOqSmy5j1ljP2EAHsTPmz4Cp3klsrUgTaUVI,1564
-Cryptodome/SelfTest/Signature/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/Signature/__pycache__/test_dss.cpython-38.pyc,,
-Cryptodome/SelfTest/Signature/__pycache__/test_pkcs1_15.cpython-38.pyc,,
-Cryptodome/SelfTest/Signature/__pycache__/test_pss.cpython-38.pyc,,
-Cryptodome/SelfTest/Signature/test_dss.py,sha256=pNFOUpR_XNTRW6YYbevhL47JH-YKuMT4Tn2-osJtKy0,48521
-Cryptodome/SelfTest/Signature/test_pkcs1_15.py,sha256=rDFun7A_XUMiqksw6iTm7HJap-1Z1wGINiwhoSRT9CI,13961
-Cryptodome/SelfTest/Signature/test_pss.py,sha256=cniIFFvnRk7JvAIfyZHagK8emuGXMklwHYKnd5ye_AM,15834
-Cryptodome/SelfTest/Signature/test_vectors/DSA/FIPS_186_3_SigGen.txt,sha256=CgbUHJa42LSFuKhzyHqIOrOhjfty1UEbqG6mZzgwG4w,332997
-Cryptodome/SelfTest/Signature/test_vectors/DSA/FIPS_186_3_SigVer.rsp,sha256=XAzACaPYLKYnuy3k9eKMEaLLYv599wDS-P4_WPc-sFM,320900
-Cryptodome/SelfTest/Signature/test_vectors/ECDSA/README.txt,sha256=-9a-bk38fNGDOL5A0MuvoMv_-DGDyXv-Hy_hi9lPVdU,233
-Cryptodome/SelfTest/Signature/test_vectors/ECDSA/SigGen.txt,sha256=fmR9CA0A0OBmTk0VXO3dLF6JuWpfYnTiR0GbKJ46u8c,73092
-Cryptodome/SelfTest/Signature/test_vectors/ECDSA/SigVer.rsp,sha256=2mRCPlaCZaEKtHnQaNT4UyV4y4Ugp2ym431pVWlO5Qs,59083
-Cryptodome/SelfTest/Signature/test_vectors/PKCS1-PSS/SigGenPSS_186-2.txt,sha256=rcKJqoIznZ4T1n7CWiQF1IdS--TtECXiJTvu9cuIlEY,241521
-Cryptodome/SelfTest/Signature/test_vectors/PKCS1-PSS/SigGenPSS_186-3.txt,sha256=Rt5_L8y1-JUW5ktb2xxP1FagnJzGgN1k4HVuYv9QAOw,84721
-Cryptodome/SelfTest/Signature/test_vectors/PKCS1-PSS/SigVerPSS_186-3.rsp,sha256=eMQgBgTucJ1k6lMI9E9r5JNWyaaYjDdojMugWQz4O_o,618655
-Cryptodome/SelfTest/Signature/test_vectors/PKCS1-v1.5/SigGen15_186-2.txt,sha256=O-UB5gD4svYkt_DtBDsPNeF-7KhkRF-DUwHhv3IAloc,228502
-Cryptodome/SelfTest/Signature/test_vectors/PKCS1-v1.5/SigGen15_186-3.txt,sha256=GcSbj8cQLMEkduIVhUzSKPH4wNMW8Oot9sGD8Wfpcko,78424
-Cryptodome/SelfTest/Signature/test_vectors/PKCS1-v1.5/SigVer15_186-3.rsp,sha256=b2A4FDStYP85DmeRO00HLufCVkvVdjaW7xspnh2WezM,248174
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/dsa_test.json,sha256=dY9VnMaPZ0VYhzjyXXu4DUa5OyN1HM8HXZFIata5Kj8,361835
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha224_p1363_test.json,sha256=NUzTUOvq8KUgnhgblXylo_xC0prDUrBJnvHT2COMDhY,126917
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha224_test.json,sha256=h0ZfND_VTKlrULr6fsqhWi1NOwSkCZQYLOY1k5kuo3Q,182708
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha256_p1363_test.json,sha256=frm9Q9JD6btb9aYrfeSrqu1JisTmOcsNMR67oRZUPjg,136148
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha256_test.json,sha256=fllUI96pdYYPSmtNnf5wengqklQcNl1Fv5tmYgGajRA,191745
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha3_224_test.json,sha256=rYp3SAmNMqI5Oiek4o2JradM7YsCN3sgJTm3Q2191OU,192369
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha3_256_test.json,sha256=DSwWgANVGnI6l3tTT_f6IX7ld1x6TWQq1QLvmkn_AmA,195342
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha3_512_test.json,sha256=rUn9FPrUbfFRa9Rti9mAeT1WH8TCjXvQ-SkN6ymx6_Y,216893
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha512_p1363_test.json,sha256=m-6HhNQBAO0oP7Hvu5qOm7y0_RhwpiavN4H7SPJKZ94,158057
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp224r1_sha512_test.json,sha256=srxXDnc8w0HyPC1cFGYEum5u9WlaFilCM2969gFRf1w,215238
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp256r1_sha256_p1363_test.json,sha256=eEd59aM1Yyrmq1aojPZKLgyRixx_tJ0-nxc_sl_Q8JQ,169360
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp256r1_sha256_test.json,sha256=Yvg1kKnp4mpdc1n4Y-1BKqzSnt3ySPgXWbCcPEiT9O0,209501
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp256r1_sha3_256_test.json,sha256=tQCOWU-wS8pwztc_QQB2vK1IXmflAvR91WGplVKfcto,212335
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp256r1_sha3_512_test.json,sha256=GO0BLh57BNYJK3ZcuiPjAynKzBLek5z9SP1EacmOkIU,235525
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp256r1_sha512_p1363_test.json,sha256=LTH5hr5Eqciwd64TdLiL9OfUTk0_YEVFyYWiCQw-4AE,192688
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp256r1_sha512_test.json,sha256=TbH2DT14pKwLQdnqdc3LJkRaf2EcdkECPZX0qtUMHqM,233815
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp384r1_sha384_p1363_test.json,sha256=fLjtA_INZ1ZC4JIwbnbTLZYvmvVN7cHn6c_sbX7-1qY,202354
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp384r1_sha384_test.json,sha256=QPdf0K6THBEM9aSkl35s6kDkh3-SIomshoX6bEtwxXI,248834
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp384r1_sha3_384_test.json,sha256=WwCSeAmsmAnJtYpRdxpT1M4GMn9SabbgiRIkSVij7AY,252441
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp384r1_sha3_512_test.json,sha256=llhW4ydRgaY_Uq663LDVieLPOz6EN-d_vqKJq1VuPj4,266529
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp384r1_sha512_p1363_test.json,sha256=ZTO1O-Z_eTEfXMXX_gZ8tyr1qHUUIxKb-8mOHOmHffs,217518
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp384r1_sha512_test.json,sha256=ycWfQpYvSTBG6B3Q3-cVoKG1rUblxAc3ric7QxZrBbs,264814
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp521r1_sha3_512_test.json,sha256=zvNdmzSSuNUmf_ZusWRljRxJspgiN_IThYGVdmzqJhE,316628
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp521r1_sha512_p1363_test.json,sha256=nivx2a4HuAwfaERUwBuTZDREIve8uGstu0wN5ZZoBCc,265577
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_secp521r1_sha512_test.json,sha256=gLytODmZ8DmUJTrTGbg0WuvG1wGm3uq-wwZhzNpmEAM,315478
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_test.json,sha256=1XbwmavbVPefYmWJhS7x1byueiJ5DAzTmo2eQhlG-7I,1333478
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/ecdsa_webcrypto_test.json,sha256=Qa7kaY0Xohqsixuy-ezkDSLG8yGL8L98Hubfj9DGOs0,385262
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_2048_sha1_mgf1_20_test.json,sha256=bD0sOop9DKD2OIBaJOBTqN9piTU_1lqk-pBpXvAW6BU,63308
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_2048_sha256_mgf1_0_test.json,sha256=ZZGPT7_oIvbgwLFKM1iFfKJefD6C9-VnuP8fgEga9Bw,72789
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_2048_sha256_mgf1_32_test.json,sha256=hR7EkUvCMwshuYQW1lChpfQJdgwCsJTiEAHK1DyjV3c,74923
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_2048_sha512_256_mgf1_28_test.json,sha256=LQ8ufxpctrj2VHOZ2I7TBWuNpTpzW3r9YOsPcaCGfQk,37903
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_2048_sha512_256_mgf1_32_test.json,sha256=2RkYwmvFpuP1XIWTR5fKshYJyif7TObvzYxlpWQLXO8,37191
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_3072_sha256_mgf1_32_test.json,sha256=xkx8gcULOEd0N9SfcehBSUQBKDOrv2Q-dDmc3MQ2NKk,101979
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_4096_sha256_mgf1_32_test.json,sha256=8omUot7aJDuhggbUHYGF0qCR7DNRLjvIwnSAGXqCVEM,129037
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_4096_sha512_mgf1_32_test.json,sha256=uOksGZcx2x4A_DPnnE0DXmI166rNshpY8oWfmlPcWgs,211443
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_pss_misc_test.json,sha256=d2w-C4-V2t7yCDW92y_UMEtbSdTJ3QGOLqPQs4Jxifw,463761
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_sig_gen_misc_test.json,sha256=Q1OTIr166OUg4uAMbRGsXP3_Ty9wQ8weOhZgsS0GuvQ,372540
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha224_test.json,sha256=1ANoEKJ6Mc94iKCS-cqNqnhx79ZsHCy9a8pWV8Popsk,175874
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha256_test.json,sha256=BHjrlYexXC5nCb_wGGNT5VBRYcKhU9bUuEzauElpBGU,181387
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha384_test.json,sha256=bt4DMVo3j7HgRFE5l7m03aVv68UZJm6g39kmgh-Etr4,184281
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha3_224_test.json,sha256=AdsypMqO6_GRil0LRBG7zuWJD80EEVjA3mY-9Or_Ako,181604
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha3_256_test.json,sha256=hQ4Fs6ZQzL55QtPQmJUYAXrBP7bSukas9rL482hflOA,180890
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha3_384_test.json,sha256=FSXUlpTnygKfQbhyKog1iSebDjG6zFxav9HInKYheHw,181604
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha3_512_test.json,sha256=Znlqjz8DFWdsjZv40HBxn_juSuIjsoossTYYQsPiuWw,181604
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha512_224_test.json,sha256=kC_TABoVqLd1Jo8wxqd-4NTJVCQYWRQpBTJ3_1_8jYk,183800
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha512_256_test.json,sha256=tYXtc6895ZxNzy_uvxnRdWCOHC6pk2Jy39vi533DZjc,183086
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_2048_sha512_test.json,sha256=WsNGI8iC3jx2AqGoGzS4MEM9QDJ_Ky-bhgmrowrUuJ8,178542
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_3072_sha256_test.json,sha256=INZNK4hxDkjguICmNnPOUCkToSMFjeWWq9moA6GZ1CA,240992
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_3072_sha384_test.json,sha256=AoHmTwjmNhhJmfkGNWNXnlxPhnWP1lWs5ccMRb1llMM,236965
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_3072_sha3_256_test.json,sha256=fRdlVlSs_r1BDqFl3B7yQvCKGQTBwWeDaWV1B-k3PgE,245066
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_3072_sha3_384_test.json,sha256=RWjb1l5WR1hVKuqZ09BuLuBnpWhFcmhnXVr-r7Iipww,246036
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_3072_sha3_512_test.json,sha256=15-WDZpI2meYFNnFeRpSaAtuxapszz8MkfR8eskTu5E,246036
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_3072_sha512_256_test.json,sha256=p9euedS_ywKSYRD0T80klmDpyt52vvsZzRXwDaTPioA,248030
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_3072_sha512_test.json,sha256=695qzX0M3a9enz0Botw3LejEcMQKQ2CMATBcuY0JzUY,241950
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_4096_sha384_test.json,sha256=FvvLp8tnOeoeFjd91W8sBOMbI75sHj5fkH_DT2Q1eGA,299010
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_4096_sha512_256_test.json,sha256=dRHPuI8avsTKUBRAp8ej2VszXamupiMqYi_TzDec1no,312976
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_4096_sha512_test.json,sha256=dwFh4ADPbnVs-1T-PnHahFfIBTitecFHT-aAzlk1k4E,299010
-Cryptodome/SelfTest/Signature/test_vectors/wycheproof/rsa_signature_test.json,sha256=j_yzdGf4xK7M0bxP_iF3n6-p-cY7FKUJV76pttMADl0,353455
-Cryptodome/SelfTest/Util/__init__.py,sha256=0Ov0gHqo91NR0f639IzQMU-UX1pxOm90PI-uUaOJlro,2021
-Cryptodome/SelfTest/Util/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/Util/__pycache__/test_Counter.cpython-38.pyc,,
-Cryptodome/SelfTest/Util/__pycache__/test_Padding.cpython-38.pyc,,
-Cryptodome/SelfTest/Util/__pycache__/test_asn1.cpython-38.pyc,,
-Cryptodome/SelfTest/Util/__pycache__/test_number.cpython-38.pyc,,
-Cryptodome/SelfTest/Util/__pycache__/test_rfc1751.cpython-38.pyc,,
-Cryptodome/SelfTest/Util/__pycache__/test_strxor.cpython-38.pyc,,
-Cryptodome/SelfTest/Util/test_Counter.py,sha256=ApOFXU5UI7v6Fyud6x9DOxxzknMs5mRhdiPxrEayeKE,2214
-Cryptodome/SelfTest/Util/test_Padding.py,sha256=YS6QCpAg4wO1f_uF1yjRCfljxLV9exTjxzZJEzdJvQk,5642
-Cryptodome/SelfTest/Util/test_asn1.py,sha256=H8bZeUqd3I8y1eWhR_XgOTLfCTvhgIqyu6HxCb7JjM8,29439
-Cryptodome/SelfTest/Util/test_number.py,sha256=E4AuphgplCJEVK8NWQzhCQgOtUZXQDnLCKyxUCKQjm0,6440
-Cryptodome/SelfTest/Util/test_rfc1751.py,sha256=iRu-xLLslb_ktNOPkKs4TAWPljrxDMksFnSqo25q9dA,1121
-Cryptodome/SelfTest/Util/test_strxor.py,sha256=CMOooo3QahU0wx3n-gNdmpqio5FanEUOosse0XfS_jo,10618
-Cryptodome/SelfTest/__init__.py,sha256=bsbo1dGYE-girZ4Mc7JeMbsgKWQ-WccHPAlLAzd3028,3686
-Cryptodome/SelfTest/__main__.py,sha256=aQAx7W62ztb2utGTClg3Qgb8iD9zSCnThhil_cIdL84,1506
-Cryptodome/SelfTest/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/SelfTest/__pycache__/__main__.cpython-38.pyc,,
-Cryptodome/SelfTest/__pycache__/loader.cpython-38.pyc,,
-Cryptodome/SelfTest/__pycache__/st_common.cpython-38.pyc,,
-Cryptodome/SelfTest/loader.py,sha256=xO6_2DEpt-7RH6CD1YEWv8AjKjTxQsalKWLLb0ALbws,4101
-Cryptodome/SelfTest/st_common.py,sha256=XsoFHmR_gylMxGhRJrQHfarNnIT_Mu8t9oAebRPReck,1949
-Cryptodome/Signature/DSS.py,sha256=GG7RirihwrofE8dzjMDcbQfOVkit4MXobaB_55qP09A,15333
-Cryptodome/Signature/DSS.pyi,sha256=zay6LNZ3NIlu42Q63ICT3mZEcz_aVG1rXLOkJ2tfasc,1102
-Cryptodome/Signature/PKCS1_PSS.py,sha256=o3Ky9DF9iI-wpGHDi5vZs7spzFSlANYIkqgqu0zCkAo,2103
-Cryptodome/Signature/PKCS1_PSS.pyi,sha256=fzw5vQvHchfJHvlHEr24CMTY2Gw8_pqsz76jNmMUBlc,280
-Cryptodome/Signature/PKCS1_v1_5.py,sha256=aEzzt1ccFM71pJfG6drwzGZeTI-ntM4-LLxBPyaFXLA,1993
-Cryptodome/Signature/PKCS1_v1_5.pyi,sha256=eqweCPvqayn2xiO9Aqv4Bc38GKOLcca6PazT9T87ufE,157
-Cryptodome/Signature/__init__.py,sha256=Y7O7plqZibJUIIyRDTPHxUKYBNvl4botFXvjEUA0y0A,1686
-Cryptodome/Signature/__pycache__/DSS.cpython-38.pyc,,
-Cryptodome/Signature/__pycache__/PKCS1_PSS.cpython-38.pyc,,
-Cryptodome/Signature/__pycache__/PKCS1_v1_5.cpython-38.pyc,,
-Cryptodome/Signature/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Signature/__pycache__/pkcs1_15.cpython-38.pyc,,
-Cryptodome/Signature/__pycache__/pss.cpython-38.pyc,,
-Cryptodome/Signature/pkcs1_15.py,sha256=C0tGVrnMF3caVBJArhpEYZ0dsQ2RD8taIIzv50j85gg,8749
-Cryptodome/Signature/pkcs1_15.pyi,sha256=k8o74VVp_Zw11VmbhLBxPiU6CzzTm7NbaNwGeWeNn9A,568
-Cryptodome/Signature/pss.py,sha256=1443VYy8pEuvB7t8sWJ9p--pGHnRz2yqChKx3EowkXI,13494
-Cryptodome/Signature/pss.pyi,sha256=O_6YOe-iR4rHIzNnm6vCzcwxVNPGRgfAXhhzp1N9jPE,1044
-Cryptodome/Util/Counter.py,sha256=IWid224Wy-kmQ1UxqRsutwiTDzJq-ajxQGx0rx-_M3E,2811
-Cryptodome/Util/Counter.pyi,sha256=2JrTHJYq263XosQSC_NIP0TufUsTlG7WUr-lRqjJCuA,290
-Cryptodome/Util/Padding.py,sha256=KMwvlHUL6zRNA_XMa_SXwbm7RBIND_3sK155NeSocI8,4229
-Cryptodome/Util/Padding.pyi,sha256=47R3H2kE66PtKO82eT_Vc5eCSgNe4qOFgqOIPRdlp9c,238
-Cryptodome/Util/RFC1751.py,sha256=zHC63Jx-PqZQ2ebcYGUhaG62vfkFSklQc8MZmapE7SY,21204
-Cryptodome/Util/RFC1751.pyi,sha256=B42LvsE6G786rNEsrhta_BANazgrpb0WoSBPqKyjt5g,159
-Cryptodome/Util/__init__.py,sha256=fsZWRqGXZR2gmM0jxuiogKW3WwzlzKuTRRWYiwtOOd0,1951
-Cryptodome/Util/__pycache__/Counter.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/Padding.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/RFC1751.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/_cpu_features.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/_file_system.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/_raw_api.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/asn1.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/number.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/py3compat.cpython-38.pyc,,
-Cryptodome/Util/__pycache__/strxor.cpython-38.pyc,,
-Cryptodome/Util/_cpu_features.py,sha256=f_JiluwzxhmltMbptIQ8qA03YUdgSNBr3RwcyX9z-xc,1997
-Cryptodome/Util/_cpu_features.pyi,sha256=3wKXZ0Z8llc2uxADvbhz3dHV6YLyRrDujOsabXlffCQ,59
-Cryptodome/Util/_cpuid_c.cpython-38-x86_64-linux-gnu.so,sha256=0XsY-HTCy_DusKyRTYtS92e6dfrvqiKb17YhkONXQwM,10899
-Cryptodome/Util/_file_system.py,sha256=m7HsPgKuKRsTQjgov6Vg02dn7Xsa52xhCLmqLjPIoZg,2183
-Cryptodome/Util/_file_system.pyi,sha256=5QruEWPE4urPtlCT5Eg8tBQyhV9ffBfZIAjmMo727dM,100
-Cryptodome/Util/_raw_api.py,sha256=_Uzt_wQ1_lm5GnENEF_s2Zya-LOCfG-UCA26ELB0DLg,10461
-Cryptodome/Util/_raw_api.pyi,sha256=Ohc2rr6RS-nhs6T5AL1YyQtaqsx6BVrJa092CiwAvNM,906
-Cryptodome/Util/_strxor.cpython-38-x86_64-linux-gnu.so,sha256=lvjppxLIMiolJvn5lp_CIYEloWiyFmDzeg-4v08mxcE,13213
-Cryptodome/Util/asn1.py,sha256=uOFoioOtH5ko3E59qR_zHHsVE2I9ZEDHPg6cMmIJanc,31772
-Cryptodome/Util/asn1.pyi,sha256=xR4oQKBf4SXiz0IQ_K0lw427jvvgX9SiEXejIu9fdV8,3579
-Cryptodome/Util/number.py,sha256=xwH1LGqkVsg0fufxrbWlX88pVPxbE11FvO3L4Oc3zhs,94868
-Cryptodome/Util/number.pyi,sha256=ixX1BS8EvvuPXN1_8aosdYHKmtXGB9NlRNVI9T9MAA8,975
-Cryptodome/Util/py3compat.py,sha256=PrPeqRZP9glhLCzrj-G_8BFmTui7EOO3bwA1y1bBgmw,5246
-Cryptodome/Util/py3compat.pyi,sha256=GeZXPUe7HqATRZ9ijsDRt3sVXEioOvi_T8dzLrUMBN4,824
-Cryptodome/Util/strxor.py,sha256=SEcBSWY8xqSAPBmPA2TdTjFJnqTs9A4WoxVX4VyNv2Y,5126
-Cryptodome/Util/strxor.pyi,sha256=OuBvuuK_ezq3eaHY10J89xpER9IQ9wcYzFI7j1tpll0,243
-Cryptodome/__init__.py,sha256=oIHjFUCVTvgyuhVOuPLSQ29PXjOgb4XN7UiRdTs8GbU,184
-Cryptodome/__init__.pyi,sha256=e5Ea45Jy2RdOr6bmLF9jiS2Bw65WnYTD1NMLJlbGAaw,99
-Cryptodome/__pycache__/__init__.cpython-38.pyc,,
-Cryptodome/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pycryptodomex-3.9.9.dist-info/AUTHORS.rst,sha256=4AeRvMPhQSqwZcXaicX3Uv6MzyU98gNxUNcQsE6XiNg,735
-pycryptodomex-3.9.9.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-pycryptodomex-3.9.9.dist-info/LICENSE.rst,sha256=0a8_qy74zFO2x_SL3rF4rIdLBPr0ugFZqWthCfHTk-I,14685
-pycryptodomex-3.9.9.dist-info/METADATA,sha256=P7sdFrKssGKWsJR1a92GfdG4CNCtXFB3XFUPR2KWAWA,3188
-pycryptodomex-3.9.9.dist-info/RECORD,,
-pycryptodomex-3.9.9.dist-info/WHEEL,sha256=lmsU4pfb_60LHFgAOwGQv63gTX7Ny9agYdFe9vUdh58,108
-pycryptodomex-3.9.9.dist-info/top_level.txt,sha256=eHU9ase6in1ZSBEtTDpl7fwIPION42nbqZ1uFTyccxs,11
diff --git a/frozen_deps/pycryptodomex-3.9.9.dist-info/WHEEL b/frozen_deps/pycryptodomex-3.9.9.dist-info/WHEEL deleted file mode 100644 index 460075a..0000000 --- a/frozen_deps/pycryptodomex-3.9.9.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.35.1) -Root-Is-Purelib: false -Tag: cp38-cp38-manylinux1_x86_64 - diff --git a/frozen_deps/pycryptodomex-3.9.9.dist-info/top_level.txt b/frozen_deps/pycryptodomex-3.9.9.dist-info/top_level.txt deleted file mode 100644 index 9cbd375..0000000 --- a/frozen_deps/pycryptodomex-3.9.9.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -Cryptodome diff --git a/frozen_deps/pysha3-1.0.2.dist-info/INSTALLER b/frozen_deps/pysha3-1.0.2.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/frozen_deps/pysha3-1.0.2.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/frozen_deps/pysha3-1.0.2.dist-info/LICENSE b/frozen_deps/pysha3-1.0.2.dist-info/LICENSE deleted file mode 100644 index 311690c..0000000 --- a/frozen_deps/pysha3-1.0.2.dist-info/LICENSE +++ /dev/null @@ -1,49 +0,0 @@ -PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 --------------------------------------------- - -1. This LICENSE AGREEMENT is between the Python Software Foundation -("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using this software ("Python") in source or binary form and -its associated documentation. - -2. Subject to the terms and conditions of this License Agreement, PSF -hereby grants Licensee a nonexclusive, royalty-free, world-wide -license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python -alone or in any derivative version, provided, however, that PSF's -License Agreement and PSF's notice of copyright, i.e., "Copyright (c) -2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Python Software Foundation; -All Rights Reserved" are retained in Python alone or in any derivative -version prepared by Licensee. - -3. In the event Licensee prepares a derivative work that is based on -or incorporates Python or any part thereof, and wants to make -the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python. - -4. PSF is making Python available to Licensee on an "AS IS" -basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT -INFRINGE ANY THIRD PARTY RIGHTS. - -5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, -OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between PSF and -Licensee. This License Agreement does not grant permission to use PSF -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using Python, Licensee -agrees to be bound by the terms and conditions of this License -Agreement. - diff --git a/frozen_deps/pysha3-1.0.2.dist-info/METADATA b/frozen_deps/pysha3-1.0.2.dist-info/METADATA deleted file mode 100644 index 5e11ab7..0000000 --- a/frozen_deps/pysha3-1.0.2.dist-info/METADATA +++ /dev/null @@ -1,251 +0,0 @@ -Metadata-Version: 2.1 -Name: pysha3 -Version: 1.0.2 -Summary: SHA-3 (Keccak) for Python 2.7 - 3.5 -Home-page: https://github.com/tiran/pysha3 -Author: Christian Heimes -Author-email: christian@python.org -Maintainer: Christian Heimes -Maintainer-email: christian@python.org -License: PSFL (Keccak: CC0 1.0 Universal) -Keywords: sha3 sha-3 keccak hash -Platform: POSIX -Platform: Windows -Classifier: Development Status :: 4 - Beta -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Python Software Foundation License -Classifier: License :: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication -Classifier: Natural Language :: English -Classifier: Operating System :: MacOS :: MacOS X -Classifier: Operating System :: POSIX -Classifier: Operating System :: POSIX :: BSD -Classifier: Operating System :: POSIX :: Linux -Classifier: Operating System :: Microsoft :: Windows -Classifier: Programming Language :: C -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Topic :: Security :: Cryptography - -====== -pysha3 -====== - -SHA-3 wrapper (keccak) for Python. The package is a wrapper around the -optimized Keccak Code Package, https://github.com/gvanas/KeccakCodePackage . - -The module is a standalone version of my SHA-3 module from Python 3.6 -(currently under development). The code in sha3module.c has been modified to -be compatible with Python 2.7 to 3.5. Python 2.6 and earlier are not -supported. - - -Updates since pysha 0.3 -======================= - -**pysha3 1.0 is not compatible with pysha3 0.3!** - -pysha3 < 1.0 used the old Keccak implementation. During the finalization of -SHA3, NIST changed the delimiter suffix from 0x01 to 0x06. The Keccak sponge -function stayed the same. pysha3 1.0 provides the previous Keccak hash, too. - - -Platforms -========= - -pysha3 has been successfully tested on several platforms: - - - Linux (GCC, clang) on X86, X86_64 and ARMv6 (little endian) - - Windows (VS 2008, VS 2010, VS2015) on X86 and X86_64 - - -Usage -===== - -The `sha3` module contains several constructors for hash objects with a -PEP 247 compatible interface. The module provides SHA3, SHAKE and Keccak: - -* `sha3_228()`, `sha3_256()`, `sha3_384()`, and `sha3_512()` -* `shake_128()`, `shake_256()` -* `keccak_228()`, `keccak_256()`, `keccak_384()`, and `keccak_512()` - -The `sha3` module monkey patches the `hashlib` module . The monkey patch is -automatically activated with the first import of the `sha3` module. The -`hashlib` module of Python 3.6 will support the four SHA-3 algorithms and -the two SHAKE algorithms on all platforms. Therefore you shouldn't use the -sha3 module directly and rather go through the `hashlib` interface:: - - >>> import sys - >>> import hashlib - >>> if sys.version_info < (3, 6): - ... import sha3 - >>> s = hashlib.sha3_512() - >>> s.name - 'sha3_512' - >>> s.digest_size - 64 - >>> s.update(b"data") - >>> s.hexdigest() - 'ceca4daf960c2bbfb4a9edaca9b8137a801b65bae377e0f534ef9141c8684c0fedc1768d1afde9766572846c42b935f61177eaf97d355fa8dc2bca3fecfa754d' - - >>> s = hashlib.shake_256() - >>> s.update(b"data") - >>> s.hexdigest(4) - 'c73dbed8' - >>> s.hexdigest(8) - 'c73dbed8527f5ae0' - >>> s.hexdigest(16) - 'c73dbed8527f5ae0568679f30ecc5cb6' - - >>> import sha3 - >>> k = sha3.keccak_512() - >>> k.update(b"data") - >>> k.hexdigest() - '1065aceeded3a5e4412e2187e919bffeadf815f5bd73d37fe00d384fe29f55f08462fdabe1007b993ce5b8119630e7db93101d9425d6e352e22ffe3dcb56b825' - -Changelog -========= - -pysha3 1.0.2 ------------- - -*Release: 05-Feb-2017* - -- Rename internal C extension to _pysha3 to avoild conflict with Python 3.6' - _sha3 extension. - -pysha3 1.0.1 ------------- - -*Release: 24-Jan-2017* - -- Fix github.org -> github.com (Pi Delport) - -- Fix endianness checks for Python 2 (William Grant) - -- Fix changelog, the Christmas release was 1.0.0, not 1.1.0 - -pysha3 1.0.0 ------------- - -*Release date: 24-Dec-2016* - -- Synchronize with Python 3.6.0 release - -- Move all backport related additions to backport.inc - -- Fix flake8 violations - - -pysha3 1.0b1 ------------- - -*Release date: 01-May-2016* - -- Update backend to use the latest Keccak Code Package. pysha3 now implements - the official NIST standard. The old Keccak hashes are available with - keccak prefix. - -- Add SHAKE support. - -- All sha3, shake and keccak variants are separate types instead of factory - functions that return the same type. - -- Drop Python 2.6 and Python 3.0 to 3.3 support. - -- Fix typo that disabled threading optimization. - -- Add vector files for additional tests. - -- Add experimental HMAC support based on examples from - http://wolfgang-ehrhardt.de/hmac-sha3-testvectors.html . - -- Test hashing of unaligned data. - -- Add ISO C11 memset_s() function as _Py_memset_s() in order to securely - wipe memory that holds sensitive data. The page - https://www.securecoding.cert.org/confluence/display/seccode/MSC06-C.+Be+aware+of+compiler+optimization+when+dealing+with+sensitive+data - explains the motivation for memset_s(). - -- Add tox support. - -- Add Travis and appveyor integration. - -- Add _capacity_bits, _rate_bits and _suffix attributes for diagnostic - purposes. - - -pysha3 0.3 ----------- - -*Release date: 14-Oct-2012* - -- Fix 64bit big endian support - -- Add workaround for alignment error on 64bit SPARC machine by using the opt32 - implementation. - -- block_size now returns NotImplemented to prevent users from using pysha3 - with the hmac module. - - -pysha3 0.2.2 ------------- - -*Release date: 07-Oct-2012* - -- Re-add brg_endian.h to fix issue on Solaris (big endian platform) - - -pysha3 0.2.1 ------------- - -*Release date: 06-Oct-2012* - -- Fix MANIFEST.in to include Makefile and tests.py - -- Add setup.py test command with hack for inplace builds - -- Enhance README.txt and fixed its markup - - -pysha3 0.2 ----------- - -*Release date: 06-Oct-2012* - -- Change directory struct to use the same directory layout as Python 3.4. - -- Remove C++ comments from Keccak sources for ANSI C compatibility. - -- Declare all Keccak functions and globals as static to avoid name clashes. - -- Remove alias sha3() for sha3_512(). - -- Add block_size attribute. Keccak has a internal sponge size of 1600 bits. - -- Release GIL around SHA3_update() calls. - -- Monkey patch the hashlib module to support, e.g. hashlib.sha3_512() and - hashlib.new("sha3_512") - -- Release GIL around SHA3_update() when the data exceeds a certain size. - -- Fix build on platforms with an unsigned 64bit integer type (uint64_t). The - module falls back to 32bit implementation of Keccak with interleave tables. - - -pysha3 0.1 ----------- - -*Release date: 04-Oct-2012* - -- first release - -- based on KeccakReferenceAndOptimized-3.2.zip - - - diff --git a/frozen_deps/pysha3-1.0.2.dist-info/RECORD b/frozen_deps/pysha3-1.0.2.dist-info/RECORD deleted file mode 100644 index 17ecd37..0000000 --- a/frozen_deps/pysha3-1.0.2.dist-info/RECORD +++ /dev/null @@ -1,9 +0,0 @@ -__pycache__/sha3.cpython-38.pyc,,
-_pysha3.cpython-38-x86_64-linux-gnu.so,sha256=JM0m-PvpwkIqoUIHO_5AuJYgbybynAEV8mKc7qw-hjA,517664
-pysha3-1.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-pysha3-1.0.2.dist-info/LICENSE,sha256=uAzp2oxCofkQeWJ_u-K_JyEK4Qig_-Xwd9WwjgdsJMg,2409
-pysha3-1.0.2.dist-info/METADATA,sha256=mp8k9OmbwPabv7k2zKNy45GRr2rUJ8auKH5xtoi9wIM,6810
-pysha3-1.0.2.dist-info/RECORD,,
-pysha3-1.0.2.dist-info/WHEEL,sha256=TpFVeXF_cAlV118WSIPWtjqW7nPvzoOw-49FmS3fDKQ,103
-pysha3-1.0.2.dist-info/top_level.txt,sha256=FdKZVala00U6bdey3Qbc6yW7Z1rzdaDs8Iet_iwYDP8,13
-sha3.py,sha256=QeJrjR0om_CROYj4xnndQXqkkr9Y9R11XsCKKiyYTzs,746
diff --git a/frozen_deps/pysha3-1.0.2.dist-info/WHEEL b/frozen_deps/pysha3-1.0.2.dist-info/WHEEL deleted file mode 100644 index d193dea..0000000 --- a/frozen_deps/pysha3-1.0.2.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.34.2) -Root-Is-Purelib: false -Tag: cp38-cp38-linux_x86_64 - diff --git a/frozen_deps/pysha3-1.0.2.dist-info/top_level.txt b/frozen_deps/pysha3-1.0.2.dist-info/top_level.txt deleted file mode 100644 index a9e88ad..0000000 --- a/frozen_deps/pysha3-1.0.2.dist-info/top_level.txt +++ /dev/null @@ -1,2 +0,0 @@ -_pysha3 -sha3 diff --git a/frozen_deps/sha3.py b/frozen_deps/sha3.py deleted file mode 100644 index 5657f66..0000000 --- a/frozen_deps/sha3.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (C) 2012-2016 Christian Heimes (christian@python.org) -# Licensed to PSF under a Contributor Agreement. -# - -# monkey patch _hashlib -import hashlib as _hashlib - -from _pysha3 import keccak_224, keccak_256, keccak_384, keccak_512 -from _pysha3 import sha3_224, sha3_256, sha3_384, sha3_512 -from _pysha3 import shake_128, shake_256 - - -__all__ = ("sha3_224", "sha3_256", "sha3_384", "sha3_512", - "keccak_224", "keccak_256", "keccak_384", "keccak_512", - "shake_128", "shake_256") - - -if not hasattr(_hashlib, "sha3_512"): - _hashlib.sha3_224 = sha3_224 - _hashlib.sha3_256 = sha3_256 - _hashlib.sha3_384 = sha3_384 - _hashlib.sha3_512 = sha3_512 - _hashlib.shake_128 = shake_128 - _hashlib.shake_256 = shake_256 diff --git a/frozen_deps/six-1.15.0.dist-info/INSTALLER b/frozen_deps/six-1.15.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/frozen_deps/six-1.15.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/frozen_deps/six-1.15.0.dist-info/LICENSE b/frozen_deps/six-1.15.0.dist-info/LICENSE deleted file mode 100644 index de66331..0000000 --- a/frozen_deps/six-1.15.0.dist-info/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -Copyright (c) 2010-2020 Benjamin Peterson - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/frozen_deps/six-1.15.0.dist-info/METADATA b/frozen_deps/six-1.15.0.dist-info/METADATA deleted file mode 100644 index 869bf25..0000000 --- a/frozen_deps/six-1.15.0.dist-info/METADATA +++ /dev/null @@ -1,49 +0,0 @@ -Metadata-Version: 2.1 -Name: six -Version: 1.15.0 -Summary: Python 2 and 3 compatibility utilities -Home-page: https://github.com/benjaminp/six -Author: Benjamin Peterson -Author-email: benjamin@python.org -License: MIT -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Utilities -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.* - -.. image:: https://img.shields.io/pypi/v/six.svg - :target: https://pypi.org/project/six/ - :alt: six on PyPI - -.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master - :target: https://travis-ci.org/benjaminp/six - :alt: six on TravisCI - -.. image:: https://readthedocs.org/projects/six/badge/?version=latest - :target: https://six.readthedocs.io/ - :alt: six's documentation on Read the Docs - -.. image:: https://img.shields.io/badge/license-MIT-green.svg - :target: https://github.com/benjaminp/six/blob/master/LICENSE - :alt: MIT License badge - -Six is a Python 2 and 3 compatibility library. It provides utility functions -for smoothing over the differences between the Python versions with the goal of -writing Python code that is compatible on both Python versions. See the -documentation for more information on what is provided. - -Six supports Python 2.7 and 3.3+. It is contained in only one Python -file, so it can be easily copied into your project. (The copyright and license -notice must be retained.) - -Online documentation is at https://six.readthedocs.io/. - -Bugs can be reported to https://github.com/benjaminp/six. The code can also -be found there. - - diff --git a/frozen_deps/six-1.15.0.dist-info/RECORD b/frozen_deps/six-1.15.0.dist-info/RECORD deleted file mode 100644 index 80bf846..0000000 --- a/frozen_deps/six-1.15.0.dist-info/RECORD +++ /dev/null @@ -1,8 +0,0 @@ -__pycache__/six.cpython-38.pyc,,
-six-1.15.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-six-1.15.0.dist-info/LICENSE,sha256=i7hQxWWqOJ_cFvOkaWWtI9gq3_YPI5P8J2K2MYXo5sk,1066
-six-1.15.0.dist-info/METADATA,sha256=W6rlyoeMZHXh6srP9NXNsm0rjAf_660re8WdH5TBT8E,1795
-six-1.15.0.dist-info/RECORD,,
-six-1.15.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
-six-1.15.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4
-six.py,sha256=U4Z_yv534W5CNyjY9i8V1OXY2SjAny8y2L5vDLhhThM,34159
diff --git a/frozen_deps/six-1.15.0.dist-info/WHEEL b/frozen_deps/six-1.15.0.dist-info/WHEEL deleted file mode 100644 index ef99c6c..0000000 --- a/frozen_deps/six-1.15.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.34.2) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/frozen_deps/six-1.15.0.dist-info/top_level.txt b/frozen_deps/six-1.15.0.dist-info/top_level.txt deleted file mode 100644 index ffe2fce..0000000 --- a/frozen_deps/six-1.15.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -six diff --git a/frozen_deps/six.py b/frozen_deps/six.py index 83f6978..4e15675 100644 --- a/frozen_deps/six.py +++ b/frozen_deps/six.py @@ -29,7 +29,7 @@ import sys import types __author__ = "Benjamin Peterson <benjamin@python.org>" -__version__ = "1.15.0" +__version__ = "1.16.0" # Useful for very coarse version differentiation. @@ -71,6 +71,11 @@ else: MAXSIZE = int((1 << 63) - 1) del X +if PY34: + from importlib.util import spec_from_loader +else: + spec_from_loader = None + def _add_doc(func, doc): """Add documentation to a function.""" @@ -186,6 +191,11 @@ class _SixMetaPathImporter(object): return self return None + def find_spec(self, fullname, path, target=None): + if fullname in self.known_modules: + return spec_from_loader(fullname, self) + return None + def __get_module(self, fullname): try: return self.known_modules[fullname] @@ -223,6 +233,12 @@ class _SixMetaPathImporter(object): return None get_source = get_code # same as get_code + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + _importer = _SixMetaPathImporter(__name__) diff --git a/keytree-0.1.9-x86_64.AppImage b/keytree-0.1.9-x86_64.AppImage Binary files differnew file mode 100755 index 0000000..561a137 --- /dev/null +++ b/keytree-0.1.9-x86_64.AppImage diff --git a/keytree-0.1.9-x86_64.AppImage.zsync b/keytree-0.1.9-x86_64.AppImage.zsync Binary files differnew file mode 100644 index 0000000..f1b35ed --- /dev/null +++ b/keytree-0.1.9-x86_64.AppImage.zsync @@ -46,7 +46,8 @@ import hashlib import hmac import unicodedata import json -from getpass import getpass +from getpass import getpass as _getpass +from itertools import zip_longest, combinations import bech32 import mnemonic @@ -54,8 +55,18 @@ from ecdsa import SigningKey, VerifyingKey, SECP256k1 from ecdsa.ecdsa import generator_secp256k1 from ecdsa.ellipticcurve import INFINITY from base58 import b58encode, b58decode -from sha3 import keccak_256 +from uuid import uuid4 from Cryptodome.Cipher import AES +from Cryptodome.Util import Counter +from Cryptodome.Hash import keccak +import shamir + + +def getpass(prompt): + if sys.stdin.isatty(): + return _getpass(prompt) + else: + return sys.stdin.readline() def sha256(data): @@ -115,7 +126,7 @@ def is_infinity(P): # parse256(p): interprets a 32-byte sequence as a 256-bit number, most # significant byte first. def parse256(p): - assert(len(p) == 32) + assert len(p) == 32 return int.from_bytes(p, byteorder='big') @@ -195,7 +206,7 @@ class BIP32: def get_eth_addr(pk): pub_key = pk.to_string() - m = keccak_256() + m = keccak.new(digest_bits = 256) m.update(pub_key) return m.hexdigest()[24:] @@ -215,10 +226,15 @@ def load_from_keystore(filename): with open(filename, "r") as f: try: parsed = json.load(f) + version = parsed['version'] + try: + if parsed['keys'][0]['type'] != 'mnemonic': + raise KeytreeError("not a mnemonic keystore file") + except KeyError: + pass ciphertext = b58decode(parsed['keys'][0]['key'])[:-4] iv = b58decode(parsed['keys'][0]['iv'])[:-4] salt = b58decode(parsed['salt'])[:-4] - tag = b58decode(parsed['pass_hash'])[:-4] passwd = getpass('Enter the password to unlock keystore: ').encode('utf-8') key = hashlib.pbkdf2_hmac( 'sha256', @@ -226,9 +242,14 @@ def load_from_keystore(filename): a = AES.new(key, mode=AES.MODE_GCM, nonce=iv).update(salt) - if tag != sha256(passwd + sha256(passwd + salt)): + if version == '5.0': + tag = b58decode(parsed['pass_hash'])[:-4] + if tag != sha256(passwd + sha256(passwd + salt)): + raise KeytreeError("incorrect keystore password") + try: + return a.decrypt_and_verify(ciphertext[:-16], ciphertext[-16:]).decode('utf-8') + except: raise KeytreeError("incorrect keystore password") - return a.decrypt_and_verify(ciphertext[:-16], ciphertext[-16:]).decode('utf-8') except KeytreeError as e: raise e except: @@ -245,10 +266,13 @@ def cb58encode(raw): def save_to_keystore(filename, words): try: with open(filename, "w") as f: - passwd = getpass('Enter the password for the keystore (utf-8): ').encode('utf-8') + passwd = getpass('Enter the password for saving (utf-8): ').encode('utf-8') + passwd2 = getpass('Enter the password again (utf-8): ').encode('utf-8') + if passwd != passwd2: + raise KeytreeError("mismatching passwords") iv = os.urandom(12) salt = os.urandom(16) - pass_hash = sha256(passwd + sha256(passwd + salt)) + # pass_hash = sha256(passwd + sha256(passwd + salt)) key = hashlib.pbkdf2_hmac( 'sha256', sha256(passwd + salt), salt, 200000) @@ -258,67 +282,281 @@ def save_to_keystore(filename, words): (c, t) = a.encrypt_and_digest(words.encode('utf-8')) ciphertext = c + t json.dump({ - 'version': "5.0", + 'version': "6.0", + 'activeIndex': 0, 'keys': [ - {'key': cb58encode(ciphertext), 'iv': cb58encode(iv)}], + { + 'key': cb58encode(ciphertext), + 'iv': cb58encode(iv), + 'type': 'mnemonic' + }], 'salt': cb58encode(salt), - 'pass_hash': cb58encode(pass_hash) + # 'pass_hash': cb58encode(pass_hash) }, f) except FileNotFoundError: raise KeytreeError("failed while saving") +# MEW keystore format (version 3.0) +def save_to_mew(priv_keys, n=1 << 18, p=1, r=8, dklen=32): + try: + passwd = getpass('Enter the password for saving (utf-8): ').encode('utf-8') + passwd2 = getpass('Enter the password again (utf-8): ').encode('utf-8') + if passwd != passwd2: + raise KeytreeError("mismatching passwords") + + for priv_key in priv_keys: + addr = get_eth_addr(priv_key.get_verifying_key()) + priv_key = priv_key.to_string() + with open("mew-{}.json".format(addr), "w") as f: + iv = os.urandom(16) + salt = os.urandom(16) + + m = 128 * r * (n + p + 2) + dk = hashlib.scrypt(passwd, salt=salt, + n=n, r=r, p=p, dklen=dklen, maxmem=m) + obj = AES.new(dk[:dklen >> 1], + mode=AES.MODE_CTR, + counter=Counter.new( + 128, + initial_value=int.from_bytes(iv, 'big'))) + enc_pk = obj.encrypt(priv_key) + + # generate MAC + h = keccak_256() + h.update(dk[len(dk) >> 1:]) + h.update(enc_pk) + mac = h.digest() + + crypto = { + 'ciphertext': enc_pk.hex(), + 'cipherparams': {'iv': iv.hex()}, + 'cipher': 'aes-128-ctr', + 'kdf': 'scrypt', + 'kdfparams': {'dklen': dklen, + 'salt': salt.hex(), + 'n': n, + 'r': r, + 'p': p}, + 'mac': mac.hex()} + json.dump({ + 'version': 3, + 'id': str(uuid4()), + 'address': addr, + 'Crypto': crypto}, f) + except FileNotFoundError: + raise KeytreeError("failed while saving") + + +def to_chunks(n, iterable): + return zip_longest(*[iter(iterable)]*n, fillvalue=0) + +def shamir256_split(secret, t, n): + shares = [bytearray() for i in range(n)] + for chunk in to_chunks(32, secret): + secret = int.from_bytes(chunk, 'big') + while True: + points = shamir.split(secret, t, n) + good = True + for p in points: + if p.bit_length() > 256: + good = False + break + if good: + # all shares are within 256 bits + for (p, s) in zip(points, shares): + s.extend(p.to_bytes(32, 'big')) + break + return shares + + +def shamir256_combine(shares): + result = bytearray() + for shares in zip(*[[(i, g) for g in to_chunks(32, s)] for (i, s) in shares]): + shares = [(i, int.from_bytes(bytearray(p), 'big')) for (i, p) in shares] + try: + secret = shamir.combine(shares) + except ValueError as e: + raise KeytreeError("invalid Shamir recovery input", e) + if secret.bit_length() > 256: + raise KeytreeError("Shamir result is too long") + result.extend(secret.to_bytes(32, 'big')) + return result + + +metamask_path = r"44'/60'/0'/0" +avax_path = r"44'/9000'/0'/0" + if __name__ == '__main__': parser = argparse.ArgumentParser(description='Derive BIP32 key pairs from BIP39 mnemonic') - parser.add_argument('--load-keystore', type=str, default=None, help='load mnemonic from a keystore file (AVAX Wallet compatible)') - parser.add_argument('--save-keystore', type=str, default=None, help='save mnemonic to a keystore file (AVAX Wallet compatible)') + parser.add_argument('--load', type=str, default=None, help='load mnemonic from a file (AVAX Wallet compatible)') + parser.add_argument('--save', type=str, default=None, help='save mnemonic to a file (AVAX Wallet compatible)') + parser.add_argument('--export-mew', action='store_true', default=False, help='export keys to MEW keystore files (mnemonic is NOT saved, only keys are saved)') parser.add_argument('--show-private', action='store_true', default=False, help='also show private keys and the mnemonic') - parser.add_argument('--custom-words', action='store_true', default=False, help='use an arbitrary word combination as mnemonic') - parser.add_argument('--account-path', default="44'/9000'/0'/0", help="path prefix for key deriving (e.g. \"0/1'/2\")") + parser.add_argument('--gen-shamir', action='store_true', default=False, help='generate Shamir\'s secret shares') + parser.add_argument('--shamir-threshold', type=int, default=2, help='Shamir\'s secret sharing threshold (number of shares to decode)') + parser.add_argument('--shamir-num', type=int, default=3, help='Shamir\'s secret sharing number (total number of shares)') + parser.add_argument('--recover-shamir', type=str, default=None, help='recover the secret from Shamir shares') + parser.add_argument('--custom', action='store_true', default=False, help='use an arbitrary word combination as mnemonic') + parser.add_argument('--seed', action='store_true', default=False, help='load mnemonic from seed') + parser.add_argument('--path', default=avax_path, help="path prefix for key deriving (e.g. \"{}\" for Metamask)".format(metamask_path)) + parser.add_argument('--metamask', action='store_true', default=False, help="use metamask path for key deriving (synonym to `--path \"{}\"`)".format(metamask_path)) parser.add_argument('--gen-mnemonic', action='store_true', default=False, help='generate a mnemonic (instead of taking an input)') parser.add_argument('--lang', type=str, default="english", help='language for mnemonic words') parser.add_argument('--start-idx', type=int, default=0, help='the start index for keys') parser.add_argument('--end-idx', type=int, default=1, help='the end index for keys (exclusive)') parser.add_argument('--hrp', type=str, default="avax", help='HRP (Human Readable Prefix, defined by Bech32)') - args = parser.parse_args() - + args, unknown = parser.parse_known_args() try: - try: - if args.gen_mnemonic: - mgen = mnemonic.Mnemonic(args.lang) - words = mgen.generate(256) + for arg in unknown: + if len(arg) > 0: + raise KeytreeError("invalid argument: `{}`".format(arg)) + mgen = mnemonic.Mnemonic(args.lang) + words = None + seed = None + # here, we check the flags to see how to obtain the mnemonic phrase or just the derived seed of it: + if args.gen_mnemonic: + # generate a new mnemonic + words = mgen.generate(256) + elif args.load: + # load from a JSON keystore file + try: + words = load_from_keystore(args.load) + except FileNotFoundError: + raise KeytreeError("invalid language") + elif args.recover_shamir: + # recover from a previously set up Shamir's secret sharing + try: + idxes = [int(i) for i in args.recover_shamir.split(',')] + except ValueError: + raise KeytreeError("invalid Shamir sharing spec, should be something like \"1,2\"") + custom_mnemonic = None + shares = [] + for idx in idxes: + swords = getpass('Enter the mnemonic for Shamir share #{}: '.format(idx)).split() + try: + if len(swords) == 48: + if custom_mnemonic == False: + raise KeytreeError("invalid Shamir share format") + custom_mnemonic = True + share = mgen.to_entropy(' '.join(swords[:24])) + mgen.to_entropy(' '.join(swords[24:])) + else: + if custom_mnemonic == True: + raise KeytreeError("invalid Shamir share format") + custom_mnemonic = False + share = mgen.to_entropy(' '.join(swords)) + except (ValueError, LookupError): + raise KeytreeError('invalid mnemonic') + shares.append((idx, share)) + if custom_mnemonic: + seed = shamir256_combine(shares) else: - if args.load_keystore: - words = load_from_keystore(args.load_keystore) - else: - words = getpass('Enter the mnemonic: ').strip() - if not args.custom_words: - mchecker = mnemonic.Mnemonic(args.lang) - if not mchecker.check(words): - raise KeytreeError("invalid mnemonic") - except FileNotFoundError: - raise KeytreeError("invalid language") + words = mgen.to_mnemonic(shamir256_combine(shares)) + elif args.seed: + seedstr = getpass('Enter the seed: ').strip() + try: + seed = bytes.fromhex(seedstr) + if len(seed) != 64: + raise ValueError + except ValueError: + raise KeytreeError("invalid seed") + else: + words = getpass('Enter the mnemonic: ').strip() + if not args.custom: + mchecker = mnemonic.Mnemonic(args.lang) + if not mchecker.check(words): + raise KeytreeError("invalid mnemonic") + + if seed is None: + seed = hashlib.pbkdf2_hmac('sha512', unicodedata.normalize('NFKD', words).encode("utf-8"), b"mnemonic", 2048) + + if args.end_idx < args.start_idx: + args.end_idx = args.start_idx + 1 + if args.show_private or args.gen_mnemonic: - print("KEEP THIS PRIVATE: {}".format(words)) - seed = hashlib.pbkdf2_hmac('sha512', unicodedata.normalize('NFKD', words).encode("utf-8"), b"mnemonic", 2048) + if words is not None: + print("KEEP THIS PRIVATE (mnemonic): {}".format(words)) + print("KEEP THIS PRIVATE (seed): {}".format(seed.hex())) + + # generate Shamir shares if the user says so + + if args.shamir_threshold: + if args.shamir_num > 20: + raise KeytreeError('Shamir threshold should be <= 20') + if args.shamir_threshold < 2 or args.shamir_threshold > args.shamir_num: + raise KeytreeError('Shamir threshold should be (2, N]') + + if args.gen_shamir: + try: + entropy = mgen.to_entropy(words) + except (ValueError, LookupError): + # not a standard BIP mnemonic, let's fallback to seed mode + entropy = None + if entropy: + shares = shamir256_split(mgen.to_entropy(words), args.shamir_threshold, args.shamir_num) + shares = [mgen.to_mnemonic(share) for share in shares] + + # checking + for case in combinations(range(args.shamir_num), args.shamir_threshold): + verify = [(i + 1, mgen.to_entropy(shares[i])) for i in case] + recovered = mgen.to_mnemonic(shamir256_combine(verify)) + if words != recovered: + raise KeytreeError('Shamir sanity check failed: {} = {}'.format(case, recovered)) + print("checked {}".format(','.join([str(i + 1) for i in case]))) + else: + shares = shamir256_split(seed, args.shamir_threshold, args.shamir_num) + shares = [mgen.to_mnemonic(share[:32]) + ' ' + mgen.to_mnemonic(share[32:]) for share in shares] + + # checking + for case in combinations(range(args.shamir_num), args.shamir_threshold): + verify = [] + for i in case: + swords = shares[i].split() + verify.append((i + 1, mgen.to_entropy(' '.join(swords[:24])) + mgen.to_entropy(' '.join(swords[24:])))) + recovered = shamir256_combine(verify) + if seed != recovered: + raise KeytreeError('Shamir sanity check failed: {} = {}'.format(case, recovered.hex())) + print("checked {}".format(','.join([str(i + 1) for i in case]))) + + + for idx, share in enumerate(shares): + print("KEEP THIS PRIVATE (share) #{} {}".format(idx + 1, share)) + + # derive the keys at the requested paths + gen = BIP32(seed) if args.start_idx < 0 or args.end_idx < 0: raise KeytreeError("invalid start/end index") + keys = [] for i in range(args.start_idx, args.end_idx): - path = "m/{}/{}".format(args.account_path, i) + path = "m/{}/{}".format(metamask_path if args.metamask else args.path, i) priv = gen.derive(path) + keys.append(priv) pub = priv.get_verifying_key() cpub = pub.to_string(encoding="compressed") if args.show_private: - print("{}.priv(raw) {}".format(i, priv.to_string().hex())) + print("{}.priv(raw/ETH/AVAX-X) 0x{}".format(i, priv.to_string().hex())) print("{}.priv(BTC) {}".format(i, get_privkey_btc(priv))) - print("{}.addr(AVAX) X-{}".format(i, bech32.bech32_encode(args.hrp, bech32.convertbits(ripemd160(sha256(cpub)), 8, 5)))) + print("{}.addr(AVAX-X/P) {}".format(i, bech32.bech32_encode(args.hrp, bech32.convertbits(ripemd160(sha256(cpub)), 8, 5)))) + + path2 = "m/{}/{}".format(metamask_path, i) + priv2 = gen.derive(path2) + pub2 = priv2.get_verifying_key() + if args.show_private: + print("{}.priv(AVAX-C) 0x{}".format(i, priv2.to_string().hex())) + print("{}.addr(AVAX-C) 0x{}".format(i, get_eth_addr(pub2))) + print("{}.addr(BTC) {}".format(i, get_btc_addr(pub))) - print("{}.addr(ETH) {}".format(i, get_eth_addr(pub))) - if args.save_keystore: - save_to_keystore(args.save_keystore, words) + print("{}.addr(ETH) 0x{}".format(i, get_eth_addr(pub))) + if args.export_mew: + save_to_mew(keys) + if args.save: + save_to_keystore(args.save, words) + print("Saved to keystore file: {}".format(args.save)) except KeytreeError as e: sys.stderr.write("error: {}\n".format(str(e))) sys.exit(1) + except KeyboardInterrupt: + sys.exit(1) diff --git a/frozen_deps/mnemonic/mnemonic.py b/mnemonic.py index 935620a..e45111b 100644 --- a/frozen_deps/mnemonic/mnemonic.py +++ b/mnemonic.py @@ -20,15 +20,15 @@ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # -import binascii import bisect import hashlib import hmac import itertools import os -import sys +from typing import AnyStr, List, Optional, Sequence, TypeVar, Union import unicodedata +_T = TypeVar("_T") PBKDF2_ROUNDS = 2048 @@ -37,20 +37,23 @@ class ConfigurationError(Exception): # From <https://stackoverflow.com/questions/212358/binary-search-bisection-in-python/2233940#2233940> -def binary_search(a, x, lo=0, hi=None): # can't use a to specify default for hi +def binary_search( + a: Sequence[_T], + x: _T, + lo: int = 0, + hi: Optional[int] = None, # can't use a to specify default for hi +) -> int: hi = hi if hi is not None else len(a) # hi defaults to len(a) pos = bisect.bisect_left(a, x, lo, hi) # find insertion position return pos if pos != hi and a[pos] == x else -1 # don't walk off the end # Refactored code segments from <https://github.com/keis/base58> -def b58encode(v): +def b58encode(v: bytes) -> str: alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" p, acc = 1, 0 for c in reversed(v): - if sys.version < "3": - c = ord(c) acc += p * c p = p << 8 @@ -62,39 +65,36 @@ def b58encode(v): class Mnemonic(object): - def __init__(self, language): + def __init__(self, language: str): + self.language = language self.radix = 2048 - if sys.version < "3": - with open("%s/%s.txt" % (self._get_directory(), language), "r") as f: - self.wordlist = [w.strip().decode("utf8") for w in f.readlines()] - else: - with open( - "%s/%s.txt" % (self._get_directory(), language), "r", encoding="utf-8" - ) as f: - self.wordlist = [w.strip() for w in f.readlines()] + with open( + "%s/%s.txt" % (self._get_directory(), language), "r", encoding="utf-8" + ) as f: + self.wordlist = [w.strip() for w in f.readlines()] if len(self.wordlist) != self.radix: raise ConfigurationError( "Wordlist should contain %d words, but it contains %d words." % (self.radix, len(self.wordlist)) ) - @classmethod - def _get_directory(cls): + @staticmethod + def _get_directory() -> str: return os.path.join(os.path.dirname(__file__), "wordlist") @classmethod - def list_languages(cls): + def list_languages(cls) -> List[str]: return [ f.split(".")[0] for f in os.listdir(cls._get_directory()) if f.endswith(".txt") ] - @classmethod - def normalize_string(cls, txt): - if isinstance(txt, str if sys.version < "3" else bytes): + @staticmethod + def normalize_string(txt: AnyStr) -> str: + if isinstance(txt, bytes): utxt = txt.decode("utf8") - elif isinstance(txt, unicode if sys.version < "3" else str): # noqa: F821 + elif isinstance(txt, str): utxt = txt else: raise TypeError("String value expected") @@ -102,7 +102,7 @@ class Mnemonic(object): return unicodedata.normalize("NFKD", utxt) @classmethod - def detect_language(cls, code): + def detect_language(cls, code: str) -> str: code = cls.normalize_string(code) first = code.split(" ")[0] languages = cls.list_languages() @@ -114,7 +114,7 @@ class Mnemonic(object): raise ConfigurationError("Language not detected") - def generate(self, strength=128): + def generate(self, strength: int = 128) -> str: if strength not in [128, 160, 192, 224, 256]: raise ValueError( "Strength should be one of the following [128, 160, 192, 224, 256], but it is not (%d)." @@ -123,7 +123,7 @@ class Mnemonic(object): return self.to_mnemonic(os.urandom(strength // 8)) # Adapted from <http://tinyurl.com/oxmn476> - def to_entropy(self, words): + def to_entropy(self, words: Union[List[str], str]) -> bytearray: if not isinstance(words, list): words = words.split(" ") if len(words) not in [12, 15, 18, 21, 24]: @@ -136,7 +136,7 @@ class Mnemonic(object): concatLenBits = len(words) * 11 concatBits = [False] * concatLenBits wordindex = 0 - if self.detect_language(" ".join(words)) == "english": + if self.language == "english": use_binary_search = True else: use_binary_search = False @@ -163,28 +163,18 @@ class Mnemonic(object): entropy[ii] |= 1 << (7 - jj) # Take the digest of the entropy. hashBytes = hashlib.sha256(entropy).digest() - if sys.version < "3": - hashBits = list( - itertools.chain.from_iterable( - ( - [ord(c) & (1 << (7 - i)) != 0 for i in range(8)] - for c in hashBytes - ) - ) - ) - else: - hashBits = list( - itertools.chain.from_iterable( - ([c & (1 << (7 - i)) != 0 for i in range(8)] for c in hashBytes) - ) + hashBits = list( + itertools.chain.from_iterable( + [c & (1 << (7 - i)) != 0 for i in range(8)] for c in hashBytes ) + ) # Check all the checksum bits. for i in range(checksumLengthBits): if concatBits[entropyLengthBits + i] != hashBits[i]: raise ValueError("Failed checksum.") return entropy - def to_mnemonic(self, data): + def to_mnemonic(self, data: bytes) -> str: if len(data) not in [16, 20, 24, 28, 32]: raise ValueError( "Data length should be one of the following: [16, 20, 24, 28, 32], but it is not (%d)." @@ -192,39 +182,39 @@ class Mnemonic(object): ) h = hashlib.sha256(data).hexdigest() b = ( - bin(int(binascii.hexlify(data), 16))[2:].zfill(len(data) * 8) + bin(int.from_bytes(data, byteorder="big"))[2:].zfill(len(data) * 8) + bin(int(h, 16))[2:].zfill(256)[: len(data) * 8 // 32] ) result = [] for i in range(len(b) // 11): idx = int(b[i * 11 : (i + 1) * 11], 2) result.append(self.wordlist[idx]) - if ( - self.detect_language(" ".join(result)) == "japanese" - ): # Japanese must be joined by ideographic space. + if self.language == "japanese": # Japanese must be joined by ideographic space. result_phrase = u"\u3000".join(result) else: result_phrase = " ".join(result) return result_phrase - def check(self, mnemonic): - mnemonic = self.normalize_string(mnemonic).split(" ") + def check(self, mnemonic: str) -> bool: + mnemonic_list = self.normalize_string(mnemonic).split(" ") # list of valid mnemonic lengths - if len(mnemonic) not in [12, 15, 18, 21, 24]: + if len(mnemonic_list) not in [12, 15, 18, 21, 24]: return False try: - idx = map(lambda x: bin(self.wordlist.index(x))[2:].zfill(11), mnemonic) + idx = map( + lambda x: bin(self.wordlist.index(x))[2:].zfill(11), mnemonic_list + ) b = "".join(idx) except ValueError: return False l = len(b) # noqa: E741 d = b[: l // 33 * 32] h = b[-l // 33 :] - nd = binascii.unhexlify(hex(int(d, 2))[2:].rstrip("L").zfill(l // 33 * 8)) + nd = int(d, 2).to_bytes(l // 33 * 4, byteorder="big") nh = bin(int(hashlib.sha256(nd).hexdigest(), 16))[2:].zfill(256)[: l // 33] return h == nh - def expand_word(self, prefix): + def expand_word(self, prefix: str) -> str: if prefix in self.wordlist: return prefix else: @@ -236,21 +226,23 @@ class Mnemonic(object): # this is not a validation routine, just return the input return prefix - def expand(self, mnemonic): + def expand(self, mnemonic: str) -> str: return " ".join(map(self.expand_word, mnemonic.split(" "))) @classmethod - def to_seed(cls, mnemonic, passphrase=""): + def to_seed(cls, mnemonic: str, passphrase: str = "") -> bytes: mnemonic = cls.normalize_string(mnemonic) passphrase = cls.normalize_string(passphrase) passphrase = "mnemonic" + passphrase - mnemonic = mnemonic.encode("utf-8") - passphrase = passphrase.encode("utf-8") - stretched = hashlib.pbkdf2_hmac("sha512", mnemonic, passphrase, PBKDF2_ROUNDS) + mnemonic_bytes = mnemonic.encode("utf-8") + passphrase_bytes = passphrase.encode("utf-8") + stretched = hashlib.pbkdf2_hmac( + "sha512", mnemonic_bytes, passphrase_bytes, PBKDF2_ROUNDS + ) return stretched[:64] - @classmethod - def to_hd_master_key(cls, seed): + @staticmethod + def to_hd_master_key(seed: bytes, testnet: bool = False) -> str: if len(seed) != 64: raise ValueError("Provided seed should have length of 64") @@ -259,6 +251,8 @@ class Mnemonic(object): # Serialization format can be found at: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Serialization_format xprv = b"\x04\x88\xad\xe4" # Version for private mainnet + if testnet: + xprv = b"\x04\x35\x83\x94" # Version for private testnet xprv += b"\x00" * 9 # Depth, parent fingerprint, and child number xprv += seed[32:] # Chain code xprv += b"\x00" + seed[:32] # Master key @@ -274,15 +268,14 @@ class Mnemonic(object): return b58encode(xprv) -def main(): - import binascii +def main() -> None: import sys if len(sys.argv) > 1: - data = sys.argv[1] + hex_data = sys.argv[1] else: - data = sys.stdin.readline().strip() - data = binascii.unhexlify(data) + hex_data = sys.stdin.readline().strip() + data = bytes.fromhex(hex_data) m = Mnemonic("english") print(m.to_mnemonic(data)) @@ -8,5 +8,5 @@ setup(name='keytree.py', author_email='tederminant@gmail.com', license='MIT', scripts=['keytree.py'], - py_modules=['bech32'], - install_requires=['ecdsa', 'base58', 'pysha3', 'pycryptodomex', 'mnemonic']) + py_modules=['bech32', 'mnemonic', 'shamir'], + install_requires=['ecdsa', 'base58', 'pycryptodomex']) diff --git a/shamir.py b/shamir.py new file mode 100644 index 0000000..cb7312c --- /dev/null +++ b/shamir.py @@ -0,0 +1,80 @@ +# Code modified from https://github.com/kurtbrose/shamir/tree/master (under CC0 +# license, so we took liberty to refactor it here) + +import secrets + +# use the prime to be compatible with the Shamir tool developed by Ava Labs: +# https://github.com/ava-labs/mnemonic-shamir-secret-sharing-cli/tree/main +# This is a 257-bit prime, so the returned points could be either 256-bit or +# (infrequently) 257-bit. +_PRIME = 187110422339161656731757292403725394067928975545356095774785896842956550853219 +# Other good choices: +# 12th Mersenne Prime is 2**127 - 1 +# 13th Mersenne Prime is 2**521 - 1 + + +def split(secret, minimum, shares, prime=_PRIME): + def y(poly, x, prime): + # evaluate polynomial (coefficient tuple) at x + accum = 0 + for coeff in reversed(poly): + accum *= x + accum += coeff + accum %= prime + return accum + + if minimum > shares: + raise ValueError("pool secret would be irrecoverable") + poly = [secrets.randbelow(prime) for i in range(minimum - 1)] + poly.insert(0, secret) + return [y(poly, i, prime) for i in range(1, shares + 1)] + + +def _divmod(num, a, p): + # extended gcd will find ax + py = gcd(a, p) + # so if p is a big prime and a < p, then ax + py = gcd(a, p) = 1, + # then y = 0, so ax = 1, x will be the multiplicative inverse for a modulo p + x = 0 + y = 1 + last_x = 1 + last_y = 0 + while p != 0: + quot = a // p + a, p = p, a % p + x, last_x = last_x - quot * x, x + y, last_y = last_y - quot * y, y + return num * last_x + +def _lagrange_interpolate(x, x_s, y_s, p): + k = len(x_s) + assert k == len(set(x_s)), "points must be distinct" + + def prod(vals): # product of inputs + r = 1 + for v in vals: + r = (r * v) % p + return r + l_s = [] + n_all = prod(x - x_j for x_j in x_s) + for i in range(k): + others = list(x_s) + x_i = others.pop(i) + # \Prod_{j \neq i}{(x - x_j)} / \Prod_{j \neq i}{(x_i - x_j)} + l_s.append(_divmod( + n_all, + (prod(x_i - x_j for x_j in others) * (x - x_i)) % p, p)) + sum = 0 + for (y, l) in zip(y_s, l_s): + sum = (sum + (y * l) % p) % p + return (sum + p) % p + + +def combine(shares, prime=_PRIME): + ''' + Recover the secret from share points + (shares contain (x, y) as points on the polynomial) + ''' + if len(shares) < 2: + raise ValueError("need at least two shares") + x_s, y_s = zip(*shares) + return _lagrange_interpolate(0, x_s, y_s, prime) diff --git a/frozen_deps/mnemonic/wordlist/chinese_simplified.txt b/wordlist/chinese_simplified.txt index b90f1ed..b90f1ed 100644 --- a/frozen_deps/mnemonic/wordlist/chinese_simplified.txt +++ b/wordlist/chinese_simplified.txt diff --git a/frozen_deps/mnemonic/wordlist/chinese_traditional.txt b/wordlist/chinese_traditional.txt index 9b02047..9b02047 100644 --- a/frozen_deps/mnemonic/wordlist/chinese_traditional.txt +++ b/wordlist/chinese_traditional.txt diff --git a/frozen_deps/mnemonic/wordlist/english.txt b/wordlist/english.txt index 942040e..942040e 100644 --- a/frozen_deps/mnemonic/wordlist/english.txt +++ b/wordlist/english.txt diff --git a/frozen_deps/mnemonic/wordlist/french.txt b/wordlist/french.txt index 8600949..bcf7942 100644 --- a/frozen_deps/mnemonic/wordlist/french.txt +++ b/wordlist/french.txt @@ -1,4 +1,4 @@ -abaisser +abaisser abandon abdiquer abeille diff --git a/frozen_deps/mnemonic/wordlist/italian.txt b/wordlist/italian.txt index c47370f..c47370f 100644 --- a/frozen_deps/mnemonic/wordlist/italian.txt +++ b/wordlist/italian.txt diff --git a/frozen_deps/mnemonic/wordlist/japanese.txt b/wordlist/japanese.txt index fb8501a..fb8501a 100644 --- a/frozen_deps/mnemonic/wordlist/japanese.txt +++ b/wordlist/japanese.txt diff --git a/frozen_deps/mnemonic/wordlist/korean.txt b/wordlist/korean.txt index 1acebf7..1acebf7 100644 --- a/frozen_deps/mnemonic/wordlist/korean.txt +++ b/wordlist/korean.txt diff --git a/frozen_deps/mnemonic/wordlist/spanish.txt b/wordlist/spanish.txt index fdbc23c..fdbc23c 100644 --- a/frozen_deps/mnemonic/wordlist/spanish.txt +++ b/wordlist/spanish.txt |