115 lines
2.3 KiB
Go
115 lines
2.3 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// CMAC message authentication code, defined in
|
|
// NIST Special Publication SP 800-38B.
|
|
|
|
package cmac
|
|
|
|
import (
|
|
"crypto/cipher"
|
|
"hash"
|
|
|
|
"github.com/miscreant/miscreant-go/block"
|
|
)
|
|
|
|
type cmac struct {
|
|
// c is the block cipher we're using (i.e. AES-128 or AES-256)
|
|
c cipher.Block
|
|
|
|
// k1 and k2 are CMAC subkeys (for finishing the tag)
|
|
k1, k2 block.Block
|
|
|
|
// digest contains the PMAC tag-in-progress
|
|
digest block.Block
|
|
|
|
// buffer contains a part of the input message, processed a block-at-a-time
|
|
buf block.Block
|
|
|
|
// pos marks the end of plaintext in the buffer
|
|
pos uint
|
|
}
|
|
|
|
// New returns a new instance of a CMAC message authentication code
|
|
// digest using the given cipher.Block.
|
|
func New(c cipher.Block) hash.Hash {
|
|
if c.BlockSize() != block.Size {
|
|
panic("pmac: invalid cipher block size")
|
|
}
|
|
|
|
d := new(cmac)
|
|
d.c = c
|
|
|
|
// Subkey generation, p. 7
|
|
d.k1.Encrypt(c)
|
|
d.k1.Dbl()
|
|
|
|
copy(d.k2[:], d.k1[:])
|
|
d.k2.Dbl()
|
|
|
|
return d
|
|
}
|
|
|
|
// Reset clears the digest state, starting a new digest.
|
|
func (d *cmac) Reset() {
|
|
d.digest.Clear()
|
|
d.buf.Clear()
|
|
d.pos = 0
|
|
}
|
|
|
|
// Write adds the given data to the digest state.
|
|
func (d *cmac) Write(p []byte) (nn int, err error) {
|
|
nn = len(p)
|
|
left := block.Size - d.pos
|
|
|
|
if uint(len(p)) > left {
|
|
xor(d.buf[d.pos:], p[:left])
|
|
p = p[left:]
|
|
d.buf.Encrypt(d.c)
|
|
d.pos = 0
|
|
}
|
|
|
|
for uint(len(p)) > block.Size {
|
|
xor(d.buf[:], p[:block.Size])
|
|
p = p[block.Size:]
|
|
d.buf.Encrypt(d.c)
|
|
}
|
|
|
|
if len(p) > 0 {
|
|
xor(d.buf[d.pos:], p)
|
|
d.pos += uint(len(p))
|
|
}
|
|
return
|
|
}
|
|
|
|
// Sum returns the CMAC digest, one cipher block in length,
|
|
// of the data written with Write.
|
|
func (d *cmac) Sum(in []byte) []byte {
|
|
// Finish last block, mix in key, encrypt.
|
|
// Don't edit ci, in case caller wants
|
|
// to keep digesting after call to Sum.
|
|
k := d.k1
|
|
if d.pos < uint(len(d.digest)) {
|
|
k = d.k2
|
|
}
|
|
for i := 0; i < len(d.buf); i++ {
|
|
d.digest[i] = d.buf[i] ^ k[i]
|
|
}
|
|
if d.pos < uint(len(d.digest)) {
|
|
d.digest[d.pos] ^= 0x80
|
|
}
|
|
d.digest.Encrypt(d.c)
|
|
return append(in, d.digest[:]...)
|
|
}
|
|
|
|
func (d *cmac) Size() int { return len(d.digest) }
|
|
|
|
func (d *cmac) BlockSize() int { return d.c.BlockSize() }
|
|
|
|
func xor(a, b []byte) {
|
|
for i, v := range b {
|
|
a[i] ^= v
|
|
}
|
|
}
|