X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=pygost%2Ftest_gost3413.py;h=6bf2f885ec74b68d8ccc6bf9c9f1408bd0b83f89;hb=4277661e11e63906d923827e5c124877f1dc0c8d;hp=5e3a39b87397bfbcc0c62e0dda738a75e620572a;hpb=43fdce36120844bc0fc38e0d5664dfc7090c119a;p=pygost.git diff --git a/pygost/test_gost3413.py b/pygost/test_gost3413.py index 5e3a39b..6bf2f88 100644 --- a/pygost/test_gost3413.py +++ b/pygost/test_gost3413.py @@ -1,22 +1,45 @@ +# coding: utf-8 +# PyGOST -- Pure Python GOST cryptographic functions library +# Copyright (C) 2015-2020 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, version 3 of the License. +# +# 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 random import randint from unittest import TestCase -from pygost.gost3412 import GOST3412Kuz +from pygost.gost3412 import GOST3412Kuznechik +from pygost.gost3412 import GOST3412Magma from pygost.gost3413 import _mac_ks +from pygost.gost3413 import acpkm +from pygost.gost3413 import acpkm_master from pygost.gost3413 import cbc_decrypt from pygost.gost3413 import cbc_encrypt from pygost.gost3413 import cfb_decrypt from pygost.gost3413 import cfb_encrypt from pygost.gost3413 import ctr +from pygost.gost3413 import ctr_acpkm from pygost.gost3413 import ecb_decrypt from pygost.gost3413 import ecb_encrypt +from pygost.gost3413 import KEY_SIZE from pygost.gost3413 import mac +from pygost.gost3413 import mac_acpkm_master from pygost.gost3413 import ofb from pygost.gost3413 import pad2 from pygost.gost3413 import unpad2 from pygost.utils import hexdec from pygost.utils import hexenc +from pygost.utils import strxor class Pad2Test(TestCase): @@ -30,9 +53,9 @@ class Pad2Test(TestCase): ) -class GOST3412KuzModesTest(TestCase): +class GOST3412KuznechikModesTest(TestCase): key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef") - ciph = GOST3412Kuz(key) + ciph = GOST3412Kuznechik(key) plaintext = "" plaintext += "1122334455667700ffeeddccbbaa9988" plaintext += "00112233445566778899aabbcceeff0a" @@ -58,7 +81,7 @@ class GOST3412KuzModesTest(TestCase): def test_ecb_symmetric(self): for _ in range(100): pt = pad2(urandom(randint(0, 16 * 2)), 16) - ciph = GOST3412Kuz(urandom(32)) + ciph = GOST3412Kuznechik(urandom(32)) ct = ecb_encrypt(ciph.encrypt, 16, pt) self.assertSequenceEqual(ecb_decrypt(ciph.decrypt, 16, ct), pt) @@ -82,7 +105,7 @@ class GOST3412KuzModesTest(TestCase): for _ in range(100): pt = urandom(randint(0, 16 * 2)) iv = urandom(8) - ciph = GOST3412Kuz(urandom(32)) + ciph = GOST3412Kuznechik(urandom(32)) ct = ctr(ciph.encrypt, 16, pt, iv) self.assertSequenceEqual(ctr(ciph.encrypt, 16, ct, iv), pt) @@ -105,10 +128,23 @@ class GOST3412KuzModesTest(TestCase): for _ in range(100): pt = urandom(randint(0, 16 * 2)) iv = urandom(16 * 2) - ciph = GOST3412Kuz(urandom(32)) + ciph = GOST3412Kuznechik(urandom(32)) ct = ofb(ciph.encrypt, 16, pt, iv) self.assertSequenceEqual(ofb(ciph.encrypt, 16, ct, iv), pt) + def test_ofb_manual(self): + iv = [urandom(16) for _ in range(randint(2, 10))] + pt = [urandom(16) for _ in range(len(iv), len(iv) + randint(1, 10))] + ciph = GOST3412Kuznechik(urandom(32)) + r = [ciph.encrypt(i) for i in iv] + for i in range(len(pt) - len(iv)): + r.append(ciph.encrypt(r[i])) + ct = [strxor(g, r) for g, r in zip(pt, r)] + self.assertSequenceEqual( + ofb(ciph.encrypt, 16, b"".join(pt), b"".join(iv)), + b"".join(ct), + ) + def test_cbc_vectors(self): ciphtext = "" ciphtext += "689972d4a085fa4d90e52e3d6d7dcc27" @@ -128,7 +164,7 @@ class GOST3412KuzModesTest(TestCase): for _ in range(100): pt = pad2(urandom(randint(0, 16 * 2)), 16) iv = urandom(16 * 2) - ciph = GOST3412Kuz(urandom(32)) + ciph = GOST3412Kuznechik(urandom(32)) ct = cbc_encrypt(ciph.encrypt, 16, pt, iv) self.assertSequenceEqual(cbc_decrypt(ciph.decrypt, 16, ct, iv), pt) @@ -151,7 +187,7 @@ class GOST3412KuzModesTest(TestCase): for _ in range(100): pt = urandom(randint(0, 16 * 2)) iv = urandom(16 * 2) - ciph = GOST3412Kuz(urandom(32)) + ciph = GOST3412Kuznechik(urandom(32)) ct = cfb_encrypt(ciph.encrypt, 16, pt, iv) self.assertSequenceEqual(cfb_decrypt(ciph.encrypt, 16, ct, iv), pt) @@ -167,5 +203,378 @@ class GOST3412KuzModesTest(TestCase): def test_mac_applies(self): for _ in range(100): data = urandom(randint(0, 16 * 2)) - ciph = GOST3412Kuz(urandom(32)) + ciph = GOST3412Kuznechik(urandom(32)) mac(ciph.encrypt, 16, data) + + +class GOST3412MagmaModesTest(TestCase): + key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff") + ciph = GOST3412Magma(key) + plaintext = "" + plaintext += "92def06b3c130a59" + plaintext += "db54c704f8189d20" + plaintext += "4a98fb2e67a8024c" + plaintext += "8912409b17b57e41" + iv = hexdec("1234567890abcdef234567890abcdef134567890abcdef12") + + def test_ecb_vectors(self): + ciphtext = "" + ciphtext += "2b073f0494f372a0" + ciphtext += "de70e715d3556e48" + ciphtext += "11d8d9e9eacfbc1e" + ciphtext += "7c68260996c67efb" + self.assertSequenceEqual( + hexenc(ecb_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext))), + ciphtext, + ) + self.assertSequenceEqual( + hexenc(ecb_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext))), + self.plaintext, + ) + + def test_ecb_symmetric(self): + for _ in range(100): + pt = pad2(urandom(randint(0, 16 * 2)), 16) + ciph = GOST3412Magma(urandom(32)) + ct = ecb_encrypt(ciph.encrypt, 8, pt) + self.assertSequenceEqual(ecb_decrypt(ciph.decrypt, 8, ct), pt) + + def test_ctr_vectors(self): + ciphtext = "" + ciphtext += "4e98110c97b7b93c" + ciphtext += "3e250d93d6e85d69" + ciphtext += "136d868807b2dbef" + ciphtext += "568eb680ab52a12d" + iv = self.iv[:4] + self.assertSequenceEqual( + hexenc(ctr(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)), + ciphtext, + ) + self.assertSequenceEqual( + hexenc(ctr(self.ciph.encrypt, 8, hexdec(ciphtext), iv)), + self.plaintext, + ) + + def test_ctr_symmetric(self): + for _ in range(100): + pt = urandom(randint(0, 16 * 2)) + iv = urandom(4) + ciph = GOST3412Magma(urandom(32)) + ct = ctr(ciph.encrypt, 8, pt, iv) + self.assertSequenceEqual(ctr(ciph.encrypt, 8, ct, iv), pt) + + def test_ofb_vectors(self): + iv = self.iv[:16] + ciphtext = "" + ciphtext += "db37e0e266903c83" + ciphtext += "0d46644c1f9a089c" + ciphtext += "a0f83062430e327e" + ciphtext += "c824efb8bd4fdb05" + self.assertSequenceEqual( + hexenc(ofb(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)), + ciphtext, + ) + self.assertSequenceEqual( + hexenc(ofb(self.ciph.encrypt, 8, hexdec(ciphtext), iv)), + self.plaintext, + ) + + def test_ofb_symmetric(self): + for _ in range(100): + pt = urandom(randint(0, 16 * 2)) + iv = urandom(8 * 2) + ciph = GOST3412Magma(urandom(32)) + ct = ofb(ciph.encrypt, 8, pt, iv) + self.assertSequenceEqual(ofb(ciph.encrypt, 8, ct, iv), pt) + + def test_cbc_vectors(self): + ciphtext = "" + ciphtext += "96d1b05eea683919" + ciphtext += "aff76129abb937b9" + ciphtext += "5058b4a1c4bc0019" + ciphtext += "20b78b1a7cd7e667" + self.assertSequenceEqual( + hexenc(cbc_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext), self.iv)), + ciphtext, + ) + self.assertSequenceEqual( + hexenc(cbc_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext), self.iv)), + self.plaintext, + ) + + def test_cbc_symmetric(self): + for _ in range(100): + pt = pad2(urandom(randint(0, 16 * 2)), 16) + iv = urandom(8 * 2) + ciph = GOST3412Magma(urandom(32)) + ct = cbc_encrypt(ciph.encrypt, 8, pt, iv) + self.assertSequenceEqual(cbc_decrypt(ciph.decrypt, 8, ct, iv), pt) + + def test_cfb_vectors(self): + iv = self.iv[:16] + ciphtext = "" + ciphtext += "db37e0e266903c83" + ciphtext += "0d46644c1f9a089c" + ciphtext += "24bdd2035315d38b" + ciphtext += "bcc0321421075505" + self.assertSequenceEqual( + hexenc(cfb_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)), + ciphtext, + ) + self.assertSequenceEqual( + hexenc(cfb_decrypt(self.ciph.encrypt, 8, hexdec(ciphtext), iv)), + self.plaintext, + ) + + def test_cfb_symmetric(self): + for _ in range(100): + pt = urandom(randint(0, 16 * 2)) + iv = urandom(8 * 2) + ciph = GOST3412Magma(urandom(32)) + ct = cfb_encrypt(ciph.encrypt, 8, pt, iv) + self.assertSequenceEqual(cfb_decrypt(ciph.encrypt, 8, ct, iv), pt) + + def test_mac_vectors(self): + k1, k2 = _mac_ks(self.ciph.encrypt, 8) + self.assertSequenceEqual(hexenc(k1), "5f459b3342521424") + self.assertSequenceEqual(hexenc(k2), "be8b366684a42848") + self.assertSequenceEqual( + hexenc(mac(self.ciph.encrypt, 8, hexdec(self.plaintext))[:4]), + "154e7210", + ) + + def test_mac_applies(self): + for _ in range(100): + data = urandom(randint(0, 16 * 2)) + ciph = GOST3412Magma(urandom(32)) + mac(ciph.encrypt, 8, data) + + +class TestVectorACPKM(TestCase): + """Test vectors from Р 1323565.1.017-2018 + """ + key = hexdec("8899AABBCCDDEEFF0011223344556677FEDCBA98765432100123456789ABCDEF") + + def test_magma_ctr_acpkm(self): + key = acpkm(GOST3412Magma(self.key).encrypt, 8) + self.assertSequenceEqual(key, hexdec("863EA017842C3D372B18A85A28E2317D74BEFC107720DE0C9E8AB974ABD00CA0")) + key = acpkm(GOST3412Magma(key).encrypt, 8) + self.assertSequenceEqual(key, hexdec("49A5E2677DE555982B8AD5E826652D17EEC847BF5B3997A81CF7FE7F1187BD27")) + key = acpkm(GOST3412Magma(key).encrypt, 8) + self.assertSequenceEqual(key, hexdec("3256BF3F97B5667426A9FB1C5EAABE41893CCDD5A868F9B63B0AA90720FA43C4")) + + def test_magma_ctr(self): + encrypter = GOST3412Magma(self.key).encrypt + plaintext = hexdec(""" +11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88 +00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A +11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 +22 33 44 55 66 77 88 99 + """.replace("\n", "").replace(" ", "")) + iv = hexdec("12345678") + ciphertext = hexdec(""" +2A B8 1D EE EB 1E 4C AB 68 E1 04 C4 BD 6B 94 EA +C7 2C 67 AF 6C 2E 5B 6B 0E AF B6 17 70 F1 B3 2E +A1 AE 71 14 9E ED 13 82 AB D4 67 18 06 72 EC 6F +84 A2 F1 5B 3F CA 72 C1 + """.replace("\n", "").replace(" ", "")) + self.assertSequenceEqual( + ctr_acpkm(GOST3412Magma, encrypter, bs=8, section_size=16, data=plaintext, iv=iv), + ciphertext, + ) + self.assertSequenceEqual( + ctr_acpkm(GOST3412Magma, encrypter, bs=8, section_size=16, data=ciphertext, iv=iv), + plaintext, + ) + + def test_kuznechik_ctr_acpkm(self): + key = acpkm(GOST3412Kuznechik(self.key).encrypt, 16) + self.assertSequenceEqual(key, hexdec("2666ED40AE687811745CA0B448F57A7B390ADB5780307E8E9659AC403AE60C60")) + key = acpkm(GOST3412Kuznechik(key).encrypt, 16) + self.assertSequenceEqual(key, hexdec("BB3DD5402E999B7A3DEBB0DB45448EC530F07365DFEE3ABA8415F77AC8F34CE8")) + key = acpkm(GOST3412Kuznechik(key).encrypt, 16) + self.assertSequenceEqual(key, hexdec("23362FD553CAD2178299A5B5A2D4722E3BB83C730A8BF57CE2DD004017F8C565")) + + def test_kuznechik_ctr(self): + encrypter = GOST3412Kuznechik(self.key).encrypt + iv = hexdec("1234567890ABCEF0") + plaintext = hexdec(""" +11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88 +00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A +11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 +22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 +33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 +44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33 +55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33 44 + """.replace("\n", "").replace(" ", "")) + ciphertext = hexdec(""" +F1 95 D8 BE C1 0E D1 DB D5 7B 5F A2 40 BD A1 B8 +85 EE E7 33 F6 A1 3E 5D F3 3C E4 B3 3C 45 DE E4 +4B CE EB 8F 64 6F 4C 55 00 17 06 27 5E 85 E8 00 +58 7C 4D F5 68 D0 94 39 3E 48 34 AF D0 80 50 46 +CF 30 F5 76 86 AE EC E1 1C FC 6C 31 6B 8A 89 6E +DF FD 07 EC 81 36 36 46 0C 4F 3B 74 34 23 16 3E +64 09 A9 C2 82 FA C8 D4 69 D2 21 E7 FB D6 DE 5D + """.replace("\n", "").replace(" ", "")) + self.assertSequenceEqual( + ctr_acpkm( + GOST3412Kuznechik, + encrypter, + bs=16, + section_size=32, + data=plaintext, + iv=iv, + ), + ciphertext, + ) + self.assertSequenceEqual( + ctr_acpkm( + GOST3412Kuznechik, + encrypter, + bs=16, + section_size=32, + data=ciphertext, + iv=iv, + ), + plaintext, + ) + + def test_magma_omac_1_5_blocks(self): + encrypter = GOST3412Magma(self.key).encrypt + key_section_size = 640 // 8 + self.assertSequenceEqual( + acpkm_master( + GOST3412Magma, + encrypter, + key_section_size=key_section_size, + bs=8, + keymat_len=KEY_SIZE + 8, + ), + hexdec("0DF2F5273DA328932AC49D81D36B2558A50DBF9BBCAC74A614B2CCB2F1CBCD8A70638E3DE8B3571E"), + ) + text = hexdec("1122334455667700FFEEDDCC") + self.assertSequenceEqual( + mac_acpkm_master( + GOST3412Magma, + encrypter, + key_section_size, + section_size=16, + bs=8, + data=text, + ), + hexdec("A0540E3730ACBCF3"), + ) + + def test_magma_omac_5_blocks(self): + encrypter = GOST3412Magma(self.key).encrypt + key_section_size = 640 // 8 + self.assertSequenceEqual( + acpkm_master( + GOST3412Magma, + encrypter, + key_section_size=key_section_size, + bs=8, + keymat_len=3 * (KEY_SIZE + 8), + ), + hexdec(""" +0D F2 F5 27 3D A3 28 93 2A C4 9D 81 D3 6B 25 58 +A5 0D BF 9B BC AC 74 A6 14 B2 CC B2 F1 CB CD 8A +70 63 8E 3D E8 B3 57 1E 8D 38 26 D5 5E 63 A1 67 +E2 40 66 40 54 7B 9F 1F 5F 2B 43 61 2A AE AF DA +18 0B AC 86 04 DF A6 FE 53 C2 CE 27 0E 9C 9F 52 +68 D0 FD BF E1 A3 BD D9 BE 5B 96 D0 A1 20 23 48 +6E F1 71 0F 92 4A E0 31 30 52 CB 5F CA 0B 79 1E +1B AB E8 57 6D 0F E3 A8 + """.replace("\n", "").replace(" ", "")), + ) + text = hexdec(""" +11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88 +00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A +11 22 33 44 55 66 77 88 + """.replace("\n", "").replace(" ", "")) + self.assertSequenceEqual( + mac_acpkm_master( + GOST3412Magma, + encrypter, + key_section_size, + section_size=16, + bs=8, + data=text, + ), + hexdec("34008DAD5496BB8E"), + ) + + def test_kuznechik_omac_1_5_blocks(self): + encrypter = GOST3412Kuznechik(self.key).encrypt + key_section_size = 768 // 8 + self.assertSequenceEqual( + acpkm_master( + GOST3412Kuznechik, + encrypter, + key_section_size=key_section_size, + bs=16, + keymat_len=KEY_SIZE + 16, + ), + hexdec(""" +0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2 +C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE +0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37 + """.replace("\n", "").replace(" ", "")) + ) + text = hexdec(""" +11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88 +00 11 22 33 44 55 66 77 + """.replace("\n", "").replace(" ", "")) + self.assertSequenceEqual( + mac_acpkm_master( + GOST3412Kuznechik, + encrypter, + key_section_size, + section_size=32, + bs=16, + data=text, + ), + hexdec("B5367F47B62B995EEB2A648C5843145E"), + ) + + def test_kuznechik_omac_5_blocks(self): + encrypter = GOST3412Kuznechik(self.key).encrypt + key_section_size = 768 // 8 + self.assertSequenceEqual( + acpkm_master( + GOST3412Kuznechik, + encrypter, + key_section_size=key_section_size, + bs=16, + keymat_len=3 * (KEY_SIZE + 16), + ), + hexdec(""" +0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2 +C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE +0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37 +C9 DD A8 9C FF A4 91 FE AD D9 B3 EA B7 03 BB 31 +BC 7E 92 7F 04 94 72 9F 51 B4 9D 3D F9 C9 46 08 +00 FB BC F5 ED EE 61 0E A0 2F 01 09 3C 7B C7 42 +D7 D6 27 15 01 B1 77 77 52 63 C2 A3 49 5A 83 18 +A8 1C 79 A0 4F 29 66 0E A3 FD A8 74 C6 30 79 9E +14 2C 57 79 14 FE A9 0D 3B C2 50 2E 83 36 85 D9 + """.replace("\n", "").replace(" ", "")), + ) + text = hexdec(""" +11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88 +00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A +11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 +22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 +33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 + """.replace("\n", "").replace(" ", "")) + self.assertSequenceEqual( + mac_acpkm_master( + GOST3412Kuznechik, + encrypter, + key_section_size, + section_size=32, + bs=16, + data=text, + ), + hexdec("FBB8DCEE45BEA67C35F58C5700898E5D"), + )