2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2023 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 R 34.11-2012 (Streebog) hash function common files
18 This is implementation of :rfc:`6986`. Most function and variable names are
19 taken according to specification's terminology.
23 from struct import pack
24 from struct import unpack
26 from pygost.iface import PEP247
27 from pygost.utils import hexdec
28 from pygost.utils import strxor
29 from pygost.utils import xrange
34 252, 238, 221, 17, 207, 110, 49, 22, 251, 196, 250,
35 218, 35, 197, 4, 77, 233, 119, 240, 219, 147, 46,
36 153, 186, 23, 54, 241, 187, 20, 205, 95, 193, 249,
37 24, 101, 90, 226, 92, 239, 33, 129, 28, 60, 66,
38 139, 1, 142, 79, 5, 132, 2, 174, 227, 106, 143,
39 160, 6, 11, 237, 152, 127, 212, 211, 31, 235, 52,
40 44, 81, 234, 200, 72, 171, 242, 42, 104, 162, 253,
41 58, 206, 204, 181, 112, 14, 86, 8, 12, 118, 18,
42 191, 114, 19, 71, 156, 183, 93, 135, 21, 161, 150,
43 41, 16, 123, 154, 199, 243, 145, 120, 111, 157, 158,
44 178, 177, 50, 117, 25, 61, 255, 53, 138, 126, 109,
45 84, 198, 128, 195, 189, 13, 87, 223, 245, 36, 169,
46 62, 168, 67, 201, 215, 121, 214, 246, 124, 34, 185,
47 3, 224, 15, 236, 222, 122, 148, 176, 188, 220, 232,
48 40, 80, 78, 51, 10, 74, 167, 151, 96, 115, 30,
49 0, 98, 68, 26, 184, 56, 130, 100, 159, 38, 65,
50 173, 69, 70, 146, 39, 94, 85, 47, 140, 163, 165,
51 125, 105, 213, 149, 59, 7, 88, 179, 64, 134, 172,
52 29, 247, 48, 55, 107, 228, 136, 217, 231, 137, 225,
53 27, 131, 73, 76, 63, 248, 254, 141, 83, 170, 144,
54 202, 216, 133, 97, 32, 113, 103, 164, 45, 43, 9,
55 91, 203, 155, 37, 208, 190, 229, 108, 82, 89, 166,
56 116, 210, 230, 244, 180, 192, 209, 102, 175, 194, 57,
60 A = [unpack(">Q", hexdec(s))[0] for s in (
61 "8e20faa72ba0b470", "47107ddd9b505a38", "ad08b0e0c3282d1c", "d8045870ef14980e",
62 "6c022c38f90a4c07", "3601161cf205268d", "1b8e0b0e798c13c8", "83478b07b2468764",
63 "a011d380818e8f40", "5086e740ce47c920", "2843fd2067adea10", "14aff010bdd87508",
64 "0ad97808d06cb404", "05e23c0468365a02", "8c711e02341b2d01", "46b60f011a83988e",
65 "90dab52a387ae76f", "486dd4151c3dfdb9", "24b86a840e90f0d2", "125c354207487869",
66 "092e94218d243cba", "8a174a9ec8121e5d", "4585254f64090fa0", "accc9ca9328a8950",
67 "9d4df05d5f661451", "c0a878a0a1330aa6", "60543c50de970553", "302a1e286fc58ca7",
68 "18150f14b9ec46dd", "0c84890ad27623e0", "0642ca05693b9f70", "0321658cba93c138",
69 "86275df09ce8aaa8", "439da0784e745554", "afc0503c273aa42a", "d960281e9d1d5215",
70 "e230140fc0802984", "71180a8960409a42", "b60c05ca30204d21", "5b068c651810a89e",
71 "456c34887a3805b9", "ac361a443d1c8cd2", "561b0d22900e4669", "2b838811480723ba",
72 "9bcf4486248d9f5d", "c3e9224312c8c1a0", "effa11af0964ee50", "f97d86d98a327728",
73 "e4fa2054a80b329c", "727d102a548b194e", "39b008152acb8227", "9258048415eb419d",
74 "492c024284fbaec0", "aa16012142f35760", "550b8e9e21f7a530", "a48b474f9ef5dc18",
75 "70a6a56e2440598e", "3853dc371220a247", "1ca76e95091051ad", "0edd37c48a08a6d8",
76 "07e095624504536c", "8d70c431ac02a736", "c83862965601dd1b", "641c314b2b8ee083",
80 0, 8, 16, 24, 32, 40, 48, 56,
81 1, 9, 17, 25, 33, 41, 49, 57,
82 2, 10, 18, 26, 34, 42, 50, 58,
83 3, 11, 19, 27, 35, 43, 51, 59,
84 4, 12, 20, 28, 36, 44, 52, 60,
85 5, 13, 21, 29, 37, 45, 53, 61,
86 6, 14, 22, 30, 38, 46, 54, 62,
87 7, 15, 23, 31, 39, 47, 55, 63,
90 C = [hexdec("".join(s))[::-1] for s in (
92 "b1085bda1ecadae9ebcb2f81c0657c1f",
93 "2f6a76432e45d016714eb88d7585c4fc",
94 "4b7ce09192676901a2422a08a460d315",
95 "05767436cc744d23dd806559f2a64507",
98 "6fa3b58aa99d2f1a4fe39d460f70b5d7",
99 "f3feea720a232b9861d55e0f16b50131",
100 "9ab5176b12d699585cb561c2db0aa7ca",
101 "55dda21bd7cbcd56e679047021b19bb7",
104 "f574dcac2bce2fc70a39fc286a3d8435",
105 "06f15e5f529c1f8bf2ea7514b1297b7b",
106 "d3e20fe490359eb1c1c93a376062db09",
107 "c2b6f443867adb31991e96f50aba0ab2",
110 "ef1fdfb3e81566d2f948e1a05d71e4dd",
111 "488e857e335c3c7d9d721cad685e353f",
112 "a9d72c82ed03d675d8b71333935203be",
113 "3453eaa193e837f1220cbebc84e3d12e",
116 "4bea6bacad4747999a3f410c6ca92363",
117 "7f151c1f1686104a359e35d7800fffbd",
118 "bfcd1747253af5a3dfff00b723271a16",
119 "7a56a27ea9ea63f5601758fd7c6cfe57",
122 "ae4faeae1d3ad3d96fa4c33b7a3039c0",
123 "2d66c4f95142a46c187f9ab49af08ec6",
124 "cffaa6b71c9ab7b40af21f66c2bec6b6",
125 "bf71c57236904f35fa68407a46647d6e",
128 "f4c70e16eeaac5ec51ac86febf240954",
129 "399ec6c7e6bf87c9d3473e33197a93c9",
130 "0992abc52d822c3706476983284a0504",
131 "3517454ca23c4af38886564d3a14d493",
134 "9b1f5b424d93c9a703e7aa020c6e4141",
135 "4eb7f8719c36de1e89b4443b4ddbc49a",
136 "f4892bcb929b069069d18d2bd1a5c42f",
137 "36acc2355951a8d9a47f0dd4bf02e71e",
140 "378f5a541631229b944c9ad8ec165fde",
141 "3a7d3a1b258942243cd955b7e00d0984",
142 "800a440bdbb2ceb17b2b8a9aa6079c54",
143 "0e38dc92cb1f2a607261445183235adb",
146 "abbedea680056f52382ae548b2e4f3f3",
147 "8941e71cff8a78db1fffe18a1b336103",
148 "9fe76702af69334b7a1e6c303b7652f4",
149 "3698fad1153bb6c374b4c7fb98459ced",
152 "7bcd9ed0efc889fb3002c6cd635afe94",
153 "d8fa6bbbebab07612001802114846679",
154 "8a1d71efea48b9caefbacd1d7d476e98",
155 "dea2594ac06fd85d6bcaa4cd81f32d1b",
158 "378ee767f11631bad21380b00449b17a",
159 "cda43c32bcdf1d77f82012d430219f9b",
160 "5d80ef9d1891cc86e71da4aa88e12852",
161 "faf417d5d9b21b9948bc924af11bd720",
168 for byteN in xrange(8):
169 cache.append([0 for _ in xrange(256)])
170 for byteN in xrange(8):
171 for byteVal in xrange(256):
174 for bitN in xrange(8):
176 res64 ^= A[(7 - byteN) * 8 + bitN]
178 cache[byteN][byteVal] = res64
182 # Trade memory for CPU for part of L() calculations
187 a = int.from_bytes(a, "little")
188 b = int.from_bytes(b, "little")
189 r = (a + b) % (1 << 512)
190 return r.to_bytes(512 // 8, "little")
194 res = E(LPS(strxor(hsh[:8], pack("<Q", n)) + hsh[8:]), msg)
195 return strxor(strxor(res, hsh), msg)
200 msg = LPS(strxor(k, msg))
201 k = LPS(strxor(k, C[i]))
202 return strxor(k, msg)
206 return L(PS(bytearray(data)))
210 res = bytearray(BLOCKSIZE)
211 for i in range(BLOCKSIZE):
212 res[Tau[i]] = Pi[data[i]]
221 res64 ^= LCache[j][data[8 * i + j]]
222 res.append(pack("<Q", res64))
226 class GOST34112012(PEP247):
227 """GOST 34.11-2012 big-endian hash
229 >>> m = GOST34112012(digest_size=32)
233 'e3c9fd89226d93b489a9fe27d686806e24a514e3787bca053c698ec4616ceb78'
235 block_size = BLOCKSIZE
237 def __init__(self, data=b"", digest_size=64):
239 :param digest_size: hash digest size to compute
240 :type digest_size: 32 or 64 bytes
242 self._digest_size = digest_size
243 self.hsh = BLOCKSIZE * (b"\x01" if digest_size == 32 else b"\x00")
244 self.chk = bytearray(BLOCKSIZE * b"\x00")
251 obj._digest_size = self._digest_size
253 obj.chk = copy(self.chk)
259 def digest_size(self):
260 return self._digest_size
262 def _update_block(self, block):
263 self.hsh = g(self.n, self.hsh, block)
264 self.chk = add512bit(self.chk, block)
267 def update(self, data):
268 """Update state with the new data
270 if len(self.buf) > 0:
271 chunk_len = BLOCKSIZE - len(self.buf)
272 self.buf += data[:chunk_len]
273 data = data[chunk_len:]
274 if len(self.buf) == BLOCKSIZE:
275 self._update_block(self.buf)
277 while len(data) >= BLOCKSIZE:
278 self._update_block(data[:BLOCKSIZE])
279 data = data[BLOCKSIZE:]
283 """Get hash of the provided data
288 padblock_size = len(data) * 8
290 padlen = BLOCKSIZE - len(data)
291 if padlen != BLOCKSIZE:
292 data += b"\x00" * padlen
294 hsh = g(self.n, self.hsh, data)
295 n = self.n + padblock_size
296 chk = add512bit(self.chk, data)
297 hsh = g(0, hsh, pack("<Q", n) + 56 * b"\x00")
299 return hsh[-self._digest_size:]