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,