aes_asm.mx raw

   1  // Copyright 2012 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  //go:build (amd64 || arm64 || ppc64 || ppc64le) && !purego
   6  
   7  package aes
   8  
   9  import (
  10  	"crypto/internal/fips140deps/cpu"
  11  	"crypto/internal/fips140deps/godebug"
  12  	"crypto/internal/impl"
  13  )
  14  
  15  //go:noescape
  16  func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
  17  
  18  //go:noescape
  19  func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
  20  
  21  //go:noescape
  22  func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
  23  
  24  var supportsAES = cpu.X86HasAES && cpu.X86HasSSE41 && cpu.X86HasSSSE3 ||
  25  	cpu.ARM64HasAES || cpu.PPC64 || cpu.PPC64le
  26  
  27  func init() {
  28  	if cpu.AMD64 {
  29  		impl.Register("aes", "AES-NI", &supportsAES)
  30  	}
  31  	if cpu.ARM64 {
  32  		impl.Register("aes", "Armv8.0", &supportsAES)
  33  	}
  34  	if cpu.PPC64 || cpu.PPC64le {
  35  		// The POWER architecture doesn't have a way to turn off AES support
  36  		// at runtime with GODEBUG=cpu.something=off, so introduce a new GODEBUG
  37  		// knob for that. It's intentionally only checked at init() time, to
  38  		// avoid the performance overhead of checking it every time.
  39  		if godebug.Value("#ppc64aes") == "off" {
  40  			supportsAES = false
  41  		}
  42  		impl.Register("aes", "POWER8", &supportsAES)
  43  	}
  44  }
  45  
  46  // checkGenericIsExpected is called by the variable-time implementation to make
  47  // sure it is not used when hardware support is available. It shouldn't happen,
  48  // but this way it's more evidently correct.
  49  func checkGenericIsExpected() {
  50  	if supportsAES {
  51  		panic("crypto/aes: internal error: using generic implementation despite hardware support")
  52  	}
  53  }
  54  
  55  type block struct {
  56  	blockExpanded
  57  }
  58  
  59  func newBlock(c *Block, key []byte) *Block {
  60  	switch len(key) {
  61  	case aes128KeySize:
  62  		c.rounds = aes128Rounds
  63  	case aes192KeySize:
  64  		c.rounds = aes192Rounds
  65  	case aes256KeySize:
  66  		c.rounds = aes256Rounds
  67  	}
  68  	if supportsAES {
  69  		expandKeyAsm(c.rounds, &key[0], &c.enc[0], &c.dec[0])
  70  	} else {
  71  		expandKeyGeneric(&c.blockExpanded, key)
  72  	}
  73  	return c
  74  }
  75  
  76  // EncryptionKeySchedule is used from the GCM implementation to access the
  77  // precomputed AES key schedule, to pass to the assembly implementation.
  78  func EncryptionKeySchedule(c *Block) []uint32 {
  79  	return c.enc[:c.roundKeysSize()]
  80  }
  81  
  82  func encryptBlock(c *Block, dst, src []byte) {
  83  	if supportsAES {
  84  		encryptBlockAsm(c.rounds, &c.enc[0], &dst[0], &src[0])
  85  	} else {
  86  		encryptBlockGeneric(&c.blockExpanded, dst, src)
  87  	}
  88  }
  89  
  90  func decryptBlock(c *Block, dst, src []byte) {
  91  	if supportsAES {
  92  		decryptBlockAsm(c.rounds, &c.dec[0], &dst[0], &src[0])
  93  	} else {
  94  		decryptBlockGeneric(&c.blockExpanded, dst, src)
  95  	}
  96  }
  97