aboutsummaryrefslogtreecommitdiff
path: root/frozen_deps/Cryptodome
diff options
context:
space:
mode:
Diffstat (limited to 'frozen_deps/Cryptodome')
-rw-r--r--frozen_deps/Cryptodome/Cipher/AES.py4
-rw-r--r--frozen_deps/Cryptodome/Cipher/ChaCha20.py7
-rw-r--r--frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py6
-rw-r--r--frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py140
-rw-r--r--frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.pyi7
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_ARC4.abi3.sobin0 -> 13768 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_Salsa20.abi3.sobin0 -> 26784 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_chacha20.abi3.sobin0 -> 28224 bytes
-rw-r--r--frozen_deps/Cryptodome/Cipher/_mode_ctr.py26
-rw-r--r--frozen_deps/Cryptodome/Cipher/_mode_ecb.py2
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_pkcs1_decode.abi3.sobin0 -> 28096 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_aes.abi3.sobin0 -> 66256 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_aesni.abi3.sobin0 -> 101136 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_arc2.abi3.sobin0 -> 43776 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_blowfish.abi3.sobin0 -> 69976 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_cast.abi3.sobin0 -> 42976 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_cbc.abi3.sobin0 -> 20736 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_cfb.abi3.sobin0 -> 25440 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_ctr.abi3.sobin0 -> 28600 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_des.abi3.sobin0 -> 75672 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_des3.abi3.sobin0 -> 76480 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_ecb.abi3.sobin0 -> 12440 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_eksblowfish.abi3.sobin0 -> 166264 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_ocb.abi3.sobin0 -> 37344 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Cipher/_raw_ofb.abi3.sobin0 -> 15368 bytes
-rw-r--r--frozen_deps/Cryptodome/Hash/BLAKE2b.pyi1
-rw-r--r--frozen_deps/Cryptodome/Hash/CMAC.py3
-rw-r--r--frozen_deps/Cryptodome/Hash/CMAC.pyi6
-rw-r--r--frozen_deps/Cryptodome/Hash/HMAC.py4
-rw-r--r--frozen_deps/Cryptodome/Hash/KMAC128.py179
-rw-r--r--frozen_deps/Cryptodome/Hash/KMAC128.pyi33
-rw-r--r--frozen_deps/Cryptodome/Hash/KMAC256.py74
-rw-r--r--frozen_deps/Cryptodome/Hash/KMAC256.pyi10
-rw-r--r--frozen_deps/Cryptodome/Hash/KangarooTwelve.py262
-rw-r--r--frozen_deps/Cryptodome/Hash/KangarooTwelve.pyi16
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_224.py39
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_224.pyi5
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_256.py39
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_256.pyi5
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_384.py42
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_384.pyi5
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_512.py38
-rw-r--r--frozen_deps/Cryptodome/Hash/SHA3_512.pyi5
-rw-r--r--frozen_deps/Cryptodome/Hash/SHAKE128.py8
-rw-r--r--frozen_deps/Cryptodome/Hash/SHAKE256.py9
-rw-r--r--frozen_deps/Cryptodome/Hash/TupleHash128.py138
-rw-r--r--frozen_deps/Cryptodome/Hash/TupleHash128.pyi22
-rw-r--r--frozen_deps/Cryptodome/Hash/TupleHash256.py73
-rw-r--r--frozen_deps/Cryptodome/Hash/TupleHash256.pyi5
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_BLAKE2b.abi3.sobin0 -> 21888 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_BLAKE2s.abi3.sobin0 -> 21712 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_MD2.abi3.sobin0 -> 20128 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_MD4.abi3.sobin0 -> 25576 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_MD5.abi3.sobin0 -> 31704 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_RIPEMD160.abi3.sobin0 -> 55608 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_SHA1.abi3.sobin0 -> 74416 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_SHA224.abi3.sobin0 -> 43792 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_SHA256.abi3.sobin0 -> 43872 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_SHA384.abi3.sobin0 -> 50520 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_SHA512.abi3.sobin0 -> 50624 bytes
-rw-r--r--frozen_deps/Cryptodome/Hash/__init__.py4
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_ghash_clmul.abi3.sobin0 -> 50160 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_ghash_portable.abi3.sobin0 -> 17432 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_keccak.abi3.sobin0 -> 35064 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Hash/_poly1305.abi3.sobin0 -> 33360 bytes
-rw-r--r--frozen_deps/Cryptodome/Hash/cSHAKE128.py187
-rw-r--r--frozen_deps/Cryptodome/Hash/cSHAKE128.pyi14
-rw-r--r--frozen_deps/Cryptodome/Hash/cSHAKE256.py56
-rw-r--r--frozen_deps/Cryptodome/Hash/cSHAKE256.pyi8
-rw-r--r--frozen_deps/Cryptodome/Hash/keccak.py20
-rw-r--r--frozen_deps/Cryptodome/IO/PKCS8.py60
-rw-r--r--frozen_deps/Cryptodome/IO/PKCS8.pyi2
-rw-r--r--frozen_deps/Cryptodome/Math/Primality.py5
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerBase.py6
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerBase.pyi4
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerCustom.py9
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerGMP.py96
-rw-r--r--frozen_deps/Cryptodome/Math/_IntegerNative.py21
-rwxr-xr-xfrozen_deps/Cryptodome/Math/_modexp.abi3.sobin0 -> 294464 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/Protocol/_scrypt.abi3.sobin0 -> 25024 bytes
-rw-r--r--frozen_deps/Cryptodome/PublicKey/DSA.py9
-rw-r--r--frozen_deps/Cryptodome/PublicKey/DSA.pyi3
-rw-r--r--frozen_deps/Cryptodome/PublicKey/ECC.py1036
-rw-r--r--frozen_deps/Cryptodome/PublicKey/ECC.pyi10
-rw-r--r--frozen_deps/Cryptodome/PublicKey/RSA.py20
-rw-r--r--frozen_deps/Cryptodome/PublicKey/RSA.pyi3
-rw-r--r--frozen_deps/Cryptodome/PublicKey/__init__.py17
-rwxr-xr-xfrozen_deps/Cryptodome/PublicKey/_ec_ws.abi3.sobin0 -> 1068008 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/PublicKey/_ed25519.abi3.sobin0 -> 578280 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/PublicKey/_ed448.abi3.sobin0 -> 329424 bytes
-rwxr-xr-xfrozen_deps/Cryptodome/PublicKey/_x25519.abi3.sobin0 -> 124632 bytes
-rw-r--r--frozen_deps/Cryptodome/Signature/DSS.py158
-rw-r--r--frozen_deps/Cryptodome/Signature/__init__.py2
-rw-r--r--frozen_deps/Cryptodome/Signature/eddsa.py341
-rw-r--r--frozen_deps/Cryptodome/Signature/eddsa.pyi21
-rw-r--r--frozen_deps/Cryptodome/Signature/pkcs1_15.py2
-rw-r--r--frozen_deps/Cryptodome/Util/Counter.py7
-rw-r--r--frozen_deps/Cryptodome/Util/Padding.py2
-rwxr-xr-xfrozen_deps/Cryptodome/Util/_cpuid_c.abi3.sobin0 -> 12776 bytes
-rw-r--r--frozen_deps/Cryptodome/Util/_raw_api.py62
-rwxr-xr-xfrozen_deps/Cryptodome/Util/_strxor.abi3.sobin0 -> 14960 bytes
-rw-r--r--frozen_deps/Cryptodome/Util/asn1.py19
-rw-r--r--frozen_deps/Cryptodome/Util/number.py101
-rw-r--r--frozen_deps/Cryptodome/Util/py3compat.py34
-rw-r--r--frozen_deps/Cryptodome/Util/py3compat.pyi12
-rw-r--r--frozen_deps/Cryptodome/Util/strxor.py51
-rw-r--r--frozen_deps/Cryptodome/__init__.py2
107 files changed, 2982 insertions, 635 deletions
diff --git a/frozen_deps/Cryptodome/Cipher/AES.py b/frozen_deps/Cryptodome/Cipher/AES.py
index dd2671a..566a207 100644
--- a/frozen_deps/Cryptodome/Cipher/AES.py
+++ b/frozen_deps/Cryptodome/Cipher/AES.py
@@ -111,7 +111,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.
"""
@@ -180,7 +180,7 @@ def new(key, mode, *args, **kwargs):
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.
diff --git a/frozen_deps/Cryptodome/Cipher/ChaCha20.py b/frozen_deps/Cryptodome/Cipher/ChaCha20.py
index 0cd9102..b4f8b5f 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,8 +104,7 @@ class ChaCha20Cipher(object):
self._name = "XChaCha20"
else:
self._name = "ChaCha20"
-
- self.nonce = _copy_bytes(None, None, nonce)
+ nonce = self.nonce
self._next = ( self.encrypt, self.decrypt )
@@ -112,7 +113,7 @@ class ChaCha20Cipher(object):
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,
diff --git a/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py b/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py
index 3207bbe..7525c5d 100644
--- a/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py
+++ b/frozen_deps/Cryptodome/Cipher/PKCS1_OAEP.py
@@ -188,9 +188,9 @@ class PKCS1OAEP_Cipher:
# Step 3f
db = strxor(maskedDB, dbMask)
# Step 3g
- one_pos = db[hLen:].find(b'\x01')
+ one_pos = hLen + db[hLen:].find(b'\x01')
lHash1 = db[:hLen]
- invalid = bord(y) | int(one_pos < 0)
+ invalid = bord(y) | int(one_pos < hLen)
hash_compare = strxor(lHash1, lHash)
for x in hash_compare:
invalid |= bord(x)
@@ -199,7 +199,7 @@ class PKCS1OAEP_Cipher:
if invalid != 0:
raise ValueError("Incorrect decryption.")
# Step 4
- return db[hLen + one_pos + 1:]
+ return db[one_pos + 1:]
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.
diff --git a/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py b/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py
index 1fd1626..17ef9eb 100644
--- a/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py
+++ b/frozen_deps/Cryptodome/Cipher/PKCS1_v1_5.py
@@ -20,12 +20,37 @@
# 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 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);
+ """)
+
+
+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
+
class PKCS115_Cipher:
"""This cipher can perform PKCS#1 v1.5 RSA encryption or decryption.
@@ -74,8 +99,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
@@ -100,81 +124,76 @@ 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
-
- :Returns: A byte string. It is either the original message or the ``sentinel`` (in case of an error).
+ expected_pt_len (integer):
+ The length the plaintext is known to have, or 0 if unknown.
- :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 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 +215,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/_ARC4.abi3.so b/frozen_deps/Cryptodome/Cipher/_ARC4.abi3.so
new file mode 100755
index 0000000..c367472
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_ARC4.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_Salsa20.abi3.so b/frozen_deps/Cryptodome/Cipher/_Salsa20.abi3.so
new file mode 100755
index 0000000..10ba4b7
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_Salsa20.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_chacha20.abi3.so b/frozen_deps/Cryptodome/Cipher/_chacha20.abi3.so
new file mode 100755
index 0000000..316d6cb
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_chacha20.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_mode_ctr.py b/frozen_deps/Cryptodome/Cipher/_mode_ctr.py
index 99712d0..74783ec 100644
--- a/frozen_deps/Cryptodome/Cipher/_mode_ctr.py
+++ b/frozen_deps/Cryptodome/Cipher/_mode_ctr.py
@@ -184,15 +184,15 @@ class CtrMode(object):
if self.encrypt not in self._next:
raise TypeError("encrypt() cannot be called after decrypt()")
self._next = [self.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:
@@ -248,7 +248,7 @@ class CtrMode(object):
if self.decrypt not in self._next:
raise TypeError("decrypt() cannot be called after encrypt()")
self._next = [self.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_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/_pkcs1_decode.abi3.so b/frozen_deps/Cryptodome/Cipher/_pkcs1_decode.abi3.so
new file mode 100755
index 0000000..cbb4a6f
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_pkcs1_decode.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_aes.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_aes.abi3.so
new file mode 100755
index 0000000..883fc94
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_aes.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_aesni.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_aesni.abi3.so
new file mode 100755
index 0000000..8e971c8
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_aesni.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_arc2.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_arc2.abi3.so
new file mode 100755
index 0000000..2370b62
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_arc2.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_blowfish.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_blowfish.abi3.so
new file mode 100755
index 0000000..48af6a3
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_blowfish.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cast.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_cast.abi3.so
new file mode 100755
index 0000000..7efb7e7
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_cast.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cbc.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_cbc.abi3.so
new file mode 100755
index 0000000..0696380
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_cbc.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_cfb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_cfb.abi3.so
new file mode 100755
index 0000000..32d333a
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_cfb.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ctr.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ctr.abi3.so
new file mode 100755
index 0000000..1810b56
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_ctr.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_des.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_des.abi3.so
new file mode 100755
index 0000000..01a2495
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_des.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_des3.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_des3.abi3.so
new file mode 100755
index 0000000..ec932c1
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_des3.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ecb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ecb.abi3.so
new file mode 100755
index 0000000..7dc6a67
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_ecb.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.abi3.so
new file mode 100755
index 0000000..43734c9
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_eksblowfish.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ocb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ocb.abi3.so
new file mode 100755
index 0000000..50e0016
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_ocb.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Cipher/_raw_ofb.abi3.so b/frozen_deps/Cryptodome/Cipher/_raw_ofb.abi3.so
new file mode 100755
index 0000000..e0db6db
--- /dev/null
+++ b/frozen_deps/Cryptodome/Cipher/_raw_ofb.abi3.so
Binary files differ
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/CMAC.py b/frozen_deps/Cryptodome/Hash/CMAC.py
index df69f00..e831700 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
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..165dd83 100644
--- a/frozen_deps/Cryptodome/Hash/HMAC.py
+++ b/frozen_deps/Cryptodome/Hash/HMAC.py
@@ -31,7 +31,7 @@
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
-from Cryptodome.Util.py3compat import bord, tobytes, _memoryview
+from Cryptodome.Util.py3compat import bord, tobytes
from binascii import unhexlify
@@ -64,7 +64,7 @@ class HMAC(object):
self._digestmod = digestmod
- if isinstance(key, _memoryview):
+ 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 <[email protected]>
+# 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 <[email protected]>
+# 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..44d935f
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/KangarooTwelve.py
@@ -0,0 +1,262 @@
+# ===================================================================
+#
+# Copyright (c) 2021, Legrandin <[email protected]>
+# 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 (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
+
+
+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
+ self._hash1 = self._create_keccak()
+ 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 _create_keccak(self):
+ state = VoidPointer()
+ result = _raw_keccak_lib.keccak_init(state.address_of(),
+ c_size_t(32), # 32 bytes of capacity (256 bits)
+ c_ubyte(12)) # Reduced number of rounds
+ if result:
+ raise ValueError("Error %d while instantiating KangarooTwelve"
+ % result)
+ return SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy)
+
+ def _update(self, data, hash_obj):
+ result = _raw_keccak_lib.keccak_absorb(hash_obj.get(),
+ c_uint8_ptr(data),
+ c_size_t(len(data)))
+ if result:
+ raise ValueError("Error %d while updating KangarooTwelve state"
+ % result)
+
+ def _squeeze(self, hash_obj, length, padding):
+ bfr = create_string_buffer(length)
+ result = _raw_keccak_lib.keccak_squeeze(hash_obj.get(),
+ bfr,
+ c_size_t(length),
+ c_ubyte(padding))
+ if result:
+ raise ValueError("Error %d while extracting from KangarooTwelve"
+ % result)
+
+ return get_raw_buffer(bfr)
+
+ def _reset(self, hash_obj):
+ result = _raw_keccak_lib.keccak_reset(hash_obj.get())
+ if result:
+ raise ValueError("Error %d while resetting KangarooTwelve state"
+ % result)
+
+ 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._update(data, self._hash1)
+ 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._update(data_mem[:dtc], self._hash1)
+ 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._update(divider, self._hash1)
+ self._length1 += 8
+
+ self._hash2 = self._create_keccak()
+ 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._update(data_mem[index:new_index], self._hash2)
+ self._length2 += new_index - index
+ index = new_index
+
+ if self._length2 == 8192:
+ cv_i = self._squeeze(self._hash2, 32, 0x0B)
+ self._update(cv_i, self._hash1)
+ self._length1 += 32
+ self._reset(self._hash2)
+ 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._update(self._custom, self._hash1)
+ 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._squeeze(self._hash2, 32, 0x0B)
+ self._update(cv_i, self._hash1)
+ self._length1 += 32
+ self._reset(self._hash2)
+ self._length2 = 0
+ self._ctr += 1
+
+ trailer = _length_encode(self._ctr - 1) + b'\xFF\xFF'
+ self._update(trailer, self._hash1)
+
+ self._padding = 0x06
+ self._state = SQUEEZING
+
+ return self._squeeze(self._hash1, length, self._padding)
+
+ 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..5c910e4
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/TupleHash128.py
@@ -0,0 +1,138 @@
+# ===================================================================
+#
+# Copyright (c) 2021, Legrandin <[email protected]>
+# 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 byte string in the tuple.
+
+ Args:
+ data (bytes/bytearray/memoryview): The next byte string.
+ """
+
+ if self._digest is not None:
+ raise TypeError("You cannot call 'update' after 'digest' or 'hexdigest'")
+
+ if not is_bytes(data):
+ raise TypeError("You can only call 'update' on bytes")
+
+ self._cshake.update(_encode_str(tobytes(data)))
+
+ 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'')
+
+ if kwargs:
+ raise TypeError("Unknown parameters: " + str(kwargs))
+
+ 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..3b1e81e
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/TupleHash128.pyi
@@ -0,0 +1,22 @@
+from typing import Any, Union
+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..9b4fba0
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/TupleHash256.py
@@ -0,0 +1,73 @@
+# ===================================================================
+#
+# Copyright (c) 2021, Legrandin <[email protected]>
+# 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'')
+
+ if kwargs:
+ raise TypeError("Unknown parameters: " + str(kwargs))
+
+ 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/_BLAKE2b.abi3.so b/frozen_deps/Cryptodome/Hash/_BLAKE2b.abi3.so
new file mode 100755
index 0000000..dfdf331
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_BLAKE2b.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_BLAKE2s.abi3.so b/frozen_deps/Cryptodome/Hash/_BLAKE2s.abi3.so
new file mode 100755
index 0000000..26e69e8
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_BLAKE2s.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_MD2.abi3.so b/frozen_deps/Cryptodome/Hash/_MD2.abi3.so
new file mode 100755
index 0000000..576ba1e
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_MD2.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_MD4.abi3.so b/frozen_deps/Cryptodome/Hash/_MD4.abi3.so
new file mode 100755
index 0000000..0afc5ca
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_MD4.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_MD5.abi3.so b/frozen_deps/Cryptodome/Hash/_MD5.abi3.so
new file mode 100755
index 0000000..38caf8d
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_MD5.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_RIPEMD160.abi3.so b/frozen_deps/Cryptodome/Hash/_RIPEMD160.abi3.so
new file mode 100755
index 0000000..2c02e71
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_RIPEMD160.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_SHA1.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA1.abi3.so
new file mode 100755
index 0000000..2d86b06
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_SHA1.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_SHA224.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA224.abi3.so
new file mode 100755
index 0000000..c462c9b
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_SHA224.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_SHA256.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA256.abi3.so
new file mode 100755
index 0000000..c51c162
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_SHA256.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_SHA384.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA384.abi3.so
new file mode 100755
index 0000000..4a4237e
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_SHA384.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_SHA512.abi3.so b/frozen_deps/Cryptodome/Hash/_SHA512.abi3.so
new file mode 100755
index 0000000..ff9a01f
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_SHA512.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/__init__.py b/frozen_deps/Cryptodome/Hash/__init__.py
index 719cd8d..4bda084 100644
--- a/frozen_deps/Cryptodome/Hash/__init__.py
+++ b/frozen_deps/Cryptodome/Hash/__init__.py
@@ -19,4 +19,6 @@
# ===================================================================
__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1',
- 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'CMAC', 'Poly1305']
+ 'SHA224', 'SHA256', 'SHA384', 'SHA512', 'CMAC', 'Poly1305',
+ 'cSHAKE128', 'cSHAKE256', 'KMAC128', 'KMAC256',
+ 'TupleHash128', 'TupleHash256', 'KangarooTwelve']
diff --git a/frozen_deps/Cryptodome/Hash/_ghash_clmul.abi3.so b/frozen_deps/Cryptodome/Hash/_ghash_clmul.abi3.so
new file mode 100755
index 0000000..248bdb7
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_ghash_clmul.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_ghash_portable.abi3.so b/frozen_deps/Cryptodome/Hash/_ghash_portable.abi3.so
new file mode 100755
index 0000000..292f45d
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_ghash_portable.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_keccak.abi3.so b/frozen_deps/Cryptodome/Hash/_keccak.abi3.so
new file mode 100755
index 0000000..b251995
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_keccak.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/_poly1305.abi3.so b/frozen_deps/Cryptodome/Hash/_poly1305.abi3.so
new file mode 100755
index 0000000..e8da59e
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/_poly1305.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Hash/cSHAKE128.py b/frozen_deps/Cryptodome/Hash/cSHAKE128.py
new file mode 100644
index 0000000..7c2f30a
--- /dev/null
+++ b/frozen_deps/Cryptodome/Hash/cSHAKE128.py
@@ -0,0 +1,187 @@
+# ===================================================================
+#
+# Copyright (c) 2021, Legrandin <[email protected]>
+# 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
+
+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 _left_encode(bitlen) + x
+
+
+def _bytepad(x, length):
+ """Zero pad byte string as defined in NIST SP 800-185"""
+
+ to_pad = _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 <[email protected]>
+# 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..d02aed9 100644
--- a/frozen_deps/Cryptodome/IO/PKCS8.py
+++ b/frozen_deps/Cryptodome/IO/PKCS8.py
@@ -48,7 +48,7 @@ __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:
@@ -92,9 +92,10 @@ def wrap(private_key, key_oid, passphrase=None, protection=None,
| | 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.
+ 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
@@ -106,9 +107,6 @@ def wrap(private_key, key_oid, passphrase=None, protection=None,
The PKCS#8-wrapped private key (possibly encrypted), as a byte string.
"""
- if key_params is None:
- key_params = DerNull()
-
#
# PrivateKeyInfo ::= SEQUENCE {
# version Version,
@@ -117,12 +115,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()
@@ -185,11 +185,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 +198,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 +231,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..be716af 100644
--- a/frozen_deps/Cryptodome/IO/PKCS8.pyi
+++ b/frozen_deps/Cryptodome/IO/PKCS8.pyi
@@ -7,7 +7,7 @@ def wrap(private_key: bytes,
passphrase: Union[bytes, str] = ...,
protection: str = ...,
prot_params: Dict = ...,
- key_params: DerObject = ...,
+ key_params: Optional[DerObject] = ...,
randfunc: Optional[Callable[[int],str]] = ...) -> bytes: ...
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..7d78c4b 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
diff --git a/frozen_deps/Cryptodome/Math/_IntegerBase.pyi b/frozen_deps/Cryptodome/Math/_IntegerBase.pyi
index 3f534db..362c512 100644
--- a/frozen_deps/Cryptodome/Math/_IntegerBase.pyi
+++ b/frozen_deps/Cryptodome/Math/_IntegerBase.pyi
@@ -7,9 +7,9 @@ class IntegerBase:
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: ...
diff --git a/frozen_deps/Cryptodome/Math/_IntegerCustom.py b/frozen_deps/Cryptodome/Math/_IntegerCustom.py
index b626014..0e23152 100644
--- a/frozen_deps/Cryptodome/Math/_IntegerCustom.py
+++ b/frozen_deps/Cryptodome/Math/_IntegerCustom.py
@@ -57,7 +57,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):
diff --git a/frozen_deps/Cryptodome/Math/_IntegerGMP.py b/frozen_deps/Cryptodome/Math/_IntegerGMP.py
index c860020..3ab7c59 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,7 +746,7 @@ 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)
# Clean-up
diff --git a/frozen_deps/Cryptodome/Math/_IntegerNative.py b/frozen_deps/Cryptodome/Math/_IntegerNative.py
index 896107f..9b857ea 100644
--- a/frozen_deps/Cryptodome/Math/_IntegerNative.py
+++ b/frozen_deps/Cryptodome/Math/_IntegerNative.py
@@ -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
@@ -348,7 +363,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
diff --git a/frozen_deps/Cryptodome/Math/_modexp.abi3.so b/frozen_deps/Cryptodome/Math/_modexp.abi3.so
new file mode 100755
index 0000000..3e0e3b2
--- /dev/null
+++ b/frozen_deps/Cryptodome/Math/_modexp.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so b/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so
new file mode 100755
index 0000000..6ba8f35
--- /dev/null
+++ b/frozen_deps/Cryptodome/Protocol/_scrypt.abi3.so
Binary files differ
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..84a4e07 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, 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,34 @@ 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())
+ 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 +555,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 +587,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 +608,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 +621,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 +639,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 +663,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 +688,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,34 +726,79 @@ 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 = curve_name
+
+ 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 other.has_private() != self.has_private():
@@ -481,7 +808,10 @@ class EccKey(object):
def __repr__(self):
if self.has_private():
- extra = ", d=%d" % int(self._d)
+ if self._is_eddsa():
+ extra = ", seed=%s" % self._seed.hex()
+ else:
+ extra = ", d=%d" % int(self._d)
else:
extra = ""
x, y = self.pointQ.xy
@@ -492,6 +822,7 @@ class EccKey(object):
return self._d is not None
+ # ECDSA
def _sign(self, z, k):
assert 0 < k < self._curve.order
@@ -506,6 +837,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 +852,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 +872,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 +888,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
- unrestricted_oid = "1.2.840.10045.2.1"
- return _create_subject_public_key_info(unrestricted_oid,
+ 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)
+
+ 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()
@@ -593,11 +959,18 @@ class EccKey(object):
if kwargs.get('passphrase', None) is not None and 'protection' not in kwargs:
raise ValueError("At least the 'protection' parameter should be present")
- unrestricted_oid = "1.2.840.10045.2.1"
- private_key = self._export_private_der(include_ec_params=False)
+ 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)
+
result = PKCS8.wrap(private_key,
- unrestricted_oid,
- key_params=DerObjectId(self._curve.oid),
+ oid,
+ key_params=params,
**kwargs)
return result
@@ -610,7 +983,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 +1006,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))
@@ -665,6 +1046,15 @@ 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.
+
+ * For NIST P-curves: equivalent to ``'SEC1'``.
+ * For EdDSA curves: ``bytes`` in the format defined in `RFC8032`_.
passphrase (byte string or string):
The passphrase to use for protecting the private key.
@@ -673,9 +1063,7 @@ class EccKey(object):
Only relevant for private keys.
If ``True`` (default and recommended), the `PKCS#8`_ representation
- will be used.
-
- If ``False``, the much weaker `PEM encryption`_ mechanism will be used.
+ will be used. It must be ``True`` for EdDSA curves.
protection (string):
When a private key is exported with password-protection
@@ -684,10 +1072,13 @@ class EccKey(object):
It is recommended to use ``PBKDF2WithHMAC-SHA1AndAES128-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 method returns the full public key.
- If ``False`` (default), the full public key will be exported.
+ This parameter is ignored for EdDSA curves, as compression is
+ mandatory.
.. warning::
If you don't provide a passphrase, the private key will be
@@ -700,18 +1091,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 +1114,10 @@ class EccKey(object):
if not passphrase:
raise ValueError("Empty passphrase")
use_pkcs8 = args.pop("use_pkcs8", True)
+
+ if not use_pkcs8 and self._is_eddsa():
+ raise ValueError("'pkcs8' must be True for EdDSA curves")
+
if ext_format == "PEM":
if use_pkcs8:
if passphrase:
@@ -738,9 +1133,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 +1144,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 +1161,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 +1174,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 +1231,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 +1283,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 +1296,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 +1307,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
#
@@ -949,7 +1392,7 @@ def _import_private_der(encoded, passphrase, curve_oid=None):
# 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)
+ 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 +1404,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 +1452,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 +1469,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)
- return _import_public_der(curve.oid, keyparts[2])
+ # 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])
+
+ 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 +1519,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"):
+
+ 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)
+
+ 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")
- 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
+ point_x = Integer.from_bytes(public_key[1:1+modulus_bytes])
+ point_y = Integer.from_bytes(public_key[1+modulus_bytes:])
- public_key, decrypted = read_bytes(decrypted)
+ private_key, decrypted = read_bytes(decrypted)
+ d = Integer.from_bytes(private_key)
- 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")
+ params = {'d': d, 'curve': ecdsa_curve_name}
- 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)
+ elif key_type in eddsa_keys:
- private_key, decrypted = read_bytes(decrypted)
- d = Integer.from_bytes(private_key)
+ 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
+ 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
+ """
-def import_key(encoded, passphrase=None):
+ 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 +1688,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 +1710,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 +1740,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 +1758,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 b'\x02\x03\x04':
+ 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..b0bfbec 100644
--- a/frozen_deps/Cryptodome/PublicKey/ECC.pyi
+++ b/frozen_deps/Cryptodome/PublicKey/ECC.pyi
@@ -38,7 +38,7 @@ class EccKey(object):
@property
def pointQ(self) -> EccPoint: ...
def public_key(self) -> EccKey: ...
- def export_key(self, **kwargs: Union[str, bytes, bool]) -> str: ...
+ def export_key(self, **kwargs: Union[str, bytes, bool]) -> Union[str,bytes]: ...
_Curve = NamedTuple("_Curve", [('p', Integer),
@@ -51,7 +51,7 @@ _Curve = NamedTuple("_Curve", [('p', Integer),
('oid', str),
('context', Any),
('desc', str),
- ('openssh', str),
+ ('openssh', Union[str, None]),
])
_curves : Dict[str, _Curve]
@@ -59,4 +59,8 @@ _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..bafe036 100644
--- a/frozen_deps/Cryptodome/PublicKey/RSA.py
+++ b/frozen_deps/Cryptodome/PublicKey/RSA.py
@@ -37,7 +37,7 @@ 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.Math.Numbers import Integer
from Cryptodome.Math.Primality import (test_probable_prime,
@@ -69,7 +69,9 @@ class RsaKey(object):
:vartype q: integer
:ivar u: Chinese remainder component (:math:`p^{-1} \text{mod } q`)
- :vartype q: integer
+ :vartype u: integer
+
+ :undocumented: exportKey, publickey
"""
def __init__(self, **kwargs):
@@ -164,7 +166,7 @@ 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
+ # 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):
@@ -182,7 +184,7 @@ class RsaKey(object):
def can_sign(self): # legacy
return True
- def publickey(self):
+ def public_key(self):
"""A matching RSA public key.
Returns:
@@ -337,19 +339,22 @@ 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:
protection = 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC'
binary_key = PKCS8.wrap(binary_key, oid,
- passphrase, protection)
+ passphrase, protection,
+ 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':
@@ -364,6 +369,7 @@ class RsaKey(object):
# Backward compatibility
exportKey = export_key
+ publickey = public_key
# Methods defined in PyCryptodome that we don't support anymore
def sign(self, M, K):
diff --git a/frozen_deps/Cryptodome/PublicKey/RSA.pyi b/frozen_deps/Cryptodome/PublicKey/RSA.pyi
index e4d0369..d436acf 100644
--- a/frozen_deps/Cryptodome/PublicKey/RSA.pyi
+++ b/frozen_deps/Cryptodome/PublicKey/RSA.pyi
@@ -24,7 +24,7 @@ class RsaKey(object):
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: ...
@@ -35,6 +35,7 @@ class RsaKey(object):
# Backward compatibility
exportKey = export_key
+ publickey = public_key
def generate(bits: int, randfunc: Optional[RNG]=None, e: Optional[int]=65537) -> RsaKey: ...
def construct(rsa_components: Union[Tuple[int, int], # n, e
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.abi3.so b/frozen_deps/Cryptodome/PublicKey/_ec_ws.abi3.so
new file mode 100755
index 0000000..b6fd404
--- /dev/null
+++ b/frozen_deps/Cryptodome/PublicKey/_ec_ws.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/PublicKey/_ed25519.abi3.so b/frozen_deps/Cryptodome/PublicKey/_ed25519.abi3.so
new file mode 100755
index 0000000..bd8bcc5
--- /dev/null
+++ b/frozen_deps/Cryptodome/PublicKey/_ed25519.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/PublicKey/_ed448.abi3.so b/frozen_deps/Cryptodome/PublicKey/_ed448.abi3.so
new file mode 100755
index 0000000..ee47399
--- /dev/null
+++ b/frozen_deps/Cryptodome/PublicKey/_ed448.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/PublicKey/_x25519.abi3.so b/frozen_deps/Cryptodome/PublicKey/_x25519.abi3.so
new file mode 100755
index 0000000..bbdc726
--- /dev/null
+++ b/frozen_deps/Cryptodome/PublicKey/_x25519.abi3.so
Binary files differ
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/__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..e80a866
--- /dev/null
+++ b/frozen_deps/Cryptodome/Signature/eddsa.py
@@ -0,0 +1,341 @@
+# ===================================================================
+#
+# Copyright (c) 2022, Legrandin <[email protected]>
+# 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):
+ """Import an EdDSA ECC public key, when encoded as raw ``bytes`` as 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):
+ """Import an EdDSA ECC private key, when encoded as raw ``bytes`` as 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..bf985c4
--- /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: bytes, 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..ae9257e 100644
--- a/frozen_deps/Cryptodome/Signature/pkcs1_15.py
+++ b/frozen_deps/Cryptodome/Signature/pkcs1_15.py
@@ -202,7 +202,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("Selected hash algorithm has a too long digest (%d bytes)." % len(digest))
PS = b'\xFF' * (emLen - len(digestInfo) - 3)
return b'\x00\x01' + PS + b'\x00' + digestInfo
diff --git a/frozen_deps/Cryptodome/Util/Counter.py b/frozen_deps/Cryptodome/Util/Counter.py
index 423f91f..c67bc95 100644
--- a/frozen_deps/Cryptodome/Util/Counter.py
+++ b/frozen_deps/Cryptodome/Util/Counter.py
@@ -45,6 +45,7 @@ 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.
@@ -61,6 +62,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
new file mode 100755
index 0000000..60f1e26
--- /dev/null
+++ b/frozen_deps/Cryptodome/Util/_cpuid_c.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Util/_raw_api.py b/frozen_deps/Cryptodome/Util/_raw_api.py
index 9423738..c2e0187 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.
@@ -98,7 +93,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 +106,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 +170,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 +197,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 +206,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 +234,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 +259,6 @@ except ImportError:
return VoidPointer_ctypes()
backend = "ctypes"
- del ctypes
class SmartPointer(object):
@@ -301,27 +299,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
new file mode 100755
index 0000000..c028978
--- /dev/null
+++ b/frozen_deps/Cryptodome/Util/_strxor.abi3.so
Binary files differ
diff --git a/frozen_deps/Cryptodome/Util/asn1.py b/frozen_deps/Cryptodome/Util/asn1.py
index 18e080c..a88f087 100644
--- a/frozen_deps/Cryptodome/Util/asn1.py
+++ b/frozen_deps/Cryptodome/Util/asn1.py
@@ -137,7 +137,7 @@ class DerObject(object):
self._tag_octet = 0xA0 | self._convertTag(explicit)
self._inner_tag_octet = 0x20 * constructed | asn1Id
return
-
+
self._tag_octet = 0x20 * constructed | asn1Id
def _convertTag(self, tag):
@@ -442,7 +442,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)
@@ -704,21 +704,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"
@@ -751,7 +750,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/number.py b/frozen_deps/Cryptodome/Util/number.py
index 0367fdc..5af85a3 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
@@ -141,14 +141,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
@@ -375,46 +380,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 +470,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..9a982e9 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,11 @@ 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
+ 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 +100,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 +128,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 +137,10 @@ else:
def byte_string(s):
return isinstance(s, bytes)
- # In Python 3.x, StringIO is a sub-module of io
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 +149,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..9c2f83b 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, 15, '0')
__version__ = ".".join([str(x) for x in version_info])