]> Cypherpunks.ru repositories - pygost.git/blob - pygost/test_gost3413.py
Raise copyright years
[pygost.git] / pygost / test_gost3413.py
1 # coding: utf-8
2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2018 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, either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 from os import urandom
19 from random import randint
20 from unittest import TestCase
21
22 from pygost.gost3412 import GOST3412Kuznechik
23 from pygost.gost3412 import GOST3412Magma
24 from pygost.gost3413 import _mac_ks
25 from pygost.gost3413 import cbc_decrypt
26 from pygost.gost3413 import cbc_encrypt
27 from pygost.gost3413 import cfb_decrypt
28 from pygost.gost3413 import cfb_encrypt
29 from pygost.gost3413 import ctr
30 from pygost.gost3413 import ecb_decrypt
31 from pygost.gost3413 import ecb_encrypt
32 from pygost.gost3413 import mac
33 from pygost.gost3413 import ofb
34 from pygost.gost3413 import pad2
35 from pygost.gost3413 import unpad2
36 from pygost.utils import hexdec
37 from pygost.utils import hexenc
38 from pygost.utils import strxor
39
40
41 class Pad2Test(TestCase):
42     def test_symmetric(self):
43         for _ in range(100):
44             for blocksize in (8, 16):
45                 data = urandom(randint(0, blocksize * 3))
46                 self.assertSequenceEqual(
47                     unpad2(pad2(data, blocksize), blocksize),
48                     data,
49                 )
50
51
52 class GOST3412KuznechikModesTest(TestCase):
53     key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")
54     ciph = GOST3412Kuznechik(key)
55     plaintext = ""
56     plaintext += "1122334455667700ffeeddccbbaa9988"
57     plaintext += "00112233445566778899aabbcceeff0a"
58     plaintext += "112233445566778899aabbcceeff0a00"
59     plaintext += "2233445566778899aabbcceeff0a0011"
60     iv = hexdec("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")
61
62     def test_ecb_vectors(self):
63         ciphtext = ""
64         ciphtext += "7f679d90bebc24305a468d42b9d4edcd"
65         ciphtext += "b429912c6e0032f9285452d76718d08b"
66         ciphtext += "f0ca33549d247ceef3f5a5313bd4b157"
67         ciphtext += "d0b09ccde830b9eb3a02c4c5aa8ada98"
68         self.assertSequenceEqual(
69             hexenc(ecb_encrypt(self.ciph.encrypt, 16, hexdec(self.plaintext))),
70             ciphtext,
71         )
72         self.assertSequenceEqual(
73             hexenc(ecb_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext))),
74             self.plaintext,
75         )
76
77     def test_ecb_symmetric(self):
78         for _ in range(100):
79             pt = pad2(urandom(randint(0, 16 * 2)), 16)
80             ciph = GOST3412Kuznechik(urandom(32))
81             ct = ecb_encrypt(ciph.encrypt, 16, pt)
82             self.assertSequenceEqual(ecb_decrypt(ciph.decrypt, 16, ct), pt)
83
84     def test_ctr_vectors(self):
85         ciphtext = ""
86         ciphtext += "f195d8bec10ed1dbd57b5fa240bda1b8"
87         ciphtext += "85eee733f6a13e5df33ce4b33c45dee4"
88         ciphtext += "a5eae88be6356ed3d5e877f13564a3a5"
89         ciphtext += "cb91fab1f20cbab6d1c6d15820bdba73"
90         iv = self.iv[:8]
91         self.assertSequenceEqual(
92             hexenc(ctr(self.ciph.encrypt, 16, hexdec(self.plaintext), iv)),
93             ciphtext,
94         )
95         self.assertSequenceEqual(
96             hexenc(ctr(self.ciph.encrypt, 16, hexdec(ciphtext), iv)),
97             self.plaintext,
98         )
99
100     def test_ctr_symmetric(self):
101         for _ in range(100):
102             pt = urandom(randint(0, 16 * 2))
103             iv = urandom(8)
104             ciph = GOST3412Kuznechik(urandom(32))
105             ct = ctr(ciph.encrypt, 16, pt, iv)
106             self.assertSequenceEqual(ctr(ciph.encrypt, 16, ct, iv), pt)
107
108     def test_ofb_vectors(self):
109         ciphtext = ""
110         ciphtext += "81800a59b1842b24ff1f795e897abd95"
111         ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
112         ciphtext += "66a257ac3ca0b8b1c80fe7fc10288a13"
113         ciphtext += "203ebbc066138660a0292243f6903150"
114         self.assertSequenceEqual(
115             hexenc(ofb(self.ciph.encrypt, 16, hexdec(self.plaintext), self.iv)),
116             ciphtext,
117         )
118         self.assertSequenceEqual(
119             hexenc(ofb(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
120             self.plaintext,
121         )
122
123     def test_ofb_symmetric(self):
124         for _ in range(100):
125             pt = urandom(randint(0, 16 * 2))
126             iv = urandom(16 * 2)
127             ciph = GOST3412Kuznechik(urandom(32))
128             ct = ofb(ciph.encrypt, 16, pt, iv)
129             self.assertSequenceEqual(ofb(ciph.encrypt, 16, ct, iv), pt)
130
131     def test_ofb_manual(self):
132         iv = [urandom(16) for _ in range(randint(2, 10))]
133         pt = [urandom(16) for _ in range(len(iv), len(iv) + randint(1, 10))]
134         ciph = GOST3412Kuznechik(urandom(32))
135         r = [ciph.encrypt(i) for i in iv]
136         for i in range(len(pt) - len(iv)):
137             r.append(ciph.encrypt(r[i]))
138         ct = [strxor(g, r) for g, r in zip(pt, r)]
139         self.assertSequenceEqual(
140             ofb(ciph.encrypt, 16, b"".join(pt), b"".join(iv)),
141             b"".join(ct),
142         )
143
144     def test_cbc_vectors(self):
145         ciphtext = ""
146         ciphtext += "689972d4a085fa4d90e52e3d6d7dcc27"
147         ciphtext += "2826e661b478eca6af1e8e448d5ea5ac"
148         ciphtext += "fe7babf1e91999e85640e8b0f49d90d0"
149         ciphtext += "167688065a895c631a2d9a1560b63970"
150         self.assertSequenceEqual(
151             hexenc(cbc_encrypt(self.ciph.encrypt, 16, hexdec(self.plaintext), self.iv)),
152             ciphtext,
153         )
154         self.assertSequenceEqual(
155             hexenc(cbc_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext), self.iv)),
156             self.plaintext,
157         )
158
159     def test_cbc_symmetric(self):
160         for _ in range(100):
161             pt = pad2(urandom(randint(0, 16 * 2)), 16)
162             iv = urandom(16 * 2)
163             ciph = GOST3412Kuznechik(urandom(32))
164             ct = cbc_encrypt(ciph.encrypt, 16, pt, iv)
165             self.assertSequenceEqual(cbc_decrypt(ciph.decrypt, 16, ct, iv), pt)
166
167     def test_cfb_vectors(self):
168         ciphtext = ""
169         ciphtext += "81800a59b1842b24ff1f795e897abd95"
170         ciphtext += "ed5b47a7048cfab48fb521369d9326bf"
171         ciphtext += "79f2a8eb5cc68d38842d264e97a238b5"
172         ciphtext += "4ffebecd4e922de6c75bd9dd44fbf4d1"
173         self.assertSequenceEqual(
174             hexenc(cfb_encrypt(self.ciph.encrypt, 16, hexdec(self.plaintext), self.iv)),
175             ciphtext,
176         )
177         self.assertSequenceEqual(
178             hexenc(cfb_decrypt(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
179             self.plaintext,
180         )
181
182     def test_cfb_symmetric(self):
183         for _ in range(100):
184             pt = urandom(randint(0, 16 * 2))
185             iv = urandom(16 * 2)
186             ciph = GOST3412Kuznechik(urandom(32))
187             ct = cfb_encrypt(ciph.encrypt, 16, pt, iv)
188             self.assertSequenceEqual(cfb_decrypt(ciph.encrypt, 16, ct, iv), pt)
189
190     def test_mac_vectors(self):
191         k1, k2 = _mac_ks(self.ciph.encrypt, 16)
192         self.assertSequenceEqual(hexenc(k1), "297d82bc4d39e3ca0de0573298151dc7")
193         self.assertSequenceEqual(hexenc(k2), "52fb05789a73c7941bc0ae65302a3b8e")
194         self.assertSequenceEqual(
195             hexenc(mac(self.ciph.encrypt, 16, hexdec(self.plaintext))[:8]),
196             "336f4d296059fbe3",
197         )
198
199     def test_mac_applies(self):
200         for _ in range(100):
201             data = urandom(randint(0, 16 * 2))
202             ciph = GOST3412Kuznechik(urandom(32))
203             mac(ciph.encrypt, 16, data)
204
205
206 class GOST3412MagmaModesTest(TestCase):
207     key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
208     ciph = GOST3412Magma(key)
209     plaintext = ""
210     plaintext += "92def06b3c130a59"
211     plaintext += "db54c704f8189d20"
212     plaintext += "4a98fb2e67a8024c"
213     plaintext += "8912409b17b57e41"
214     iv = hexdec("1234567890abcdef234567890abcdef134567890abcdef12")
215
216     def test_ecb_vectors(self):
217         ciphtext = ""
218         ciphtext += "2b073f0494f372a0"
219         ciphtext += "de70e715d3556e48"
220         ciphtext += "11d8d9e9eacfbc1e"
221         ciphtext += "7c68260996c67efb"
222         self.assertSequenceEqual(
223             hexenc(ecb_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext))),
224             ciphtext,
225         )
226         self.assertSequenceEqual(
227             hexenc(ecb_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext))),
228             self.plaintext,
229         )
230
231     def test_ecb_symmetric(self):
232         for _ in range(100):
233             pt = pad2(urandom(randint(0, 16 * 2)), 16)
234             ciph = GOST3412Magma(urandom(32))
235             ct = ecb_encrypt(ciph.encrypt, 8, pt)
236             self.assertSequenceEqual(ecb_decrypt(ciph.decrypt, 8, ct), pt)
237
238     def test_ctr_vectors(self):
239         ciphtext = ""
240         ciphtext += "4e98110c97b7b93c"
241         ciphtext += "3e250d93d6e85d69"
242         ciphtext += "136d868807b2dbef"
243         ciphtext += "568eb680ab52a12d"
244         iv = self.iv[:4]
245         self.assertSequenceEqual(
246             hexenc(ctr(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
247             ciphtext,
248         )
249         self.assertSequenceEqual(
250             hexenc(ctr(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
251             self.plaintext,
252         )
253
254     def test_ctr_symmetric(self):
255         for _ in range(100):
256             pt = urandom(randint(0, 16 * 2))
257             iv = urandom(4)
258             ciph = GOST3412Magma(urandom(32))
259             ct = ctr(ciph.encrypt, 8, pt, iv)
260             self.assertSequenceEqual(ctr(ciph.encrypt, 8, ct, iv), pt)
261
262     def test_ofb_vectors(self):
263         iv = self.iv[:16]
264         ciphtext = ""
265         ciphtext += "db37e0e266903c83"
266         ciphtext += "0d46644c1f9a089c"
267         ciphtext += "a0f83062430e327e"
268         ciphtext += "c824efb8bd4fdb05"
269         self.assertSequenceEqual(
270             hexenc(ofb(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
271             ciphtext,
272         )
273         self.assertSequenceEqual(
274             hexenc(ofb(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
275             self.plaintext,
276         )
277
278     def test_ofb_symmetric(self):
279         for _ in range(100):
280             pt = urandom(randint(0, 16 * 2))
281             iv = urandom(8 * 2)
282             ciph = GOST3412Magma(urandom(32))
283             ct = ofb(ciph.encrypt, 8, pt, iv)
284             self.assertSequenceEqual(ofb(ciph.encrypt, 8, ct, iv), pt)
285
286     def test_cbc_vectors(self):
287         ciphtext = ""
288         ciphtext += "96d1b05eea683919"
289         ciphtext += "aff76129abb937b9"
290         ciphtext += "5058b4a1c4bc0019"
291         ciphtext += "20b78b1a7cd7e667"
292         self.assertSequenceEqual(
293             hexenc(cbc_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext), self.iv)),
294             ciphtext,
295         )
296         self.assertSequenceEqual(
297             hexenc(cbc_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext), self.iv)),
298             self.plaintext,
299         )
300
301     def test_cbc_symmetric(self):
302         for _ in range(100):
303             pt = pad2(urandom(randint(0, 16 * 2)), 16)
304             iv = urandom(8 * 2)
305             ciph = GOST3412Magma(urandom(32))
306             ct = cbc_encrypt(ciph.encrypt, 8, pt, iv)
307             self.assertSequenceEqual(cbc_decrypt(ciph.decrypt, 8, ct, iv), pt)
308
309     def test_cfb_vectors(self):
310         iv = self.iv[:16]
311         ciphtext = ""
312         ciphtext += "db37e0e266903c83"
313         ciphtext += "0d46644c1f9a089c"
314         ciphtext += "24bdd2035315d38b"
315         ciphtext += "bcc0321421075505"
316         self.assertSequenceEqual(
317             hexenc(cfb_encrypt(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
318             ciphtext,
319         )
320         self.assertSequenceEqual(
321             hexenc(cfb_decrypt(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
322             self.plaintext,
323         )
324
325     def test_cfb_symmetric(self):
326         for _ in range(100):
327             pt = urandom(randint(0, 16 * 2))
328             iv = urandom(8 * 2)
329             ciph = GOST3412Magma(urandom(32))
330             ct = cfb_encrypt(ciph.encrypt, 8, pt, iv)
331             self.assertSequenceEqual(cfb_decrypt(ciph.encrypt, 8, ct, iv), pt)
332
333     def test_mac_vectors(self):
334         k1, k2 = _mac_ks(self.ciph.encrypt, 8)
335         self.assertSequenceEqual(hexenc(k1), "5f459b3342521424")
336         self.assertSequenceEqual(hexenc(k2), "be8b366684a42848")
337         self.assertSequenceEqual(
338             hexenc(mac(self.ciph.encrypt, 8, hexdec(self.plaintext))[:4]),
339             "154e7210",
340         )
341
342     def test_mac_applies(self):
343         for _ in range(100):
344             data = urandom(randint(0, 16 * 2))
345             ciph = GOST3412Magma(urandom(32))
346             mac(ciph.encrypt, 8, data)