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 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
40 class Pad2Test(TestCase):
41 def test_symmetric(self):
43 for blocksize in (8, 16):
44 data = urandom(randint(0, blocksize * 3))
45 self.assertSequenceEqual(
46 unpad2(pad2(data, blocksize), blocksize),
51 class GOST3412KuznechikModesTest(TestCase):
52 key = hexdec("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")
53 ciph = GOST3412Kuznechik(key)
55 plaintext += "1122334455667700ffeeddccbbaa9988"
56 plaintext += "00112233445566778899aabbcceeff0a"
57 plaintext += "112233445566778899aabbcceeff0a00"
58 plaintext += "2233445566778899aabbcceeff0a0011"
59 iv = hexdec("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")
61 def test_ecb_vectors(self):
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))),
71 self.assertSequenceEqual(
72 hexenc(ecb_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext))),
76 def test_ecb_symmetric(self):
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)
83 def test_ctr_vectors(self):
85 ciphtext += "f195d8bec10ed1dbd57b5fa240bda1b8"
86 ciphtext += "85eee733f6a13e5df33ce4b33c45dee4"
87 ciphtext += "a5eae88be6356ed3d5e877f13564a3a5"
88 ciphtext += "cb91fab1f20cbab6d1c6d15820bdba73"
90 self.assertSequenceEqual(
91 hexenc(ctr(self.ciph.encrypt, 16, hexdec(self.plaintext), iv)),
94 self.assertSequenceEqual(
95 hexenc(ctr(self.ciph.encrypt, 16, hexdec(ciphtext), iv)),
99 def test_ctr_symmetric(self):
101 pt = urandom(randint(0, 16 * 2))
103 ciph = GOST3412Kuznechik(urandom(32))
104 ct = ctr(ciph.encrypt, 16, pt, iv)
105 self.assertSequenceEqual(ctr(ciph.encrypt, 16, ct, iv), pt)
107 def test_ofb_vectors(self):
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)),
117 self.assertSequenceEqual(
118 hexenc(ofb(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
122 def test_ofb_symmetric(self):
124 pt = urandom(randint(0, 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)
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)),
143 def test_cbc_vectors(self):
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)),
153 self.assertSequenceEqual(
154 hexenc(cbc_decrypt(self.ciph.decrypt, 16, hexdec(ciphtext), self.iv)),
158 def test_cbc_symmetric(self):
160 pt = pad2(urandom(randint(0, 16 * 2)), 16)
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)
166 def test_cfb_vectors(self):
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)),
176 self.assertSequenceEqual(
177 hexenc(cfb_decrypt(self.ciph.encrypt, 16, hexdec(ciphtext), self.iv)),
181 def test_cfb_symmetric(self):
183 pt = urandom(randint(0, 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)
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]),
198 def test_mac_applies(self):
200 data = urandom(randint(0, 16 * 2))
201 ciph = GOST3412Kuznechik(urandom(32))
202 mac(ciph.encrypt, 16, data)
205 class GOST3412MagmaModesTest(TestCase):
206 key = hexdec("ffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")
207 ciph = GOST3412Magma(key)
209 plaintext += "92def06b3c130a59"
210 plaintext += "db54c704f8189d20"
211 plaintext += "4a98fb2e67a8024c"
212 plaintext += "8912409b17b57e41"
213 iv = hexdec("1234567890abcdef234567890abcdef134567890abcdef12")
215 def test_ecb_vectors(self):
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))),
225 self.assertSequenceEqual(
226 hexenc(ecb_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext))),
230 def test_ecb_symmetric(self):
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)
237 def test_ctr_vectors(self):
239 ciphtext += "4e98110c97b7b93c"
240 ciphtext += "3e250d93d6e85d69"
241 ciphtext += "136d868807b2dbef"
242 ciphtext += "568eb680ab52a12d"
244 self.assertSequenceEqual(
245 hexenc(ctr(self.ciph.encrypt, 8, hexdec(self.plaintext), iv)),
248 self.assertSequenceEqual(
249 hexenc(ctr(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
253 def test_ctr_symmetric(self):
255 pt = urandom(randint(0, 16 * 2))
257 ciph = GOST3412Magma(urandom(32))
258 ct = ctr(ciph.encrypt, 8, pt, iv)
259 self.assertSequenceEqual(ctr(ciph.encrypt, 8, ct, iv), pt)
261 def test_ofb_vectors(self):
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)),
272 self.assertSequenceEqual(
273 hexenc(ofb(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
277 def test_ofb_symmetric(self):
279 pt = urandom(randint(0, 16 * 2))
281 ciph = GOST3412Magma(urandom(32))
282 ct = ofb(ciph.encrypt, 8, pt, iv)
283 self.assertSequenceEqual(ofb(ciph.encrypt, 8, ct, iv), pt)
285 def test_cbc_vectors(self):
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)),
295 self.assertSequenceEqual(
296 hexenc(cbc_decrypt(self.ciph.decrypt, 8, hexdec(ciphtext), self.iv)),
300 def test_cbc_symmetric(self):
302 pt = pad2(urandom(randint(0, 16 * 2)), 16)
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)
308 def test_cfb_vectors(self):
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)),
319 self.assertSequenceEqual(
320 hexenc(cfb_decrypt(self.ciph.encrypt, 8, hexdec(ciphtext), iv)),
324 def test_cfb_symmetric(self):
326 pt = urandom(randint(0, 16 * 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)
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]),
341 def test_mac_applies(self):
343 data = urandom(randint(0, 16 * 2))
344 ciph = GOST3412Magma(urandom(32))
345 mac(ciph.encrypt, 8, data)