]> Cypherpunks.ru repositories - gogost.git/blob - src/cypherpunks.ru/gogost/gost28147/mac.go
Simplify keys and IVs arguments passing: use slices instead of arrays
[gogost.git] / src / cypherpunks.ru / gogost / 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, either version 3 of the License, or
7 // (at your option) any later version.
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
17 package gost28147
18
19 import (
20         "errors"
21 )
22
23 var (
24         SeqMAC = Seq([]uint8{
25                 0, 1, 2, 3, 4, 5, 6, 7,
26                 0, 1, 2, 3, 4, 5, 6, 7,
27         })
28 )
29
30 type MAC struct {
31         c    *Cipher
32         size int
33         iv   []byte
34         prev []byte
35         buf  []byte
36         n1   nv
37         n2   nv
38 }
39
40 // Create MAC with given tag size and initial initialization vector.
41 // Size is in bytes and must be between 1 and 8. To be RFC conformant,
42 // iv must be the first block of the authenticated data, second and
43 // following ones are fed to Write function.
44 func (c *Cipher) NewMAC(size int, iv []byte) (*MAC, error) {
45         if size == 0 || size > 8 {
46                 return nil, errors.New("Invalid tag size")
47         }
48         if len(iv) != BlockSize {
49                 return nil, errors.New("iv length is not equal to blocksize")
50         }
51         m := MAC{c: c, size: size, iv: iv}
52         n2, n1 := block2nvs(iv)
53         m.iv = make([]byte, BlockSize)
54         nvs2block(n1, n2, m.iv)
55         m.prev = make([]byte, BlockSize)
56         m.Reset()
57         return &m, nil
58 }
59
60 func (m *MAC) Reset() {
61         copy(m.prev, m.iv)
62         m.buf = nil
63 }
64
65 func (m *MAC) BlockSize() int {
66         return BlockSize
67 }
68
69 func (m *MAC) Size() int {
70         return m.size
71 }
72
73 func (m *MAC) Write(b []byte) (int, error) {
74         m.buf = append(m.buf, b...)
75         for len(m.buf) >= BlockSize {
76                 for i := 0; i < BlockSize; i++ {
77                         m.prev[i] ^= m.buf[i]
78                 }
79                 m.n1, m.n2 = block2nvs(m.prev)
80                 m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2)
81                 nvs2block(m.n2, m.n1, m.prev)
82                 m.buf = m.buf[8:]
83         }
84         return len(b), nil
85 }
86
87 func (m *MAC) Sum(b []byte) []byte {
88         if len(m.buf) == 0 {
89                 return append(b, m.prev[0:m.size]...)
90         }
91         buf := m.buf
92         var i int
93         for i = 0; i < BlockSize-len(m.buf); i++ {
94                 buf = append(buf, byte(0))
95         }
96         for i = 0; i < BlockSize; i++ {
97                 buf[i] ^= m.prev[i]
98         }
99         m.n1, m.n2 = block2nvs(buf)
100         m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2)
101         nvs2block(m.n2, m.n1, buf)
102         return append(b, buf[0:m.size]...)
103 }