Source file
src/crypto/aes/gcm_ppc64x.go
1
2
3
4
5
6
7 package aes
8
9 import (
10 "crypto/cipher"
11 "crypto/internal/alias"
12 "crypto/subtle"
13 "errors"
14 "internal/byteorder"
15 "runtime"
16 )
17
18
19
20
21 func gcmInit(productTable *[256]byte, h []byte)
22
23
24 func gcmHash(output []byte, productTable *[256]byte, inp []byte, len int)
25
26
27 func gcmMul(output []byte, productTable *[256]byte)
28
29 const (
30 gcmCounterSize = 16
31 gcmBlockSize = 16
32 gcmTagSize = 16
33 gcmStandardNonceSize = 12
34 )
35
36 var errOpen = errors.New("cipher: message authentication failed")
37
38
39 var _ gcmAble = (*aesCipherAsm)(nil)
40
41 type gcmAsm struct {
42 cipher *aesCipherAsm
43
44
45 ks []uint32
46
47
48 productTable [256]byte
49
50 nonceSize int
51
52 tagSize int
53 }
54
55 func counterCryptASM(nr int, out, in []byte, counter *[gcmBlockSize]byte, key *uint32)
56
57
58
59 func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
60 var h1, h2 uint64
61 g := &gcmAsm{cipher: c, ks: c.enc[:c.l], nonceSize: nonceSize, tagSize: tagSize}
62
63 hle := make([]byte, gcmBlockSize)
64
65 c.Encrypt(hle, hle)
66
67
68
69 if runtime.GOARCH == "ppc64le" {
70 h1 = byteorder.LeUint64(hle[:8])
71 h2 = byteorder.LeUint64(hle[8:])
72 } else {
73 h1 = byteorder.BeUint64(hle[:8])
74 h2 = byteorder.BeUint64(hle[8:])
75 }
76 byteorder.BePutUint64(hle[:8], h1)
77 byteorder.BePutUint64(hle[8:], h2)
78 gcmInit(&g.productTable, hle)
79
80 return g, nil
81 }
82
83 func (g *gcmAsm) NonceSize() int {
84 return g.nonceSize
85 }
86
87 func (g *gcmAsm) Overhead() int {
88 return g.tagSize
89 }
90
91 func sliceForAppend(in []byte, n int) (head, tail []byte) {
92 if total := len(in) + n; cap(in) >= total {
93 head = in[:total]
94 } else {
95 head = make([]byte, total)
96 copy(head, in)
97 }
98 tail = head[len(in):]
99 return
100 }
101
102
103 func (g *gcmAsm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
104 if len(nonce) == gcmStandardNonceSize {
105 copy(counter[:], nonce)
106 counter[gcmBlockSize-1] = 1
107 } else {
108 var hash [16]byte
109 g.paddedGHASH(&hash, nonce)
110 lens := gcmLengths(0, uint64(len(nonce))*8)
111 g.paddedGHASH(&hash, lens[:])
112 copy(counter[:], hash[:])
113 }
114 }
115
116
117
118
119
120
121
122 func (g *gcmAsm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
123 counterCryptASM(int(g.cipher.l)/4-1, out, in, counter, &g.cipher.enc[0])
124
125 }
126
127
128 func gcmInc32(counterBlock *[16]byte) {
129 c := counterBlock[len(counterBlock)-4:]
130 x := byteorder.BeUint32(c) + 1
131 byteorder.BePutUint32(c, x)
132 }
133
134
135
136
137 func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
138 if siz := len(data) - (len(data) % gcmBlockSize); siz > 0 {
139 gcmHash(hash[:], &g.productTable, data[:], siz)
140 data = data[siz:]
141 }
142 if len(data) > 0 {
143 var s [16]byte
144 copy(s[:], data)
145 gcmHash(hash[:], &g.productTable, s[:], len(s))
146 }
147 }
148
149
150
151 func (g *gcmAsm) auth(out, ciphertext, aad []byte, tagMask *[gcmTagSize]byte) {
152 var hash [16]byte
153 g.paddedGHASH(&hash, aad)
154 g.paddedGHASH(&hash, ciphertext)
155 lens := gcmLengths(uint64(len(aad))*8, uint64(len(ciphertext))*8)
156 g.paddedGHASH(&hash, lens[:])
157
158 copy(out, hash[:])
159 for i := range out {
160 out[i] ^= tagMask[i]
161 }
162 }
163
164
165
166 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
167 if len(nonce) != g.nonceSize {
168 panic("cipher: incorrect nonce length given to GCM")
169 }
170 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
171 panic("cipher: message too large for GCM")
172 }
173
174 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
175 if alias.InexactOverlap(out[:len(plaintext)], plaintext) {
176 panic("crypto/cipher: invalid buffer overlap")
177 }
178
179 var counter, tagMask [gcmBlockSize]byte
180 g.deriveCounter(&counter, nonce)
181
182 g.cipher.Encrypt(tagMask[:], counter[:])
183 gcmInc32(&counter)
184
185 g.counterCrypt(out, plaintext, &counter)
186 g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask)
187
188 return ret
189 }
190
191
192
193 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
194 if len(nonce) != g.nonceSize {
195 panic("cipher: incorrect nonce length given to GCM")
196 }
197 if len(ciphertext) < g.tagSize {
198 return nil, errOpen
199 }
200 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
201 return nil, errOpen
202 }
203
204 tag := ciphertext[len(ciphertext)-g.tagSize:]
205 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
206
207 var counter, tagMask [gcmBlockSize]byte
208 g.deriveCounter(&counter, nonce)
209
210 g.cipher.Encrypt(tagMask[:], counter[:])
211 gcmInc32(&counter)
212
213 var expectedTag [gcmTagSize]byte
214 g.auth(expectedTag[:], ciphertext, data, &tagMask)
215
216 ret, out := sliceForAppend(dst, len(ciphertext))
217 if alias.InexactOverlap(out, ciphertext) {
218 panic("crypto/cipher: invalid buffer overlap")
219 }
220
221 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
222 clear(out)
223 return nil, errOpen
224 }
225
226 g.counterCrypt(out, ciphertext, &counter)
227 return ret, nil
228 }
229
230 func gcmLengths(len0, len1 uint64) [16]byte {
231 return [16]byte{
232 byte(len0 >> 56),
233 byte(len0 >> 48),
234 byte(len0 >> 40),
235 byte(len0 >> 32),
236 byte(len0 >> 24),
237 byte(len0 >> 16),
238 byte(len0 >> 8),
239 byte(len0),
240 byte(len1 >> 56),
241 byte(len1 >> 48),
242 byte(len1 >> 40),
243 byte(len1 >> 32),
244 byte(len1 >> 24),
245 byte(len1 >> 16),
246 byte(len1 >> 8),
247 byte(len1),
248 }
249 }
250
View as plain text