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
5package aes
6
7import (
8	"crypto/cipher"
9	"crypto/internal/cipherhw"
10)
11
12type code int
13
14// Function codes for the cipher message family of instructions.
15const (
16	aes128 code = 18
17	aes192      = 19
18	aes256      = 20
19)
20
21type aesCipherAsm struct {
22	function code      // code for cipher message instruction
23	key      []byte    // key (128, 192 or 256 bytes)
24	storage  [256]byte // array backing key slice
25}
26
27// cryptBlocks invokes the cipher message (KM) instruction with
28// the given function code. This is equivalent to AES in ECB
29// mode. The length must be a multiple of BlockSize (16).
30//go:noescape
31func cryptBlocks(c code, key, dst, src *byte, length int)
32
33var useAsm = cipherhw.AESGCMSupport()
34
35func newCipher(key []byte) (cipher.Block, error) {
36	if !useAsm {
37		return newCipherGeneric(key)
38	}
39
40	var function code
41	switch len(key) {
42	case 128 / 8:
43		function = aes128
44	case 192 / 8:
45		function = aes192
46	case 256 / 8:
47		function = aes256
48	default:
49		return nil, KeySizeError(len(key))
50	}
51
52	var c aesCipherAsm
53	c.function = function
54	c.key = c.storage[:len(key)]
55	copy(c.key, key)
56	return &c, nil
57}
58
59func (c *aesCipherAsm) BlockSize() int { return BlockSize }
60
61func (c *aesCipherAsm) Encrypt(dst, src []byte) {
62	if len(src) < BlockSize {
63		panic("crypto/aes: input not full block")
64	}
65	if len(dst) < BlockSize {
66		panic("crypto/aes: output not full block")
67	}
68	cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
69}
70
71func (c *aesCipherAsm) Decrypt(dst, src []byte) {
72	if len(src) < BlockSize {
73		panic("crypto/aes: input not full block")
74	}
75	if len(dst) < BlockSize {
76		panic("crypto/aes: output not full block")
77	}
78	// The decrypt function code is equal to the function code + 128.
79	cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
80}
81
82// expandKey is used by BenchmarkExpand. cipher message (KM) does not need key
83// expansion so there is no assembly equivalent.
84func expandKey(key []byte, enc, dec []uint32) {
85	expandKeyGo(key, enc, dec)
86}
87