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 7package aes 8 9import ( 10 "crypto/cipher" 11 "crypto/internal/alias" 12 "crypto/internal/boring" 13 "internal/cpu" 14 "internal/goarch" 15) 16 17// defined in asm_*.s 18 19//go:noescape 20func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) 21 22//go:noescape 23func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) 24 25//go:noescape 26func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32) 27 28type aesCipherAsm struct { 29 aesCipher 30} 31 32// aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM 33// will use the optimised implementation in aes_gcm.go when possible. 34// Instances of this type only exist when hasGCMAsm returns true. Likewise, 35// the gcmAble implementation is in aes_gcm.go. 36type aesCipherGCM struct { 37 aesCipherAsm 38} 39 40var supportsAES = cpu.X86.HasAES || cpu.ARM64.HasAES || goarch.IsPpc64 == 1 || goarch.IsPpc64le == 1 41var supportsGFMUL = cpu.X86.HasPCLMULQDQ || cpu.ARM64.HasPMULL 42 43func newCipher(key []byte) (cipher.Block, error) { 44 if !supportsAES { 45 return newCipherGeneric(key) 46 } 47 // Note that under certain circumstances, we only return the inner aesCipherAsm. 48 // This avoids an unnecessary allocation of the aesCipher struct. 49 c := aesCipherGCM{aesCipherAsm{aesCipher{l: uint8(len(key) + 28)}}} 50 var rounds int 51 switch len(key) { 52 case 128 / 8: 53 rounds = 10 54 case 192 / 8: 55 rounds = 12 56 case 256 / 8: 57 rounds = 14 58 default: 59 return nil, KeySizeError(len(key)) 60 } 61 62 expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0]) 63 if supportsAES && supportsGFMUL { 64 return &c, nil 65 } 66 return &c.aesCipherAsm, nil 67} 68 69func (c *aesCipherAsm) BlockSize() int { return BlockSize } 70 71func (c *aesCipherAsm) Encrypt(dst, src []byte) { 72 boring.Unreachable() 73 if len(src) < BlockSize { 74 panic("crypto/aes: input not full block") 75 } 76 if len(dst) < BlockSize { 77 panic("crypto/aes: output not full block") 78 } 79 if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 80 panic("crypto/aes: invalid buffer overlap") 81 } 82 encryptBlockAsm(int(c.l)/4-1, &c.enc[0], &dst[0], &src[0]) 83} 84 85func (c *aesCipherAsm) Decrypt(dst, src []byte) { 86 boring.Unreachable() 87 if len(src) < BlockSize { 88 panic("crypto/aes: input not full block") 89 } 90 if len(dst) < BlockSize { 91 panic("crypto/aes: output not full block") 92 } 93 if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { 94 panic("crypto/aes: invalid buffer overlap") 95 } 96 decryptBlockAsm(int(c.l)/4-1, &c.dec[0], &dst[0], &src[0]) 97} 98 99// expandKey is used by BenchmarkExpand to ensure that the asm implementation 100// of key expansion is used for the benchmark when it is available. 101func expandKey(key []byte, enc, dec []uint32) { 102 if supportsAES { 103 rounds := 10 // rounds needed for AES128 104 switch len(key) { 105 case 192 / 8: 106 rounds = 12 107 case 256 / 8: 108 rounds = 14 109 } 110 expandKeyAsm(rounds, &key[0], &enc[0], &dec[0]) 111 } else { 112 expandKeyGo(key, enc, dec) 113 } 114} 115