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 "encoding/binary"
13 "errors"
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, 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 = binary.LittleEndian.Uint64(hle[:8])
70 h2 = binary.LittleEndian.Uint64(hle[8:])
71 } else {
72 h1 = binary.BigEndian.Uint64(hle[:8])
73 h2 = binary.BigEndian.Uint64(hle[8:])
74 }
75 binary.BigEndian.PutUint64(hle[:8], h1)
76 binary.BigEndian.PutUint64(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(len(g.cipher.enc)/4-1, out, in, counter, &g.cipher.enc[0])
123 }
124
125
126 func gcmInc32(counterBlock *[16]byte) {
127 c := counterBlock[len(counterBlock)-4:]
128 x := binary.BigEndian.Uint32(c) + 1
129 binary.BigEndian.PutUint32(c, x)
130 }
131
132
133
134
135 func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
136 if siz := len(data) - (len(data) % gcmBlockSize); siz > 0 {
137 gcmHash(hash[:], &g.productTable, data[:], siz)
138 data = data[siz:]
139 }
140 if len(data) > 0 {
141 var s [16]byte
142 copy(s[:], data)
143 gcmHash(hash[:], &g.productTable, s[:], len(s))
144 }
145 }
146
147
148
149 func (g *gcmAsm) auth(out, ciphertext, aad []byte, tagMask *[gcmTagSize]byte) {
150 var hash [16]byte
151 g.paddedGHASH(&hash, aad)
152 g.paddedGHASH(&hash, ciphertext)
153 lens := gcmLengths(uint64(len(aad))*8, uint64(len(ciphertext))*8)
154 g.paddedGHASH(&hash, lens[:])
155
156 copy(out, hash[:])
157 for i := range out {
158 out[i] ^= tagMask[i]
159 }
160 }
161
162
163
164 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
165 if len(nonce) != g.nonceSize {
166 panic("cipher: incorrect nonce length given to GCM")
167 }
168 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
169 panic("cipher: message too large for GCM")
170 }
171
172 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
173
174 var counter, tagMask [gcmBlockSize]byte
175 g.deriveCounter(&counter, nonce)
176
177 g.cipher.Encrypt(tagMask[:], counter[:])
178 gcmInc32(&counter)
179
180 g.counterCrypt(out, plaintext, &counter)
181 g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask)
182
183 return ret
184 }
185
186
187
188 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
189 if len(nonce) != g.nonceSize {
190 panic("cipher: incorrect nonce length given to GCM")
191 }
192 if len(ciphertext) < g.tagSize {
193 return nil, errOpen
194 }
195 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
196 return nil, errOpen
197 }
198
199 tag := ciphertext[len(ciphertext)-g.tagSize:]
200 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
201
202 var counter, tagMask [gcmBlockSize]byte
203 g.deriveCounter(&counter, nonce)
204
205 g.cipher.Encrypt(tagMask[:], counter[:])
206 gcmInc32(&counter)
207
208 var expectedTag [gcmTagSize]byte
209 g.auth(expectedTag[:], ciphertext, data, &tagMask)
210
211 ret, out := sliceForAppend(dst, len(ciphertext))
212
213 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
214 for i := range out {
215 out[i] = 0
216 }
217 return nil, errOpen
218 }
219
220 g.counterCrypt(out, ciphertext, &counter)
221 return ret, nil
222 }
223
224 func gcmLengths(len0, len1 uint64) [16]byte {
225 return [16]byte{
226 byte(len0 >> 56),
227 byte(len0 >> 48),
228 byte(len0 >> 40),
229 byte(len0 >> 32),
230 byte(len0 >> 24),
231 byte(len0 >> 16),
232 byte(len0 >> 8),
233 byte(len0),
234 byte(len1 >> 56),
235 byte(len1 >> 48),
236 byte(len1 >> 40),
237 byte(len1 >> 32),
238 byte(len1 >> 24),
239 byte(len1 >> 16),
240 byte(len1 >> 8),
241 byte(len1),
242 }
243 }
244
View as plain text