github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/src/crypto/aes/gcm_s390x.go (about)

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