2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2020 Sergey Matveev <stargrave@stargrave.org>
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, version 3 of the License.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17 from os import urandom
18 from random import randint
19 from unittest import TestCase
21 from pygost.gost3412 import GOST3412Kuznechik
22 from pygost.gost3412 import GOST3412Magma
23 from pygost.gost3413 import _mac_ks
24 from pygost.gost3413 import acpkm
25 from pygost.gost3413 import acpkm_master
26 from pygost.gost3413 import cbc_decrypt
27 from pygost.gost3413 import cbc_encrypt
28 from pygost.gost3413 import cfb_decrypt
29 from pygost.gost3413 import cfb_encrypt
30 from pygost.gost3413 import ctr
31 from pygost.gost3413 import ctr_acpkm
32 from pygost.gost3413 import ecb_decrypt
33 from pygost.gost3413 import ecb_encrypt
34 from pygost.gost3413 import KEY_SIZE
35 from pygost.gost3413 import mac
36 from pygost.gost3413 import mac_acpkm_master
37 from pygost.gost3413 import ofb
38 from pygost.gost3413 import pad2
39 from pygost.gost3413 import unpad2
40 from pygost.utils import hexdec
41 from pygost.utils import hexenc
42 from pygost.utils import strxor
45 class Pad2Test(TestCase):
46 def test_symmetric(self):
48 for blocksize in (8, 16):
49 data = urandom(randint(0, blocksize * 3))
50 self.assertSequenceEqual(
51 unpad2(pad2(data, blocksize), blocksize),
56 class GOST3412KuznechikModesTest(TestCase):
57 key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")
58 ciph = GOST3412Kuznechik(key)
60 plaintext += "1122334455667700ffeeddccbbaa9988"
61 plaintext += "00112233445566778899aabbcceeff0a"
62 plaintext += "112233445566778899aabbcceeff0a00"
63 plaintext += "2233445566778899aabbcceeff0a0011"
64 iv = hexdec("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")
66 def test_ecb_vectors(self):
68 ciphtext += "7f679d90bebc24305a468d42b9d4edcd"
69 ciphtext += "b429912c6e0032f9285452d76718d08b"
70 ciphtext += "f0ca33549d247ceef3f5a5313bd4b157"
71 ciphtext += "d0b09ccde830b9eb3a02c4c5aa8ada98"
72 self.assertSequenceEqual(
73 hexenc(ecb_encrypt(self.ciph.encrypt, 16, hexdec(self.plaintext))),
76 self.assertSequenceEqual(
77 hexenc(ecb_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext))),
81 def test_ecb_symmetric(self):
83 pt = pad2(urandom(randint(0, 16 * 2)), 16)
84 ciph = GOST3412Kuznechik(urandom(32))
85 ct = ecb_encrypt(ciph.encrypt, 16, pt)
86 self.assertSequenceEqual(ecb_decrypt(ciph.decrypt, 16, ct), pt)
88 def test_ctr_vectors(self):
90 ciphtext += "f195d8bec10ed1dbd57b5fa240bda1b8"
91 ciphtext += "85eee733f6a13e5df33ce4b33c45dee4"
92 ciphtext += "a5eae88be6356ed3d5e877f13564a3a5"
93 ciphtext += "cb91fab1f20cbab6d1c6d15820bdba73"
95 self.assertSequenceEqual(
96 hexenc(ctr(self.ciph.encrypt, 16, hexdec(self.plaintext), iv)),
99 self.assertSequenceEqual(
100 hexenc(ctr(self.ciph.encrypt, 16, hexdec(ciphtext), iv)),
104 def test_ctr_symmetric(self):
106 pt = urandom(randint(0, 16 * 2))
108 ciph = GOST3412Kuznechik(urandom(32))
109 ct = ctr(ciph.encrypt, 16, pt, iv)
110 self.assertSequenceEqual(ctr(ciph.encrypt, 16, ct, iv), pt)
112 def test_ofb_vectors(self):
114 ciphtext += "81800a59b1842b24ff1f795e897abd95"
115 ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
116 ciphtext += "66a257ac3ca0b8b1c80fe7fc10288a13"
117 ciphtext += "203ebbc066138660a0292243f6903150"
118 self.assertSequenceEqual(
119 hexenc(ofb(self.ciph.encrypt, 16, hexdec(self.plaintext), self.iv)),
122 self.assertSequenceEqual(
123 hexenc(ofb(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
127 def test_ofb_symmetric(self):
129 pt = urandom(randint(0, 16 * 2))
131 ciph = GOST3412Kuznechik(urandom(32))
132 ct = ofb(ciph.encrypt, 16, pt, iv)
133 self.assertSequenceEqual(ofb(ciph.encrypt, 16, ct, iv), pt)
135 def test_ofb_manual(self):
136 iv = [urandom(16) for _ in range(randint(2, 10))]
137 pt = [urandom(16) for _ in range(len(iv), len(iv) + randint(1, 10))]
138 ciph = GOST3412Kuznechik(urandom(32))
139 r = [ciph.encrypt(i) for i in iv]
140 for i in range(len(pt) - len(iv)):
141 r.append(ciph.encrypt(r[i]))
142 ct = [strxor(g, r) for g, r in zip(pt, r)]
143 self.assertSequenceEqual(
144 ofb(ciph.encrypt, 16, b"".join(pt), b"".join(iv)),
148 def test_cbc_vectors(self):
150 ciphtext += "689972d4a085fa4d90e52e3d6d7dcc27"
151 ciphtext += "2826e661b478eca6af1e8e448d5ea5ac"
152 ciphtext += "fe7babf1e91999e85640e8b0f49d90d0"
153 ciphtext += "167688065a895c631a2d9a1560b63970"
154 self.assertSequenceEqual(
155 hexenc(cbc_encrypt(self.ciph.encrypt, 16, hexdec(self.plaintext), self.iv)),
158 self.assertSequenceEqual(
159 hexenc(cbc_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext), self.iv)),
163 def test_cbc_symmetric(self):
165 pt = pad2(urandom(randint(0, 16 * 2)), 16)
167 ciph = GOST3412Kuznechik(urandom(32))
168 ct = cbc_encrypt(ciph.encrypt, 16, pt, iv)
169 self.assertSequenceEqual(cbc_decrypt(ciph.decrypt, 16, ct, iv), pt)
171 def test_cfb_vectors(self):
173 ciphtext += "81800a59b1842b24ff1f795e897abd95"
174 ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
175 ciphtext += "79f2a8eb5cc68d38842d264e97a238b5"
176 ciphtext += "4ffebecd4e922de6c75bd9dd44fbf4d1"
177 self.assertSequenceEqual(
178 hexenc(cfb_encrypt(self.ciph.encrypt, 16, hexdec(self.plaintext), self.iv)),
181 self.assertSequenceEqual(
182 hexenc(cfb_decrypt(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
186 def test_cfb_symmetric(self):
188 pt = urandom(randint(0, 16 * 2))
190 ciph = GOST3412Kuznechik(urandom(32))
191 ct = cfb_encrypt(ciph.encrypt, 16, pt, iv)
192 self.assertSequenceEqual(cfb_decrypt(ciph.encrypt, 16, ct, iv), pt)
194 def test_mac_vectors(self):
195 k1, k2 = _mac_ks(self.ciph.encrypt, 16)
196 self.assertSequenceEqual(hexenc(k1), "297d82bc4d39e3ca0de0573298151dc7")
197 self.assertSequenceEqual(hexenc(k2), "52fb05789a73c7941bc0ae65302a3b8e")
198 self.assertSequenceEqual(
199 hexenc(mac(self.ciph.encrypt, 16, hexdec(self.plaintext))[:8]),
203 def test_mac_applies(self):
205 data = urandom(randint(0, 16 * 2))
206 ciph = GOST3412Kuznechik(urandom(32))
207 mac(ciph.encrypt, 16, data)
210 class GOST3412MagmaModesTest(TestCase):
211 key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
212 ciph = GOST3412Magma(key)
214 plaintext += "92def06b3c130a59"
215 plaintext += "db54c704f8189d20"
216 plaintext += "4a98fb2e67a8024c"
217 plaintext += "8912409b17b57e41"
218 iv = hexdec("1234567890abcdef234567890abcdef134567890abcdef12")
220 def test_ecb_vectors(self):
222 ciphtext += "2b073f0494f372a0"
223 ciphtext += "de70e715d3556e48"
224 ciphtext += "11d8d9e9eacfbc1e"
225 ciphtext += "7c68260996c67efb"
226 self.assertSequenceEqual(
227 hexenc(ecb_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext))),
230 self.assertSequenceEqual(
231 hexenc(ecb_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext))),
235 def test_ecb_symmetric(self):
237 pt = pad2(urandom(randint(0, 16 * 2)), 16)
238 ciph = GOST3412Magma(urandom(32))
239 ct = ecb_encrypt(ciph.encrypt, 8, pt)
240 self.assertSequenceEqual(ecb_decrypt(ciph.decrypt, 8, ct), pt)
242 def test_ctr_vectors(self):
244 ciphtext += "4e98110c97b7b93c"
245 ciphtext += "3e250d93d6e85d69"
246 ciphtext += "136d868807b2dbef"
247 ciphtext += "568eb680ab52a12d"
249 self.assertSequenceEqual(
250 hexenc(ctr(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
253 self.assertSequenceEqual(
254 hexenc(ctr(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
258 def test_ctr_symmetric(self):
260 pt = urandom(randint(0, 16 * 2))
262 ciph = GOST3412Magma(urandom(32))
263 ct = ctr(ciph.encrypt, 8, pt, iv)
264 self.assertSequenceEqual(ctr(ciph.encrypt, 8, ct, iv), pt)
266 def test_ofb_vectors(self):
269 ciphtext += "db37e0e266903c83"
270 ciphtext += "0d46644c1f9a089c"
271 ciphtext += "a0f83062430e327e"
272 ciphtext += "c824efb8bd4fdb05"
273 self.assertSequenceEqual(
274 hexenc(ofb(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
277 self.assertSequenceEqual(
278 hexenc(ofb(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
282 def test_ofb_symmetric(self):
284 pt = urandom(randint(0, 16 * 2))
286 ciph = GOST3412Magma(urandom(32))
287 ct = ofb(ciph.encrypt, 8, pt, iv)
288 self.assertSequenceEqual(ofb(ciph.encrypt, 8, ct, iv), pt)
290 def test_cbc_vectors(self):
292 ciphtext += "96d1b05eea683919"
293 ciphtext += "aff76129abb937b9"
294 ciphtext += "5058b4a1c4bc0019"
295 ciphtext += "20b78b1a7cd7e667"
296 self.assertSequenceEqual(
297 hexenc(cbc_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext), self.iv)),
300 self.assertSequenceEqual(
301 hexenc(cbc_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext), self.iv)),
305 def test_cbc_symmetric(self):
307 pt = pad2(urandom(randint(0, 16 * 2)), 16)
309 ciph = GOST3412Magma(urandom(32))
310 ct = cbc_encrypt(ciph.encrypt, 8, pt, iv)
311 self.assertSequenceEqual(cbc_decrypt(ciph.decrypt, 8, ct, iv), pt)
313 def test_cfb_vectors(self):
316 ciphtext += "db37e0e266903c83"
317 ciphtext += "0d46644c1f9a089c"
318 ciphtext += "24bdd2035315d38b"
319 ciphtext += "bcc0321421075505"
320 self.assertSequenceEqual(
321 hexenc(cfb_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
324 self.assertSequenceEqual(
325 hexenc(cfb_decrypt(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
329 def test_cfb_symmetric(self):
331 pt = urandom(randint(0, 16 * 2))
333 ciph = GOST3412Magma(urandom(32))
334 ct = cfb_encrypt(ciph.encrypt, 8, pt, iv)
335 self.assertSequenceEqual(cfb_decrypt(ciph.encrypt, 8, ct, iv), pt)
337 def test_mac_vectors(self):
338 k1, k2 = _mac_ks(self.ciph.encrypt, 8)
339 self.assertSequenceEqual(hexenc(k1), "5f459b3342521424")
340 self.assertSequenceEqual(hexenc(k2), "be8b366684a42848")
341 self.assertSequenceEqual(
342 hexenc(mac(self.ciph.encrypt, 8, hexdec(self.plaintext))[:4]),
346 def test_mac_applies(self):
348 data = urandom(randint(0, 16 * 2))
349 ciph = GOST3412Magma(urandom(32))
350 mac(ciph.encrypt, 8, data)
353 class TestVectorACPKM(TestCase):
354 """Test vectors from Ð 1323565.1.017-2018
356 key = hexdec("8899AABBCCDDEEFF0011223344556677FEDCBA98765432100123456789ABCDEF")
358 def test_magma_ctr_acpkm(self):
359 key = acpkm(GOST3412Magma(self.key).encrypt, 8)
360 self.assertSequenceEqual(key, hexdec("863EA017842C3D372B18A85A28E2317D74BEFC107720DE0C9E8AB974ABD00CA0"))
361 key = acpkm(GOST3412Magma(key).encrypt, 8)
362 self.assertSequenceEqual(key, hexdec("49A5E2677DE555982B8AD5E826652D17EEC847BF5B3997A81CF7FE7F1187BD27"))
363 key = acpkm(GOST3412Magma(key).encrypt, 8)
364 self.assertSequenceEqual(key, hexdec("3256BF3F97B5667426A9FB1C5EAABE41893CCDD5A868F9B63B0AA90720FA43C4"))
366 def test_magma_ctr(self):
367 encrypter = GOST3412Magma(self.key).encrypt
368 plaintext = hexdec("""
369 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
370 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
371 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
372 22 33 44 55 66 77 88 99
373 """.replace("\n", "").replace(" ", ""))
374 iv = hexdec("12345678")
375 ciphertext = hexdec("""
376 2A B8 1D EE EB 1E 4C AB 68 E1 04 C4 BD 6B 94 EA
377 C7 2C 67 AF 6C 2E 5B 6B 0E AF B6 17 70 F1 B3 2E
378 A1 AE 71 14 9E ED 13 82 AB D4 67 18 06 72 EC 6F
379 84 A2 F1 5B 3F CA 72 C1
380 """.replace("\n", "").replace(" ", ""))
381 self.assertSequenceEqual(
382 ctr_acpkm(GOST3412Magma, encrypter, bs=8, section_size=16, data=plaintext, iv=iv),
385 self.assertSequenceEqual(
386 ctr_acpkm(GOST3412Magma, encrypter, bs=8, section_size=16, data=ciphertext, iv=iv),
390 def test_kuznechik_ctr_acpkm(self):
391 key = acpkm(GOST3412Kuznechik(self.key).encrypt, 16)
392 self.assertSequenceEqual(key, hexdec("2666ED40AE687811745CA0B448F57A7B390ADB5780307E8E9659AC403AE60C60"))
393 key = acpkm(GOST3412Kuznechik(key).encrypt, 16)
394 self.assertSequenceEqual(key, hexdec("BB3DD5402E999B7A3DEBB0DB45448EC530F07365DFEE3ABA8415F77AC8F34CE8"))
395 key = acpkm(GOST3412Kuznechik(key).encrypt, 16)
396 self.assertSequenceEqual(key, hexdec("23362FD553CAD2178299A5B5A2D4722E3BB83C730A8BF57CE2DD004017F8C565"))
398 def test_kuznechik_ctr(self):
399 encrypter = GOST3412Kuznechik(self.key).encrypt
400 iv = hexdec("1234567890ABCEF0")
401 plaintext = hexdec("""
402 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
403 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
404 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
405 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11
406 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22
407 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33
408 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33 44
409 """.replace("\n", "").replace(" ", ""))
410 ciphertext = hexdec("""
411 F1 95 D8 BE C1 0E D1 DB D5 7B 5F A2 40 BD A1 B8
412 85 EE E7 33 F6 A1 3E 5D F3 3C E4 B3 3C 45 DE E4
413 4B CE EB 8F 64 6F 4C 55 00 17 06 27 5E 85 E8 00
414 58 7C 4D F5 68 D0 94 39 3E 48 34 AF D0 80 50 46
415 CF 30 F5 76 86 AE EC E1 1C FC 6C 31 6B 8A 89 6E
416 DF FD 07 EC 81 36 36 46 0C 4F 3B 74 34 23 16 3E
417 64 09 A9 C2 82 FA C8 D4 69 D2 21 E7 FB D6 DE 5D
418 """.replace("\n", "").replace(" ", ""))
419 self.assertSequenceEqual(
430 self.assertSequenceEqual(
442 def test_magma_omac_1_5_blocks(self):
443 encrypter = GOST3412Magma(self.key).encrypt
444 key_section_size = 640 // 8
445 self.assertSequenceEqual(
449 key_section_size=key_section_size,
451 keymat_len=KEY_SIZE + 8,
453 hexdec("0DF2F5273DA328932AC49D81D36B2558A50DBF9BBCAC74A614B2CCB2F1CBCD8A70638E3DE8B3571E"),
455 text = hexdec("1122334455667700FFEEDDCC")
456 self.assertSequenceEqual(
465 hexdec("A0540E3730ACBCF3"),
468 def test_magma_omac_5_blocks(self):
469 encrypter = GOST3412Magma(self.key).encrypt
470 key_section_size = 640 // 8
471 self.assertSequenceEqual(
475 key_section_size=key_section_size,
477 keymat_len=3 * (KEY_SIZE + 8),
480 0D F2 F5 27 3D A3 28 93 2A C4 9D 81 D3 6B 25 58
481 A5 0D BF 9B BC AC 74 A6 14 B2 CC B2 F1 CB CD 8A
482 70 63 8E 3D E8 B3 57 1E 8D 38 26 D5 5E 63 A1 67
483 E2 40 66 40 54 7B 9F 1F 5F 2B 43 61 2A AE AF DA
484 18 0B AC 86 04 DF A6 FE 53 C2 CE 27 0E 9C 9F 52
485 68 D0 FD BF E1 A3 BD D9 BE 5B 96 D0 A1 20 23 48
486 6E F1 71 0F 92 4A E0 31 30 52 CB 5F CA 0B 79 1E
487 1B AB E8 57 6D 0F E3 A8
488 """.replace("\n", "").replace(" ", "")),
491 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
492 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
493 11 22 33 44 55 66 77 88
494 """.replace("\n", "").replace(" ", ""))
495 self.assertSequenceEqual(
504 hexdec("34008DAD5496BB8E"),
507 def test_kuznechik_omac_1_5_blocks(self):
508 encrypter = GOST3412Kuznechik(self.key).encrypt
509 key_section_size = 768 // 8
510 self.assertSequenceEqual(
514 key_section_size=key_section_size,
516 keymat_len=KEY_SIZE + 16,
519 0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2
520 C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE
521 0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37
522 """.replace("\n", "").replace(" ", ""))
525 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
526 00 11 22 33 44 55 66 77
527 """.replace("\n", "").replace(" ", ""))
528 self.assertSequenceEqual(
537 hexdec("B5367F47B62B995EEB2A648C5843145E"),
540 def test_kuznechik_omac_5_blocks(self):
541 encrypter = GOST3412Kuznechik(self.key).encrypt
542 key_section_size = 768 // 8
543 self.assertSequenceEqual(
547 key_section_size=key_section_size,
549 keymat_len=3 * (KEY_SIZE + 16),
552 0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2
553 C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE
554 0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37
555 C9 DD A8 9C FF A4 91 FE AD D9 B3 EA B7 03 BB 31
556 BC 7E 92 7F 04 94 72 9F 51 B4 9D 3D F9 C9 46 08
557 00 FB BC F5 ED EE 61 0E A0 2F 01 09 3C 7B C7 42
558 D7 D6 27 15 01 B1 77 77 52 63 C2 A3 49 5A 83 18
559 A8 1C 79 A0 4F 29 66 0E A3 FD A8 74 C6 30 79 9E
560 14 2C 57 79 14 FE A9 0D 3B C2 50 2E 83 36 85 D9
561 """.replace("\n", "").replace(" ", "")),
564 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
565 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
566 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
567 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11
568 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22
569 """.replace("\n", "").replace(" ", ""))
570 self.assertSequenceEqual(
579 hexdec("FBB8DCEE45BEA67C35F58C5700898E5D"),