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

View as plain text