From: Sergey Matveev Date: Sat, 19 Nov 2016 11:46:19 +0000 (+0300) Subject: 34.10-2012 VKO implementation and remove X.509-compatibility helpers X-Git-Tag: 3.0~22 X-Git-Url: http://www.git.cypherpunks.ru/?p=pygost.git;a=commitdiff_plain;h=282cb5e23df11f9d5e3c29185f0e6c72f038f731 34.10-2012 VKO implementation and remove X.509-compatibility helpers --- diff --git a/README b/README index 00bdb8a..42b3c2e 100644 --- a/README +++ b/README @@ -11,6 +11,7 @@ GOST is GOvernment STandard of Russian Federation (and Soviet Union). * GOST R 34.10-2012 (RFC 7091) public key signature function * various 34.10 curve parameters included * VKO 34.10-2001 Diffie-Hellman function (RFC 4357) +* VKO 34.10-2012 Diffie-Hellman function * 28147-89 and CryptoPro key wrapping (RFC 4357) * 28147-89 CryptoPro key meshing for CFB mode (RFC 4357) * RFC 4491 (using GOST algorithms with X.509) compatibility helpers diff --git a/pygost/Makefile b/pygost/Makefile index efa51a0..a6df861 100644 --- a/pygost/Makefile +++ b/pygost/Makefile @@ -6,6 +6,6 @@ test: PYTHONPATH=.. $(PYTHON) -m unittest test_gost3411_94 PYTHONPATH=.. $(PYTHON) -m unittest test_gost3411_2012 PYTHONPATH=.. $(PYTHON) -m unittest test_gost3410 - PYTHONPATH=.. $(PYTHON) -m unittest test_x509 + PYTHONPATH=.. $(PYTHON) -m unittest test_gost3410_vko PYTHONPATH=.. $(PYTHON) -m unittest test_wrap PYTHONPATH=.. $(PYTHON) -m unittest test_gost3412 diff --git a/pygost/gost3410.py b/pygost/gost3410.py index c9b905e..8ef068f 100644 --- a/pygost/gost3410.py +++ b/pygost/gost3410.py @@ -23,7 +23,6 @@ key, digest and signature lengths. from os import urandom -from pygost.gost3411_94 import GOST341194 from pygost.utils import bytes2long from pygost.utils import hexdec from pygost.utils import long2bytes @@ -32,6 +31,10 @@ from pygost.utils import modinvert SIZE_3410_2001 = 32 SIZE_3410_2012 = 64 +MODE2SIZE = { + 2001: SIZE_3410_2001, + 2012: SIZE_3410_2012, +} DEFAULT_CURVE = "GostR3410_2001_CryptoPro_A_ParamSet" @@ -183,41 +186,17 @@ def public_key(curve, private_key): return curve.exp(private_key) -def kek(curve, private_key, ukm, pubkey): - """ Make Diffie-Hellman computation - - :param GOST3410Curve curve: curve to use - :param long private_key: private key - :param ukm: UKM value (VKO-factor) - :type ukm: bytes, 8 bytes - :param pubkey: public key's part - :type pubkey: (long, long) - :return: Key Encryption Key (shared key) - :rtype: bytes, 32 bytes - - Shared Key Encryption Key computation is based on - :rfc:`4357` VKO GOST 34.10-2001 with little-endian - hash output. - """ - key = curve.exp(private_key, pubkey[0], pubkey[1]) - key = curve.exp(bytes2long(24 * b"\x00" + ukm), key[0], key[1]) - return GOST341194( - (long2bytes(key[1]) + long2bytes(key[0]))[::-1], - "GostR3411_94_CryptoProParamSet" - ).digest()[::-1] - - def sign(curve, private_key, digest, size=SIZE_3410_2001): """ Calculate signature for provided digest :param GOST3410Curve curve: curve to use :param long private_key: private key :param digest: digest for signing - :type digest: bytes, 32 bytes + :type digest: bytes, 32 or 64 bytes :param size: signature size :type size: 32 (for 34.10-2001) or 64 (for 34.10-2012) :return: signature - :rtype: bytes, 64 bytes + :rtype: bytes, 64 or 128 bytes """ if len(digest) != size: raise ValueError("Invalid digest length") @@ -249,9 +228,9 @@ def verify(curve, pubkeyX, pubkeyY, digest, signature, size=SIZE_3410_2001): :param long pubkeyX: public key's X :param long pubkeyY: public key's Y :param digest: digest needed to check - :type digest: bytes, 32 bytes + :type digest: bytes, 32 or 64 bytes :param signature: signature to verify with - :type signature: bytes, 64 bytes + :type signature: bytes, 64 or 128 bytes :param size: signature size :type size: 32 (for 34.10-2001) or 64 (for 34.10-2012) :rtype: bool @@ -288,3 +267,33 @@ def verify(curve, pubkeyX, pubkeyY, digest, signature, size=SIZE_3410_2001): lm %= q # This is not constant time comparison! return lm == r + + +def prv_unmarshal(private_key): + """Unmarshal private key + + :param bytes private_key: serialized private key + :rtype: long + """ + return bytes2long(private_key[::-1]) + + +def pub_marshal(pub, mode=2001): + """Marshal public key + + :type pub: (long, long) + :rtype: bytes + """ + size = MODE2SIZE[mode] + return (long2bytes(pub[1], size) + long2bytes(pub[0], size))[::-1] + + +def pub_unmarshal(pub, mode=2001): + """Unmarshal public key + + :type pub: bytes + :rtype: (long, long) + """ + pub = pub[::-1] + size = MODE2SIZE[mode] + return (bytes2long(pub[size:]), bytes2long(pub[:size])) diff --git a/pygost/gost3410_vko.py b/pygost/gost3410_vko.py new file mode 100644 index 0000000..4326677 --- /dev/null +++ b/pygost/gost3410_vko.py @@ -0,0 +1,60 @@ +from pygost.gost3410 import pub_marshal +from pygost.gost3411_2012_256 import GOST34112012256 +from pygost.gost3411_2012_512 import GOST34112012512 +from pygost.gost3411_94 import GOST341194 +from pygost.utils import bytes2long + + +def vko_34102001(curve, private_key, pubkey, ukm): + """ Make Diffie-Hellman computation (34.10-2001, 34.11-94) + + :param GOST3410Curve curve: curve to use + :param long private_key: private key + :param ukm: UKM value (VKO-factor) + :type ukm: bytes, 8 bytes + :param pubkey: public key's part + :type pubkey: (long, long) + :return: Key Encryption Key (shared key) + :rtype: bytes, 32 bytes + + Shared Key Encryption Key computation is based on + :rfc:`4357` VKO GOST 34.10-2001 with little-endian + hash output. + """ + key = curve.exp(private_key, pubkey[0], pubkey[1]) + key = curve.exp(bytes2long(24 * b"\x00" + ukm), key[0], key[1]) + return GOST341194(pub_marshal(key), "GostR3411_94_CryptoProParamSet").digest()[::-1] + + +def vko_34102012256(curve, private_key, pubkey, ukm=b"\x00\x00\x00\x00\x00\x00\x00\01"): + """ Make Diffie-Hellman computation (34.10-2012, 34.11-2012 256 bit) + + :param GOST3410Curve curve: curve to use + :param long private_key: private key + :param ukm: UKM value (VKO-factor) + :type ukm: bytes, 8 bytes + :param pubkey: public key's part + :type pubkey: (long, long) + :return: Key Encryption Key (shared key) + :rtype: bytes, 32 bytes + """ + key = curve.exp(private_key, pubkey[0], pubkey[1]) + key = curve.exp(bytes2long(ukm[::-1]), key[0], key[1]) + return GOST34112012256(pub_marshal(key, mode=2012)).digest() + + +def vko_34102012512(curve, private_key, pubkey, ukm=b"\x00\x00\x00\x00\x00\x00\x00\01"): + """ Make Diffie-Hellman computation (34.10-2012, 34.11-2012 512 bit) + + :param GOST3410Curve curve: curve to use + :param long private_key: private key + :param ukm: UKM value (VKO-factor) + :type ukm: bytes, 8 bytes + :param pubkey: public key's part + :type pubkey: (long, long) + :return: Key Encryption Key (shared key) + :rtype: bytes, 32 bytes + """ + key = curve.exp(private_key, pubkey[0], pubkey[1]) + key = curve.exp(bytes2long(ukm[::-1]), key[0], key[1]) + return GOST34112012512(pub_marshal(key, mode=2012)).digest() diff --git a/pygost/stubs/pygost/gost3410.pyi b/pygost/stubs/pygost/gost3410.pyi index 9151e99..aacb9ab 100644 --- a/pygost/stubs/pygost/gost3410.pyi +++ b/pygost/stubs/pygost/gost3410.pyi @@ -3,6 +3,7 @@ from typing import Tuple CURVE_PARAMS = ... # type: Dict[str, Tuple[bytes, bytes, bytes, bytes, bytes, bytes]] +PublicKey = Tuple[int, int] class GOST3410Curve(object): @@ -20,20 +21,9 @@ class GOST3410Curve(object): def exp(self, degree: int, x: int=..., y: int=...) -> int: ... -PublicKey = Tuple[int, int] - - def public_key(curve: GOST3410Curve, private_key: int) -> PublicKey: ... -def kek( - curve: GOST3410Curve, - private_key: int, - ukm: bytes, - pubkey: PublicKey, -) -> bytes: ... - - def sign( curve: GOST3410Curve, private_key: int, @@ -50,3 +40,12 @@ def verify( signature: bytes, size: int=..., ) -> bool: ... + + +def prv_unmarshal(private_key: bytes) -> int: ... + + +def pub_marshal(pub: PublicKey, mode: int) -> bytes: ... + + +def pub_unmarshal(pub: bytes, mode: int) -> PublicKey: ... diff --git a/pygost/stubs/pygost/gost3410_vko.pyi b/pygost/stubs/pygost/gost3410_vko.pyi new file mode 100644 index 0000000..3362793 --- /dev/null +++ b/pygost/stubs/pygost/gost3410_vko.pyi @@ -0,0 +1,26 @@ +from pygost.gost3410 import GOST3410Curve +from pygost.gost3410 import PublicKey + + +def vko_34102001( + curve: GOST3410Curve, + private_key: int , + pubkey: PublicKey, + ukm: bytes, +) -> bytes: ... + + +def vko_34102012256( + curve: GOST3410Curve, + private_key: int, + pubkey: PublicKey, + ukm=...: bytes, +) -> bytes: ... + + +def vko_34102012512( + curve: GOST3410Curve, + private_key: int, + pubkey: PublicKey, + ukm=...: bytes, +) -> bytes: ... diff --git a/pygost/stubs/pygost/x509.pyi b/pygost/stubs/pygost/x509.pyi deleted file mode 100644 index 1e0f232..0000000 --- a/pygost/stubs/pygost/x509.pyi +++ /dev/null @@ -1,46 +0,0 @@ -from typing import Tuple - - -SIZE_3410_2001 = ... # type: int -SIZE_3410_2012 = ... # type: int - - -def keypair_gen( - seed: bytes, - mode: int=..., - curve_params: str=..., -) -> Tuple[bytes, bytes]: ... - - -def sign_digest( - private_key: bytes, - digest: bytes, - mode: int=..., - curve_params: str=..., -) -> bytes: ... - - -def verify_digest( - public_key: bytes, - digest: bytes, - signature: bytes, - mode: int=..., - curve_params: str=..., -) -> bool: ... - - -def sign( - private_key: bytes, - data: bytes, - mode: int=..., - curve_params: str=..., -) -> bytes: ... - - -def verify( - public_key: bytes, - data: bytes, - signature: bytes, - mode: int=..., - curve_params: str=..., -) -> bool: ... diff --git a/pygost/test_gost3410.py b/pygost/test_gost3410.py index 0dc9d3e..9704320 100644 --- a/pygost/test_gost3410.py +++ b/pygost/test_gost3410.py @@ -20,7 +20,6 @@ from unittest import TestCase from pygost.gost3410 import CURVE_PARAMS from pygost.gost3410 import GOST3410Curve -from pygost.gost3410 import kek from pygost.gost3410 import public_key from pygost.gost3410 import sign from pygost.gost3410 import SIZE_3410_2001 @@ -231,20 +230,3 @@ class Test34102012(TestCase): s = sign(c, private_key, digest, size=SIZE_3410_2012) self.assertTrue(verify(c, pubX, pubY, digest, s, size=SIZE_3410_2012)) self.assertNotIn(b"\x00" * 8, s) - - -class TestVKO(TestCase): - def test_sequence(self): - curve = GOST3410Curve(*CURVE_PARAMS["GostR3410_2001_TestParamSet"]) - for _ in range(20): - ukm = urandom(8) - prv1 = bytes2long(urandom(32)) - prv2 = bytes2long(urandom(32)) - pub1 = public_key(curve, prv1) - pub2 = public_key(curve, prv2) - kek1 = kek(curve, prv1, ukm, pub2) - kek2 = kek(curve, prv2, ukm, pub1) - self.assertEqual(kek1, kek2) - kek1 = kek(curve, prv1, ukm, pub1) - kek2 = kek(curve, prv2, ukm, pub2) - self.assertNotEqual(kek1, kek2) diff --git a/pygost/test_gost3410_vko.py b/pygost/test_gost3410_vko.py new file mode 100644 index 0000000..1ec5c02 --- /dev/null +++ b/pygost/test_gost3410_vko.py @@ -0,0 +1,107 @@ +# coding: utf-8 +# PyGOST -- Pure Python GOST cryptographic functions library +# Copyright (C) 2015-2016 Sergey Matveev +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from os import urandom +from unittest import TestCase + +from pygost.gost3410 import CURVE_PARAMS +from pygost.gost3410 import GOST3410Curve +from pygost.gost3410 import prv_unmarshal +from pygost.gost3410 import pub_unmarshal +from pygost.gost3410 import public_key +from pygost.gost3410_vko import vko_34102001 +from pygost.gost3410_vko import vko_34102012256 +from pygost.gost3410_vko import vko_34102012512 +from pygost.utils import bytes2long +from pygost.utils import hexdec + + +class TestVKO34102001(TestCase): + def test_sequence(self): + curve = GOST3410Curve(*CURVE_PARAMS["GostR3410_2001_TestParamSet"]) + for _ in range(10): + ukm = urandom(8) + prv1 = bytes2long(urandom(32)) + prv2 = bytes2long(urandom(32)) + pub1 = public_key(curve, prv1) + pub2 = public_key(curve, prv2) + kek1 = vko_34102001(curve, prv1, pub2, ukm) + kek2 = vko_34102001(curve, prv2, pub1, ukm) + self.assertEqual(kek1, kek2) + kek1 = vko_34102001(curve, prv1, pub1, ukm) + kek2 = vko_34102001(curve, prv2, pub2, ukm) + self.assertNotEqual(kek1, kek2) + + +class TestVKO34102012256(TestCase): + """http://tc26.ru/methods/recommendation/%D0%A2%D0%9A26%D0%90%D0%9B%D0%93.pdf test vectors + """ + def test_vector(self): + curve = GOST3410Curve(*CURVE_PARAMS["GostR3410_2012_TC26_ParamSetA"]) + ukm = hexdec("1d80603c8544c727") + prvA = prv_unmarshal(hexdec("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667")) + pubA = pub_unmarshal(hexdec("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a"), mode=2012) + prvB = prv_unmarshal(hexdec("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db")) + pubB = pub_unmarshal(hexdec("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79"), mode=2012) + vko = hexdec("c9a9a77320e2cc559ed72dce6f47e2192ccea95fa648670582c054c0ef36c221") + self.assertEqual(vko_34102012256(curve, prvA, pubB, ukm), vko) + self.assertEqual(vko_34102012256(curve, prvB, pubA, ukm), vko) + + def test_sequence(self): + curve = GOST3410Curve(*CURVE_PARAMS["GostR3410_2012_TC26_ParamSetA"]) + for _ in range(10): + ukm = urandom(8) + prv1 = bytes2long(urandom(32)) + prv2 = bytes2long(urandom(32)) + pub1 = public_key(curve, prv1) + pub2 = public_key(curve, prv2) + kek1 = vko_34102012256(curve, prv1, pub2, ukm) + kek2 = vko_34102012256(curve, prv2, pub1, ukm) + self.assertEqual(kek1, kek2) + kek1 = vko_34102012256(curve, prv1, pub1, ukm) + kek2 = vko_34102012256(curve, prv2, pub2, ukm) + self.assertNotEqual(kek1, kek2) + + +class TestVKO34102012512(TestCase): + """http://tc26.ru/methods/recommendation/%D0%A2%D0%9A26%D0%90%D0%9B%D0%93.pdf test vectors + """ + def test_vector(self): + curve = GOST3410Curve(*CURVE_PARAMS["GostR3410_2012_TC26_ParamSetA"]) + ukm = hexdec("1d80603c8544c727") + prvA = prv_unmarshal(hexdec("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667")) + pubA = pub_unmarshal(hexdec("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a"), mode=2012) + prvB = prv_unmarshal(hexdec("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db")) + pubB = pub_unmarshal(hexdec("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79"), mode=2012) + vko = hexdec("79f002a96940ce7bde3259a52e015297adaad84597a0d205b50e3e1719f97bfa7ee1d2661fa9979a5aa235b558a7e6d9f88f982dd63fc35a8ec0dd5e242d3bdf") + self.assertEqual(vko_34102012512(curve, prvA, pubB, ukm), vko) + self.assertEqual(vko_34102012512(curve, prvB, pubA, ukm), vko) + + def test_sequence(self): + curve = GOST3410Curve(*CURVE_PARAMS["GostR3410_2012_TC26_ParamSetA"]) + for _ in range(10): + ukm = urandom(8) + prv1 = bytes2long(urandom(32)) + prv2 = bytes2long(urandom(32)) + pub1 = public_key(curve, prv1) + pub2 = public_key(curve, prv2) + kek1 = vko_34102012512(curve, prv1, pub2, ukm) + kek2 = vko_34102012512(curve, prv2, pub1, ukm) + self.assertEqual(kek1, kek2) + kek1 = vko_34102012512(curve, prv1, pub1, ukm) + kek2 = vko_34102012512(curve, prv2, pub2, ukm) + self.assertNotEqual(kek1, kek2) diff --git a/pygost/test_x509.py b/pygost/test_x509.py deleted file mode 100644 index 0939546..0000000 --- a/pygost/test_x509.py +++ /dev/null @@ -1,55 +0,0 @@ -# coding: utf-8 -# PyGOST -- Pure Python GOST cryptographic functions library -# Copyright (C) 2015-2016 Sergey Matveev -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -from os import urandom -from unittest import TestCase - -from pygost.x509 import keypair_gen -from pygost.x509 import sign -from pygost.x509 import sign_digest -from pygost.x509 import verify -from pygost.x509 import verify_digest -from pygost.x509 import SIZE_3410_2001 -from pygost.x509 import SIZE_3410_2012 - - -class X5092001Test(TestCase): - def test_symmetric(self): - for _ in range(1 << 4): - prv, pub = keypair_gen(urandom(SIZE_3410_2001), mode=2001) - digest = urandom(SIZE_3410_2001) - self.assertTrue(verify_digest( - pub, digest, sign_digest(prv, digest, mode=2001), mode=2001 - )) - data = digest - self.assertTrue(verify( - pub, data, sign(prv, data, mode=2001), mode=2001 - )) - - -class X5092012Test(TestCase): - def test_symmetric(self): - for _ in range(1 << 4): - prv, pub = keypair_gen(urandom(SIZE_3410_2012), mode=2012) - digest = urandom(SIZE_3410_2012) - self.assertTrue(verify_digest( - pub, digest, sign_digest(prv, digest, mode=2012), mode=2012, - )) - data = digest - self.assertTrue(verify( - pub, data, sign(prv, data, mode=2012), mode=2012, - )) diff --git a/pygost/x509.py b/pygost/x509.py deleted file mode 100644 index 441f74b..0000000 --- a/pygost/x509.py +++ /dev/null @@ -1,157 +0,0 @@ -# coding: utf-8 -# PyGOST -- Pure Python GOST cryptographic functions library -# Copyright (C) 2015-2016 Sergey Matveev -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -""" :rfc:`4491` (using GOST algorithms with X.509) compatibility helpers - -Signature, public and private keys formats are defined in the RFC above. -""" - -from pygost.gost3410 import CURVE_PARAMS -from pygost.gost3410 import GOST3410Curve -from pygost.gost3410 import public_key as _public_key -from pygost.gost3410 import sign as _sign -from pygost.gost3410 import SIZE_3410_2001 -from pygost.gost3410 import SIZE_3410_2012 -from pygost.gost3410 import verify as _verify -from pygost.gost3411_2012 import GOST34112012 -from pygost.gost3411_94 import GOST341194 -from pygost.utils import bytes2long -from pygost.utils import long2bytes - - -GOST341194_SBOX = "GostR3411_94_CryptoProParamSet" -MODE2PARAMS = { - 2001: "GostR3410_2001_CryptoPro_A_ParamSet", - 2012: "GostR3410_2012_TC26_ParamSetA", -} -MODE2SIZE = { - 2001: SIZE_3410_2001, - 2012: SIZE_3410_2012, -} -MODE2DIGEST = { - 2001: lambda data: GOST341194(data, sbox=GOST341194_SBOX).digest(), - 2012: lambda data: GOST34112012(data).digest(), -} - - -def keypair_gen(seed, mode=2001, curve_params=None): - """ Generate keypair - - :param bytes seed: random data used as an entropy source - :param int mode: either 2001 or 2012 - :param str curve_params: :py:data:`gost3410.CURVE_PARAMS` key identifying - curve parameters. GostR3410_2001_CryptoPro_A_ParamSet - will be used by default for 2001 mode and - GostR3410_2012_TC26_ParamSetA for 2012 one. - :return: private and public keys - :rtype: (bytes, bytes), 32/64 and 64/128 bytes - """ - if len(seed) != MODE2SIZE[mode]: - raise ValueError("Invalid seed size") - curve_params = curve_params or MODE2PARAMS[mode] - curve = GOST3410Curve(*CURVE_PARAMS[curve_params]) - private_key = seed - public_key_x, public_key_y = _public_key(curve, bytes2long(private_key)) - public_key = (long2bytes(public_key_y) + long2bytes(public_key_x))[::-1] - return private_key[::-1], public_key - - -def sign_digest(private_key, digest, mode=2001, curve_params=None): - """ Sign digest - - :param bytes private_key: private key to sign with - :param bytes digest: precalculated digest - :param int mode: either 2001 or 2012 - :param str curve_params: :py:data:`gost3410.CURVE_PARAMS` key identifying - curve parameters. GostR3410_2001_CryptoPro_A_ParamSet - will be used by default for 2001 mode and - GostR3410_2012_TC26_ParamSetA for 2012 one. - :return: signature - :rtype: bytes, 64/128 bytes - """ - curve_params = curve_params or MODE2PARAMS[mode] - curve = GOST3410Curve(*CURVE_PARAMS[curve_params]) - return _sign( - curve, - bytes2long(private_key[::-1]), - digest, - size=MODE2SIZE[mode], - ) - - -def verify_digest(public_key, digest, signature, mode=2001, curve_params=None): - """ Verify signature of the digest - - :param bytes public_key: public key to verify with - :param bytes digest: precalculated digest - :param bytes signature: signature - :param int mode: either 2001 or 2012 - :param str curve_params: :py:data:`gost3410.CURVE_PARAMS` key identifying - curve parameters. GostR3410_2001_CryptoPro_A_ParamSet - will be used by default for 2001 mode and - GostR3410_2012_TC26_ParamSetA for 2012 one. - :rtype: bool - """ - curve_params = curve_params or MODE2PARAMS[mode] - curve = GOST3410Curve(*CURVE_PARAMS[curve_params]) - public_key = public_key[::-1] - size = MODE2SIZE[mode] - return _verify( - curve, - bytes2long(public_key[size:]), - bytes2long(public_key[:size]), - digest, - signature, - size=size, - ) - - -def sign(private_key, data, mode=2001, curve_params=None): - """ Calculate data's digest and sign it - - :param bytes private_key: private key to sign with - :param bytes data: arbitrary data - :param int mode: either 2001 or 2012 - :param str curve_params: :py:data:`gost3410.CURVE_PARAMS` key identifying - curve parameters. GostR3410_2001_CryptoPro_A_ParamSet - will be used by default for 2001 mode and - GostR3410_2012_TC26_ParamSetA for 2012 one. - :return: signature - :rtype: bytes, 64/128 bytes - """ - return sign_digest(private_key, MODE2DIGEST[mode](data), mode, curve_params) - - -def verify(public_key, data, signature, mode=2001, curve_params=None): - """ Verify signature of the digest - - :param bytes public_key: public key to verify with - :param bytes digest: precalculated digest - :param bytes signature: signature - :param int mode: either 2001 or 2012 - :param str curve_params: :py:data:`gost3410.CURVE_PARAMS` key identifying - curve parameters. GostR3410_2001_CryptoPro_A_ParamSet - will be used by default for 2001 mode and - GostR3410_2012_TC26_ParamSetA for 2012 one. - :rtype: bool - """ - return verify_digest( - public_key, - MODE2DIGEST[mode](data), - signature, - mode, - curve_params, - )