...

Source file src/pkg/crypto/aes/gcm_s390x.go

     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