-
Notifications
You must be signed in to change notification settings - Fork 13
/
aes.go
147 lines (119 loc) · 3.84 KB
/
aes.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//go:build !cmd_go_bootstrap
package openssl
// #include "goopenssl.h"
import "C"
import (
"crypto/cipher"
"errors"
)
//go:generate go run github.com/golang-fips/openssl/v2/cmd/genaesmodes -in aes.go -modes CBC,CTR,GCM -out zaes.go
//go:generate go run github.com/golang-fips/openssl/v2/cmd/gentestvectors -out vectors_test.go
// Steps to support a new AES mode, e.g. `FOO`:
// 1. Add `FOO` to the list of modes in the `genaesmodes` command.
// 2. Run `go generate` to update the generated code.
// 3. Implement the necessary interfaces for the new struct, which will be named `cipherWithFOO`.
// NewAESCipher creates and returns a new AES cipher.Block.
// The key argument should be the AES key, either 16, 24, or 32 bytes to select
// AES-128, AES-192, or AES-256.
// The returned cipher.Block implements the CBC, CTR, and/or GCM modes if
// the underlying OpenSSL library supports them.
func NewAESCipher(key []byte) (cipher.Block, error) {
var kind cipherKind
switch len(key) * 8 {
case 128:
kind = cipherAES128
case 192:
kind = cipherAES192
case 256:
kind = cipherAES256
default:
return nil, errors.New("crypto/aes: invalid key size")
}
c, err := newEVPCipher(key, kind)
if err != nil {
return nil, err
}
return newAESBlock(c, kind), nil
}
// NewGCMTLS returns a GCM cipher specific to TLS
// and should not be used for non-TLS purposes.
func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
if c, ok := c.(interface {
NewGCMTLS() (cipher.AEAD, error)
}); ok {
return c.NewGCMTLS()
}
return nil, errors.New("GCM not supported")
}
// NewGCMTLS13 returns a GCM cipher specific to TLS 1.3 and should not be used
// for non-TLS purposes.
func NewGCMTLS13(c cipher.Block) (cipher.AEAD, error) {
if c, ok := c.(interface {
NewGCMTLS13() (cipher.AEAD, error)
}); ok {
return c.NewGCMTLS13()
}
return nil, errors.New("GCM not supported")
}
// aesCipher implements the cipher.Block interface.
type aesCipher struct {
cipher *evpCipher
}
func (c aesCipher) BlockSize() int {
return c.cipher.blockSize
}
func (c aesCipher) Encrypt(dst, src []byte) {
if err := c.cipher.encrypt(dst, src); err != nil {
// crypto/aes expects that the panic message starts with "crypto/aes: ".
panic("crypto/aes: " + err.Error())
}
}
func (c aesCipher) Decrypt(dst, src []byte) {
if err := c.cipher.decrypt(dst, src); err != nil {
// crypto/aes expects that the panic message starts with "crypto/aes: ".
panic("crypto/aes: " + err.Error())
}
}
// Implement optional interfaces for AES modes.
func (c cipherWithCBC) NewCBCEncrypter(iv []byte) cipher.BlockMode {
return c.cipher.newCBC(iv, cipherOpEncrypt)
}
func (c cipherWithCBC) NewCBCDecrypter(iv []byte) cipher.BlockMode {
return c.cipher.newCBC(iv, cipherOpDecrypt)
}
func (c cipherWithCTR) NewCTR(iv []byte) cipher.Stream {
return c.cipher.newCTR(iv)
}
func (c cipherWithGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
return c.cipher.newGCMChecked(nonceSize, tagSize)
}
func (c cipherWithGCM) NewGCMTLS() (cipher.AEAD, error) {
return c.cipher.newGCM(cipherGCMTLS12)
}
func (c cipherWithGCM) NewGCMTLS13() (cipher.AEAD, error) {
return c.cipher.newGCM(cipherGCMTLS13)
}
// The following interfaces have been copied out of crypto/aes/modes.go.
type gcmAble interface {
NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
}
type cbcEncAble interface {
NewCBCEncrypter(iv []byte) cipher.BlockMode
}
type cbcDecAble interface {
NewCBCDecrypter(iv []byte) cipher.BlockMode
}
type ctrAble interface {
NewCTR(iv []byte) cipher.Stream
}
// Test that the interfaces are implemented.
var (
_ cipher.Block = (*aesCipher)(nil)
_ cipher.Block = (*cipherWithCBC)(nil)
_ cbcEncAble = (*cipherWithCBC)(nil)
_ cbcDecAble = (*cipherWithCBC)(nil)
_ cipher.Block = (*cipherWithCTR)(nil)
_ ctrAble = (*cipherWithCTR)(nil)
_ cipher.Block = (*cipherWithGCM)(nil)
_ gcmAble = (*cipherWithGCM)(nil)
)