]> Cypherpunks.ru repositories - pygost.git/blob - pygost/gost34112012.py
Auto fill Streebog's cache
[pygost.git] / pygost / gost34112012.py
1 # coding: utf-8
2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2021 Sergey Matveev <stargrave@stargrave.org>
4 #
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.
8 #
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.
13 #
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
17
18 This is implementation of :rfc:`6986`. Most function and variable names are
19 taken according to specification's terminology.
20 """
21
22 from copy import copy
23 from struct import pack
24 from struct import unpack
25
26 from pygost.iface import PEP247
27 from pygost.utils import hexdec
28 from pygost.utils import strxor
29 from pygost.utils import xrange
30
31
32 BLOCKSIZE = 64
33 Pi = bytearray((
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,
57      75,  99, 182,
58 ))
59
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",
77 )]
78
79 Tau = (
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,
88 )
89
90 C = [hexdec("".join(s))[::-1] for s in (
91     (
92         "b1085bda1ecadae9ebcb2f81c0657c1f",
93         "2f6a76432e45d016714eb88d7585c4fc",
94         "4b7ce09192676901a2422a08a460d315",
95         "05767436cc744d23dd806559f2a64507",
96     ),
97     (
98         "6fa3b58aa99d2f1a4fe39d460f70b5d7",
99         "f3feea720a232b9861d55e0f16b50131",
100         "9ab5176b12d699585cb561c2db0aa7ca",
101         "55dda21bd7cbcd56e679047021b19bb7",
102     ),
103     (
104         "f574dcac2bce2fc70a39fc286a3d8435",
105         "06f15e5f529c1f8bf2ea7514b1297b7b",
106         "d3e20fe490359eb1c1c93a376062db09",
107         "c2b6f443867adb31991e96f50aba0ab2",
108     ),
109     (
110         "ef1fdfb3e81566d2f948e1a05d71e4dd",
111         "488e857e335c3c7d9d721cad685e353f",
112         "a9d72c82ed03d675d8b71333935203be",
113         "3453eaa193e837f1220cbebc84e3d12e",
114     ),
115     (
116         "4bea6bacad4747999a3f410c6ca92363",
117         "7f151c1f1686104a359e35d7800fffbd",
118         "bfcd1747253af5a3dfff00b723271a16",
119         "7a56a27ea9ea63f5601758fd7c6cfe57",
120     ),
121     (
122         "ae4faeae1d3ad3d96fa4c33b7a3039c0",
123         "2d66c4f95142a46c187f9ab49af08ec6",
124         "cffaa6b71c9ab7b40af21f66c2bec6b6",
125         "bf71c57236904f35fa68407a46647d6e",
126     ),
127     (
128         "f4c70e16eeaac5ec51ac86febf240954",
129         "399ec6c7e6bf87c9d3473e33197a93c9",
130         "0992abc52d822c3706476983284a0504",
131         "3517454ca23c4af38886564d3a14d493",
132     ),
133     (
134         "9b1f5b424d93c9a703e7aa020c6e4141",
135         "4eb7f8719c36de1e89b4443b4ddbc49a",
136         "f4892bcb929b069069d18d2bd1a5c42f",
137         "36acc2355951a8d9a47f0dd4bf02e71e",
138     ),
139     (
140         "378f5a541631229b944c9ad8ec165fde",
141         "3a7d3a1b258942243cd955b7e00d0984",
142         "800a440bdbb2ceb17b2b8a9aa6079c54",
143         "0e38dc92cb1f2a607261445183235adb",
144     ),
145     (
146         "abbedea680056f52382ae548b2e4f3f3",
147         "8941e71cff8a78db1fffe18a1b336103",
148         "9fe76702af69334b7a1e6c303b7652f4",
149         "3698fad1153bb6c374b4c7fb98459ced",
150     ),
151     (
152         "7bcd9ed0efc889fb3002c6cd635afe94",
153         "d8fa6bbbebab07612001802114846679",
154         "8a1d71efea48b9caefbacd1d7d476e98",
155         "dea2594ac06fd85d6bcaa4cd81f32d1b",
156     ),
157     (
158         "378ee767f11631bad21380b00449b17a",
159         "cda43c32bcdf1d77f82012d430219f9b",
160         "5d80ef9d1891cc86e71da4aa88e12852",
161         "faf417d5d9b21b9948bc924af11bd720",
162     ),
163 )]
164
165
166 def _lcache():
167     cache = []
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):
172             res64 = 0
173             val = byteVal
174             for bitN in xrange(8):
175                 if val & 0x80 > 0:
176                     res64 ^= A[(7 - byteN) * 8 + bitN]
177                 val <<= 1
178             cache[byteN][byteVal] = res64
179     return cache
180
181
182 # Trade memory for CPU for part of L() calculations
183 LCache = _lcache()
184
185
186 def add512bit(a, b):
187     """Add two 512 integers
188     """
189     a = bytearray(a)
190     b = bytearray(b)
191     cb = 0
192     res = bytearray(64)
193     for i in range(64):
194         cb = a[i] + b[i] + (cb >> 8)
195         res[i] = cb & 0xff
196     return res
197
198
199 def g(n, hsh, msg):
200     res = E(LPS(strxor(hsh[:8], pack("<Q", n)) + hsh[8:]), msg)
201     return strxor(strxor(res, hsh), msg)
202
203
204 def E(k, msg):
205     for i in range(12):
206         msg = LPS(strxor(k, msg))
207         k = LPS(strxor(k, C[i]))
208     return strxor(k, msg)
209
210
211 def LPS(data):
212     return L(PS(bytearray(data)))
213
214
215 def PS(data):
216     res = bytearray(BLOCKSIZE)
217     for i in range(BLOCKSIZE):
218         res[Tau[i]] = Pi[data[i]]
219     return res
220
221
222 def L(data):
223     res = []
224     for i in range(8):
225         res64 = 0
226         for j in range(8):
227             res64 ^= LCache[j][data[8 * i + j]]
228         res.append(pack("<Q", res64))
229     return b"".join(res)
230
231
232 class GOST34112012(PEP247):
233     """GOST 34.11-2012 big-endian hash
234
235     >>> m = GOST34112012(digest_size=32)
236     >>> m.update("foo")
237     >>> m.update("bar")
238     >>> m.hexdigest()
239     'e3c9fd89226d93b489a9fe27d686806e24a514e3787bca053c698ec4616ceb78'
240     """
241     block_size = BLOCKSIZE
242
243     def __init__(self, data=b"", digest_size=64):
244         """
245         :param digest_size: hash digest size to compute
246         :type digest_size: 32 or 64 bytes
247         """
248         self.data = data
249         self._digest_size = digest_size
250
251     def copy(self):
252         return GOST34112012(copy(self.data), self.digest_size)
253
254     @property
255     def digest_size(self):
256         return self._digest_size
257
258     def update(self, data):
259         """Append data that has to be hashed
260         """
261         self.data += data
262
263     def digest(self):
264         """Get hash of the provided data
265         """
266         hsh = BLOCKSIZE * (b"\x01" if self.digest_size == 32 else b"\x00")
267         chk = bytearray(BLOCKSIZE * b"\x00")
268         n = 0
269         data = self.data
270         for i in xrange(0, len(data) // BLOCKSIZE * BLOCKSIZE, BLOCKSIZE):
271             block = data[i:i + BLOCKSIZE]
272             hsh = g(n, hsh, block)
273             chk = add512bit(chk, block)
274             n += 512
275
276         # Padding
277         padblock_size = len(data) * 8 - n
278         data += b"\x01"
279         padlen = BLOCKSIZE - len(data) % BLOCKSIZE
280         if padlen != BLOCKSIZE:
281             data += b"\x00" * padlen
282
283         hsh = g(n, hsh, data[-BLOCKSIZE:])
284         n += padblock_size
285         chk = add512bit(chk, data[-BLOCKSIZE:])
286         hsh = g(0, hsh, pack("<Q", n) + 56 * b"\x00")
287         hsh = g(0, hsh, chk)
288         return hsh[-self._digest_size:]