]> Cypherpunks.ru repositories - pygost.git/blob - pygost/gost28147_mac.py
Unify docstring's leading space presence
[pygost.git] / pygost / gost28147_mac.py
1 # coding: utf-8
2 # PyGOST -- Pure Python GOST cryptographic functions library
3 # Copyright (C) 2015-2020 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 28147-89 MAC
17 """
18
19 from copy import copy
20
21 from pygost.gost28147 import block2ns
22 from pygost.gost28147 import BLOCKSIZE
23 from pygost.gost28147 import DEFAULT_SBOX
24 from pygost.gost28147 import ns2block
25 from pygost.gost28147 import validate_iv
26 from pygost.gost28147 import validate_key
27 from pygost.gost28147 import validate_sbox
28 from pygost.gost28147 import xcrypt
29 from pygost.gost3413 import pad1
30 from pygost.iface import PEP247
31 from pygost.utils import strxor
32 from pygost.utils import xrange
33
34 digest_size = 8
35 SEQ_MAC = (
36     0, 1, 2, 3, 4, 5, 6, 7,
37     0, 1, 2, 3, 4, 5, 6, 7,
38 )
39
40
41 class MAC(PEP247):
42     """GOST 28147-89 MAC mode of operation
43
44     >>> m = MAC(key=key)
45     >>> m.update("some data")
46     >>> m.update("another data")
47     >>> m.hexdigest()[:8]
48     'a687a08b'
49     """
50     digest_size = digest_size
51
52     def __init__(self, key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX):
53         """
54         :param key: authentication key
55         :type key: bytes, 32 bytes
56         :param iv: initialization vector
57         :type iv: bytes, BLOCKSIZE length
58         :param sbox: S-box parameters to use
59         :type sbox: str, SBOXES'es key
60         """
61         validate_key(key)
62         validate_iv(iv)
63         validate_sbox(sbox)
64         self.key = key
65         self.data = data
66         self.iv = iv
67         self.sbox = sbox
68
69     def copy(self):
70         return MAC(self.key, copy(self.data), self.iv, self.sbox)
71
72     def update(self, data):
73         """Append data that has to be authenticated
74         """
75         self.data += data
76
77     def digest(self):
78         """Get MAC tag of supplied data
79
80         You have to provide at least single byte of data.
81         If you want to produce tag length of 3 bytes, then
82         ``digest()[:3]``.
83         """
84         if not self.data:
85             raise ValueError("No data processed")
86         data = pad1(self.data, BLOCKSIZE)
87         prev = block2ns(self.iv)[::-1]
88         for i in xrange(0, len(data), BLOCKSIZE):
89             prev = xcrypt(
90                 SEQ_MAC, self.sbox, self.key, block2ns(strxor(
91                     data[i:i + BLOCKSIZE],
92                     ns2block(prev),
93                 )),
94             )[::-1]
95         return ns2block(prev)
96
97
98 def new(key, data=b"", iv=8 * b"\x00", sbox=DEFAULT_SBOX):
99     return MAC(key, data, iv, sbox)