forked from mutecomm/mute
-
Notifications
You must be signed in to change notification settings - Fork 0
/
aes256.go
137 lines (114 loc) · 4.66 KB
/
aes256.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
// Copyright (c) 2015 Mute Communications Ltd.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package cipher
import (
"crypto/aes"
"crypto/cipher"
"io"
"github.com/mutecomm/mute/log"
)
// AES256CBCEncrypt encrypts the given plaintext with AES-256 in CBC mode.
// The supplied key must be 32 bytes long.
// The returned ciphertext is prepended by a randomly generated IV.
func AES256CBCEncrypt(key, plaintext []byte, rand io.Reader) (ciphertext []byte) {
if len(key) != 32 {
panic(log.Critical("cipher: AES-256 key is not 32 bytes long"))
}
block, _ := aes.NewCipher(key) // correct key length was enforced above
// CBC mode works on blocks so plaintexts may need to be padded to the
// next whole block. For an example of such padding, see
// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
// assume that the plaintext is already of the correct length.
if len(plaintext)%aes.BlockSize != 0 {
panic(log.Critical("cipher: plaintext is not a multiple of the block size"))
}
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext = make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
_, err := io.ReadFull(rand, iv)
if err != nil {
panic(log.Critical(err))
}
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
return
}
// AES256CBCDecrypt decrypts the given ciphertext with AES-256 in CBC mode and
// returns the resulting plaintext. The supplied key must be 32 bytes long and
// the ciphertext must be prepended by the corresponding IV.
func AES256CBCDecrypt(key, ciphertext []byte) (plaintext []byte) {
if len(key) != 32 {
panic(log.Critical("cipher: AES-256 key is not 32 bytes long"))
}
block, _ := aes.NewCipher(key) // correct key length was enforced above
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
panic(log.Critical("cipher: ciphertext too short"))
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
plaintext = make([]byte, len(ciphertext))
// CBC mode always works in whole blocks.
if len(ciphertext)%aes.BlockSize != 0 {
panic(log.Critical("cipher: ciphertext is not a multiple of the block size"))
}
mode := cipher.NewCBCDecrypter(block, iv)
// CryptBlocks can work in-place if the two arguments are the same.
mode.CryptBlocks(plaintext, ciphertext)
return
}
// AES256CTREncrypt encrypts the given plaintext with AES-256 in CTR mode.
// The supplied key must be 32 bytes long.
// The returned ciphertext is prepended by a randomly generated IV.
func AES256CTREncrypt(key, plaintext []byte, rand io.Reader) (ciphertext []byte) {
if len(key) != 32 {
panic(log.Critical("cipher: AES-256 key is not 32 bytes long"))
}
block, _ := aes.NewCipher(key) // correct key length was enforced above
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
ciphertext = make([]byte, aes.BlockSize+len(plaintext))
iv := ciphertext[:aes.BlockSize]
_, err := io.ReadFull(rand, iv)
if err != nil {
panic(log.Critical(err))
}
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
return
}
// AES256CTRDecrypt decrypts the given ciphertext with AES-256 in CTR mode and
// returns the resulting plaintext. The supplied key must be 32 bytes long and
// the ciphertext must be prepended by the corresponding IV.
func AES256CTRDecrypt(key, ciphertext []byte) (plaintext []byte) {
if len(key) != 32 {
panic(log.Critical("cipher: AES-256 key is not 32 bytes long"))
}
block, _ := aes.NewCipher(key) // correct key length was enforced above
// The IV needs to be unique, but not secure. Therefore it's common to
// include it at the beginning of the ciphertext.
if len(ciphertext) < aes.BlockSize {
panic(log.Critical("cipher: ciphertext too short"))
}
iv := ciphertext[:aes.BlockSize]
ciphertext = ciphertext[aes.BlockSize:]
plaintext = make([]byte, len(ciphertext))
stream := cipher.NewCTR(block, iv)
stream.XORKeyStream(plaintext, ciphertext)
return
}
// AES256CTRStream creates a new AES-256 stream in CTR mode.
// The supplied key must be 32 bytes long and the iv 16 bytes.
func AES256CTRStream(key, iv []byte) cipher.Stream {
if len(key) != 32 {
panic(log.Critical("cipher: AES-256 key is not 32 bytes long"))
}
if len(iv) != 16 {
panic(log.Critical("cipher: AES-256 IV is not 16 bytes long"))
}
block, _ := aes.NewCipher(key) // correct key length was enforced above
return cipher.NewCTR(block, iv)
}