doc: Remove i?86-*-linux* installation note from 2003
[official-gcc.git] / libgo / go / crypto / aes / gcm_s390x.go
blobbd1f9a0781dbc8b18eaf271ec3498ae31c46fa33
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // +build ignore
7 package aes
9 import (
10 "crypto/cipher"
11 subtleoverlap "crypto/internal/subtle"
12 "crypto/subtle"
13 "encoding/binary"
14 "errors"
15 "internal/cpu"
18 // This file contains two implementations of AES-GCM. The first implementation
19 // (gcmAsm) uses the KMCTR instruction to encrypt using AES in counter mode and
20 // the KIMD instruction for GHASH. The second implementation (gcmKMA) uses the
21 // newer KMA instruction which performs both operations.
23 // gcmCount represents a 16-byte big-endian count value.
24 type gcmCount [16]byte
26 // inc increments the rightmost 32-bits of the count value by 1.
27 func (x *gcmCount) inc() {
28 binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1)
31 // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array.
32 func gcmLengths(len0, len1 uint64) [16]byte {
33 v := [16]byte{}
34 binary.BigEndian.PutUint64(v[0:], len0)
35 binary.BigEndian.PutUint64(v[8:], len1)
36 return v
39 // gcmHashKey represents the 16-byte hash key required by the GHASH algorithm.
40 type gcmHashKey [16]byte
42 type gcmAsm struct {
43 block *aesCipherAsm
44 hashKey gcmHashKey
45 nonceSize int
46 tagSize int
49 const (
50 gcmBlockSize = 16
51 gcmTagSize = 16
52 gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
53 gcmStandardNonceSize = 12
56 var errOpen = errors.New("cipher: message authentication failed")
58 // Assert that aesCipherAsm implements the gcmAble interface.
59 var _ gcmAble = (*aesCipherAsm)(nil)
61 // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
62 // called by crypto/cipher.NewGCM via the gcmAble interface.
63 func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
64 var hk gcmHashKey
65 c.Encrypt(hk[:], hk[:])
66 g := gcmAsm{
67 block: c,
68 hashKey: hk,
69 nonceSize: nonceSize,
70 tagSize: tagSize,
72 if cpu.S390X.HasAESGCM {
73 g := gcmKMA{g}
74 return &g, nil
76 return &g, nil
79 func (g *gcmAsm) NonceSize() int {
80 return g.nonceSize
83 func (g *gcmAsm) Overhead() int {
84 return g.tagSize
87 // sliceForAppend takes a slice and a requested number of bytes. It returns a
88 // slice with the contents of the given slice followed by that many bytes and a
89 // second slice that aliases into it and contains only the extra bytes. If the
90 // original slice has sufficient capacity then no allocation is performed.
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)
98 tail = head[len(in):]
99 return
102 // ghash uses the GHASH algorithm to hash data with the given key. The initial
103 // hash value is given by hash which will be updated with the new hash value.
104 // The length of data must be a multiple of 16-bytes.
105 //go:noescape
106 func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
108 // paddedGHASH pads data with zeroes until its length is a multiple of
109 // 16-bytes. It then calculates a new value for hash using the GHASH algorithm.
110 func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
111 siz := len(data) &^ 0xf // align size to 16-bytes
112 if siz > 0 {
113 ghash(&g.hashKey, hash, data[:siz])
114 data = data[siz:]
116 if len(data) > 0 {
117 var s [16]byte
118 copy(s[:], data)
119 ghash(&g.hashKey, hash, s[:])
123 // cryptBlocksGCM encrypts src using AES in counter mode using the given
124 // function code and key. The rightmost 32-bits of the counter are incremented
125 // between each block as required by the GCM spec. The initial counter value
126 // is given by cnt, which is updated with the value of the next counter value
127 // to use.
129 // The lengths of both dst and buf must be greater than or equal to the length
130 // of src. buf may be partially or completely overwritten during the execution
131 // of the function.
132 //go:noescape
133 func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount)
135 // counterCrypt encrypts src using AES in counter mode and places the result
136 // into dst. cnt is the initial count value and will be updated with the next
137 // count value. The length of dst must be greater than or equal to the length
138 // of src.
139 func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) {
140 // Copying src into a buffer improves performance on some models when
141 // src and dst point to the same underlying array. We also need a
142 // buffer for counter values.
143 var ctrbuf, srcbuf [2048]byte
144 for len(src) >= 16 {
145 siz := len(src)
146 if len(src) > len(ctrbuf) {
147 siz = len(ctrbuf)
149 siz &^= 0xf // align siz to 16-bytes
150 copy(srcbuf[:], src[:siz])
151 cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt)
152 src = src[siz:]
153 dst = dst[siz:]
155 if len(src) > 0 {
156 var x [16]byte
157 g.block.Encrypt(x[:], cnt[:])
158 for i := range src {
159 dst[i] = src[i] ^ x[i]
161 cnt.inc()
165 // deriveCounter computes the initial GCM counter state from the given nonce.
166 // See NIST SP 800-38D, section 7.1.
167 func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount {
168 // GCM has two modes of operation with respect to the initial counter
169 // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
170 // for nonces of other lengths. For a 96-bit nonce, the nonce, along
171 // with a four-byte big-endian counter starting at one, is used
172 // directly as the starting counter. For other nonce sizes, the counter
173 // is computed by passing it through the GHASH function.
174 var counter gcmCount
175 if len(nonce) == gcmStandardNonceSize {
176 copy(counter[:], nonce)
177 counter[gcmBlockSize-1] = 1
178 } else {
179 var hash [16]byte
180 g.paddedGHASH(&hash, nonce)
181 lens := gcmLengths(0, uint64(len(nonce))*8)
182 g.paddedGHASH(&hash, lens[:])
183 copy(counter[:], hash[:])
185 return counter
188 // auth calculates GHASH(ciphertext, additionalData), masks the result with
189 // tagMask and writes the result to out.
190 func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
191 var hash [16]byte
192 g.paddedGHASH(&hash, additionalData)
193 g.paddedGHASH(&hash, ciphertext)
194 lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8)
195 g.paddedGHASH(&hash, lens[:])
197 copy(out, hash[:])
198 for i := range out {
199 out[i] ^= tagMask[i]
203 // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
204 // details.
205 func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
206 if len(nonce) != g.nonceSize {
207 panic("crypto/cipher: incorrect nonce length given to GCM")
209 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
210 panic("crypto/cipher: message too large for GCM")
213 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
214 if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
215 panic("crypto/cipher: invalid buffer overlap")
218 counter := g.deriveCounter(nonce)
220 var tagMask [gcmBlockSize]byte
221 g.block.Encrypt(tagMask[:], counter[:])
222 counter.inc()
224 var tagOut [gcmTagSize]byte
225 g.counterCrypt(out, plaintext, &counter)
226 g.auth(tagOut[:], out[:len(plaintext)], data, &tagMask)
227 copy(out[len(plaintext):], tagOut[:])
229 return ret
232 // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
233 // for details.
234 func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
235 if len(nonce) != g.nonceSize {
236 panic("crypto/cipher: incorrect nonce length given to GCM")
238 // Sanity check to prevent the authentication from always succeeding if an implementation
239 // leaves tagSize uninitialized, for example.
240 if g.tagSize < gcmMinimumTagSize {
241 panic("crypto/cipher: incorrect GCM tag size")
243 if len(ciphertext) < g.tagSize {
244 return nil, errOpen
246 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
247 return nil, errOpen
250 tag := ciphertext[len(ciphertext)-g.tagSize:]
251 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
253 counter := g.deriveCounter(nonce)
255 var tagMask [gcmBlockSize]byte
256 g.block.Encrypt(tagMask[:], counter[:])
257 counter.inc()
259 var expectedTag [gcmTagSize]byte
260 g.auth(expectedTag[:], ciphertext, data, &tagMask)
262 ret, out := sliceForAppend(dst, len(ciphertext))
263 if subtleoverlap.InexactOverlap(out, ciphertext) {
264 panic("crypto/cipher: invalid buffer overlap")
267 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
268 // The AESNI code decrypts and authenticates concurrently, and
269 // so overwrites dst in the event of a tag mismatch. That
270 // behavior is mimicked here in order to be consistent across
271 // platforms.
272 for i := range out {
273 out[i] = 0
275 return nil, errOpen
278 g.counterCrypt(out, ciphertext, &counter)
279 return ret, nil
282 // gcmKMA implements the cipher.AEAD interface using the KMA instruction. It should
283 // only be used if hasKMA is true.
284 type gcmKMA struct {
285 gcmAsm
288 // flags for the KMA instruction
289 const (
290 kmaHS = 1 << 10 // hash subkey supplied
291 kmaLAAD = 1 << 9 // last series of additional authenticated data
292 kmaLPC = 1 << 8 // last series of plaintext or ciphertext blocks
293 kmaDecrypt = 1 << 7 // decrypt
296 // kmaGCM executes the encryption or decryption operation given by fn. The tag
297 // will be calculated and written to tag. cnt should contain the current
298 // counter state and will be overwritten with the updated counter state.
299 // TODO(mundaym): could pass in hash subkey
300 //go:noescape
301 func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount)
303 // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
304 // details.
305 func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
306 if len(nonce) != g.nonceSize {
307 panic("crypto/cipher: incorrect nonce length given to GCM")
309 if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
310 panic("crypto/cipher: message too large for GCM")
313 ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
314 if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
315 panic("crypto/cipher: invalid buffer overlap")
318 counter := g.deriveCounter(nonce)
319 fc := g.block.function | kmaLAAD | kmaLPC
321 var tag [gcmTagSize]byte
322 kmaGCM(fc, g.block.key, out[:len(plaintext)], plaintext, data, &tag, &counter)
323 copy(out[len(plaintext):], tag[:])
325 return ret
328 // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
329 // for details.
330 func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
331 if len(nonce) != g.nonceSize {
332 panic("crypto/cipher: incorrect nonce length given to GCM")
334 if len(ciphertext) < g.tagSize {
335 return nil, errOpen
337 if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
338 return nil, errOpen
341 tag := ciphertext[len(ciphertext)-g.tagSize:]
342 ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
343 ret, out := sliceForAppend(dst, len(ciphertext))
344 if subtleoverlap.InexactOverlap(out, ciphertext) {
345 panic("crypto/cipher: invalid buffer overlap")
348 if g.tagSize < gcmMinimumTagSize {
349 panic("crypto/cipher: incorrect GCM tag size")
352 counter := g.deriveCounter(nonce)
353 fc := g.block.function | kmaLAAD | kmaLPC | kmaDecrypt
355 var expectedTag [gcmTagSize]byte
356 kmaGCM(fc, g.block.key, out[:len(ciphertext)], ciphertext, data, &expectedTag, &counter)
358 if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
359 // The AESNI code decrypts and authenticates concurrently, and
360 // so overwrites dst in the event of a tag mismatch. That
361 // behavior is mimicked here in order to be consistent across
362 // platforms.
363 for i := range out {
364 out[i] = 0
366 return nil, errOpen
369 return ret, nil