This repository has been archived by the owner on Feb 5, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
cmac.go
114 lines (91 loc) · 2.31 KB
/
cmac.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 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
}
}