From 2335694cd5ee459de19d261c08e9427438325bc8 Mon Sep 17 00:00:00 2001 From: Sergey Matveev Date: Tue, 28 Jul 2020 20:10:30 +0300 Subject: [PATCH] KExp15/KImp15 --- README | 1 + news.texi | 1 + pygost/stubs/pygost/wrap.pyi | 21 +++++++++++++ pygost/test_wrap.py | 57 ++++++++++++++++++++++++++++++++++++ pygost/wrap.py | 34 +++++++++++++++++++++ www.texi | 1 + 6 files changed, 115 insertions(+) diff --git a/README b/README index 7fde53f..b9156ca 100644 --- a/README +++ b/README @@ -25,6 +25,7 @@ GOST is GOvernment STandard of Russian Federation (and Soviet Union). (ECB, CTR, OFB, CBC, CFB, MAC) * MGM AEAD mode for 64 and 128 bit ciphers (Р 1323565.1.026–2019) * CTR-ACPKM, OMAC-ACPKM-Master modes of operation (Р 1323565.1.017-2018) +* KExp15/KImp15 key export/import functions (Р 1323565.1.017-2018) * PEP247-compatible hash/MAC functions Known problems: low performance and non time-constant calculations. diff --git a/news.texi b/news.texi index d1c27b6..55bd80a 100644 --- a/news.texi +++ b/news.texi @@ -8,6 +8,7 @@ @itemize @item CTR-ACPKM mode of operation @item OMAC-ACPKM-Master moder of operation + @item KExp15/KImp15 key export/import functions @end itemize @anchor{Release 4.8} diff --git a/pygost/stubs/pygost/wrap.pyi b/pygost/stubs/pygost/wrap.pyi index 23080ab..776a6e7 100644 --- a/pygost/stubs/pygost/wrap.pyi +++ b/pygost/stubs/pygost/wrap.pyi @@ -1,3 +1,6 @@ +from typing import Callable + + def wrap_gost(ukm: bytes, kek: bytes, cek: bytes, sbox: str = ...) -> bytes: ... @@ -8,3 +11,21 @@ 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/test_wrap.py b/pygost/test_wrap.py index 9576ba9..6949195 100644 --- a/pygost/test_wrap.py +++ b/pygost/test_wrap.py @@ -17,6 +17,11 @@ from os import urandom from unittest import TestCase +from pygost.gost3412 import GOST3412Kuznechik +from pygost.gost3412 import GOST3412Magma +from pygost.utils import hexdec +from pygost.wrap import kexp15 +from pygost.wrap import kimp15 from pygost.wrap import unwrap_cryptopro from pygost.wrap import unwrap_gost from pygost.wrap import wrap_cryptopro @@ -49,3 +54,55 @@ class WrapCryptoproTest(TestCase): wrapped = wrap_cryptopro(ukm, kek, cek) unwrapped = unwrap_cryptopro(kek, wrapped) self.assertSequenceEqual(unwrapped, cek) + + +class TestVectorKExp15(TestCase): + """Test vectors from Р 1323565.1.017-2018 + """ + key = hexdec("8899AABBCCDDEEFF0011223344556677FEDCBA98765432100123456789ABCDEF") + key_enc = hexdec("202122232425262728292A2B2C2D2E2F38393A3B3C3D3E3F3031323334353637") + key_mac = hexdec("08090A0B0C0D0E0F0001020304050607101112131415161718191A1B1C1D1E1F") + + def test_magma(self): + iv = hexdec("67BED654") + kexp = kexp15( + GOST3412Magma(self.key_enc).encrypt, + GOST3412Magma(self.key_mac).encrypt, + GOST3412Magma.blocksize, + self.key, + iv, + ) + self.assertSequenceEqual(kexp, hexdec(""" +CF D5 A1 2D 5B 81 B6 E1 E9 9C 91 6D 07 90 0C 6A +C1 27 03 FB 3A BD ED 55 56 7B F3 74 2C 89 9C 75 +5D AF E7 B4 2E 3A 8B D9 + """.replace("\n", "").replace(" ", ""))) + self.assertSequenceEqual(kimp15( + GOST3412Magma(self.key_enc).encrypt, + GOST3412Magma(self.key_mac).encrypt, + GOST3412Magma.blocksize, + kexp, + iv, + ), self.key) + + def test_kuznechik(self): + iv = hexdec("0909472DD9F26BE8") + kexp = kexp15( + GOST3412Kuznechik(self.key_enc).encrypt, + GOST3412Kuznechik(self.key_mac).encrypt, + GOST3412Kuznechik.blocksize, + self.key, + iv, + ) + self.assertSequenceEqual(kexp, hexdec(""" +E3 61 84 E8 4E 8D 73 6F F3 6C C2 E5 AE 06 5D C6 +56 B2 3C 20 F5 49 B0 2F DF F8 8E 1F 3F 30 D8 C2 +9A 53 F3 CA 55 4D BA D8 0D E1 52 B9 A4 62 5B 32 + """.replace("\n", "").replace(" ", ""))) + self.assertSequenceEqual(kimp15( + GOST3412Kuznechik(self.key_enc).encrypt, + GOST3412Kuznechik(self.key_mac).encrypt, + GOST3412Kuznechik.blocksize, + kexp, + iv, + ), self.key) diff --git a/pygost/wrap.py b/pygost/wrap.py index a3c206c..301023e 100644 --- a/pygost/wrap.py +++ b/pygost/wrap.py @@ -18,6 +18,7 @@ :rfc:`4357` key wrapping (28147-89 and CryptoPro). """ +from hmac import compare_digest from struct import pack from struct import unpack @@ -26,6 +27,8 @@ from pygost.gost28147 import DEFAULT_SBOX from pygost.gost28147 import ecb_decrypt from pygost.gost28147 import ecb_encrypt from pygost.gost28147_mac import MAC +from pygost.gost3413 import ctr +from pygost.gost3413 import mac def wrap_gost(ukm, kek, cek, sbox=DEFAULT_SBOX): @@ -111,3 +114,34 @@ def diversify(kek, ukm, sbox=DEFAULT_SBOX): iv = pack("