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