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/>.
16 """GOST 34.12-2015 64 and 128 bit block ciphers (:rfc:`7801`)
18 Several precalculations are performed during this module importing.
21 from pygost.gost28147 import block2ns as gost28147_block2ns
22 from pygost.gost28147 import decrypt as gost28147_decrypt
23 from pygost.gost28147 import encrypt as gost28147_encrypt
24 from pygost.gost28147 import ns2block as gost28147_ns2block
25 from pygost.utils import strxor
26 from pygost.utils import xrange
30 148, 32, 133, 16, 194, 192, 1, 251, 1, 192, 194, 16, 133, 32, 148, 1,
33 252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250, 218, 35, 197, 4, 77,
34 233, 119, 240, 219, 147, 46, 153, 186, 23, 54, 241, 187, 20, 205, 95, 193,
35 249, 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66, 139, 1, 142, 79, 5,
36 132, 2, 174, 227, 106, 143, 160, 6, 11, 237, 152, 127, 212, 211, 31, 235,
37 52, 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253, 58, 206, 204, 181,
38 112, 14, 86, 8, 12, 118, 18, 191, 114, 19, 71, 156, 183, 93, 135, 21, 161,
39 150, 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158, 178, 177, 50, 117,
40 25, 61, 255, 53, 138, 126, 109, 84, 198, 128, 195, 189, 13, 87, 223, 245,
41 36, 169, 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185, 3, 224, 15,
42 236, 222, 122, 148, 176, 188, 220, 232, 40, 80, 78, 51, 10, 74, 167, 151,
43 96, 115, 30, 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65, 173, 69, 70,
44 146, 39, 94, 85, 47, 140, 163, 165, 125, 105, 213, 149, 59, 7, 88, 179, 64,
45 134, 172, 29, 247, 48, 55, 107, 228, 136, 217, 231, 137, 225, 27, 131, 73,
46 76, 63, 248, 254, 141, 83, 170, 144, 202, 216, 133, 97, 32, 113, 103, 164,
47 45, 43, 9, 91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166, 116, 210, 230,
48 244, 180, 192, 209, 102, 175, 194, 57, 75, 99, 182,
51 ########################################################################
52 # Precalculate inverted PI value as a performance optimization.
53 # Actually it can be computed only once and saved on the disk.
54 ########################################################################
55 PIinv = bytearray(256)
72 ########################################################################
73 # Precalculate all possible gf(byte, byte) values as a performance
75 # Actually it can be computed only once and saved on the disk.
76 ########################################################################
79 GF = [bytearray(256) for _ in xrange(256)]
86 def L(blk, rounds=16):
87 for _ in range(rounds):
89 for i in range(14, -1, -1):
91 t ^= GF[blk[i]][LC[i]]
101 t ^= GF[blk[i]][LC[i]]
105 ########################################################################
106 # Precalculate values of the C -- it does not depend on key.
107 # Actually it can be computed only once and saved on the disk.
108 ########################################################################
113 for x in range(1, 33):
120 return L([PI[v] for v in blk])
123 class GOST3412Kuznechik(object):
124 """GOST 34.12-2015 128-bit block cipher Кузнечик (Kuznechik)
126 def __init__(self, key):
128 :param key: encryption/decryption key
129 :type key: bytes, 32 bytes
131 Key scheduling (roundkeys precomputation) is performed here.
133 kr0 = bytearray(key[:16])
134 kr1 = bytearray(key[16:])
138 k = lp(bytearray(strxor(C[8 * i + j], kr0)))
139 kr0, kr1 = [strxor(k, kr1), kr0]
143 def encrypt(self, blk):
146 blk = lp(bytearray(strxor(self.ks[i], blk)))
147 return bytes(strxor(self.ks[9], blk))
149 def decrypt(self, blk):
151 for i in range(9, 0, -1):
152 blk = [PIinv[v] for v in Linv(bytearray(strxor(self.ks[i], blk)))]
153 return bytes(strxor(self.ks[0], blk))
156 class GOST3412Magma(object):
157 """GOST 34.12-2015 64-bit block cipher Магма (Magma)
159 def __init__(self, key):
161 :param key: encryption/decryption key
162 :type key: bytes, 32 bytes
164 # Backward compatibility key preparation for 28147-89 key schedule
165 self.key = b"".join(key[i * 4:i * 4 + 4][::-1] for i in range(8))
166 self.sbox = "id-tc26-gost-28147-param-Z"
168 def encrypt(self, blk):
169 return gost28147_ns2block(gost28147_encrypt(
172 gost28147_block2ns(blk[::-1]),
175 def decrypt(self, blk):
176 return gost28147_ns2block(gost28147_decrypt(
179 gost28147_block2ns(blk[::-1]),