2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2017 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/>.
17 """ GOST 28147-89 block cipher
19 This is implementation of :rfc:`5830` ECB, CNT, CFB and :rfc:`4357`
20 CBC modes of operation. N1, N2, K names are taken according to
21 specification's terminology. CNT and CFB modes can work with arbitrary
25 from functools import partial
27 from pygost.gost3413 import pad2
28 from pygost.gost3413 import pad_size
29 from pygost.gost3413 import unpad2
30 from pygost.utils import hexdec
31 from pygost.utils import strxor
32 from pygost.utils import xrange # pylint: disable=redefined-builtin
40 # Sequence of K_i S-box applying for encryption and decryption
42 0, 1, 2, 3, 4, 5, 6, 7,
43 0, 1, 2, 3, 4, 5, 6, 7,
44 0, 1, 2, 3, 4, 5, 6, 7,
45 7, 6, 5, 4, 3, 2, 1, 0,
48 0, 1, 2, 3, 4, 5, 6, 7,
49 7, 6, 5, 4, 3, 2, 1, 0,
50 7, 6, 5, 4, 3, 2, 1, 0,
51 7, 6, 5, 4, 3, 2, 1, 0,
55 DEFAULT_SBOX = "Gost28147_CryptoProParamSetA"
57 "Gost2814789_TestParamSet": (
58 (4, 2, 15, 5, 9, 1, 0, 8, 14, 3, 11, 12, 13, 7, 10, 6),
59 (12, 9, 15, 14, 8, 1, 3, 10, 2, 7, 4, 13, 6, 0, 11, 5),
60 (13, 8, 14, 12, 7, 3, 9, 10, 1, 5, 2, 4, 6, 15, 0, 11),
61 (14, 9, 11, 2, 5, 15, 7, 1, 0, 13, 12, 6, 10, 4, 3, 8),
62 (3, 14, 5, 9, 6, 8, 0, 13, 10, 11, 7, 12, 2, 1, 15, 4),
63 (8, 15, 6, 11, 1, 9, 12, 5, 13, 3, 7, 10, 0, 14, 2, 4),
64 (9, 11, 12, 0, 3, 6, 7, 5, 4, 8, 14, 15, 1, 10, 2, 13),
65 (12, 6, 5, 2, 11, 0, 9, 13, 3, 14, 7, 10, 15, 4, 1, 8),
67 "Gost28147_CryptoProParamSetA": (
68 (9, 6, 3, 2, 8, 11, 1, 7, 10, 4, 14, 15, 12, 0, 13, 5),
69 (3, 7, 14, 9, 8, 10, 15, 0, 5, 2, 6, 12, 11, 4, 13, 1),
70 (14, 4, 6, 2, 11, 3, 13, 8, 12, 15, 5, 10, 0, 7, 1, 9),
71 (14, 7, 10, 12, 13, 1, 3, 9, 0, 2, 11, 4, 15, 8, 5, 6),
72 (11, 5, 1, 9, 8, 13, 15, 0, 14, 4, 2, 3, 12, 7, 10, 6),
73 (3, 10, 13, 12, 1, 2, 0, 11, 7, 5, 9, 4, 8, 15, 14, 6),
74 (1, 13, 2, 9, 7, 10, 6, 0, 8, 12, 4, 5, 15, 3, 11, 14),
75 (11, 10, 15, 5, 0, 12, 14, 8, 6, 2, 3, 9, 1, 7, 13, 4),
77 "Gost28147_CryptoProParamSetB": (
78 (8, 4, 11, 1, 3, 5, 0, 9, 2, 14, 10, 12, 13, 6, 7, 15),
79 (0, 1, 2, 10, 4, 13, 5, 12, 9, 7, 3, 15, 11, 8, 6, 14),
80 (14, 12, 0, 10, 9, 2, 13, 11, 7, 5, 8, 15, 3, 6, 1, 4),
81 (7, 5, 0, 13, 11, 6, 1, 2, 3, 10, 12, 15, 4, 14, 9, 8),
82 (2, 7, 12, 15, 9, 5, 10, 11, 1, 4, 0, 13, 6, 8, 14, 3),
83 (8, 3, 2, 6, 4, 13, 14, 11, 12, 1, 7, 15, 10, 0, 9, 5),
84 (5, 2, 10, 11, 9, 1, 12, 3, 7, 4, 13, 0, 6, 15, 8, 14),
85 (0, 4, 11, 14, 8, 3, 7, 1, 10, 2, 9, 6, 15, 13, 5, 12),
87 "Gost28147_CryptoProParamSetC": (
88 (1, 11, 12, 2, 9, 13, 0, 15, 4, 5, 8, 14, 10, 7, 6, 3),
89 (0, 1, 7, 13, 11, 4, 5, 2, 8, 14, 15, 12, 9, 10, 6, 3),
90 (8, 2, 5, 0, 4, 9, 15, 10, 3, 7, 12, 13, 6, 14, 1, 11),
91 (3, 6, 0, 1, 5, 13, 10, 8, 11, 2, 9, 7, 14, 15, 12, 4),
92 (8, 13, 11, 0, 4, 5, 1, 2, 9, 3, 12, 14, 6, 15, 10, 7),
93 (12, 9, 11, 1, 8, 14, 2, 4, 7, 3, 6, 5, 10, 0, 15, 13),
94 (10, 9, 6, 8, 13, 14, 2, 0, 15, 3, 5, 11, 4, 1, 12, 7),
95 (7, 4, 0, 5, 10, 2, 15, 14, 12, 6, 1, 11, 13, 9, 3, 8),
97 "Gost28147_CryptoProParamSetD": (
98 (15, 12, 2, 10, 6, 4, 5, 0, 7, 9, 14, 13, 1, 11, 8, 3),
99 (11, 6, 3, 4, 12, 15, 14, 2, 7, 13, 8, 0, 5, 10, 9, 1),
100 (1, 12, 11, 0, 15, 14, 6, 5, 10, 13, 4, 8, 9, 3, 7, 2),
101 (1, 5, 14, 12, 10, 7, 0, 13, 6, 2, 11, 4, 9, 3, 15, 8),
102 (0, 12, 8, 9, 13, 2, 10, 11, 7, 3, 6, 5, 4, 14, 15, 1),
103 (8, 0, 15, 3, 2, 5, 14, 11, 1, 10, 4, 7, 12, 9, 13, 6),
104 (3, 0, 6, 15, 1, 14, 9, 2, 13, 8, 12, 4, 11, 10, 5, 7),
105 (1, 10, 6, 8, 15, 11, 0, 4, 12, 3, 5, 9, 7, 13, 2, 14),
107 "GostR3411_94_TestParamSet": (
108 (4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3),
109 (14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9),
110 (5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11),
111 (7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3),
112 (6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2),
113 (4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14),
114 (13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12),
115 (1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12),
117 "GostR3411_94_CryptoProParamSet": (
118 (10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15),
119 (5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8),
120 (7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13),
121 (4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3),
122 (7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5),
123 (7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3),
124 (13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11),
125 (1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12),
127 "Gost28147_tc26_ParamZ": (
128 (12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1),
129 (6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15),
130 (11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0),
131 (12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11),
132 (7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12),
133 (5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0),
134 (8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7),
135 (1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2),
138 (11, 4, 8, 10, 9, 7, 0, 3, 1, 6, 2, 15, 14, 5, 12, 13),
139 (1, 7, 14, 9, 11, 3, 15, 12, 0, 5, 4, 6, 13, 10, 8, 2),
140 (7, 3, 1, 9, 2, 4, 13, 15, 8, 10, 12, 6, 5, 0, 11, 14),
141 (10, 5, 15, 7, 14, 11, 3, 9, 2, 8, 1, 12, 0, 4, 6, 13),
142 (0, 14, 6, 11, 9, 3, 8, 4, 12, 15, 10, 5, 13, 7, 1, 2),
143 (9, 2, 11, 12, 0, 4, 5, 6, 3, 15, 13, 8, 1, 7, 14, 10),
144 (4, 0, 14, 1, 5, 11, 8, 3, 12, 2, 9, 7, 6, 10, 13, 15),
145 (7, 14, 12, 13, 9, 4, 8, 15, 10, 2, 6, 0, 3, 11, 5, 1),
148 SBOXES["AppliedCryptography"] = SBOXES["GostR3411_94_TestParamSet"]
152 """ S-box substitution
155 :param _in: 32-bit word
156 :returns: substituted 32-bit word
159 (s[0][(_in >> 0) & 0x0F] << 0) +
160 (s[1][(_in >> 4) & 0x0F] << 4) +
161 (s[2][(_in >> 8) & 0x0F] << 8) +
162 (s[3][(_in >> 12) & 0x0F] << 12) +
163 (s[4][(_in >> 16) & 0x0F] << 16) +
164 (s[5][(_in >> 20) & 0x0F] << 20) +
165 (s[6][(_in >> 24) & 0x0F] << 24) +
166 (s[7][(_in >> 28) & 0x0F] << 28)
171 """ Convert block to N1 and N2 integers
173 data = bytearray(data)
175 data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24,
176 data[4] | data[5] << 8 | data[6] << 16 | data[7] << 24,
181 """ Convert N1 and N2 integers to 8-byte block
184 return bytes(bytearray((
185 (n2 >> 0) & 255, (n2 >> 8) & 255, (n2 >> 16) & 255, (n2 >> 24) & 255,
186 (n1 >> 0) & 255, (n1 >> 8) & 255, (n1 >> 16) & 255, (n1 >> 24) & 255,
190 def addmod(x, y, mod=2 ** 32):
191 """ Modulo adding of two integers
194 return r if r < mod else r - mod
198 """ 11-bit cyclic shift
200 return ((x << 11) & (2 ** 32 - 1)) | ((x >> (32 - 11)) & (2 ** 32 - 1))
203 def validate_key(key):
204 if len(key) != KEYSIZE:
205 raise ValueError("Invalid key size")
209 if len(iv) != BLOCKSIZE:
210 raise ValueError("Invalid IV size")
213 def validate_sbox(sbox):
214 if sbox not in SBOXES:
215 raise ValueError("Unknown sbox supplied")
218 def xcrypt(seq, sbox, key, ns):
219 """ Perform full-round single-block operation
221 :param seq: sequence of K_i S-box applying (either encrypt or decrypt)
222 :param sbox: S-box parameters to use
223 :type sbox: str, SBOXES'es key
224 :param bytes key: 256-bit encryption key
225 :param ns: N1 and N2 integers
227 :returns: resulting N1 and N2
236 w[3 + i * 4] << 24 for i in range(8)
240 n1, n2 = _shift11(_K(s, addmod(n1, x[i]))) ^ n2, n1
244 def encrypt(sbox, key, ns):
245 """ Encrypt single block
247 return xcrypt(SEQ_ENCRYPT, sbox, key, ns)
250 def decrypt(sbox, key, ns):
251 """ Decrypt single block
253 return xcrypt(SEQ_DECRYPT, sbox, key, ns)
256 def ecb(key, data, action, sbox=DEFAULT_SBOX):
257 """ ECB mode of operation
259 :param bytes key: encryption key
260 :param data: plaintext
261 :type data: bytes, multiple of BLOCKSIZE
262 :param func action: "encrypt"/"decrypt"
263 :param sbox: S-box parameters to use
264 :type sbox: str, SBOXES'es key
270 if not data or len(data) % BLOCKSIZE != 0:
271 raise ValueError("Data is not blocksize aligned")
273 for i in xrange(0, len(data), BLOCKSIZE):
274 result.append(ns2block(action(
275 sbox, key, block2ns(data[i:i + BLOCKSIZE])
277 return b"".join(result)
280 ecb_encrypt = partial(ecb, action=encrypt)
281 ecb_decrypt = partial(ecb, action=decrypt)
284 def cbc_encrypt(key, data, iv=8 * b"\x00", pad=True, sbox=DEFAULT_SBOX):
285 """ CBC encryption mode of operation
287 :param bytes key: encryption key
288 :param bytes data: plaintext
289 :param iv: initialization vector
290 :type iv: bytes, BLOCKSIZE length
291 :type bool pad: perform ISO/IEC 7816-4 padding
292 :param sbox: S-box parameters to use
293 :type sbox: str, SBOXES'es key
297 34.13-2015 padding method 2 is used.
303 raise ValueError("No data supplied")
305 data = pad2(data, BLOCKSIZE)
306 if len(data) % BLOCKSIZE != 0:
307 raise ValueError("Data is not blocksize aligned")
309 for i in xrange(0, len(data), BLOCKSIZE):
310 ciphertext.append(ns2block(encrypt(sbox, key, block2ns(
311 strxor(ciphertext[-1], data[i:i + BLOCKSIZE])
313 return b"".join(ciphertext)
316 def cbc_decrypt(key, data, pad=True, sbox=DEFAULT_SBOX):
317 """ CBC decryption mode of operation
319 :param bytes key: encryption key
320 :param bytes data: ciphertext
321 :param iv: initialization vector
322 :type iv: bytes, BLOCKSIZE length
323 :type bool pad: perform ISO/IEC 7816-4 unpadding after decryption
324 :param sbox: S-box parameters to use
325 :type sbox: str, SBOXES'es key
331 if not data or len(data) % BLOCKSIZE != 0:
332 raise ValueError("Data is not blocksize aligned")
333 if len(data) < 2 * BLOCKSIZE:
334 raise ValueError("There is no either data, or IV in ciphertext")
336 for i in xrange(BLOCKSIZE, len(data), BLOCKSIZE):
337 plaintext.append(strxor(
338 ns2block(decrypt(sbox, key, block2ns(data[i:i + BLOCKSIZE]))),
339 data[i - BLOCKSIZE:i],
342 plaintext[-1] = unpad2(plaintext[-1], BLOCKSIZE)
343 return b"".join(plaintext)
346 def cnt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX):
347 """ Counter mode of operation
349 :param bytes key: encryption key
350 :param bytes data: plaintext
351 :param iv: initialization vector
352 :type iv: bytes, BLOCKSIZE length
353 :param sbox: S-box parameters to use
354 :type sbox: str, SBOXES'es key
358 For decryption you use the same function again.
364 raise ValueError("No data supplied")
365 n2, n1 = encrypt(sbox, key, block2ns(iv))
367 for _ in xrange(0, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
368 n1 = addmod(n1, C2, 2 ** 32)
369 n2 = addmod(n2, C1, 2 ** 32 - 1)
370 gamma.append(ns2block(encrypt(sbox, key, (n1, n2))))
371 return strxor(b"".join(gamma), data)
374 MESH_CONST = hexdec("6900722264C904238D3ADB9646E92AC418FEAC9400ED0712C086DCC2EF4CA92B")
378 def meshing(key, iv, sbox=DEFAULT_SBOX):
379 """:rfc:`4357` key meshing
381 key = ecb_decrypt(key, MESH_CONST, sbox=sbox)
382 iv = ecb_encrypt(key, iv, sbox=sbox)
386 def cfb_encrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False):
387 """ CFB encryption mode of operation
389 :param bytes key: encryption key
390 :param bytes data: plaintext
391 :param iv: initialization vector
392 :type iv: bytes, BLOCKSIZE length
393 :param sbox: S-box parameters to use
394 :type sbox: str, SBOXES'es key
395 :param bool mesh: enable key meshing
403 raise ValueError("No data supplied")
405 for i in xrange(0, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
406 if mesh and i >= MESH_MAX_DATA and i % MESH_MAX_DATA == 0:
407 key, iv = meshing(key, ciphertext[-1], sbox=sbox)
408 ciphertext.append(strxor(
409 data[i:i + BLOCKSIZE],
410 ns2block(encrypt(sbox, key, block2ns(iv))),
413 ciphertext.append(strxor(
414 data[i:i + BLOCKSIZE],
415 ns2block(encrypt(sbox, key, block2ns(ciphertext[-1]))),
417 return b"".join(ciphertext[1:])
420 def cfb_decrypt(key, data, iv=8 * b"\x00", sbox=DEFAULT_SBOX, mesh=False):
421 """ CFB decryption mode of operation
423 :param bytes key: encryption key
424 :param bytes data: plaintext
425 :param iv: initialization vector
426 :type iv: bytes, BLOCKSIZE length
427 :param sbox: S-box parameters to use
428 :type sbox: str, SBOXES'es key
429 :param bool mesh: enable key meshing
437 raise ValueError("No data supplied")
440 for i in xrange(BLOCKSIZE, len(data) + pad_size(len(data), BLOCKSIZE), BLOCKSIZE):
443 (i - BLOCKSIZE) >= MESH_MAX_DATA and
444 (i - BLOCKSIZE) % MESH_MAX_DATA == 0
446 key, iv = meshing(key, data[i - BLOCKSIZE:i], sbox=sbox)
447 plaintext.append(strxor(
448 data[i:i + BLOCKSIZE],
449 ns2block(encrypt(sbox, key, block2ns(iv))),
452 plaintext.append(strxor(
453 data[i:i + BLOCKSIZE],
454 ns2block(encrypt(sbox, key, block2ns(data[i - BLOCKSIZE:i]))),
456 return b"".join(plaintext)