pygost/gost28147.py | 83 +++++++++++++++++++++++++++-------------------------- pygost/gost28147_mac.py | 10 +++++----- pygost/gost3410.py | 106 +++++++++++++++++++++++++++--------------------------- pygost/gost3410_vko.py | 25 +++++++------------------ pygost/gost34112012.py | 8 ++++---- pygost/gost34112012256.py | 2 +- pygost/gost34112012512.py | 2 +- pygost/gost341194.py | 12 ++++++------ pygost/gost3412.py | 26 +++++++++++--------------- pygost/gost3413.py | 132 ++++++++++++++++++++++++++++++----------------------- pygost/iface.py | 10 +++++----- pygost/kdf.py | 33 +++++++++++++++------------------ pygost/mgm.py | 36 ++++++++++++++++++------------------ pygost/pbkdf2.py | 2 +- pygost/sespake.py | 5 +++-- pygost/stubs/pygost/gost28147.pyi | 101 ----------------------------------------------------- pygost/stubs/pygost/gost28147_mac.pyi | 25 ------------------------- pygost/stubs/pygost/gost3410.pyi | 72 ----------------------------------------------------- pygost/stubs/pygost/gost3410_vko.pyi | 17 ----------------- pygost/stubs/pygost/gost34112012.pyi | 18 ------------------ pygost/stubs/pygost/gost34112012256.pyi | 21 --------------------- pygost/stubs/pygost/gost34112012512.pyi | 24 ------------------------ pygost/stubs/pygost/gost341194.pyi | 25 ------------------------- pygost/stubs/pygost/gost3412.pyi | 18 ------------------ pygost/stubs/pygost/gost3413.pyi | 81 ----------------------------------------------------- pygost/stubs/pygost/iface.pyi | 19 ------------------- pygost/stubs/pygost/kdf.pyi | 22 ---------------------- pygost/stubs/pygost/mgm.pyi | 17 ----------------- pygost/stubs/pygost/utils.pyi | 19 ------------------- pygost/stubs/pygost/wrap.pyi | 31 ------------------------------- pygost/utils.py | 7 ++----- pygost/wrap.py | 18 +++++++++--------- diff --git a/pygost/gost28147.py b/pygost/gost28147.py index 033104637bcacde977d3f518dd8aa51a572fe5eb598f4adea8e55644980d5acd..deb7feb07a51b9867426069e06dafc9e86e148a6042e42e59a1d0aab44fb0a9d 100644 --- a/pygost/gost28147.py +++ b/pygost/gost28147.py @@ -22,6 +22,7 @@ data lengths. """ from functools import partial +from typing import Tuple from pygost.gost3413 import pad2 from pygost.gost3413 import pad_size @@ -165,7 +166,7 @@ (s[7][(_in >> 28) & 0x0F] << 28) ) -def block2ns(data): +def block2ns(data: bytes) -> Tuple[int, int]: """Convert block to N1 and N2 integers """ data = bytearray(data) @@ -175,7 +176,7 @@ data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24, ) -def ns2block(ns): +def ns2block(ns: Tuple[int, int]) -> bytes: """Convert N1 and N2 integers to 8-byte block """ n1, n2 = ns @@ -191,17 +192,17 @@ """ return ((x << 11) & (2 ** 32 - 1)) | ((x >> (32 - 11)) & (2 ** 32 - 1)) -def validate_key(key): +def validate_key(key: bytes): if len(key) != KEYSIZE: raise ValueError("Invalid key size") -def validate_iv(iv): +def validate_iv(iv: bytes): if len(iv) != BLOCKSIZE: raise ValueError("Invalid IV size") -def validate_sbox(sbox): +def validate_sbox(sbox: str): if sbox not in SBOXES: raise ValueError("Unknown sbox supplied") @@ -212,7 +213,7 @@ :param seq: sequence of K_i S-box applying (either encrypt or decrypt) :param sbox: S-box parameters to use :type sbox: str, SBOXES'es key - :param bytes key: 256-bit encryption key + :param key: 256-bit encryption key :param ns: N1 and N2 integers :type ns: (int, int) :returns: resulting N1 and N2 @@ -232,29 +233,28 @@ n1, n2 = _shift11(_K(s, (n1 + x[i]) % (2 ** 32))) ^ n2, n1 return n1, n2 -def encrypt(sbox, key, ns): +def encrypt(sbox: str, key: bytes, ns: Tuple[int, int]) -> Tuple[int, int]: """Encrypt single block """ return xcrypt(SEQ_ENCRYPT, sbox, key, ns) -def decrypt(sbox, key, ns): +def decrypt(sbox: str, key: bytes, ns: Tuple[int, int]) -> Tuple[int, int]: """Decrypt single block """ return xcrypt(SEQ_DECRYPT, sbox, key, ns) -def ecb(key, data, action, sbox=DEFAULT_SBOX): +def ecb(key: bytes, data: bytes, action, sbox=DEFAULT_SBOX) -> bytes: """ECB mode of operation - :param bytes key: encryption key - :param data: plaintext + :param key: encryption key + :param plaintext :type data: bytes, multiple of BLOCKSIZE :param func action: "encrypt"/"decrypt" :param sbox: S-box parameters to use :type sbox: str, SBOXES'es key :returns: ciphertext - :rtype: bytes """ validate_key(key) validate_sbox(sbox) @@ -272,19 +272,24 @@ ecb_encrypt = partial(ecb, action=encrypt) ecb_decrypt = partial(ecb, action=decrypt) -def cbc_encrypt(key, data, iv=8 * b"\x00", pad=True, sbox=DEFAULT_SBOX, mesh=False): +def cbc_encrypt( + key: bytes, + data: bytes, + iv=8 * b"\x00", + pad=True, + sbox=DEFAULT_SBOX, + mesh=False, +) -> bytes: """CBC encryption mode of operation - :param bytes key: encryption key - :param bytes data: plaintext + :param key: encryption key + :param data: plaintext :param iv: initialization vector :type iv: bytes, BLOCKSIZE length :type bool pad: perform ISO/IEC 7816-4 padding :param sbox: S-box parameters to use :type sbox: str, SBOXES'es key :param bool mesh: enable key meshing - :returns: ciphertext - :rtype: bytes 34.13-2015 padding method 2 is used. """ @@ -307,17 +312,13 @@ )))) return b"".join(ciphertext) -def cbc_decrypt(key, data, pad=True, sbox=DEFAULT_SBOX, mesh=False): +def cbc_decrypt(key: bytes, data: bytes, pad=True, sbox=DEFAULT_SBOX, mesh=False) -> bytes: """CBC decryption mode of operation - :param bytes key: encryption key - :param bytes data: ciphertext :type bool pad: perform ISO/IEC 7816-4 unpadding after decryption :param sbox: S-box parameters to use :type sbox: str, SBOXES'es key :param bool mesh: enable key meshing - :returns: plaintext - :rtype: bytes """ validate_key(key) validate_sbox(sbox) @@ -343,17 +344,13 @@ plaintext[-1] = unpad2(plaintext[-1], BLOCKSIZE) return b"".join(plaintext) -def cnt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX): +def cnt(key: bytes, data: bytes, iv=8 * b"\x00", sbox=DEFAULT_SBOX) -> bytes: """Counter mode of operation - :param bytes key: encryption key - :param bytes data: plaintext :param iv: initialization vector :type iv: bytes, BLOCKSIZE length :param sbox: S-box parameters to use :type sbox: str, SBOXES'es key - :returns: ciphertext - :rtype: bytes For decryption you use the same function again. """ @@ -375,7 +372,7 @@ MESH_CONST = hexdec("6900722264C904238D3ADB9646E92AC418FEAC9400ED0712C086DCC2EF4CA92B") MESH_MAX_DATA = 1024 -def meshing(key, iv, sbox=DEFAULT_SBOX): +def meshing(key: bytes, iv: bytes, sbox=DEFAULT_SBOX) -> Tuple[bytes, bytes]: """:rfc:`4357` key meshing """ key = ecb_decrypt(key, MESH_CONST, sbox=sbox) @@ -383,18 +380,20 @@ iv = ecb_encrypt(key, iv, sbox=sbox) return key, iv -def cfb_encrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False): +def cfb_encrypt( + key: bytes, + data: bytes, + iv=8 * b"\x00", + sbox=DEFAULT_SBOX, + mesh=False +) -> bytes: """CFB encryption mode of operation - :param bytes key: encryption key - :param bytes data: plaintext :param iv: initialization vector :type iv: bytes, BLOCKSIZE length :param sbox: S-box parameters to use :type sbox: str, SBOXES'es key :param bool mesh: enable key meshing - :returns: ciphertext - :rtype: bytes """ validate_key(key) validate_iv(iv) @@ -417,18 +416,20 @@ )) return b"".join(ciphertext[1:]) -def cfb_decrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False): +def cfb_decrypt( + key: bytes, + data: bytes, + iv=8 * b"\x00", + sbox=DEFAULT_SBOX, + mesh=False +) -> bytes: """CFB decryption mode of operation - :param bytes key: encryption key - :param bytes data: plaintext :param iv: initialization vector :type iv: bytes, BLOCKSIZE length :param sbox: S-box parameters to use :type sbox: str, SBOXES'es key :param bool mesh: enable key meshing - :returns: ciphertext - :rtype: bytes """ validate_key(key) validate_iv(iv) @@ -439,9 +440,9 @@ plaintext = [] data = iv + data for i in range(BLOCKSIZE, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE): if ( - mesh and - (i - BLOCKSIZE) >= MESH_MAX_DATA and - (i - BLOCKSIZE) % MESH_MAX_DATA == 0 + mesh and + (i - BLOCKSIZE) >= MESH_MAX_DATA and + (i - BLOCKSIZE) % MESH_MAX_DATA == 0 ): key, iv = meshing(key, data[i - BLOCKSIZE:i], sbox=sbox) plaintext.append(strxor( diff --git a/pygost/gost28147_mac.py b/pygost/gost28147_mac.py index 71d5ab403d1377c7a7e4ab67501b6f535f17628bcc4c27416088480f22c4179c..e8a639652291d642326f0257784b3f89202fe9680fcef2be34e7f1a293a9cd8c 100644 --- a/pygost/gost28147_mac.py +++ b/pygost/gost28147_mac.py @@ -48,7 +48,7 @@ 'a687a08b' """ digest_size = digest_size - def __init__(self, key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX): + def __init__(self, key: bytes, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX): """ :param key: authentication key :type key: bytes, 32 bytes @@ -65,15 +65,15 @@ self.data = data self.iv = iv self.sbox = sbox - def copy(self): + def copy(self) -> "MAC": return MAC(self.key, copy(self.data), self.iv, self.sbox) - def update(self, data): + def update(self, data: bytes): """Append data that has to be authenticated """ self.data += data - def digest(self): + def digest(self) -> bytes: """Get MAC tag of supplied data You have to provide at least single byte of data. @@ -94,5 +94,5 @@ )[::-1] return ns2block(prev) -def new(key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX): +def new(key: bytes, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX): return MAC(key, data, iv, sbox) diff --git a/pygost/gost3410.py b/pygost/gost3410.py index fbb794bb5db1ff667b56e5c9ca843be18ded9c7af8db78c125dffbed0d1984bb..e03c933b8c6d7053fb8a96dafa1b553ddf8ef503f3c938525e8fd0af0f992bcf 100644 --- a/pygost/gost3410.py +++ b/pygost/gost3410.py @@ -21,18 +21,22 @@ key, digest and signature lengths. """ from os import urandom +from typing import Tuple from pygost.utils import hexdec from pygost.utils import modinvert -def point_size(point): +Point = Tuple[int, int] + + +def point_size(point: int): """Determine is it either 256 or 512 bit point """ return (512 // 8) if point.bit_length() > 256 else (256 // 8) -class GOST3410Curve(object): +class GOST3410Curve: """GOST 34.10 validated curve >>> curve = CURVES["id-GostR3410-2001-TestParamSet"] @@ -42,19 +46,31 @@ >>> pub = public_key(curve, prv) >>> verify(curve, pub, GOST341194(data).digest(), signature) True - :param long p: characteristic of the underlying prime field - :param long q: elliptic curve subgroup order - :param long a, b: coefficients of the equation of the elliptic curve in - the canonical form - :param long x, y: the coordinate of the point P (generator of the - subgroup of order q) of the elliptic curve in - the canonical form - :param long e, d: coefficients of the equation of the elliptic curve in - the twisted Edwards form - :param str name: human-readable curve name + :param p: characteristic of the underlying prime field + :param q: elliptic curve subgroup order + :param a, b: coefficients of the equation of the elliptic curve in + the canonical form + :param x, y: the coordinate of the point P (generator of the + subgroup of order q) of the elliptic curve in + the canonical form + :param e, d: coefficients of the equation of the elliptic curve in + the twisted Edwards form + :param name: human-readable curve name """ - def __init__(self, p, q, a, b, x, y, cofactor=1, e=None, d=None, name=None): + def __init__( + self, + p: int, + q: int, + a: int, + b: int, + x: int, + y: int, + cofactor: int=1, + e: int=None, + d: int=None, + name: str=None, + ): self.p = p self.q = q self.a = a @@ -70,30 +86,28 @@ self._st = None self.name = name @property - def point_size(self): + def point_size(self) -> int: return point_size(self.p) - def __repr__(self): + def __repr__(self) -> str: return "<%s: %s>" % (self.__class__.__name__, self.name) - def pos(self, v): + def pos(self, v: int) -> int: """Make positive number """ if v < 0: return v + self.p return v - def contains(self, point): + def contains(self, point: Point): """Is point on the curve? - - :type point: (long, long) """ x, y = point r1 = y * y % self.p r2 = ((x * x + self.a) * x + self.b) % self.p return r1 == self.pos(r2) - def _add(self, p1x, p1y, p2x, p2y): + def _add(self, p1x: int, p1y: int, p2x: int, p2y: int) -> Point: if p1x == p2x and p1y == p2y: # double t = ((3 * p1x * p1x + self.a) * modinvert(2 * p1y, self.p)) % self.p @@ -105,7 +119,7 @@ tx = self.pos(t * t - p1x - p2x) % self.p ty = self.pos(t * (p1x - tx) - p1y) % self.p return tx, ty - def exp(self, degree, x=None, y=None): + def exp(self, degree: int, x: int=None, y: int=None) -> Point: x = x or self.x y = y or self.y tx = x @@ -120,7 +134,7 @@ degree = degree >> 1 x, y = self._add(x, y, x, y) return tx, ty - def st(self): + def st(self) -> Point: """Compute s/t parameters for twisted Edwards curve points conversion """ if self.e is None or self.d is None: @@ -240,13 +254,8 @@ _curve.name = _name DEFAULT_CURVE = CURVES["id-tc26-gost-3410-12-256-paramSetB"] -def public_key(curve, prv, mask=None): +def public_key(curve: GOST3410Curve, prv: int, mask: int=None) -> Point: """Generate public key from the private one - - :param GOST3410Curve curve: curve to use - :param long prv: private key - :returns: public key's parts, X and Y - :rtype: (long, long) """ pub = curve.exp(prv) if mask is not None: @@ -254,12 +263,17 @@ pub = curve.exp(mask, pub[0], pub[1]) return pub -def sign(curve, prv, digest, rand=None, mask=None): +def sign( + curve: GOST3410Curve, + prv: int, + digest: bytes, + rand: bytes=None, + mask: int=None, +) -> bytes: """Calculate signature for provided digest - :param GOST3410Curve curve: curve to use - :param long prv: private key - :param digest: digest for signing + :param prv: private key + :param digest: digest to sign :type digest: bytes, 32 or 64 bytes :param rand: optional predefined random data used for k/r generation :type rand: bytes, 32 or 64 bytes @@ -297,16 +311,13 @@ break return s.to_bytes(size, "big") + r.to_bytes(size, "big") -def verify(curve, pub, digest, signature): +def verify(curve: GOST3410Curve, pub: Point, digest: bytes, signature: bytes) -> bool: """Verify provided digest with the signature - :param GOST3410Curve curve: curve to use - :type pub: (long, long) :param digest: digest needed to check :type digest: bytes, 32 or 64 bytes :param signature: signature to verify with :type signature: bytes, 64 or 128 bytes - :rtype: bool """ size = curve.point_size if len(signature) != size * 2: @@ -341,11 +352,8 @@ # This is not constant time comparison! return lm == r -def prv_unmarshal(prv): +def prv_unmarshal(prv: bytes) -> int: """Unmarshal little-endian private key - - :param bytes prv: serialized private key - :rtype: long It is advisable to use :py:func:`pygost.gost3410.prv_marshal` to assure that key i in curve's Q field for better compatibility with @@ -354,41 +362,33 @@ """ return int.from_bytes(prv, "little") -def prv_marshal(curve, prv): +def prv_marshal(curve: GOST3410Curve, prv: int) -> bytes: """Marshal little-endian private key - :param GOST3410Curve curve: curve to use - :param long prv: serialized private key - :rtype: bytes - Key is in curve's Q field. """ return (prv % curve.q).to_bytes(point_size(prv), "little") -def pub_marshal(pub): +def pub_marshal(pub: Point) -> bytes: """Marshal public key - :type pub: (long, long) - :rtype: bytes :returns: LE(X) || LE(Y) """ size = point_size(pub[0]) return pub[0].to_bytes(size, "little") + pub[1].to_bytes(size, "little") -def pub_unmarshal(pub): +def pub_unmarshal(pub: bytes) -> Point: """Unmarshal public key :param pub: LE(X) || LE(Y) - :type pub: bytes - :rtype: (long, long) """ size = len(pub) // 2 return (int.from_bytes(pub[:size], "little"), int.from_bytes(pub[size:], "little")) -def uv2xy(curve, u, v): +def uv2xy(curve: GOST3410Curve, u: int, v: int) -> Point: """Convert twisted Edwards curve U,V coordinates to Weierstrass X,Y """ s, t = curve.st() @@ -399,7 +399,7 @@ y = k1 * modinvert(u * k2, curve.p) return x % curve.p, y % curve.p -def xy2uv(curve, x, y): +def xy2uv(curve: GOST3410Curve, x: int, y: int) -> Point: """Convert Weierstrass X,Y coordinates to twisted Edwards curve U,V """ s, t = curve.st() diff --git a/pygost/gost3410_vko.py b/pygost/gost3410_vko.py index b6eb14a678dc03a524e428db88a0f325d4bd57f2933c88cdbf6f7c12257dadef..89affec548ea61ed308a252580eb92cfd1dcc92b2dfb48754b0b0a70892f80c5 100644 --- a/pygost/gost3410_vko.py +++ b/pygost/gost3410_vko.py @@ -16,22 +16,23 @@ # along with this program. If not, see . """Key agreement functions, VKO GOST R 34.10-2001/2012 """ +from pygost.gost3410 import GOST3410Curve +from pygost.gost3410 import Point from pygost.gost3410 import pub_marshal from pygost.gost34112012256 import GOST34112012256 from pygost.gost34112012512 import GOST34112012512 from pygost.gost341194 import GOST341194 -def ukm_unmarshal(ukm): +def ukm_unmarshal(ukm: bytes) -> int: """Unmarshal UKM value :type ukm: little-endian bytes - :rtype: long """ return int.from_bytes(ukm, "little") -def kek(curve, prv, pub, ukm, mask=None): +def kek(curve: GOST3410Curve, prv: int, pub: Point, ukm: int, mask: int=None) -> bytes: if not curve.contains(pub): raise ValueError("pub is not on the curve") key = curve.exp(prv, pub[0], pub[1]) @@ -41,13 +42,9 @@ key = curve.exp(mask, key[0], key[1]) return pub_marshal(key) -def kek_34102001(curve, prv, pub, ukm): +def kek_34102001(curve: GOST3410Curve, prv: int, pub: Point, ukm: int) -> bytes: """Key agreement (34.10-2001, 34.11-94) - :param GOST3410Curve curve: curve to use - :param long prv: private key - :param pub: public key - :type pub: (long, long) :param long ukm: user keying material, VKO-factor :returns: Key Encryption Key (shared key) :rtype: bytes, 32 bytes @@ -62,13 +59,9 @@ sbox="id-GostR3411-94-CryptoProParamSet", ).digest() -def kek_34102012256(curve, prv, pub, ukm=1): +def kek_34102012256(curve: GOST3410Curve, prv: int, pub: Point, ukm=1) -> bytes: """Key agreement (34.10-2012, 34.11-2012 256 bit) - :param GOST3410Curve curve: curve to use - :param long prv: private key - :param pub: public key - :type pub: (long, long) :param long ukm: user keying material, VKO-factor :returns: Key Encryption Key (shared key) :rtype: bytes, 32 bytes @@ -79,13 +72,9 @@ """ return GOST34112012256(kek(curve, prv, pub, ukm)).digest() -def kek_34102012512(curve, prv, pub, ukm=1): +def kek_34102012512(curve: GOST3410Curve, prv: int, pub: Point, ukm=1) -> bytes: """Key agreement (34.10-2012, 34.11-2012 512 bit) - :param GOST3410Curve curve: curve to use - :param long prv: private key - :param pub: public key - :type pub: (long, long) :param long ukm: user keying material, VKO-factor :returns: Key Encryption Key (shared key) :rtype: bytes, 32 bytes diff --git a/pygost/gost34112012.py b/pygost/gost34112012.py index e6e449b2835433b77ccefc1ba04a5c62439d841985d73c592f132684aa0f70f7..cd992986a85dafeda39424c47dd9111d2e19a06e7c6c290d291c709fa122e873 100644 --- a/pygost/gost34112012.py +++ b/pygost/gost34112012.py @@ -245,7 +245,7 @@ self.n = 0 self.buf = b"" self.update(data) - def copy(self): + def copy(self) -> "GOST34112012": obj = GOST34112012() obj._digest_size = self._digest_size obj.hsh = self.hsh @@ -255,7 +255,7 @@ obj.buf = self.buf return obj @property - def digest_size(self): + def digest_size(self) -> int: return self._digest_size def _update_block(self, block): @@ -263,7 +263,7 @@ self.hsh = g(self.n, self.hsh, block) self.chk = add512bit(self.chk, block) self.n += 512 - def update(self, data): + def update(self, data: bytes): """Update state with the new data """ if len(self.buf) > 0: @@ -278,7 +278,7 @@ self._update_block(data[:BLOCKSIZE]) data = data[BLOCKSIZE:] self.buf += data - def digest(self): + def digest(self) -> bytes: """Get hash of the provided data """ data = self.buf diff --git a/pygost/gost34112012256.py b/pygost/gost34112012256.py index 13bfd11ddf759b45633ed0361a49f671b2338fc95b4b4ce903e0c9dc3703535b..e8517e3468d0a21b2290d4b4886a6c35c6ea0226b33e133f9e32fac7423b372d 100644 --- a/pygost/gost34112012256.py +++ b/pygost/gost34112012256.py @@ -9,7 +9,7 @@ class GOST34112012256(GOST34112012): def __init__(self, data=b""): - super(GOST34112012256, self).__init__(data, digest_size=32) + super().__init__(data, digest_size=32) def new(data=b""): diff --git a/pygost/gost34112012512.py b/pygost/gost34112012512.py index 82fb2d005ae3eba61aab8bfa17902f90cd927d59491c1b48bc679f95295a081b..4a272cacae1fd18f93f578a897ae5c063102c04f8507b88e91f4f7fd97fdb0bd 100644 --- a/pygost/gost34112012512.py +++ b/pygost/gost34112012512.py @@ -10,7 +10,7 @@ class GOST34112012512(GOST34112012): def __init__(self, data=b""): - super(GOST34112012512, self).__init__(data, digest_size=64) + super().__init__(data, digest_size=64) def new(data=b""): diff --git a/pygost/gost341194.py b/pygost/gost341194.py index 6eae6dd129554cd28ee202488aa4efc5693778d4b48aee0f427bee699c31ab0e..fb54b1791d3e0bdbc90edec2213709dcb7d5a3a3741248e9bed8bc3dce3511d0 100644 --- a/pygost/gost341194.py +++ b/pygost/gost341194.py @@ -140,22 +140,22 @@ digest_size = digest_size def __init__(self, data=b"", sbox=DEFAULT_SBOX): """ - :param bytes data: provide initial data - :param bytes sbox: S-box to use + :param data: provide initial data + :param sbox: S-box to use """ validate_sbox(sbox) self.data = data self.sbox = sbox - def copy(self): + def copy(self) -> "GOST341194": return GOST341194(copy(self.data), self.sbox) - def update(self, data): + def update(self, data: bytes): """Append data that has to be hashed """ self.data += data - def digest(self): + def digest(self) -> bytes: """Get hash of the provided data """ _len = 0 @@ -187,5 +187,5 @@ PBKDF2_HASHER = partial(GOST341194, sbox="id-GostR3411-94-CryptoProParamSet") -def pbkdf2(password, salt, iterations, dklen): +def pbkdf2(password: bytes, salt: bytes, iterations: int, dklen: int) -> bytes: return pbkdf2_base(PBKDF2_HASHER, password, salt, iterations, dklen) diff --git a/pygost/gost3412.py b/pygost/gost3412.py index 0340308506b79475642789384f9f1f0682aeaf2d7ec2420500a961a0e51707f6..2e1a3ae6d12a965151990ac4c7884ea17b1e310dbbf1500651161b5b00fc96e1 100644 --- a/pygost/gost3412.py +++ b/pygost/gost3412.py @@ -70,6 +70,7 @@ a <<= 1 b >>= 1 return c + ######################################################################## # Precalculate all possible gf(byte, byte) values as a performance # optimization. @@ -101,12 +102,11 @@ t ^= GF[blk[i]][LC[i]] blk[15] = t return blk + ######################################################################## # Precalculate values of the C -- it does not depend on key. # Actually it can be computed only once and saved on the disk. ######################################################################## - - C = [] for x in range(1, 33): @@ -119,17 +119,13 @@ def lp(blk): return L([PI[v] for v in blk]) -class GOST3412Kuznechik(object): +class GOST3412Kuznechik: """GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) """ blocksize = 16 - def __init__(self, key): - """ - :param key: encryption/decryption key - :type key: bytes, 32 bytes - - Key scheduling (roundkeys precomputation) is performed here. + def __init__(self, key: bytes): + """Key scheduling (roundkeys precomputation) is performed here. """ kr0 = bytearray(key[:16]) kr1 = bytearray(key[16:]) @@ -141,25 +137,25 @@ kr0, kr1 = [strxor(k, kr1), kr0] self.ks.append(kr0) self.ks.append(kr1) - def encrypt(self, blk): + def encrypt(self, blk: bytes) -> bytes: blk = bytearray(blk) for i in range(9): blk = lp(bytearray(strxor(self.ks[i], blk))) return bytes(strxor(self.ks[9], blk)) - def decrypt(self, blk): + def decrypt(self, blk: bytes) -> bytes: blk = bytearray(blk) for i in range(9, 0, -1): blk = [PIinv[v] for v in Linv(bytearray(strxor(self.ks[i], blk)))] return bytes(strxor(self.ks[0], blk)) -class GOST3412Magma(object): +class GOST3412Magma: """GOST R 34.12-2015 64-bit block cipher Магма (Magma) """ blocksize = 8 - def __init__(self, key): + def __init__(self, key: bytes): """ :param key: encryption/decryption key :type key: bytes, 32 bytes @@ -168,14 +164,14 @@ # Backward compatibility key preparation for 28147-89 key schedule self.key = b"".join(key[i * 4:i * 4 + 4][::-1] for i in range(8)) self.sbox = "id-tc26-gost-28147-param-Z" - def encrypt(self, blk): + def encrypt(self, blk: bytes) -> bytes: return gost28147_ns2block(gost28147_encrypt( self.sbox, self.key, gost28147_block2ns(blk[::-1]), ))[::-1] - def decrypt(self, blk): + def decrypt(self, blk: bytes) -> bytes: return gost28147_ns2block(gost28147_decrypt( self.sbox, self.key, diff --git a/pygost/gost3413.py b/pygost/gost3413.py index c89d057905d15fd0b0671307f143cad35fb1a8745ee82313e4136337adf9544a..505354f46798994cc94c967c475dcbfe7357e147e9a87509bbaf518a3e009a38 100644 --- a/pygost/gost3413.py +++ b/pygost/gost3413.py @@ -26,7 +26,7 @@ KEYSIZE = 32 -def pad_size(data_size, blocksize): +def pad_size(data_size: int, blocksize: int) -> int: """Calculate required pad size to full up blocksize """ if data_size < blocksize: @@ -36,7 +36,7 @@ return 0 return blocksize - data_size % blocksize -def pad1(data, blocksize): +def pad1(data: bytes, blocksize: int) -> bytes: """Padding method 1 Just fill up with zeros if necessary. @@ -44,7 +44,7 @@ """ return data + b"\x00" * pad_size(len(data), blocksize) -def pad2(data, blocksize): +def pad2(data: bytes, blocksize: int) -> bytes: """Padding method 2 (also known as ISO/IEC 7816-4) Add one bit and then fill up with zeros. @@ -52,7 +52,7 @@ """ return data + b"\x80" + b"\x00" * pad_size(len(data) + 1, blocksize) -def unpad2(data, blocksize): +def unpad2(data: bytes, blocksize: int) -> bytes: """Unpad method 2 """ last_block = bytearray(data[-blocksize:]) @@ -65,7 +65,7 @@ raise ValueError("Invalid padding") return data[:-(blocksize - pad_index)] -def pad3(data, blocksize): +def pad3(data: bytes, blocksize: int) -> bytes: """Padding method 3 """ if pad_size(len(data), blocksize) == 0: @@ -73,12 +73,12 @@ return data return pad2(data, blocksize) -def ecb_encrypt(encrypter, bs, pt): +def ecb_encrypt(encrypter, bs: int, pt: bytes) -> bytes: """ECB encryption mode of operation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes pt: already padded plaintext + :param bs: cipher's blocksize, bytes + :param pt: already padded plaintext """ if not pt or len(pt) % bs != 0: raise ValueError("Plaintext is not blocksize aligned") @@ -88,12 +88,12 @@ ct.append(encrypter(pt[i:i + bs])) return b"".join(ct) -def ecb_decrypt(decrypter, bs, ct): +def ecb_decrypt(decrypter, bs: int, ct: bytes) -> bytes: """ECB decryption mode of operation :param decrypter: Decrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes ct: ciphertext + :param bs: cipher's blocksize, bytes + :param ct: ciphertext """ if not ct or len(ct) % bs != 0: raise ValueError("Ciphertext is not blocksize aligned") @@ -103,11 +103,11 @@ pt.append(decrypter(ct[i:i + bs])) return b"".join(pt) -def acpkm(encrypter, bs): +def acpkm(encrypter, bs: int) -> bytes: """Perform ACPKM key derivation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes + :param bs: cipher's blocksize, bytes """ return b"".join([ encrypter(bytes(bytearray(range(d, d + bs)))) @@ -115,13 +115,13 @@ for d in range(0x80, 0x80 + bs * (KEYSIZE // bs), bs) ]) -def ctr(encrypter, bs, data, iv, _acpkm=None): +def ctr(encrypter, bs: int, data: bytes, iv: bytes, _acpkm=None) -> bytes: """Counter mode of operation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes data: plaintext/ciphertext - :param bytes iv: half blocksize-sized initialization vector + :param bs: cipher's blocksize, bytes + :param data: plaintext/ciphertext + :param iv: half blocksize-sized initialization vector For decryption you use the same function again. """ @@ -147,15 +147,22 @@ ctr_value = (ctr_value + 1) % ctr_max_value return strxor(b"".join(stream), data) -def ctr_acpkm(algo_class, encrypter, section_size, bs, data, iv): +def ctr_acpkm( + algo_class, + encrypter, + section_size: int, + bs: int, + data: bytes, + iv: bytes, +) -> bytes: """CTR-ACPKM mode of operation :param algo_class: pygost.gost3412's algorithm class :param encrypter: encrypting function, that takes block as an input - :param int section_size: ACPKM'es section size (N), in bytes - :param int bs: cipher's blocksize, bytes - :param bytes data: plaintext/ciphertext - :param bytes iv: half blocksize-sized initialization vector + :param section_size: ACPKM'es section size (N), in bytes + :param bs: cipher's blocksize, bytes + :param data: plaintext/ciphertext + :param iv: half blocksize-sized initialization vector For decryption you use the same function again. """ @@ -164,13 +171,13 @@ raise ValueError("section_size must be multiple of bs") return ctr(encrypter, bs, data, iv, _acpkm=(algo_class, section_size)) -def ofb(encrypter, bs, data, iv): +def ofb(encrypter, bs: int, data: bytes, iv: bytes) -> bytes: """OFB mode of operation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes data: plaintext/ciphertext - :param bytes iv: blocksize-sized initialization vector + :param bs: cipher's blocksize, bytes + :param data: plaintext/ciphertext + :param iv: blocksize-sized initialization vector For decryption you use the same function again. """ @@ -184,13 +191,13 @@ result.append(strxor(r[-1], data[i:i + bs])) return b"".join(result) -def cbc_encrypt(encrypter, bs, pt, iv): +def cbc_encrypt(encrypter, bs: int, pt: bytes, iv: bytes) -> bytes: """CBC encryption mode of operation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes pt: already padded plaintext - :param bytes iv: blocksize-sized initialization vector + :param bs: cipher's blocksize, bytes + :param pt: already padded plaintext + :param iv: blocksize-sized initialization vector """ if not pt or len(pt) % bs != 0: raise ValueError("Plaintext is not blocksize aligned") @@ -204,13 +211,13 @@ r = r[1:] + [ct[-1]] return b"".join(ct) -def cbc_decrypt(decrypter, bs, ct, iv): +def cbc_decrypt(decrypter, bs: int, ct: bytes, iv: bytes) -> bytes: """CBC decryption mode of operation :param decrypter: Decrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes ct: ciphertext - :param bytes iv: blocksize-sized initialization vector + :param bs: cipher's blocksize, bytes + :param ct: ciphertext + :param iv: blocksize-sized initialization vector """ if not ct or len(ct) % bs != 0: raise ValueError("Ciphertext is not blocksize aligned") @@ -225,13 +232,13 @@ r = r[1:] + [blk] return b"".join(pt) -def cfb_encrypt(encrypter, bs, pt, iv): +def cfb_encrypt(encrypter, bs: int, pt: bytes, iv: bytes) -> bytes: """CFB encryption mode of operation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes pt: plaintext - :param bytes iv: blocksize-sized initialization vector + :param bs: cipher's blocksize, bytes + :param pt: plaintext + :param iv: blocksize-sized initialization vector """ if len(iv) < bs or len(iv) % bs != 0: raise ValueError("Invalid IV size") @@ -243,13 +250,13 @@ r = r[1:] + [ct[-1]] return b"".join(ct) -def cfb_decrypt(encrypter, bs, ct, iv): +def cfb_decrypt(encrypter, bs: int, ct: bytes, iv: bytes) -> bytes: """CFB decryption mode of operation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes ct: ciphertext - :param bytes iv: blocksize-sized initialization vector + :param bs: cipher's blocksize, bytes + :param ct: ciphertext + :param iv: blocksize-sized initialization vector """ if len(iv) < bs or len(iv) % bs != 0: raise ValueError("Invalid IV size") @@ -279,12 +286,12 @@ k2 = _mac_shift(bs, k1, Rb) if bytearray(k1)[0] & 0x80 > 0 else _mac_shift(bs, k1) return k1, k2 -def mac(encrypter, bs, data): +def mac(encrypter, bs: int, data: bytes) -> bytes: """MAC (known here as CMAC, OMAC1) mode of operation :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize, bytes - :param bytes data: data to authenticate + :param bs: cipher's blocksize, bytes + :param data: data to authenticate Implementation is based on PyCrypto's CMAC one, that is in public domain. """ @@ -303,14 +310,20 @@ k1 if len(tail) == bs else k2, )) -def acpkm_master(algo_class, encrypter, key_section_size, bs, keymat_len): +def acpkm_master( + algo_class, + encrypter, + key_section_size: int, + bs: int, + keymat_len: int, +) -> bytes: """ACPKM-Master key derivation :param algo_class: pygost.gost3412's algorithm class :param encrypter: encrypting function, that takes block as an input - :param int key_section_size: ACPKM'es key section size (T*), in bytes - :param int bs: cipher's blocksize, bytes - :param int keymat_len: length of key material to produce + :param key_section_size: ACPKM'es key section size (T*), in bytes + :param bs: cipher's blocksize, bytes + :param keymat_len: length of key material to produce """ return ctr_acpkm( algo_class, @@ -322,15 +335,22 @@ iv=b"\xFF" * (bs // 2), ) -def mac_acpkm_master(algo_class, encrypter, key_section_size, section_size, bs, data): +def mac_acpkm_master( + algo_class, + encrypter, + key_section_size: int, + section_size: int, + bs: int, + data: bytes, +) -> bytes: """OMAC-ACPKM-Master :param algo_class: pygost.gost3412's algorithm class :param encrypter: encrypting function, that takes block as an input - :param int key_section_size: ACPKM'es key section size (T*), in bytes - :param int section_size: ACPKM'es section size (N), in bytes - :param int bs: cipher's blocksize, bytes - :param bytes data: data to authenticate + :param key_section_size: ACPKM'es key section size (T*), in bytes + :param section_size: ACPKM'es section size (N), in bytes + :param bs: cipher's blocksize, bytes + :param data: data to authenticate """ if len(data) % bs == 0: tail_offset = len(data) - bs @@ -366,7 +386,7 @@ k1 if len(tail) == bs else k2, )) -def pad_iso10126(data, blocksize): +def pad_iso10126(data: bytes, blocksize: int) -> bytes: """ISO 10126 padding Does not exist in 34.13, but added for convenience. @@ -378,7 +398,7 @@ pad_len = blocksize return b"".join((data, urandom(pad_len - 1), bytes((pad_len,)))) -def unpad_iso10126(data, blocksize): +def unpad_iso10126(data: bytes, blocksize: int) -> bytes: """Unpad :py:func:`pygost.gost3413.pad_iso10126` """ if len(data) % blocksize != 0: diff --git a/pygost/iface.py b/pygost/iface.py index 1d3d0991468a645f196c315c537a75269374065e4751f19aee33b03bc6090be7..86e14e4fe086ea044796a92bba43f74ff79b40d920fac1597748a69ece136b15 100644 --- a/pygost/iface.py +++ b/pygost/iface.py @@ -7,26 +7,26 @@ class PEP247(metaclass=ABCMeta): @property @abstractmethod - def digest_size(self): + def digest_size(self) -> int: """The size of the digest produced by the hashing objects. """ @abstractmethod - def copy(self): + def copy(self) -> object: """Return a separate copy of this hashing object. """ @abstractmethod - def update(self, data): + def update(self, data: bytes) -> bytes: """Hash data into the current state of the hashing object. """ @abstractmethod - def digest(self): + def digest(self) -> bytes: """Return the hash value as a string containing 8-bit data. """ - def hexdigest(self): + def hexdigest(self) -> str: """Return the hash value as a string containing hexadecimal digits. """ return hexenc(self.digest()) diff --git a/pygost/kdf.py b/pygost/kdf.py index da4867950ab296fd88dce42e1f3eb16dfd7b0f4d93de9540bee41e7e28eb5d1a..673e71bf98853772b95fc5557891320221b232ecd4eff471211ea3e737e6367d 100644 --- a/pygost/kdf.py +++ b/pygost/kdf.py @@ -16,20 +16,18 @@ # along with this program. If not, see . """Key derivation functions, ТК26 Р 50.1.113-2016, ТК26 Р 1323565.1.020-2018 """ +from typing import List import hmac +from pygost.gost3410 import GOST3410Curve +from pygost.gost3410 import Point from pygost.gost3410_vko import kek_34102012256 from pygost.gost3410_vko import kek_34102012512 from pygost.gost34112012256 import GOST34112012256 -def kdf_gostr3411_2012_256(key, label, seed): +def kdf_gostr3411_2012_256(key: bytes, label: bytes, seed: bytes) -> bytes: """KDF_GOSTR3411_2012_256 - - :param bytes key: initial key - :param bytes label: label - :param bytes seed: seed - :returns: 32 bytes """ return hmac.new( key=key, @@ -38,14 +36,17 @@ digestmod=GOST34112012256, ).digest() -def kdf_tree_gostr3411_2012_256(key, label, seed, keys, i_len=1): +def kdf_tree_gostr3411_2012_256( + key: bytes, + label: bytes, + seed: bytes, + keys: int, + i_len=1, +) -> List[bytes]: """KDF_TREE_GOSTR3411_2012_256 - :param bytes key: initial key - :param bytes label: label - :param bytes seed: seed - :param int keys: number of generated keys - :param int i_len: length of iterations value (called "R") + :param keys: number of generated keys + :param i_len: length of iterations value (called "R") :returns: list of 256-bit keys """ keymat = [] @@ -62,14 +63,10 @@ ).digest()) return keymat -def keg(curve, prv, pub, h): +def keg(curve: GOST3410Curve, prv: int, pub: Point, h: bytes) -> bytes: """Export key generation (ТК26 Р 1323565.1.020-2018) - :param GOST3410Curve curve: curve to use - :param long prv: private key - :param pub: public key - :type pub: (long, long) - :param bytes h: "h"-value, 32 bytes + :param h: "h"-value, 32 bytes """ if len(h) != 32: raise ValueError("h must be 32 bytes long") diff --git a/pygost/mgm.py b/pygost/mgm.py index c37305571a1b74c1d59a4cc1b5e67ab113ae108b55d43953050c4b96e953d064..ed49789abfc88277046b46ae458408762aececa024bc176745244ad27da0ca6b 100644 --- a/pygost/mgm.py +++ b/pygost/mgm.py @@ -34,7 +34,7 @@ def incr_l(data, bs): return _incr(data[:bs // 2], bs) + data[bs // 2:] -def nonce_prepare(nonce): +def nonce_prepare(nonce: bytes) -> bytes: """Prepare nonce for MGM usage It just clears MSB. @@ -44,15 +44,15 @@ n[0] &= 0x7F return bytes(n) -class MGM(object): +class MGM: # Implementation is fully based on go.cypherpunks.su/gogost/mgm - def __init__(self, encrypter, bs, tag_size=None): + def __init__(self, encrypter, bs: int, tag_size: int=None): """Multilinear Galois Mode (MGM) block cipher mode :param encrypter: encrypting function, that takes block as an input - :param int bs: cipher's blocksize - :param int tag_size: authentication tag size - (defaults to blocksize if not specified) + :param bs: cipher's blocksize + :param tag_size: authentication tag size + (defaults to blocksize if not specified) """ if bs not in (8, 16): raise ValueError("Only 64/128-bit blocksizes allowed") @@ -127,14 +127,14 @@ (text_len * 8).to_bytes(self.bs // 2, "big") ))) return self.encrypter(_sum)[:self.tag_size] - def seal(self, nonce, plaintext, additional_data): + def seal(self, nonce: bytes, plaintext: bytes, additional_data: bytes) -> bytes: """Seal plaintext - :param bytes nonce: blocksize-sized nonce. - Assure that it does not have MSB bit set - (:py:func:`pygost.mgm.nonce_prepare` helps) - :param bytes plaintext: plaintext to be encrypted and authenticated - :param bytes additional_data: additional data to be authenticated + :param nonce: blocksize-sized nonce. + Assure that it does not have MSB bit set + (:py:func:`pygost.mgm.nonce_prepare` helps) + :param plaintext: plaintext to be encrypted and authenticated + :param additional_data: additional data to be authenticated """ self._validate_nonce(nonce) self._validate_sizes(plaintext, additional_data) @@ -143,14 +143,14 @@ ciphertext = self._crypt(icn, plaintext) tag = self._auth(icn, ciphertext, additional_data) return ciphertext + tag - def open(self, nonce, ciphertext, additional_data): + def open(self, nonce: bytes, ciphertext: bytes, additional_data: bytes) -> bytes: """Open ciphertext - :param bytes nonce: blocksize-sized nonce. - Assure that it does not have MSB bit set - (:py:func:`pygost.mgm.nonce_prepare` helps) - :param bytes ciphertext: ciphertext to be decrypted and authenticated - :param bytes additional_data: additional data to be authenticated + :param nonce: blocksize-sized nonce. + Assure that it does not have MSB bit set + (:py:func:`pygost.mgm.nonce_prepare` helps) + :param ciphertext: ciphertext to be decrypted and authenticated + :param additional_data: additional data to be authenticated :raises ValueError: if ciphertext authentication fails """ self._validate_nonce(nonce) diff --git a/pygost/pbkdf2.py b/pygost/pbkdf2.py index eb08b97e19bf1e0b40da953b85384d9dc2c112b2ab7de41fd5bee9da795ac193..1774da9a056d3f993eb909a4e98664b65d68ffbd1ce5d19363cf29894fdf70a9 100644 --- a/pygost/pbkdf2.py +++ b/pygost/pbkdf2.py @@ -8,7 +8,7 @@ from pygost.utils import strxor -def pbkdf2(hasher, password, salt, iterations, dklen): +def pbkdf2(hasher, password: bytes, salt: bytes, iterations: int, dklen: int) -> bytes: """PBKDF2 implementation suitable for GOST R 34.11-94/34.11-2012 """ inner = hasher() diff --git a/pygost/sespake.py b/pygost/sespake.py index 704e1d3b755bcae3b5c3a3be65037cb8de51a33b1ece4c023a68801d08036ea0..18543a9254c2015aa15e347dbc4a441d78c4d9feb0ae30269c035ebf7c7ce440 100644 --- a/pygost/sespake.py +++ b/pygost/sespake.py @@ -25,6 +25,7 @@ import hmac from pygost import gost34112012256 from pygost import gost34112012512 +from pygost.gost3410 import GOST3410Curve from pygost.pbkdf2 import pbkdf2 from pygost.utils import hexdec @@ -67,8 +68,8 @@ class A: def __init__( self, - curve, - q, + curve: GOST3410Curve, + q: , pw, salt, idA, diff --git a/pygost/stubs/pygost/__init__.pyi b/pygost/stubs/pygost/__init__.pyi deleted file mode 100644 index 473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813..0000000000000000000000000000000000000000 Binary files a/pygost/stubs/pygost/__init__.pyi and /dev/null differ diff --git a/pygost/stubs/pygost/gost28147.pyi b/pygost/stubs/pygost/gost28147.pyi deleted file mode 100644 index 0a087e58c80c66e955b30a1793fa546e09d936772cc3a6baadb6f12e1654959c..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost28147.pyi +++ /dev/null @@ -1,101 +0,0 @@ -from typing import Callable -from typing import Dict -from typing import Sequence -from typing import Tuple - - -SBOXES = ... # type: Dict[str, Tuple[Tuple[int, ...], ...]] -BLOCKSIZE = ... # type: int - -Words = Tuple[int, int] - - -def block2ns(data: bytes) -> Words: ... - - -def ns2block(ns: Words) -> bytes: ... - - -def validate_key(key: bytes) -> None: ... - - -def validate_iv(iv: bytes) -> None: ... - - -def validate_sbox(sbox: str) -> None: ... - - -def xcrypt(seq: Sequence[int], sbox: str, key: bytes, ns: Words) -> Words: ... - - -def encrypt(sbox: str, key: bytes, ns: Words) -> Words: ... - - -def decrypt(sbox: str, key: bytes, ns: Words) -> Words: ... - - -def ecb( - key: bytes, - data: bytes, - action: Callable[[str, bytes, Words], Words], - sbox: str = ..., -) -> bytes: ... - - -def ecb_encrypt( - key: bytes, - data: bytes, - sbox: str = ..., -) -> bytes: ... - - -def ecb_decrypt( - key: bytes, - data: bytes, - sbox: str = ..., -) -> bytes: ... - - -def cbc_encrypt( - key: bytes, - data: bytes, - iv: bytes = ..., - pad: bool = ..., - sbox: str = ..., - mesh: bool = ..., -) -> bytes: ... - - -def cbc_decrypt( - key: bytes, - data: bytes, - pad: bool = ..., - sbox: str = ..., - mesh: bool = ..., -) -> bytes: ... - - -def cnt( - key: bytes, - data: bytes, - iv: bytes = ..., - sbox: str = ..., -) -> bytes: ... - - -def cfb_encrypt( - key: bytes, - data: bytes, - iv: bytes = ..., - sbox: str = ..., - mesh: bool = ..., -) -> bytes: ... - - -def cfb_decrypt( - key: bytes, - data: bytes, - iv: bytes = ..., - sbox: str = ..., - mesh: bool = ..., -) -> bytes: ... diff --git a/pygost/stubs/pygost/gost28147_mac.pyi b/pygost/stubs/pygost/gost28147_mac.pyi deleted file mode 100644 index d332438a0c12a6600e9ae42d6f801b4ab634a36497f7864f0ae19a23b3ed583c..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost28147_mac.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from pygost.iface import PEP247 - - -class MAC(PEP247): - def __init__( - self, - key: bytes, - data: bytes = ..., - iv: bytes = ..., - sbox: str = ..., - ) -> None: ... - - @property - def digest_size(self) -> int: ... - - def copy(self) -> "MAC": ... - - def update(self, data: bytes) -> None: ... - - def digest(self) -> bytes: ... - - def hexdigest(self) -> str: ... - - -def new(key: bytes, data: bytes = ..., iv: bytes = ..., sbox: str = ...) -> MAC: ... diff --git a/pygost/stubs/pygost/gost3410.pyi b/pygost/stubs/pygost/gost3410.pyi deleted file mode 100644 index 14553a38f7e08958e27c71f82339c36b9f84084b515841bc8f2d8a18a85d414b..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost3410.pyi +++ /dev/null @@ -1,72 +0,0 @@ -from typing import Dict -from typing import Tuple - - -DEFAULT_CURVE = ... # type: GOST3410Curve -CURVES = ... # type: Dict[str, GOST3410Curve] -PublicKey = Tuple[int, int] - - -class GOST3410Curve(object): - p = ... # type: int - q = ... # type: int - a = ... # type: int - b = ... # type: int - x = ... # type: int - y = ... # type: int - cofactor = ... # type: int - e = ... # type: int - d = ... # type: int - name = ... # type: str - - def __init__( - self, - p: int, - q: int, - a: int, - b: int, - x: int, - y: int, - cofactor: int = 1, - e: int = None, - d: int = None, - name: str = None, - ) -> None: ... - - def pos(self, v: int) -> int: ... - - def exp(self, degree: int, x: int = ..., y: int = ...) -> int: ... - - def st(self) -> Tuple[int, int]: ... - - @property - def point_size(self) -> int: ... - - def contains(self, point: Tuple[int, int]) -> bool: ... - - -def public_key(curve: GOST3410Curve, prv: int) -> PublicKey: ... - - -def sign(curve: GOST3410Curve, prv: int, digest: bytes, rand: bytes = None) -> bytes: ... - - -def verify(curve: GOST3410Curve, pub: PublicKey, digest: bytes, signature: bytes) -> bool: ... - - -def prv_unmarshal(prv: bytes) -> int: ... - - -def prv_marshal(curve: GOST3410Curve, prv: int) -> bytes: ... - - -def pub_marshal(pub: PublicKey) -> bytes: ... - - -def pub_unmarshal(pub: bytes) -> PublicKey: ... - - -def uv2xy(curve: GOST3410Curve, u: int, v: int) -> Tuple[int, int]: ... - - -def xy2uv(curve: GOST3410Curve, x: int, y: int) -> Tuple[int, int]: ... diff --git a/pygost/stubs/pygost/gost3410_vko.pyi b/pygost/stubs/pygost/gost3410_vko.pyi deleted file mode 100644 index b80bdd3696690792324f3acabcd12a6dc96c51db3064f40bbf4e16d1e42374c3..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost3410_vko.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from pygost.gost3410 import GOST3410Curve -from pygost.gost3410 import PublicKey - - -def ukm_unmarshal(ukm: bytes) -> int: ... - - -def kek(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int) -> bytes: ... - - -def kek_34102001(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int) -> bytes: ... - - -def kek_34102012256(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int = ...) -> bytes: ... - - -def kek_34102012512(curve: GOST3410Curve, prv: int, pub: PublicKey, ukm: int = ...) -> bytes: ... diff --git a/pygost/stubs/pygost/gost34112012.pyi b/pygost/stubs/pygost/gost34112012.pyi deleted file mode 100644 index fcc3097935a19b37e56d350a02f1d7d2f03bbfb65725ecf4bd138fca5962cbf1..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost34112012.pyi +++ /dev/null @@ -1,18 +0,0 @@ -from pygost.iface import PEP247 - - -class GOST34112012(PEP247): - block_size = ... # type: int - - def __init__(self, data: bytes = ..., digest_size: int = ...) -> None: ... - - @property - def digest_size(self) -> int: ... - - def copy(self) -> "GOST34112012": ... - - def update(self, data: bytes) -> None: ... - - def digest(self) -> bytes: ... - - def hexdigest(self) -> str: ... diff --git a/pygost/stubs/pygost/gost34112012256.pyi b/pygost/stubs/pygost/gost34112012256.pyi deleted file mode 100644 index 504ad8031396faa7251efc54d80f2488d9acdee8a215620d66d50c103d4b1429..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost34112012256.pyi +++ /dev/null @@ -1,21 +0,0 @@ -from pygost.iface import PEP247 - - -class GOST34112012256(PEP247): - block_size = ... # type: int - - def __init__(self, data: bytes = ...) -> None: ... - - @property - def digest_size(self) -> int: ... - - def copy(self) -> "GOST34112012256": ... - - def update(self, data: bytes) -> None: ... - - def digest(self) -> bytes: ... - - def hexdigest(self) -> str: ... - - -def new(data: bytes = ...) -> GOST34112012256: ... diff --git a/pygost/stubs/pygost/gost34112012512.pyi b/pygost/stubs/pygost/gost34112012512.pyi deleted file mode 100644 index b83d2740ff6041d1a183f5fb8ac599349c20f0f4c991d8c781114e1df2c936e6..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost34112012512.pyi +++ /dev/null @@ -1,24 +0,0 @@ -from pygost.iface import PEP247 - - -class GOST34112012512(PEP247): - block_size = ... # type: int - - def __init__(self, data: bytes = ...) -> None: ... - - @property - def digest_size(self) -> int: ... - - def copy(self) -> "GOST34112012512": ... - - def update(self, data: bytes) -> None: ... - - def digest(self) -> bytes: ... - - def hexdigest(self) -> str: ... - - -def new(data: bytes = ...) -> GOST34112012512: ... - - -def pbkdf2(password: bytes, salt: bytes, iterations: int, dklen: int) -> bytes: ... diff --git a/pygost/stubs/pygost/gost341194.pyi b/pygost/stubs/pygost/gost341194.pyi deleted file mode 100644 index 793b188606aeea2152f5ea1d3c9bed0ecd363bf6ef19a7e5df22633e42047ba1..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost341194.pyi +++ /dev/null @@ -1,25 +0,0 @@ -from pygost.iface import PEP247 - - -class GOST341194(PEP247): - sbox = ... # type: str - block_size = ... # type: int - - def __init__(self, data: bytes = ..., sbox: str = ...) -> None: ... - - @property - def digest_size(self) -> int: ... - - def copy(self) -> "GOST341194": ... - - def update(self, data: bytes) -> None: ... - - def digest(self) -> bytes: ... - - def hexdigest(self) -> str: ... - - -def new(data: bytes = ..., sbox: str = ...) -> GOST341194: ... - - -def pbkdf2(password: bytes, salt: bytes, iterations: int, dklen: int) -> bytes: ... diff --git a/pygost/stubs/pygost/gost3412.pyi b/pygost/stubs/pygost/gost3412.pyi deleted file mode 100644 index 7df80d465339ef552c460b6e7199ce1f6f42e6c5b0225d93f7a07b3d64ca7e9e..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost3412.pyi +++ /dev/null @@ -1,18 +0,0 @@ -class GOST3412Kuznechik(object): - blocksize = ... # type: int - - def __init__(self, key: bytes) -> None: ... - - def encrypt(self, blk: bytes) -> bytes: ... - - def decrypt(self, blk: bytes) -> bytes: ... - - -class GOST3412Magma(object): - blocksize = ... # type: int - - def __init__(self, key: bytes) -> None: ... - - def encrypt(self, blk: bytes) -> bytes: ... - - def decrypt(self, blk: bytes) -> bytes: ... diff --git a/pygost/stubs/pygost/gost3413.pyi b/pygost/stubs/pygost/gost3413.pyi deleted file mode 100644 index 3a143354a2fe6bdaaf64b06dc444fb64bb7c0052ebcbc451c95451bcb24d749e..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/gost3413.pyi +++ /dev/null @@ -1,81 +0,0 @@ -from typing import Callable - - -def pad_size(data_size: int, blocksize: int) -> int: ... - - -def pad1(data: bytes, blocksize: int) -> bytes: ... - - -def pad2(data: bytes, blocksize: int) -> bytes: ... - - -def unpad2(data: bytes, blocksize: int) -> bytes: ... - - -def pad3(data: bytes, blocksize: int) -> bytes: ... - - -def ecb_encrypt(encrypter: Callable[[bytes], bytes], bs: int, pt: bytes) -> bytes: ... - - -def ecb_decrypt(decrypter: Callable[[bytes], bytes], bs: int, ct: bytes) -> bytes: ... - - -def acpkm(encrypter: Callable[[bytes], bytes], bs: int) -> bytes: ... - - -def ctr(encrypter: Callable[[bytes], bytes], bs: int, data: bytes, iv: bytes) -> bytes: ... - - -def ctr_acpkm( - algo_class: object, - encrypter: Callable[[bytes], bytes], - section_size: int, - bs: int, - data: bytes, - iv: bytes, -) -> bytes: ... - - -def ofb(encrypter: Callable[[bytes], bytes], bs: int, data: bytes, iv: bytes) -> bytes: ... - - -def cbc_encrypt(encrypter: Callable[[bytes], bytes], bs: int, pt: bytes, iv: bytes) -> bytes: ... - - -def cbc_decrypt(decrypter: Callable[[bytes], bytes], bs: int, ct: bytes, iv: bytes) -> bytes: ... - - -def cfb_encrypt(encrypter: Callable[[bytes], bytes], bs: int, pt: bytes, iv: bytes) -> bytes: ... - - -def cfb_decrypt(encrypter: Callable[[bytes], bytes], bs: int, ct: bytes, iv: bytes) -> bytes: ... - - -def mac(encrypter: Callable[[bytes], bytes], bs: int, data: bytes) -> bytes: ... - - -def acpkm_master( - algo_class: object, - encrypter: Callable[[bytes], bytes], - key_section_size: int, - bs: int, - keymat_len: int, -) -> bytes: ... - - -def mac_acpkm_master( - algo_class: object, - encrypter: Callable[[bytes], bytes], - key_section_size: int, - section_size: int, - bs: int, - data: bytes, -) -> bytes: ... - - -def pad_iso10126(data: bytes, blocksize: int) -> bytes: ... - - -def unpad_iso10126(data: bytes, blocksize: int) -> bytes: ... diff --git a/pygost/stubs/pygost/iface.pyi b/pygost/stubs/pygost/iface.pyi deleted file mode 100644 index 3b4aa0a638dce4a6912080814d544b088a06e8b53c7603614be9947b652de20b..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/iface.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from abc import ABCMeta -from abc import abstractmethod - - -class PEP247(metaclass=ABCMeta): - @abstractmethod - @property - def digest_size(self) -> int: ... - - @abstractmethod - def copy(self) -> "PEP247": ... - - @abstractmethod - def update(self, data: bytes) -> None: ... - - @abstractmethod - def digest(self) -> bytes: ... - - def hexdigest(self) -> str: ... diff --git a/pygost/stubs/pygost/kdf.pyi b/pygost/stubs/pygost/kdf.pyi deleted file mode 100644 index c1f49686be92c4d5401481806fa7c7605a70fbef0c991629cd781db4827804c8..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/kdf.pyi +++ /dev/null @@ -1,22 +0,0 @@ -from typing import Sequence -from typing import Tuple - -from pygost.gost3410 import GOST3410Curve - - -PublicKey = Tuple[int, int] - - -def kdf_gostr3411_2012_256(key: bytes, label: bytes, seed: bytes) -> bytes: ... - - -def kdf_tree_gostr3411_2012_256( - key: bytes, - label: bytes, - seed: bytes, - keys: int, - i_len: int = 1, -) -> Sequence[bytes]: ... - - -def keg(curve: GOST3410Curve, prv: int, pub: PublicKey, h: bytes) -> bytes: ... diff --git a/pygost/stubs/pygost/mgm.pyi b/pygost/stubs/pygost/mgm.pyi deleted file mode 100644 index db1b106bec95b77f0f7cce3c8c2c60e4003020c715dbde4d39bb6d0be01268e3..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/mgm.pyi +++ /dev/null @@ -1,17 +0,0 @@ -from typing import Callable - - -def nonce_prepare(nonce: bytes) -> bytes: ... - - -class MGM(object): - def __init__( - self, - encrypter: Callable[[bytes], bytes], - bs: int, - tag_size: int = None, - ) -> None: ... - - def seal(self, nonce: bytes, plaintext: bytes, additional_data: bytes) -> bytes: ... - - def open(self, nonce: bytes, ciphertext: bytes, additional_data: bytes) -> bytes: ... diff --git a/pygost/stubs/pygost/utils.pyi b/pygost/stubs/pygost/utils.pyi deleted file mode 100644 index cd90a0272fd41b8806227be251970c0ed56492880c703577b99fa76ae1f3c8bf..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/utils.pyi +++ /dev/null @@ -1,19 +0,0 @@ -from typing import AnyStr - - -def strxor(a: bytes, b: bytes) -> bytes: ... - - -def hexdec(data: AnyStr) -> bytes: ... - - -def hexenc(data: bytes) -> str: ... - - -def bytes2long(raw: bytes) -> int: ... - - -def long2bytes(n: int, size: int = ...) -> bytes: ... - - -def modinvert(a: int, n: int) -> int: ... diff --git a/pygost/stubs/pygost/wrap.pyi b/pygost/stubs/pygost/wrap.pyi deleted file mode 100644 index 85fc7cdcc4573348f35ac33dfd3132276a7928069b513de1881370c87801242b..0000000000000000000000000000000000000000 --- a/pygost/stubs/pygost/wrap.pyi +++ /dev/null @@ -1,31 +0,0 @@ -from typing import Callable - - -def wrap_gost(ukm: bytes, kek: bytes, cek: bytes, sbox: str = ...) -> bytes: ... - - -def unwrap_gost(kek: bytes, data: bytes, sbox: str = ...) -> bytes: ... - - -def wrap_cryptopro(ukm: bytes, kek: bytes, cek: bytes, sbox: str = ...) -> bytes: ... - - -def unwrap_cryptopro(kek: bytes, data: bytes, sbox: str = ...) -> bytes: ... - - -def kexp15( - encrypter_key: Callable[[bytes], bytes], - encrypter_mac: Callable[[bytes], bytes], - bs: int, - key: bytes, - iv: bytes, -) -> bytes: ... - - -def kimp15( - encrypter_key: Callable[[bytes], bytes], - encrypter_mac: Callable[[bytes], bytes], - bs: int, - kexp: bytes, - iv: bytes, -) -> bytes: ... diff --git a/pygost/utils.py b/pygost/utils.py index 88b7a324f6bfbe60f3af2de63f37f79a85a16fe4e5831848104a718d6aa7526f..4bacc04eb878afaf4e22d0cbeafe1d046b944cac7ff397ef736e228120e7e812 100644 --- a/pygost/utils.py +++ b/pygost/utils.py @@ -18,10 +18,7 @@ from codecs import getdecoder from codecs import getencoder -xrange = range if version_info[0] == 3 else xrange - - -def strxor(a, b): +def strxor(a: bytes, b: bytes) -> bytes: """XOR of two strings This function will process only shortest length of both strings, @@ -50,7 +47,7 @@ """ return _hexencoder(data)[0].decode("ascii") -def modinvert(a, n): +def modinvert(a: int, n: int) -> int: """Modular multiplicative inverse :returns: inverse number. -1 if it does not exist diff --git a/pygost/wrap.py b/pygost/wrap.py index 1106d434e3aa15070769be0361e388e6de74b2684186f4e1551a75b93506b735..37ed16901fbf393cfcdc22a152ddea5b9010674a38c3772838aab8d333f46cbb 100644 --- a/pygost/wrap.py +++ b/pygost/wrap.py @@ -31,7 +31,7 @@ from pygost.gost3413 import ctr from pygost.gost3413 import mac -def wrap_gost(ukm, kek, cek, sbox=DEFAULT_SBOX): +def wrap_gost(ukm: bytes, kek: bytes, cek: bytes, sbox=DEFAULT_SBOX) -> bytes: """28147-89 key wrapping :param ukm: UKM @@ -48,7 +48,7 @@ cek_enc = ecb_encrypt(kek, cek, sbox=sbox) return ukm + cek_enc + cek_mac -def unwrap_gost(kek, data, sbox=DEFAULT_SBOX): +def unwrap_gost(kek: bytes, data: bytes, sbox=DEFAULT_SBOX) -> bytes: """28147-89 key unwrapping :param kek: key encryption key @@ -67,7 +67,7 @@ raise ValueError("Invalid MAC") return cek -def wrap_cryptopro(ukm, kek, cek, sbox=DEFAULT_SBOX): +def wrap_cryptopro(ukm: bytes, kek: bytes, cek: bytes, sbox=DEFAULT_SBOX) -> bytes: """CryptoPro key wrapping :param ukm: UKM @@ -87,7 +87,7 @@ sbox=sbox, ) -def unwrap_cryptopro(kek, data, sbox=DEFAULT_SBOX): +def unwrap_cryptopro(kek: bytes, data: bytes, sbox=DEFAULT_SBOX) -> bytes: """CryptoPro key unwrapping :param kek: key encryption key @@ -121,21 +121,21 @@ out = cfb_encrypt(out, out, iv=iv, sbox=sbox) return out -def kexp15(encrypter_key, encrypter_mac, bs, key, iv): +def kexp15(encrypter_key, encrypter_mac, bs: int, key: bytes, iv: bytes) -> bytes: """KExp15 key exporting :param encrypter_key: encrypting function for key encryption, that takes block as an input :param encrypter_mac: encrypting function for key authentication - :param int bs: cipher's blocksize, bytes - :param bytes key: key to export - :param bytes iv: half blocksize-sized initialization vector + :param bs: cipher's blocksize, bytes + :param key: key to export + :param iv: half blocksize-sized initialization vector """ key_mac = mac(encrypter_mac, bs, iv + key) return ctr(encrypter_key, bs, key + key_mac, iv) -def kimp15(encrypter_key, encrypter_mac, bs, kexp, iv): +def kimp15(encrypter_key, encrypter_mac, bs: int, kexp: bytes, iv: bytes) -> bytes: """KImp15 key importing :param encrypter_key: encrypting function for key decryption,