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