github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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  // gcmCount represents a 16-byte big-endian count value.
    14  type gcmCount [16]byte
    15  
    16  // inc increments the rightmost 32-bits of the count value by 1.
    17  func (x *gcmCount) inc() {
    18  	// The compiler should optimize this to a 32-bit addition.
    19  	n := uint32(x[15]) | uint32(x[14])<<8 | uint32(x[13])<<16 | uint32(x[12])<<24
    20  	n += 1
    21  	x[12] = byte(n >> 24)
    22  	x[13] = byte(n >> 16)
    23  	x[14] = byte(n >> 8)
    24  	x[15] = byte(n)
    25  }
    26  
    27  // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array.
    28  func gcmLengths(len0, len1 uint64) [16]byte {
    29  	return [16]byte{
    30  		byte(len0 >> 56),
    31  		byte(len0 >> 48),
    32  		byte(len0 >> 40),
    33  		byte(len0 >> 32),
    34  		byte(len0 >> 24),
    35  		byte(len0 >> 16),
    36  		byte(len0 >> 8),
    37  		byte(len0),
    38  		byte(len1 >> 56),
    39  		byte(len1 >> 48),
    40  		byte(len1 >> 40),
    41  		byte(len1 >> 32),
    42  		byte(len1 >> 24),
    43  		byte(len1 >> 16),
    44  		byte(len1 >> 8),
    45  		byte(len1),
    46  	}
    47  }
    48  
    49  // gcmHashKey represents the 16-byte hash key required by the GHASH algorithm.
    50  type gcmHashKey [16]byte
    51  
    52  type gcmAsm struct {
    53  	block     *aesCipherAsm
    54  	hashKey   gcmHashKey
    55  	nonceSize int
    56  }
    57  
    58  const (
    59  	gcmBlockSize         = 16
    60  	gcmTagSize           = 16
    61  	gcmStandardNonceSize = 12
    62  )
    63  
    64  var errOpen = errors.New("cipher: message authentication failed")
    65  
    66  // Assert that aesCipherAsm implements the gcmAble interface.
    67  var _ gcmAble = (*aesCipherAsm)(nil)
    68  
    69  // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
    70  // called by crypto/cipher.NewGCM via the gcmAble interface.
    71  func (c *aesCipherAsm) NewGCM(nonceSize int) (cipher.AEAD, error) {
    72  	var hk gcmHashKey
    73  	c.Encrypt(hk[:], hk[:])
    74  	g := &gcmAsm{
    75  		block:     c,
    76  		hashKey:   hk,
    77  		nonceSize: nonceSize,
    78  	}
    79  	return g, nil
    80  }
    81  
    82  func (g *gcmAsm) NonceSize() int {
    83  	return g.nonceSize
    84  }
    85  
    86  func (*gcmAsm) Overhead() int {
    87  	return gcmTagSize
    88  }
    89  
    90  // sliceForAppend takes a slice and a requested number of bytes. It returns a
    91  // slice with the contents of the given slice followed by that many bytes and a
    92  // second slice that aliases into it and contains only the extra bytes. If the
    93  // original slice has sufficient capacity then no allocation is performed.
    94  func sliceForAppend(in []byte, n int) (head, tail []byte) {
    95  	if total := len(in) + n; cap(in) >= total {
    96  		head = in[:total]
    97  	} else {
    98  		head = make([]byte, total)
    99  		copy(head, in)
   100  	}
   101  	tail = head[len(in):]
   102  	return
   103  }
   104  
   105  // ghash uses the GHASH algorithm to hash data with the given key. The initial
   106  // hash value is given by hash which will be updated with the new hash value.
   107  // The length of data must be a multiple of 16-bytes.
   108  //go:noescape
   109  func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
   110  
   111  // paddedGHASH pads data with zeroes until its length is a multiple of
   112  // 16-bytes. It then calculates a new value for hash using the GHASH algorithm.
   113  func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
   114  	siz := len(data) &^ 0xf // align size to 16-bytes
   115  	if siz > 0 {
   116  		ghash(&g.hashKey, hash, data[:siz])
   117  		data = data[siz:]
   118  	}
   119  	if len(data) > 0 {
   120  		var s [16]byte
   121  		copy(s[:], data)
   122  		ghash(&g.hashKey, hash, s[:])
   123  	}
   124  }
   125  
   126  // cryptBlocksGCM encrypts src using AES in counter mode using the given
   127  // function code and key. The rightmost 32-bits of the counter are incremented
   128  // between each block as required by the GCM spec. The initial counter value
   129  // is given by cnt, which is updated with the value of the next counter value
   130  // to use.
   131  //
   132  // The lengths of both dst and buf must be greater than or equal to the length
   133  // of src. buf may be partially or completely overwritten during the execution
   134  // of the function.
   135  //go:noescape
   136  func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount)
   137  
   138  // counterCrypt encrypts src using AES in counter mode and places the result
   139  // into dst. cnt is the initial count value and will be updated with the next
   140  // count value. The length of dst must be greater than or equal to the length
   141  // of src.
   142  func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) {
   143  	// Copying src into a buffer improves performance on some models when
   144  	// src and dst point to the same underlying array. We also need a
   145  	// buffer for counter values.
   146  	var ctrbuf, srcbuf [2048]byte
   147  	for len(src) >= 16 {
   148  		siz := len(src)
   149  		if len(src) > len(ctrbuf) {
   150  			siz = len(ctrbuf)
   151  		}
   152  		siz &^= 0xf // align siz to 16-bytes
   153  		copy(srcbuf[:], src[:siz])
   154  		cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt)
   155  		src = src[siz:]
   156  		dst = dst[siz:]
   157  	}
   158  	if len(src) > 0 {
   159  		var x [16]byte
   160  		g.block.Encrypt(x[:], cnt[:])
   161  		for i := range src {
   162  			dst[i] = src[i] ^ x[i]
   163  		}
   164  		cnt.inc()
   165  	}
   166  }
   167  
   168  // deriveCounter computes the initial GCM counter state from the given nonce.
   169  // See NIST SP 800-38D, section 7.1.
   170  func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount {
   171  	// GCM has two modes of operation with respect to the initial counter
   172  	// state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
   173  	// for nonces of other lengths. For a 96-bit nonce, the nonce, along
   174  	// with a four-byte big-endian counter starting at one, is used
   175  	// directly as the starting counter. For other nonce sizes, the counter
   176  	// is computed by passing it through the GHASH function.
   177  	var counter gcmCount
   178  	if len(nonce) == gcmStandardNonceSize {
   179  		copy(counter[:], nonce)
   180  		counter[gcmBlockSize-1] = 1
   181  	} else {
   182  		var hash [16]byte
   183  		g.paddedGHASH(&hash, nonce)
   184  		lens := gcmLengths(0, uint64(len(nonce))*8)
   185  		g.paddedGHASH(&hash, lens[:])
   186  		copy(counter[:], hash[:])
   187  	}
   188  	return counter
   189  }
   190  
   191  // auth calculates GHASH(ciphertext, additionalData), masks the result with
   192  // tagMask and writes the result to out.
   193  func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
   194  	var hash [16]byte
   195  	g.paddedGHASH(&hash, additionalData)
   196  	g.paddedGHASH(&hash, ciphertext)
   197  	lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8)
   198  	g.paddedGHASH(&hash, lens[:])
   199  
   200  	copy(out, hash[:])
   201  	for i := range out {
   202  		out[i] ^= tagMask[i]
   203  	}
   204  }
   205  
   206  // Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
   207  // details.
   208  func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
   209  	if len(nonce) != g.nonceSize {
   210  		panic("cipher: incorrect nonce length given to GCM")
   211  	}
   212  	if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
   213  		panic("cipher: message too large for GCM")
   214  	}
   215  
   216  	ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
   217  
   218  	counter := g.deriveCounter(nonce)
   219  
   220  	var tagMask [gcmBlockSize]byte
   221  	g.block.Encrypt(tagMask[:], counter[:])
   222  	counter.inc()
   223  
   224  	g.counterCrypt(out, plaintext, &counter)
   225  	g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask)
   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("cipher: incorrect nonce length given to GCM")
   235  	}
   236  	if len(ciphertext) < gcmTagSize {
   237  		return nil, errOpen
   238  	}
   239  	if uint64(len(ciphertext)) > ((1<<32)-2)*BlockSize+gcmTagSize {
   240  		return nil, errOpen
   241  	}
   242  
   243  	tag := ciphertext[len(ciphertext)-gcmTagSize:]
   244  	ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
   245  
   246  	counter := g.deriveCounter(nonce)
   247  
   248  	var tagMask [gcmBlockSize]byte
   249  	g.block.Encrypt(tagMask[:], counter[:])
   250  	counter.inc()
   251  
   252  	var expectedTag [gcmTagSize]byte
   253  	g.auth(expectedTag[:], ciphertext, data, &tagMask)
   254  
   255  	ret, out := sliceForAppend(dst, len(ciphertext))
   256  
   257  	if subtle.ConstantTimeCompare(expectedTag[:], tag) != 1 {
   258  		// The AESNI code decrypts and authenticates concurrently, and
   259  		// so overwrites dst in the event of a tag mismatch. That
   260  		// behavior is mimicked here in order to be consistent across
   261  		// platforms.
   262  		for i := range out {
   263  			out[i] = 0
   264  		}
   265  		return nil, errOpen
   266  	}
   267  
   268  	g.counterCrypt(out, ciphertext, &counter)
   269  	return ret, nil
   270  }