-
Notifications
You must be signed in to change notification settings - Fork 5
/
gmac.go
108 lines (81 loc) · 2.09 KB
/
gmac.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
// Pakcage gmac implements a Galois/Counter Mode (GCM) based MAC, as defined in KS X ISO/IEC 9797-3, NIST SP 800-38D.
package gmac
// Based on https://github.com/golang/go/blob/go1.21.6/src/crypto/cipher/gcm.go
import (
"crypto/cipher"
"errors"
"hash"
"github.com/RyuaNerin/go-krypto/internal"
ikipher "github.com/RyuaNerin/go-krypto/internal/kipher"
)
var defaultIV [ikipher.GCMStandardNonceSize]byte
// new MAC using GMAC by only passing additional data(aad data).
func NewGMAC(b cipher.Block, iv []byte) (hash.Hash, error) {
kb := ikipher.WrapKipher(b)
if kb.BlockSize() != ikipher.GCMBlockSize {
return nil, errors.New(msgRequired128BitBlockCipher)
}
if len(iv) == 0 {
iv = defaultIV[:]
}
g := new(ghash)
g.gcm.Init(kb)
var counter [ikipher.GCMBlockSize]byte
g.gcm.DeriveCounter(&counter, iv)
kb.Encrypt(g.tagMask[:], counter[:])
return g, nil
}
type ghash struct {
gcm ikipher.GCM
tagMask [ikipher.GCMBlockSize]byte
y ikipher.GCMFieldElement
remains [ikipher.GCMBlockSize]byte
remainIdx int
written int
}
func (g ghash) Size() int {
return ikipher.GCMBlockSize
}
func (g ghash) BlockSize() int {
return ikipher.GCMBlockSize
}
func (g *ghash) Reset() {
g.y = ikipher.GCMFieldElement{}
g.remainIdx = 0
g.written = 0
}
func (g *ghash) Write(b []byte) (n int, err error) {
if g.remainIdx > 0 {
n = copy(g.remains[g.remainIdx:], b)
g.written += n
g.remainIdx += n
if g.remainIdx < ikipher.GCMBlockSize {
return n, nil
}
b = b[n:]
g.gcm.Update(&g.y, g.remains[:])
g.remainIdx = 0
}
fullBlocks := (len(b) / ikipher.GCMBlockSize) * ikipher.GCMBlockSize
if fullBlocks > 0 {
g.gcm.Update(&g.y, b[:fullBlocks])
n += fullBlocks
g.written += fullBlocks
b = b[fullBlocks:]
}
if len(b) > 0 {
g.remainIdx = copy(g.remains[:], b)
n += g.remainIdx
}
return
}
func (g *ghash) Sum(b []byte) []byte {
yy := g.y
written := g.written + g.remainIdx
if g.remainIdx > 0 {
g.gcm.Update(&yy, g.remains[:g.remainIdx])
}
ret, out := internal.SliceForAppend(b, len(b)+ikipher.GCMBlockSize)
g.gcm.Finish(out, &yy, 0, written, &g.tagMask)
return ret
}