]> Cypherpunks.ru repositories - gogost.git/blob - gost28147/mac.go
b49bc7d305f67f720f2cb0cfc2d37cc0bb3795c7
[gogost.git] / gost28147 / mac.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2019 Sergey Matveev <stargrave@stargrave.org>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, version 3 of the License.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 package gost28147
17
18 import (
19         "errors"
20 )
21
22 var (
23         SeqMAC = Seq([]uint8{
24                 0, 1, 2, 3, 4, 5, 6, 7,
25                 0, 1, 2, 3, 4, 5, 6, 7,
26         })
27 )
28
29 type MAC struct {
30         c    *Cipher
31         size int
32         iv   []byte
33         prev []byte
34         buf  []byte
35         n1   nv
36         n2   nv
37 }
38
39 // Create MAC with given tag size and initial initialization vector.
40 // Size is in bytes and must be between 1 and 8. To be RFC conformant,
41 // iv must be the first block of the authenticated data, second and
42 // following ones are fed to Write function.
43 func (c *Cipher) NewMAC(size int, iv []byte) (*MAC, error) {
44         if size == 0 || size > 8 {
45                 return nil, errors.New("gogost/gost28147: invalid tag size")
46         }
47         if len(iv) != BlockSize {
48                 return nil, errors.New("gogost/gost28147: len(iv) != 8")
49         }
50         m := MAC{c: c, size: size, iv: iv}
51         n2, n1 := block2nvs(iv)
52         m.iv = make([]byte, BlockSize)
53         nvs2block(n1, n2, m.iv)
54         m.prev = make([]byte, BlockSize)
55         m.Reset()
56         return &m, nil
57 }
58
59 func (m *MAC) Reset() {
60         copy(m.prev, m.iv)
61         m.buf = nil
62 }
63
64 func (m *MAC) BlockSize() int {
65         return BlockSize
66 }
67
68 func (m *MAC) Size() int {
69         return m.size
70 }
71
72 func (m *MAC) Write(b []byte) (int, error) {
73         m.buf = append(m.buf, b...)
74         for len(m.buf) >= BlockSize {
75                 for i := 0; i < BlockSize; i++ {
76                         m.prev[i] ^= m.buf[i]
77                 }
78                 m.n1, m.n2 = block2nvs(m.prev)
79                 m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2)
80                 nvs2block(m.n2, m.n1, m.prev)
81                 m.buf = m.buf[8:]
82         }
83         return len(b), nil
84 }
85
86 func (m *MAC) Sum(b []byte) []byte {
87         if len(m.buf) == 0 {
88                 return append(b, m.prev[0:m.size]...)
89         }
90         buf := m.buf
91         var i int
92         for i = 0; i < BlockSize-len(m.buf); i++ {
93                 buf = append(buf, byte(0))
94         }
95         for i = 0; i < BlockSize; i++ {
96                 buf[i] ^= m.prev[i]
97         }
98         m.n1, m.n2 = block2nvs(buf)
99         m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2)
100         nvs2block(m.n2, m.n1, buf)
101         return append(b, buf[0:m.size]...)
102 }