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