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