Skip to content

Commit

Permalink
更新
Browse files Browse the repository at this point in the history
  • Loading branch information
deatil committed Jul 16, 2024
1 parent e21aff6 commit 80befac
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 136 deletions.
123 changes: 42 additions & 81 deletions hash/cmac/cmac.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,13 @@ var (
errInvalidTagSize = errors.New("tags size must between 1 and the cipher's block size")
)

// Sum computes the CMAC checksum with the given tagsize of msg using the cipher.Block.
func Sum(msg []byte, c cipher.Block, tagsize int) ([]byte, error) {
h, err := NewWithTagSize(c, tagsize)
if err != nil {
return nil, err
}

h.Write(msg)
return h.Sum(nil), nil
}

// Verify computes the CMAC checksum with the given tagsize of msg and compares
// it with the given mac. This functions returns true if and only if the given mac
// is equal to the computed one.
func Verify(mac, msg []byte, c cipher.Block, tagsize int) bool {
sum, err := Sum(msg, c, tagsize)
if err != nil {
return false
}

return subtle.ConstantTimeCompare(mac, sum) == 1
// The CMAC message auth. function
type cmac struct {
cipher cipher.Block
k0, k1 []byte
buf []byte
off int
tagsize int
}

// New returns a hash.Hash computing the CMAC checksum.
Expand Down Expand Up @@ -91,7 +77,7 @@ func NewWithTagSize(c cipher.Block, tagsize int) (hash.Hash, error) {
p = p1024
}

m := &macFunc{
m := &cmac{
cipher: c,
k0: make([]byte, blocksize),
k1: make([]byte, blocksize),
Expand All @@ -109,46 +95,37 @@ func NewWithTagSize(c cipher.Block, tagsize int) (hash.Hash, error) {
return m, nil
}

// The CMAC message auth. function
type macFunc struct {
cipher cipher.Block
k0, k1 []byte
buf []byte
off int
tagsize int
}

func (h *macFunc) Size() int {
return h.cipher.BlockSize()
func (d *cmac) Size() int {
return d.tagsize
}

func (h *macFunc) BlockSize() int {
return h.cipher.BlockSize()
func (d *cmac) BlockSize() int {
return d.cipher.BlockSize()
}

func (h *macFunc) Reset() {
for i := range h.buf {
h.buf[i] = 0
func (d *cmac) Reset() {
for i := range d.buf {
d.buf[i] = 0
}
h.off = 0
d.off = 0
}

func (h *macFunc) Write(msg []byte) (int, error) {
bs := h.BlockSize()
func (d *cmac) Write(msg []byte) (int, error) {
bs := d.BlockSize()
n := len(msg)

if h.off > 0 {
dif := bs - h.off
if d.off > 0 {
dif := bs - d.off
if n > dif {
xor(h.buf[h.off:], msg[:dif])
xor(d.buf[d.off:], msg[:dif])

msg = msg[dif:]
h.cipher.Encrypt(h.buf, h.buf)
h.off = 0
d.cipher.Encrypt(d.buf, d.buf)
d.off = 0
} else {
xor(h.buf[h.off:], msg)
xor(d.buf[d.off:], msg)

h.off += n
d.off += n
return n, nil
}
}
Expand All @@ -159,64 +136,48 @@ func (h *macFunc) Write(msg []byte) (int, error) {
nn -= bs
}
for i := 0; i < nn; i += bs {
xor(h.buf, msg[i:i+bs])
xor(d.buf, msg[i:i+bs])

h.cipher.Encrypt(h.buf, h.buf)
d.cipher.Encrypt(d.buf, d.buf)
}
msg = msg[nn:]
}

if length := len(msg); length > 0 {
xor(h.buf[h.off:], msg)
xor(d.buf[d.off:], msg)

h.off += length
d.off += length
}

return n, nil
}

func (h *macFunc) Sum(in []byte) []byte {
func (d *cmac) Sum(in []byte) []byte {
// Make a copy of d so that caller can keep writing and summing.
d := *h
hash := d.checkSum()
d0 := *d
hash := d0.checkSum()
return append(in, hash...)
}

func (h *macFunc) checkSum() []byte {
blocksize := h.cipher.BlockSize()
func (d *cmac) checkSum() []byte {
blocksize := d.cipher.BlockSize()

// Don't change the buffer so the
// caller can keep writing and suming.
hash := make([]byte, blocksize)

if h.off < blocksize {
copy(hash, h.k1)
if d.off < blocksize {
copy(hash, d.k1)
} else {
copy(hash, h.k0)
copy(hash, d.k0)
}

xor(hash, h.buf)
if h.off < blocksize {
hash[h.off] ^= 0x80
xor(hash, d.buf)
if d.off < blocksize {
hash[d.off] ^= 0x80
}

h.cipher.Encrypt(hash, hash)

return hash[:h.tagsize]
}

func shift(dst, src []byte) int {
var b, bit byte
for i := len(src) - 1; i >= 0; i-- { // a range would be nice
bit = src[i] >> 7
dst[i] = src[i]<<1 | b
b = bit
}

return int(b)
}
d.cipher.Encrypt(hash, hash)

// XOR the contents of b into a in-place
func xor(a, b []byte) {
subtle.XORBytes(a, a, b)
return hash[:d.tagsize]
}
86 changes: 85 additions & 1 deletion hash/cmac/cmac_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import (
"encoding/hex"
)

func fromHex(s string) []byte {
res, _ := hex.DecodeString(s)
return res
}

// A cipher.Block mock, simulating block ciphers
// with any block size.
type dummyCipher int
Expand Down Expand Up @@ -80,7 +85,7 @@ func TestReset(t *testing.T) {
if err != nil {
t.Fatalf("Failed to use CMAC with the specified cipher")
}
c, ok := h.(*macFunc)
c, ok := h.(*cmac)
if !ok {
t.Fatal("Impossible situation: New returns no CMAC struct")
}
Expand Down Expand Up @@ -175,6 +180,85 @@ func TestVerify(t *testing.T) {
}
}

type testData struct {
index string
key []byte
tagsize int
msg []byte
check []byte
}

func Test_NewWithTagSize_Check(t *testing.T) {
tests := []testData{
{
index: "tagsize 16",
key: []byte("1234567812345678"),
tagsize: 16,
msg: []byte("message"),
check: fromHex("2eaf00007b76e587b37673fa12c45e74"),
},
{
index: "tagsize 14",
key: []byte("1234567812345678"),
tagsize: 14,
msg: []byte("message"),
check: fromHex("2eaf00007b76e587b37673fa12c4"),
},
{
index: "tagsize 12",
key: []byte("1234567812345678"),
tagsize: 12,
msg: []byte("message"),
check: fromHex("2eaf00007b76e587b37673fa"),
},
{
index: "tagsize 10",
key: []byte("1234567812345678"),
tagsize: 10,
msg: []byte("message"),
check: fromHex("2eaf00007b76e587b376"),
},
{
index: "tagsize 8",
key: []byte("1234567812345678"),
tagsize: 8,
msg: []byte("message"),
check: fromHex("2eaf00007b76e587"),
},
}

for _, td := range tests {
t.Run(td.index, func(t *testing.T) {
c, err := aes.NewCipher(td.key)
if err != nil {
t.Fatalf("Could not create AES instance: %s", err)
}

h, err := NewWithTagSize(c, td.tagsize)
if err != nil {
t.Fatalf("Could not create CMAC instance: %s", err)
}

if size := h.Size(); size != td.tagsize {
t.Fatalf("Size() got: %d, want: %d", size, td.tagsize)
}

if bs := h.BlockSize(); bs != c.BlockSize() {
t.Fatalf("BlockSize() got: %d, want: %d", bs, c.BlockSize())
}

h.Write(td.msg)
res := h.Sum(nil)

if !bytes.Equal(res, td.check) {
t.Fatalf("Sum() got: %x, want: %x", res, td.check)
}
})

}

}

// Benchmarks

func BenchmarkWrite_16B(b *testing.B) { benchmarkWrite(b, 16) }
Expand Down
21 changes: 21 additions & 0 deletions hash/cmac/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cmac

import (
"crypto/subtle"
)

func shift(dst, src []byte) int {
var b, bit byte
for i := len(src) - 1; i >= 0; i-- { // a range would be nice
bit = src[i] >> 7
dst[i] = src[i]<<1 | b
b = bit
}

return int(b)
}

// XOR the contents of b into a in-place
func xor(a, b []byte) {
subtle.XORBytes(a, a, b)
}
29 changes: 29 additions & 0 deletions hash/cmac/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cmac

import (
"crypto/cipher"
"crypto/subtle"
)

// Sum computes the CMAC checksum with the given tagsize of msg using the cipher.Block.
func Sum(msg []byte, c cipher.Block, tagsize int) ([]byte, error) {
h, err := NewWithTagSize(c, tagsize)
if err != nil {
return nil, err
}

h.Write(msg)
return h.Sum(nil), nil
}

// Verify computes the CMAC checksum with the given tagsize of msg and compares
// it with the given mac. This functions returns true if and only if the given mac
// is equal to the computed one.
func Verify(mac, msg []byte, c cipher.Block, tagsize int) bool {
sum, err := Sum(msg, c, tagsize)
if err != nil {
return false
}

return subtle.ConstantTimeCompare(mac, sum) == 1
}
Loading

0 comments on commit 80befac

Please sign in to comment.