2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2018 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, either version 3 of the License, or
8 # (at your option) any later version.
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.
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/>.
18 from os import urandom
19 from random import randint
20 from unittest import TestCase
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
41 class Pad2Test(TestCase):
42 def test_symmetric(self):
44 for blocksize in (8, 16):
45 data = urandom(randint(0, blocksize * 3))
46 self.assertSequenceEqual(
47 unpad2(pad2(data, blocksize), blocksize),
52 class GOST3412KuznechikModesTest(TestCase):
53 key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")
54 ciph = GOST3412Kuznechik(key)
56 plaintext += "1122334455667700ffeeddccbbaa9988"
57 plaintext += "00112233445566778899aabbcceeff0a"
58 plaintext += "112233445566778899aabbcceeff0a00"
59 plaintext += "2233445566778899aabbcceeff0a0011"
60 iv = hexdec("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")
62 def test_ecb_vectors(self):
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))),
72 self.assertSequenceEqual(
73 hexenc(ecb_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext))),
77 def test_ecb_symmetric(self):
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)
84 def test_ctr_vectors(self):
86 ciphtext += "f195d8bec10ed1dbd57b5fa240bda1b8"
87 ciphtext += "85eee733f6a13e5df33ce4b33c45dee4"
88 ciphtext += "a5eae88be6356ed3d5e877f13564a3a5"
89 ciphtext += "cb91fab1f20cbab6d1c6d15820bdba73"
91 self.assertSequenceEqual(
92 hexenc(ctr(self.ciph.encrypt, 16, hexdec(self.plaintext), iv)),
95 self.assertSequenceEqual(
96 hexenc(ctr(self.ciph.encrypt, 16, hexdec(ciphtext), iv)),
100 def test_ctr_symmetric(self):
102 pt = urandom(randint(0, 16 * 2))
104 ciph = GOST3412Kuznechik(urandom(32))
105 ct = ctr(ciph.encrypt, 16, pt, iv)
106 self.assertSequenceEqual(ctr(ciph.encrypt, 16, ct, iv), pt)
108 def test_ofb_vectors(self):
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)),
118 self.assertSequenceEqual(
119 hexenc(ofb(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
123 def test_ofb_symmetric(self):
125 pt = urandom(randint(0, 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)
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)),
144 def test_cbc_vectors(self):
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)),
154 self.assertSequenceEqual(
155 hexenc(cbc_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext), self.iv)),
159 def test_cbc_symmetric(self):
161 pt = pad2(urandom(randint(0, 16 * 2)), 16)
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)
167 def test_cfb_vectors(self):
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)),
177 self.assertSequenceEqual(
178 hexenc(cfb_decrypt(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
182 def test_cfb_symmetric(self):
184 pt = urandom(randint(0, 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)
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]),
199 def test_mac_applies(self):
201 data = urandom(randint(0, 16 * 2))
202 ciph = GOST3412Kuznechik(urandom(32))
203 mac(ciph.encrypt, 16, data)
206 class GOST3412MagmaModesTest(TestCase):
207 key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
208 ciph = GOST3412Magma(key)
210 plaintext += "92def06b3c130a59"
211 plaintext += "db54c704f8189d20"
212 plaintext += "4a98fb2e67a8024c"
213 plaintext += "8912409b17b57e41"
214 iv = hexdec("1234567890abcdef234567890abcdef134567890abcdef12")
216 def test_ecb_vectors(self):
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))),
226 self.assertSequenceEqual(
227 hexenc(ecb_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext))),
231 def test_ecb_symmetric(self):
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)
238 def test_ctr_vectors(self):
240 ciphtext += "4e98110c97b7b93c"
241 ciphtext += "3e250d93d6e85d69"
242 ciphtext += "136d868807b2dbef"
243 ciphtext += "568eb680ab52a12d"
245 self.assertSequenceEqual(
246 hexenc(ctr(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
249 self.assertSequenceEqual(
250 hexenc(ctr(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
254 def test_ctr_symmetric(self):
256 pt = urandom(randint(0, 16 * 2))
258 ciph = GOST3412Magma(urandom(32))
259 ct = ctr(ciph.encrypt, 8, pt, iv)
260 self.assertSequenceEqual(ctr(ciph.encrypt, 8, ct, iv), pt)
262 def test_ofb_vectors(self):
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)),
273 self.assertSequenceEqual(
274 hexenc(ofb(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
278 def test_ofb_symmetric(self):
280 pt = urandom(randint(0, 16 * 2))
282 ciph = GOST3412Magma(urandom(32))
283 ct = ofb(ciph.encrypt, 8, pt, iv)
284 self.assertSequenceEqual(ofb(ciph.encrypt, 8, ct, iv), pt)
286 def test_cbc_vectors(self):
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)),
296 self.assertSequenceEqual(
297 hexenc(cbc_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext), self.iv)),
301 def test_cbc_symmetric(self):
303 pt = pad2(urandom(randint(0, 16 * 2)), 16)
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)
309 def test_cfb_vectors(self):
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)),
320 self.assertSequenceEqual(
321 hexenc(cfb_decrypt(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
325 def test_cfb_symmetric(self):
327 pt = urandom(randint(0, 16 * 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)
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]),
342 def test_mac_applies(self):
344 data = urandom(randint(0, 16 * 2))
345 ciph = GOST3412Magma(urandom(32))
346 mac(ciph.encrypt, 8, data)