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