X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=gost28147%2Fmac.go;fp=gost28147%2Fmac.go;h=bcfd52c5ed5044d5eee3f08524e5d5bd588e498b;hb=c07494bbd559b9d00f391e28cfd070e18afe9900;hp=0000000000000000000000000000000000000000;hpb=107600dede989f0cc479b5a72c5f97e174307154;p=gogost.git diff --git a/gost28147/mac.go b/gost28147/mac.go new file mode 100644 index 0000000..bcfd52c --- /dev/null +++ b/gost28147/mac.go @@ -0,0 +1,102 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2019 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 3 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost28147 + +import ( + "errors" +) + +var ( + SeqMAC = Seq([]uint8{ + 0, 1, 2, 3, 4, 5, 6, 7, + 0, 1, 2, 3, 4, 5, 6, 7, + }) +) + +type MAC struct { + c *Cipher + size int + iv []byte + prev []byte + buf []byte + n1 nv + n2 nv +} + +// Create MAC with given tag size and initial initialization vector. +// Size is in bytes and must be between 1 and 8. To be RFC conformant, +// iv must be the first block of the authenticated data, second and +// following ones are fed to Write function. +func (c *Cipher) NewMAC(size int, iv []byte) (*MAC, error) { + if size == 0 || size > 8 { + return nil, errors.New("Invalid tag size") + } + if len(iv) != BlockSize { + return nil, errors.New("iv length is not equal to blocksize") + } + m := MAC{c: c, size: size, iv: iv} + n2, n1 := block2nvs(iv) + m.iv = make([]byte, BlockSize) + nvs2block(n1, n2, m.iv) + m.prev = make([]byte, BlockSize) + m.Reset() + return &m, nil +} + +func (m *MAC) Reset() { + copy(m.prev, m.iv) + m.buf = nil +} + +func (m *MAC) BlockSize() int { + return BlockSize +} + +func (m *MAC) Size() int { + return m.size +} + +func (m *MAC) Write(b []byte) (int, error) { + m.buf = append(m.buf, b...) + for len(m.buf) >= BlockSize { + for i := 0; i < BlockSize; i++ { + m.prev[i] ^= m.buf[i] + } + m.n1, m.n2 = block2nvs(m.prev) + m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2) + nvs2block(m.n2, m.n1, m.prev) + m.buf = m.buf[8:] + } + return len(b), nil +} + +func (m *MAC) Sum(b []byte) []byte { + if len(m.buf) == 0 { + return append(b, m.prev[0:m.size]...) + } + buf := m.buf + var i int + for i = 0; i < BlockSize-len(m.buf); i++ { + buf = append(buf, byte(0)) + } + for i = 0; i < BlockSize; i++ { + buf[i] ^= m.prev[i] + } + m.n1, m.n2 = block2nvs(buf) + m.n1, m.n2 = m.c.xcrypt(SeqMAC, m.n1, m.n2) + nvs2block(m.n2, m.n1, buf) + return append(b, buf[0:m.size]...) +}