]> Cypherpunks.ru repositories - pygost.git/blob - pygost/test_gost3413.py
(un)pad_iso10126
[pygost.git] / pygost / test_gost3413.py
1 # coding: utf-8
2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2022 Sergey Matveev <stargrave@stargrave.org>
4 #
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.
8 #
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.
13 #
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/>.
16
17 from os import urandom
18 from random import randint
19 from unittest import TestCase
20
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 KEYSIZE
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 pad_iso10126
40 from pygost.gost3413 import unpad2
41 from pygost.gost3413 import unpad_iso10126
42 from pygost.utils import hexdec
43 from pygost.utils import hexenc
44 from pygost.utils import strxor
45
46
47 class Pad2Test(TestCase):
48     def test_symmetric(self):
49         for _ in range(100):
50             for blocksize in (GOST3412Magma.blocksize, GOST3412Kuznechik.blocksize):
51                 data = urandom(randint(0, blocksize * 3))
52                 self.assertSequenceEqual(
53                     unpad2(pad2(data, blocksize), blocksize),
54                     data,
55                 )
56
57
58 class GOST3412KuznechikModesTest(TestCase):
59     key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")
60     ciph = GOST3412Kuznechik(key)
61     plaintext = ""
62     plaintext += "1122334455667700ffeeddccbbaa9988"
63     plaintext += "00112233445566778899aabbcceeff0a"
64     plaintext += "112233445566778899aabbcceeff0a00"
65     plaintext += "2233445566778899aabbcceeff0a0011"
66     iv = hexdec("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")
67
68     def test_ecb_vectors(self):
69         ciphtext = ""
70         ciphtext += "7f679d90bebc24305a468d42b9d4edcd"
71         ciphtext += "b429912c6e0032f9285452d76718d08b"
72         ciphtext += "f0ca33549d247ceef3f5a5313bd4b157"
73         ciphtext += "d0b09ccde830b9eb3a02c4c5aa8ada98"
74         self.assertSequenceEqual(
75             hexenc(ecb_encrypt(
76                 self.ciph.encrypt,
77                 GOST3412Kuznechik.blocksize,
78                 hexdec(self.plaintext),
79             )),
80             ciphtext,
81         )
82         self.assertSequenceEqual(
83             hexenc(ecb_decrypt(
84                 self.ciph.decrypt,
85                 GOST3412Kuznechik.blocksize,
86                 hexdec(ciphtext),
87             )),
88             self.plaintext,
89         )
90
91     def test_ecb_symmetric(self):
92         for _ in range(100):
93             pt = pad2(urandom(randint(0, 16 * 2)), GOST3412Kuznechik.blocksize)
94             ciph = GOST3412Kuznechik(urandom(KEYSIZE))
95             ct = ecb_encrypt(ciph.encrypt, GOST3412Kuznechik.blocksize, pt)
96             self.assertSequenceEqual(ecb_decrypt(
97                 ciph.decrypt,
98                 GOST3412Kuznechik.blocksize,
99                 ct,
100             ), pt)
101
102     def test_ctr_vectors(self):
103         ciphtext = ""
104         ciphtext += "f195d8bec10ed1dbd57b5fa240bda1b8"
105         ciphtext += "85eee733f6a13e5df33ce4b33c45dee4"
106         ciphtext += "a5eae88be6356ed3d5e877f13564a3a5"
107         ciphtext += "cb91fab1f20cbab6d1c6d15820bdba73"
108         iv = self.iv[:GOST3412Kuznechik.blocksize // 2]
109         self.assertSequenceEqual(
110             hexenc(ctr(
111                 self.ciph.encrypt,
112                 GOST3412Kuznechik.blocksize,
113                 hexdec(self.plaintext),
114                 iv,
115             )),
116             ciphtext,
117         )
118         self.assertSequenceEqual(
119             hexenc(ctr(
120                 self.ciph.encrypt,
121                 GOST3412Kuznechik.blocksize,
122                 hexdec(ciphtext),
123                 iv,
124             )),
125             self.plaintext,
126         )
127
128     def test_ctr_symmetric(self):
129         for _ in range(100):
130             pt = urandom(randint(0, 16 * 2))
131             iv = urandom(GOST3412Kuznechik.blocksize // 2)
132             ciph = GOST3412Kuznechik(urandom(KEYSIZE))
133             ct = ctr(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
134             self.assertSequenceEqual(ctr(
135                 ciph.encrypt,
136                 GOST3412Kuznechik.blocksize,
137                 ct,
138                 iv,
139             ), pt)
140
141     def test_ofb_vectors(self):
142         ciphtext = ""
143         ciphtext += "81800a59b1842b24ff1f795e897abd95"
144         ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
145         ciphtext += "66a257ac3ca0b8b1c80fe7fc10288a13"
146         ciphtext += "203ebbc066138660a0292243f6903150"
147         self.assertSequenceEqual(
148             hexenc(ofb(
149                 self.ciph.encrypt,
150                 GOST3412Kuznechik.blocksize,
151                 hexdec(self.plaintext),
152                 self.iv,
153             )),
154             ciphtext,
155         )
156         self.assertSequenceEqual(
157             hexenc(ofb(
158                 self.ciph.encrypt,
159                 GOST3412Kuznechik.blocksize,
160                 hexdec(ciphtext),
161                 self.iv,
162             )),
163             self.plaintext,
164         )
165
166     def test_ofb_symmetric(self):
167         for _ in range(100):
168             pt = urandom(randint(0, 16 * 2))
169             iv = urandom(GOST3412Kuznechik.blocksize * 2)
170             ciph = GOST3412Kuznechik(urandom(KEYSIZE))
171             ct = ofb(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
172             self.assertSequenceEqual(ofb(
173                 ciph.encrypt,
174                 GOST3412Kuznechik.blocksize,
175                 ct,
176                 iv,
177             ), pt)
178
179     def test_ofb_manual(self):
180         iv = [urandom(GOST3412Kuznechik.blocksize) for _ in range(randint(2, 10))]
181         pt = [
182             urandom(GOST3412Kuznechik.blocksize)
183             for _ in range(len(iv), len(iv) + randint(1, 10))
184         ]
185         ciph = GOST3412Kuznechik(urandom(KEYSIZE))
186         r = [ciph.encrypt(i) for i in iv]
187         for i in range(len(pt) - len(iv)):
188             r.append(ciph.encrypt(r[i]))
189         ct = [strxor(g, r) for g, r in zip(pt, r)]
190         self.assertSequenceEqual(
191             ofb(ciph.encrypt, GOST3412Kuznechik.blocksize, b"".join(pt), b"".join(iv)),
192             b"".join(ct),
193         )
194
195     def test_cbc_vectors(self):
196         ciphtext = ""
197         ciphtext += "689972d4a085fa4d90e52e3d6d7dcc27"
198         ciphtext += "2826e661b478eca6af1e8e448d5ea5ac"
199         ciphtext += "fe7babf1e91999e85640e8b0f49d90d0"
200         ciphtext += "167688065a895c631a2d9a1560b63970"
201         self.assertSequenceEqual(
202             hexenc(cbc_encrypt(
203                 self.ciph.encrypt,
204                 GOST3412Kuznechik.blocksize,
205                 hexdec(self.plaintext),
206                 self.iv,
207             )),
208             ciphtext,
209         )
210         self.assertSequenceEqual(
211             hexenc(cbc_decrypt(
212                 self.ciph.decrypt,
213                 GOST3412Kuznechik.blocksize,
214                 hexdec(ciphtext),
215                 self.iv,
216             )),
217             self.plaintext,
218         )
219
220     def test_cbc_symmetric(self):
221         for _ in range(100):
222             pt = pad2(urandom(randint(0, 16 * 2)), GOST3412Kuznechik.blocksize)
223             iv = urandom(GOST3412Kuznechik.blocksize * 2)
224             ciph = GOST3412Kuznechik(urandom(KEYSIZE))
225             ct = cbc_encrypt(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
226             self.assertSequenceEqual(cbc_decrypt(
227                 ciph.decrypt,
228                 GOST3412Kuznechik.blocksize,
229                 ct,
230                 iv,
231             ), pt)
232
233     def test_cfb_vectors(self):
234         ciphtext = ""
235         ciphtext += "81800a59b1842b24ff1f795e897abd95"
236         ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
237         ciphtext += "79f2a8eb5cc68d38842d264e97a238b5"
238         ciphtext += "4ffebecd4e922de6c75bd9dd44fbf4d1"
239         self.assertSequenceEqual(
240             hexenc(cfb_encrypt(
241                 self.ciph.encrypt,
242                 GOST3412Kuznechik.blocksize,
243                 hexdec(self.plaintext),
244                 self.iv,
245             )),
246             ciphtext,
247         )
248         self.assertSequenceEqual(
249             hexenc(cfb_decrypt(
250                 self.ciph.encrypt,
251                 GOST3412Kuznechik.blocksize,
252                 hexdec(ciphtext),
253                 self.iv,
254             )),
255             self.plaintext,
256         )
257
258     def test_cfb_symmetric(self):
259         for _ in range(100):
260             pt = urandom(randint(0, 16 * 2))
261             iv = urandom(GOST3412Kuznechik.blocksize * 2)
262             ciph = GOST3412Kuznechik(urandom(KEYSIZE))
263             ct = cfb_encrypt(ciph.encrypt, GOST3412Kuznechik.blocksize, pt, iv)
264             self.assertSequenceEqual(cfb_decrypt(
265                 ciph.encrypt,
266                 GOST3412Kuznechik.blocksize,
267                 ct,
268                 iv,
269             ), pt)
270
271     def test_mac_vectors(self):
272         k1, k2 = _mac_ks(self.ciph.encrypt, GOST3412Kuznechik.blocksize)
273         self.assertSequenceEqual(hexenc(k1), "297d82bc4d39e3ca0de0573298151dc7")
274         self.assertSequenceEqual(hexenc(k2), "52fb05789a73c7941bc0ae65302a3b8e")
275         self.assertSequenceEqual(
276             hexenc(mac(
277                 self.ciph.encrypt,
278                 GOST3412Kuznechik.blocksize,
279                 hexdec(self.plaintext),
280             )[:8]),
281             "336f4d296059fbe3",
282         )
283
284     def test_mac_applies(self):
285         for _ in range(100):
286             data = urandom(randint(0, 16 * 2))
287             ciph = GOST3412Kuznechik(urandom(KEYSIZE))
288             mac(ciph.encrypt, GOST3412Kuznechik.blocksize, data)
289
290
291 class GOST3412MagmaModesTest(TestCase):
292     key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
293     ciph = GOST3412Magma(key)
294     plaintext = ""
295     plaintext += "92def06b3c130a59"
296     plaintext += "db54c704f8189d20"
297     plaintext += "4a98fb2e67a8024c"
298     plaintext += "8912409b17b57e41"
299     iv = hexdec("1234567890abcdef234567890abcdef134567890abcdef12")
300
301     def test_ecb_vectors(self):
302         ciphtext = ""
303         ciphtext += "2b073f0494f372a0"
304         ciphtext += "de70e715d3556e48"
305         ciphtext += "11d8d9e9eacfbc1e"
306         ciphtext += "7c68260996c67efb"
307         self.assertSequenceEqual(
308             hexenc(ecb_encrypt(
309                 self.ciph.encrypt,
310                 GOST3412Magma.blocksize,
311                 hexdec(self.plaintext),
312             )),
313             ciphtext,
314         )
315         self.assertSequenceEqual(
316             hexenc(ecb_decrypt(
317                 self.ciph.decrypt,
318                 GOST3412Magma.blocksize,
319                 hexdec(ciphtext),
320             )),
321             self.plaintext,
322         )
323
324     def test_ecb_symmetric(self):
325         for _ in range(100):
326             pt = pad2(urandom(randint(0, 16 * 2)), 16)
327             ciph = GOST3412Magma(urandom(KEYSIZE))
328             ct = ecb_encrypt(ciph.encrypt, GOST3412Magma.blocksize, pt)
329             self.assertSequenceEqual(ecb_decrypt(
330                 ciph.decrypt,
331                 GOST3412Magma.blocksize,
332                 ct,
333             ), pt)
334
335     def test_ctr_vectors(self):
336         ciphtext = ""
337         ciphtext += "4e98110c97b7b93c"
338         ciphtext += "3e250d93d6e85d69"
339         ciphtext += "136d868807b2dbef"
340         ciphtext += "568eb680ab52a12d"
341         iv = self.iv[:4]
342         self.assertSequenceEqual(
343             hexenc(ctr(
344                 self.ciph.encrypt,
345                 GOST3412Magma.blocksize,
346                 hexdec(self.plaintext),
347                 iv,
348             )),
349             ciphtext,
350         )
351         self.assertSequenceEqual(
352             hexenc(ctr(
353                 self.ciph.encrypt,
354                 GOST3412Magma.blocksize,
355                 hexdec(ciphtext),
356                 iv,
357             )),
358             self.plaintext,
359         )
360
361     def test_ctr_symmetric(self):
362         for _ in range(100):
363             pt = urandom(randint(0, 16 * 2))
364             iv = urandom(GOST3412Magma.blocksize // 2)
365             ciph = GOST3412Magma(urandom(KEYSIZE))
366             ct = ctr(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
367             self.assertSequenceEqual(ctr(
368                 ciph.encrypt,
369                 GOST3412Magma.blocksize,
370                 ct,
371                 iv,
372             ), pt)
373
374     def test_ofb_vectors(self):
375         iv = self.iv[:16]
376         ciphtext = ""
377         ciphtext += "db37e0e266903c83"
378         ciphtext += "0d46644c1f9a089c"
379         ciphtext += "a0f83062430e327e"
380         ciphtext += "c824efb8bd4fdb05"
381         self.assertSequenceEqual(
382             hexenc(ofb(
383                 self.ciph.encrypt,
384                 GOST3412Magma.blocksize,
385                 hexdec(self.plaintext),
386                 iv,
387             )),
388             ciphtext,
389         )
390         self.assertSequenceEqual(
391             hexenc(ofb(
392                 self.ciph.encrypt,
393                 GOST3412Magma.blocksize,
394                 hexdec(ciphtext),
395                 iv,
396             )),
397             self.plaintext,
398         )
399
400     def test_ofb_symmetric(self):
401         for _ in range(100):
402             pt = urandom(randint(0, 16 * 2))
403             iv = urandom(GOST3412Magma.blocksize * 2)
404             ciph = GOST3412Magma(urandom(KEYSIZE))
405             ct = ofb(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
406             self.assertSequenceEqual(ofb(
407                 ciph.encrypt,
408                 GOST3412Magma.blocksize,
409                 ct,
410                 iv,
411             ), pt)
412
413     def test_cbc_vectors(self):
414         ciphtext = ""
415         ciphtext += "96d1b05eea683919"
416         ciphtext += "aff76129abb937b9"
417         ciphtext += "5058b4a1c4bc0019"
418         ciphtext += "20b78b1a7cd7e667"
419         self.assertSequenceEqual(
420             hexenc(cbc_encrypt(
421                 self.ciph.encrypt,
422                 GOST3412Magma.blocksize,
423                 hexdec(self.plaintext),
424                 self.iv,
425             )),
426             ciphtext,
427         )
428         self.assertSequenceEqual(
429             hexenc(cbc_decrypt(
430                 self.ciph.decrypt,
431                 GOST3412Magma.blocksize,
432                 hexdec(ciphtext),
433                 self.iv,
434             )),
435             self.plaintext,
436         )
437
438     def test_cbc_symmetric(self):
439         for _ in range(100):
440             pt = pad2(urandom(randint(0, 16 * 2)), 16)
441             iv = urandom(GOST3412Magma.blocksize * 2)
442             ciph = GOST3412Magma(urandom(KEYSIZE))
443             ct = cbc_encrypt(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
444             self.assertSequenceEqual(cbc_decrypt(
445                 ciph.decrypt,
446                 GOST3412Magma.blocksize,
447                 ct,
448                 iv,
449             ), pt)
450
451     def test_cfb_vectors(self):
452         iv = self.iv[:16]
453         ciphtext = ""
454         ciphtext += "db37e0e266903c83"
455         ciphtext += "0d46644c1f9a089c"
456         ciphtext += "24bdd2035315d38b"
457         ciphtext += "bcc0321421075505"
458         self.assertSequenceEqual(
459             hexenc(cfb_encrypt(
460                 self.ciph.encrypt,
461                 GOST3412Magma.blocksize,
462                 hexdec(self.plaintext),
463                 iv,
464             )),
465             ciphtext,
466         )
467         self.assertSequenceEqual(
468             hexenc(cfb_decrypt(
469                 self.ciph.encrypt,
470                 GOST3412Magma.blocksize,
471                 hexdec(ciphtext),
472                 iv,
473             )),
474             self.plaintext,
475         )
476
477     def test_cfb_symmetric(self):
478         for _ in range(100):
479             pt = urandom(randint(0, 16 * 2))
480             iv = urandom(GOST3412Magma.blocksize * 2)
481             ciph = GOST3412Magma(urandom(KEYSIZE))
482             ct = cfb_encrypt(ciph.encrypt, GOST3412Magma.blocksize, pt, iv)
483             self.assertSequenceEqual(cfb_decrypt(
484                 ciph.encrypt,
485                 GOST3412Magma.blocksize,
486                 ct,
487                 iv,
488             ), pt)
489
490     def test_mac_vectors(self):
491         k1, k2 = _mac_ks(self.ciph.encrypt, GOST3412Magma.blocksize)
492         self.assertSequenceEqual(hexenc(k1), "5f459b3342521424")
493         self.assertSequenceEqual(hexenc(k2), "be8b366684a42848")
494         self.assertSequenceEqual(
495             hexenc(mac(
496                 self.ciph.encrypt,
497                 GOST3412Magma.blocksize,
498                 hexdec(self.plaintext),
499             )[:4]),
500             "154e7210",
501         )
502
503     def test_mac_applies(self):
504         for _ in range(100):
505             data = urandom(randint(0, 16 * 2))
506             ciph = GOST3412Magma(urandom(KEYSIZE))
507             mac(ciph.encrypt, GOST3412Magma.blocksize, data)
508
509
510 class TestVectorACPKM(TestCase):
511     """Test vectors from Ð  1323565.1.017-2018
512     """
513     key = hexdec("8899AABBCCDDEEFF0011223344556677FEDCBA98765432100123456789ABCDEF")
514
515     def test_magma_ctr_acpkm(self):
516         key = acpkm(GOST3412Magma(self.key).encrypt, GOST3412Magma.blocksize)
517         self.assertSequenceEqual(key, hexdec("863EA017842C3D372B18A85A28E2317D74BEFC107720DE0C9E8AB974ABD00CA0"))
518         key = acpkm(GOST3412Magma(key).encrypt, GOST3412Magma.blocksize)
519         self.assertSequenceEqual(key, hexdec("49A5E2677DE555982B8AD5E826652D17EEC847BF5B3997A81CF7FE7F1187BD27"))
520         key = acpkm(GOST3412Magma(key).encrypt, GOST3412Magma.blocksize)
521         self.assertSequenceEqual(key, hexdec("3256BF3F97B5667426A9FB1C5EAABE41893CCDD5A868F9B63B0AA90720FA43C4"))
522
523     def test_magma_ctr(self):
524         encrypter = GOST3412Magma(self.key).encrypt
525         plaintext = hexdec("""
526 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
527 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
528 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
529 22 33 44 55 66 77 88 99
530         """.replace("\n", "").replace(" ", ""))
531         iv = hexdec("12345678")
532         ciphertext = hexdec("""
533 2A B8 1D EE EB 1E 4C AB 68 E1 04 C4 BD 6B 94 EA
534 C7 2C 67 AF 6C 2E 5B 6B 0E AF B6 17 70 F1 B3 2E
535 A1 AE 71 14 9E ED 13 82 AB D4 67 18 06 72 EC 6F
536 84 A2 F1 5B 3F CA 72 C1
537         """.replace("\n", "").replace(" ", ""))
538         self.assertSequenceEqual(
539             ctr_acpkm(
540                 GOST3412Magma,
541                 encrypter,
542                 bs=GOST3412Magma.blocksize,
543                 section_size=GOST3412Magma.blocksize * 2,
544                 data=plaintext,
545                 iv=iv
546             ),
547             ciphertext,
548         )
549         self.assertSequenceEqual(
550             ctr_acpkm(
551                 GOST3412Magma,
552                 encrypter,
553                 bs=GOST3412Magma.blocksize,
554                 section_size=GOST3412Magma.blocksize * 2,
555                 data=ciphertext,
556                 iv=iv
557             ),
558             plaintext,
559         )
560
561     def test_kuznechik_ctr_acpkm(self):
562         key = acpkm(GOST3412Kuznechik(self.key).encrypt, GOST3412Kuznechik.blocksize)
563         self.assertSequenceEqual(key, hexdec("2666ED40AE687811745CA0B448F57A7B390ADB5780307E8E9659AC403AE60C60"))
564         key = acpkm(GOST3412Kuznechik(key).encrypt, GOST3412Kuznechik.blocksize)
565         self.assertSequenceEqual(key, hexdec("BB3DD5402E999B7A3DEBB0DB45448EC530F07365DFEE3ABA8415F77AC8F34CE8"))
566         key = acpkm(GOST3412Kuznechik(key).encrypt, GOST3412Kuznechik.blocksize)
567         self.assertSequenceEqual(key, hexdec("23362FD553CAD2178299A5B5A2D4722E3BB83C730A8BF57CE2DD004017F8C565"))
568
569     def test_kuznechik_ctr(self):
570         encrypter = GOST3412Kuznechik(self.key).encrypt
571         iv = hexdec("1234567890ABCEF0")
572         plaintext = hexdec("""
573 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
574 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
575 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
576 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11
577 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22
578 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33
579 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22 33 44
580         """.replace("\n", "").replace(" ", ""))
581         ciphertext = hexdec("""
582 F1 95 D8 BE C1 0E D1 DB D5 7B 5F A2 40 BD A1 B8
583 85 EE E7 33 F6 A1 3E 5D F3 3C E4 B3 3C 45 DE E4
584 4B CE EB 8F 64 6F 4C 55 00 17 06 27 5E 85 E8 00
585 58 7C 4D F5 68 D0 94 39 3E 48 34 AF D0 80 50 46
586 CF 30 F5 76 86 AE EC E1 1C FC 6C 31 6B 8A 89 6E
587 DF FD 07 EC 81 36 36 46 0C 4F 3B 74 34 23 16 3E
588 64 09 A9 C2 82 FA C8 D4 69 D2 21 E7 FB D6 DE 5D
589         """.replace("\n", "").replace(" ", ""))
590         self.assertSequenceEqual(
591             ctr_acpkm(
592                 GOST3412Kuznechik,
593                 encrypter,
594                 bs=GOST3412Kuznechik.blocksize,
595                 section_size=GOST3412Kuznechik.blocksize * 2,
596                 data=plaintext,
597                 iv=iv,
598             ),
599             ciphertext,
600         )
601         self.assertSequenceEqual(
602             ctr_acpkm(
603                 GOST3412Kuznechik,
604                 encrypter,
605                 bs=GOST3412Kuznechik.blocksize,
606                 section_size=GOST3412Kuznechik.blocksize * 2,
607                 data=ciphertext,
608                 iv=iv,
609             ),
610             plaintext,
611         )
612
613     def test_magma_omac_1_5_blocks(self):
614         encrypter = GOST3412Magma(self.key).encrypt
615         key_section_size = 640 // 8
616         self.assertSequenceEqual(
617             acpkm_master(
618                 GOST3412Magma,
619                 encrypter,
620                 key_section_size=key_section_size,
621                 bs=GOST3412Magma.blocksize,
622                 keymat_len=KEYSIZE + GOST3412Magma.blocksize,
623             ),
624             hexdec("0DF2F5273DA328932AC49D81D36B2558A50DBF9BBCAC74A614B2CCB2F1CBCD8A70638E3DE8B3571E"),
625         )
626         text = hexdec("1122334455667700FFEEDDCC")
627         self.assertSequenceEqual(
628             mac_acpkm_master(
629                 GOST3412Magma,
630                 encrypter,
631                 key_section_size,
632                 section_size=GOST3412Magma.blocksize * 2,
633                 bs=GOST3412Magma.blocksize,
634                 data=text,
635             ),
636             hexdec("A0540E3730ACBCF3"),
637         )
638
639     def test_magma_omac_5_blocks(self):
640         encrypter = GOST3412Magma(self.key).encrypt
641         key_section_size = 640 // 8
642         self.assertSequenceEqual(
643             acpkm_master(
644                 GOST3412Magma,
645                 encrypter,
646                 key_section_size=key_section_size,
647                 bs=GOST3412Magma.blocksize,
648                 keymat_len=3 * (KEYSIZE + GOST3412Magma.blocksize),
649             ),
650             hexdec("""
651 0D F2 F5 27 3D A3 28 93 2A C4 9D 81 D3 6B 25 58
652 A5 0D BF 9B BC AC 74 A6 14 B2 CC B2 F1 CB CD 8A
653 70 63 8E 3D E8 B3 57 1E 8D 38 26 D5 5E 63 A1 67
654 E2 40 66 40 54 7B 9F 1F 5F 2B 43 61 2A AE AF DA
655 18 0B AC 86 04 DF A6 FE 53 C2 CE 27 0E 9C 9F 52
656 68 D0 FD BF E1 A3 BD D9 BE 5B 96 D0 A1 20 23 48
657 6E F1 71 0F 92 4A E0 31 30 52 CB 5F CA 0B 79 1E
658 1B AB E8 57 6D 0F E3 A8
659             """.replace("\n", "").replace(" ", "")),
660         )
661         text = hexdec("""
662 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
663 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
664 11 22 33 44 55 66 77 88
665         """.replace("\n", "").replace(" ", ""))
666         self.assertSequenceEqual(
667             mac_acpkm_master(
668                 GOST3412Magma,
669                 encrypter,
670                 key_section_size,
671                 section_size=GOST3412Magma.blocksize * 2,
672                 bs=GOST3412Magma.blocksize,
673                 data=text,
674             ),
675             hexdec("34008DAD5496BB8E"),
676         )
677
678     def test_kuznechik_omac_1_5_blocks(self):
679         encrypter = GOST3412Kuznechik(self.key).encrypt
680         key_section_size = 768 // 8
681         self.assertSequenceEqual(
682             acpkm_master(
683                 GOST3412Kuznechik,
684                 encrypter,
685                 key_section_size=key_section_size,
686                 bs=GOST3412Kuznechik.blocksize,
687                 keymat_len=KEYSIZE + GOST3412Kuznechik.blocksize,
688             ),
689             hexdec("""
690 0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2
691 C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE
692 0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37
693             """.replace("\n", "").replace(" ", ""))
694         )
695         text = hexdec("""
696 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
697 00 11 22 33 44 55 66 77
698         """.replace("\n", "").replace(" ", ""))
699         self.assertSequenceEqual(
700             mac_acpkm_master(
701                 GOST3412Kuznechik,
702                 encrypter,
703                 key_section_size,
704                 section_size=GOST3412Kuznechik.blocksize * 2,
705                 bs=GOST3412Kuznechik.blocksize,
706                 data=text,
707             ),
708             hexdec("B5367F47B62B995EEB2A648C5843145E"),
709         )
710
711     def test_kuznechik_omac_5_blocks(self):
712         encrypter = GOST3412Kuznechik(self.key).encrypt
713         key_section_size = 768 // 8
714         self.assertSequenceEqual(
715             acpkm_master(
716                 GOST3412Kuznechik,
717                 encrypter,
718                 key_section_size=key_section_size,
719                 bs=GOST3412Kuznechik.blocksize,
720                 keymat_len=3 * (KEYSIZE + GOST3412Kuznechik.blocksize),
721             ),
722             hexdec("""
723 0C AB F1 F2 EF BC 4A C1 60 48 DF 1A 24 C6 05 B2
724 C0 D1 67 3D 75 86 A8 EC 0D D4 2C 45 A4 F9 5B AE
725 0F 2E 26 17 E4 71 48 68 0F C3 E6 17 8D F2 C1 37
726 C9 DD A8 9C FF A4 91 FE AD D9 B3 EA B7 03 BB 31
727 BC 7E 92 7F 04 94 72 9F 51 B4 9D 3D F9 C9 46 08
728 00 FB BC F5 ED EE 61 0E A0 2F 01 09 3C 7B C7 42
729 D7 D6 27 15 01 B1 77 77 52 63 C2 A3 49 5A 83 18
730 A8 1C 79 A0 4F 29 66 0E A3 FD A8 74 C6 30 79 9E
731 14 2C 57 79 14 FE A9 0D 3B C2 50 2E 83 36 85 D9
732             """.replace("\n", "").replace(" ", "")),
733         )
734         text = hexdec("""
735 11 22 33 44 55 66 77 00 FF EE DD CC BB AA 99 88
736 00 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A
737 11 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00
738 22 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11
739 33 44 55 66 77 88 99 AA BB CC EE FF 0A 00 11 22
740         """.replace("\n", "").replace(" ", ""))
741         self.assertSequenceEqual(
742             mac_acpkm_master(
743                 GOST3412Kuznechik,
744                 encrypter,
745                 key_section_size,
746                 section_size=GOST3412Kuznechik.blocksize * 2,
747                 bs=GOST3412Kuznechik.blocksize,
748                 data=text,
749             ),
750             hexdec("FBB8DCEE45BEA67C35F58C5700898E5D"),
751         )
752
753
754 class ISO10126Test(TestCase):
755     def test_symmetric(self):
756         for _ in range(100):
757             for blocksize in (GOST3412Magma.blocksize, GOST3412Kuznechik.blocksize):
758                 data = urandom(randint(0, blocksize * 3))
759                 padded = pad_iso10126(data, blocksize)
760                 self.assertSequenceEqual(unpad_iso10126(padded, blocksize), data)
761                 with self.assertRaises(ValueError):
762                     unpad_iso10126(padded[1:], blocksize)
763
764     def test_small(self):
765         with self.assertRaises(ValueError):
766             unpad_iso10126(b"foobar\x00\x09", 8)