...
Run Format

Source file src/crypto/aes/gcm_s390x.go

Documentation: crypto/aes

     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.
     4  
     5  package aes
     6  
     7  import (
     8  	"crypto/cipher"
     9  	subtleoverlap "crypto/internal/subtle"
    10  	"crypto/subtle"
    11  	"errors"
    12  	"internal/cpu"
    13  )
    14  
    15  // This file contains two implementations of AES-GCM. The first implementation
    16  // (gcmAsm) uses the KMCTR instruction to encrypt using AES in counter mode and
    17  // the KIMD instruction for GHASH. The second implementation (gcmKMA) uses the
    18  // newer KMA instruction which performs both operations.
    19  
    20  // gcmCount represents a 16-byte big-endian count value.
    21  type gcmCount [16]byte
    22  
    23  // inc increments the rightmost 32-bits of the count value by 1.
    24  func (x *gcmCount) inc() {
    25  	// The compiler should optimize this to a 32-bit addition.
    26  	n := uint32(x[15]) | uint32(x[14])<<8 | uint32(x[13])<<16 | uint32(x[12])<<24
    27  	n += 1
    28  	x[12] = byte(n >> 24)
    29  	x[13] = byte(n >> 16)
    30  	x[14] = byte(n >> 8)
    31  	x[15] = byte(n)
    32  }
    33  
    34  // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array.
    35  func gcmLengths(len0, len1 uint64) [16]byte {
    36  	return [16]byte{
    37  		byte(len0 >> 56),
    38  		byte(len0 >> 48),
    39  		byte(len0 >> 40),
    40  		byte(len0 >> 32),
    41  		byte(len0 >> 24),
    42  		byte(len0 >> 16),
    43  		byte(len0 >> 8),
    44  		byte(len0),
    45  		byte(len1 >> 56),
    46  		byte(len1 >> 48),
    47  		byte(len1 >> 40),
    48  		byte(len1 >> 32),
    49  		byte(len1 >> 24),
    50  		byte(len1 >> 16),
    51  		byte(len1 >> 8),
    52  		byte(len1),
    53  	}
    54  }
    55  
    56  // gcmHashKey represents the 16-byte hash key required by the GHASH algorithm.
    57  type gcmHashKey [16]byte
    58  
    59  type gcmAsm struct {
    60  	block     *aesCipherAsm
    61  	hashKey   gcmHashKey
    62  	nonceSize int
    63  	tagSize   int
    64  }
    65  
    66  const (
    67  	gcmBlockSize         = 16
    68  	gcmTagSize           = 16
    69  	gcmMinimumTagSize    = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
    70  	gcmStandardNonceSize = 12
    71  )
    72  
    73  var errOpen = errors.New("cipher: message authentication failed")
    74  
    75  // Assert that aesCipherAsm implements the gcmAble interface.
    76  var _ gcmAble = (*aesCipherAsm)(nil)
    77  
    78  // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
    79  // called by crypto/cipher.NewGCM via the gcmAble interface.
    80  func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
    81  	var hk gcmHashKey
    82  	c.Encrypt(hk[:], hk[:])
    83  	g := gcmAsm{
    84  		block:     c,
    85  		hashKey:   hk,
    86  		nonceSize: nonceSize,
    87  		tagSize:   tagSize,
    88  	}
    89  	if cpu.S390X.HasAESGCM {
    90  		g := gcmKMA{g}
    91  		return &g, nil
    92  	}
    93  	return &g, nil
    94  }
    95  
    96  func (g *gcmAsm) NonceSize() int {
    97  	return g.nonceSize
    98  }
    99  
   100  func (g *gcmAsm) Overhead() int {
   101  	return g.tagSize
   102  }
   103  
   104  // sliceForAppend takes a slice and a requested number of bytes. It returns a
   105  // slice with the contents of the given slice followed by that many bytes and a
   106  // second slice that aliases into it and contains only the extra bytes. If the
   107  // original slice has sufficient capacity then no allocation is performed.
   108  func sliceForAppend(in []byte, n int) (head, tail []byte) {
   109  	if total := len(in) + n; cap(in) >= total {
   110  		head = in[:total]
   111  	} else {
   112  		head = make([]byte, total)
   113  		copy(head, in)
   114  	}
   115  	tail = head[len(in):]
   116  	return
   117  }
   118  
   119  // ghash uses the GHASH algorithm to hash data with the given key. The initial
   120  // hash value is given by hash which will be updated with the new hash value.
   121  // The length of data must be a multiple of 16-bytes.
   122  //go:noescape
   123  func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
   124  
   125  // paddedGHASH pads data with zeroes until its length is a multiple of
   126  // 16-bytes. It then calculates a new value for hash using the GHASH algorithm.
   127  func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
   128  	siz := len(data) &^ 0xf // align size to 16-bytes
   129  	if siz > 0 {
   130  		ghash(&g.hashKey, hash, data[:siz])
   131  		data = data[siz:]
   132  	}
   133  	if len(data) > 0 {
   134  		var s [16]byte
   135  		copy(s[:], data)
   136  		ghash(&g.hashKey, hash, s[:])
   137  	}
   138  }
   139  
   140  // cryptBlocksGCM encrypts src using AES in counter mode using the given
   141  // function code and key. The rightmost 32-bits of the counter are incremented
   142  // between each block as required by the GCM spec. The initial counter value
   143  // is given by cnt, which is updated with the value of the next counter value
   144  // to use.
   145  //
   146  // The lengths of both dst and buf must be greater than or equal to the length
   147  // of src. buf may be partially or completely overwritten during the execution
   148  // of the function.
   149  //go:noescape
   150  func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount)
   151  
   152  // counterCrypt encrypts src using AES in counter mode and places the result
   153  // into dst. cnt is the initial count value and will be updated with the next
   154  // count value. The length of dst must be greater than or equal to the length
   155  // of src.
   156  func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) {
   157  	// Copying src into a buffer improves performance on some models when
   158  	// src and dst point to the same underlying array. We also need a
   159  	// buffer for counter values.
   160  	var ctrbuf, srcbuf [2048]byte
   161  	for len(src) >= 16 {
   162  		siz := len(src)
   163  		if len(src) > len(ctrbuf) {
   164  			siz = len(ctrbuf)
   165  		}
   166  		siz &^= 0xf // align siz to 16-bytes
   167  		copy(srcbuf[:], src[:siz])
   168  		cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt)
   169  		src = src[siz:]
   170  		dst = dst[siz:]
   171  	}
   172  	if len(src) > 0 {
   173  		var x [16]byte
   174  		g.block.Encrypt(x[:], cnt[:])
   175  		for i := range src {
   176  			dst[i] = src[i] ^ x[i]
   177  		}
   178  		cnt.inc()
   179  	}
   180  }
   181  
   182  // deriveCounter computes the initial GCM counter state from the given nonce.
   183  // See NIST SP 800-38D, section 7.1.
   184  func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount {
   185  	// GCM has two modes of operation with respect to the initial counter
   186  	// state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
   187  	// for nonces of other lengths. For a 96-bit nonce, the nonce, along
   188  	// with a four-byte big-endian counter starting at one, is used
   189  	// directly as the starting counter. For other nonce sizes, the counter
   190  	// is computed by passing it through the GHASH function.
   191  	var counter gcmCount
   192  	if len(nonce) == gcmStandardNonceSize {
   193  		copy(counter[:], nonce)
   194  		counter[gcmBlockSize-1] = 1
   195  	} else {
   196  		var hash [16]byte
   197  		g.paddedGHASH(&hash, nonce)
   198  		lens := gcmLengths(0, uint64(len(nonce))*8)
   199  		g.paddedGHASH(&hash, lens[:])
   200  		copy(counter[:], hash[:])
   201  	}
   202  	return counter
   203  }
   204  
   205  // auth calculates GHASH(ciphertext, additionalData), masks the result with
   206  // tagMask and writes the result to out.
   207  func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
   208  	var hash [16]byte
   209  	g.paddedGHASH(&hash, additionalData)
   210  	g.paddedGHASH(&hash, ciphertext)
   211  	lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8)
   212  	g.paddedGHASH(&hash, lens[:])
   213  
   214  	copy(out, hash[:])
   215  	for i := range out {
   216  		out[i] ^= tagMask[i]
   217  	}
   218  }
   219  
   220  // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
   221  // details.
   222  func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
   223  	if len(nonce) != g.nonceSize {
   224  		panic("crypto/cipher: incorrect nonce length given to GCM")
   225  	}
   226  	if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
   227  		panic("crypto/cipher: message too large for GCM")
   228  	}
   229  
   230  	ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
   231  	if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
   232  		panic("crypto/cipher: invalid buffer overlap")
   233  	}
   234  
   235  	counter := g.deriveCounter(nonce)
   236  
   237  	var tagMask [gcmBlockSize]byte
   238  	g.block.Encrypt(tagMask[:], counter[:])
   239  	counter.inc()
   240  
   241  	var tagOut [gcmTagSize]byte
   242  	g.counterCrypt(out, plaintext, &counter)
   243  	g.auth(tagOut[:], out[:len(plaintext)], data, &tagMask)
   244  	copy(out[len(plaintext):], tagOut[:])
   245  
   246  	return ret
   247  }
   248  
   249  // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
   250  // for details.
   251  func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
   252  	if len(nonce) != g.nonceSize {
   253  		panic("crypto/cipher: incorrect nonce length given to GCM")
   254  	}
   255  	// Sanity check to prevent the authentication from always succeeding if an implementation
   256  	// leaves tagSize uninitialized, for example.
   257  	if g.tagSize < gcmMinimumTagSize {
   258  		panic("crypto/cipher: incorrect GCM tag size")
   259  	}
   260  	if len(ciphertext) < g.tagSize {
   261  		return nil, errOpen
   262  	}
   263  	if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
   264  		return nil, errOpen
   265  	}
   266  
   267  	tag := ciphertext[len(ciphertext)-g.tagSize:]
   268  	ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
   269  
   270  	counter := g.deriveCounter(nonce)
   271  
   272  	var tagMask [gcmBlockSize]byte
   273  	g.block.Encrypt(tagMask[:], counter[:])
   274  	counter.inc()
   275  
   276  	var expectedTag [gcmTagSize]byte
   277  	g.auth(expectedTag[:], ciphertext, data, &tagMask)
   278  
   279  	ret, out := sliceForAppend(dst, len(ciphertext))
   280  	if subtleoverlap.InexactOverlap(out, ciphertext) {
   281  		panic("crypto/cipher: invalid buffer overlap")
   282  	}
   283  
   284  	if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
   285  		// The AESNI code decrypts and authenticates concurrently, and
   286  		// so overwrites dst in the event of a tag mismatch. That
   287  		// behavior is mimicked here in order to be consistent across
   288  		// platforms.
   289  		for i := range out {
   290  			out[i] = 0
   291  		}
   292  		return nil, errOpen
   293  	}
   294  
   295  	g.counterCrypt(out, ciphertext, &counter)
   296  	return ret, nil
   297  }
   298  
   299  // gcmKMA implements the cipher.AEAD interface using the KMA instruction. It should
   300  // only be used if hasKMA is true.
   301  type gcmKMA struct {
   302  	gcmAsm
   303  }
   304  
   305  // flags for the KMA instruction
   306  const (
   307  	kmaHS      = 1 << 10 // hash subkey supplied
   308  	kmaLAAD    = 1 << 9  // last series of additional authenticated data
   309  	kmaLPC     = 1 << 8  // last series of plaintext or ciphertext blocks
   310  	kmaDecrypt = 1 << 7  // decrypt
   311  )
   312  
   313  // kmaGCM executes the encryption or decryption operation given by fn. The tag
   314  // will be calculated and written to tag. cnt should contain the current
   315  // counter state and will be overwritten with the updated counter state.
   316  // TODO(mundaym): could pass in hash subkey
   317  //go:noescape
   318  func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount)
   319  
   320  // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
   321  // details.
   322  func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
   323  	if len(nonce) != g.nonceSize {
   324  		panic("crypto/cipher: incorrect nonce length given to GCM")
   325  	}
   326  	if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
   327  		panic("crypto/cipher: message too large for GCM")
   328  	}
   329  
   330  	ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
   331  	if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
   332  		panic("crypto/cipher: invalid buffer overlap")
   333  	}
   334  
   335  	counter := g.deriveCounter(nonce)
   336  	fc := g.block.function | kmaLAAD | kmaLPC
   337  
   338  	var tag [gcmTagSize]byte
   339  	kmaGCM(fc, g.block.key, out[:len(plaintext)], plaintext, data, &tag, &counter)
   340  	copy(out[len(plaintext):], tag[:])
   341  
   342  	return ret
   343  }
   344  
   345  // Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
   346  // for details.
   347  func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
   348  	if len(nonce) != g.nonceSize {
   349  		panic("crypto/cipher: incorrect nonce length given to GCM")
   350  	}
   351  	if len(ciphertext) < g.tagSize {
   352  		return nil, errOpen
   353  	}
   354  	if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
   355  		return nil, errOpen
   356  	}
   357  
   358  	tag := ciphertext[len(ciphertext)-g.tagSize:]
   359  	ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
   360  	ret, out := sliceForAppend(dst, len(ciphertext))
   361  	if subtleoverlap.InexactOverlap(out, ciphertext) {
   362  		panic("crypto/cipher: invalid buffer overlap")
   363  	}
   364  
   365  	if g.tagSize < gcmMinimumTagSize {
   366  		panic("crypto/cipher: incorrect GCM tag size")
   367  	}
   368  
   369  	counter := g.deriveCounter(nonce)
   370  	fc := g.block.function | kmaLAAD | kmaLPC | kmaDecrypt
   371  
   372  	var expectedTag [gcmTagSize]byte
   373  	kmaGCM(fc, g.block.key, out[:len(ciphertext)], ciphertext, data, &expectedTag, &counter)
   374  
   375  	if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
   376  		// The AESNI code decrypts and authenticates concurrently, and
   377  		// so overwrites dst in the event of a tag mismatch. That
   378  		// behavior is mimicked here in order to be consistent across
   379  		// platforms.
   380  		for i := range out {
   381  			out[i] = 0
   382  		}
   383  		return nil, errOpen
   384  	}
   385  
   386  	return ret, nil
   387  }
   388  

View as plain text