-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcrypt.go
More file actions
180 lines (149 loc) · 4.5 KB
/
crypt.go
File metadata and controls
180 lines (149 loc) · 4.5 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package enstore
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
)
// AESCrypter is a struct that can encrypt and decypt bytes using AES and a common key
type AESCrypter struct {
key []byte // TODO: should we store the cipher here instead?
}
// NewAESCrypter creates a new AESCrypter with the provided key
func NewAESCrypter(key []byte) (*AESCrypter, error) {
_, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return &AESCrypter{key}, nil
}
// Encrypt encrypts the bytes passed to it
func (a *AESCrypter) Encrypt(bytes []byte) ([]byte, error) {
// Get the cipher using the key
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
// CipherText length is payload length + AES blocksize (for the IV)
cipherText := make([]byte, aes.BlockSize+len(bytes))
// Generated the IV
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
// Return an encrypted stream
stream := cipher.NewCFBEncrypter(block, iv)
// Encrypt bytes from plaintext to ciphertext (keeping IV at the font)
stream.XORKeyStream(cipherText[aes.BlockSize:], bytes)
return cipherText, nil
}
// Decrypt decrypts the bytes passed to it
func (a *AESCrypter) Decrypt(bytes []byte) ([]byte, error) {
// Get the cipher using the key
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
// The length of bytes to decrupt must be at least the AES blocksize (as it is preceeded by the IV)
if len(bytes) < aes.BlockSize {
return nil, errors.New("text is too short")
}
// Get the IV from the beginning
iv := bytes[:aes.BlockSize]
// The remainder if the actual ciphertext
ciphertext := bytes[aes.BlockSize:]
// Get the stream from the cipher and IV
stream := cipher.NewCFBDecrypter(block, iv)
// Decrypt the cyphertext
stream.XORKeyStream(ciphertext, ciphertext)
return ciphertext, nil
}
// Encrypter returns an io.Reader which, when read, returns the encrypted bytes of the `source` io.Reader
func (a *AESCrypter) Encrypter(source io.Reader) (io.Reader, error) {
//Make the cipher
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
// Create the IV
iv := make([]byte, aes.BlockSize)
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
// Get the stream
stream := cipher.NewCFBEncrypter(block, iv)
// Return the encrypter
return &AESEncryptionReader{
Source: source,
Stream: stream,
IV: iv,
}, nil
}
// Decrypter returns an io.Reader which, when read, returns the decrypted bytes of the `source` io.Reader
func (a *AESCrypter) Decrypter(source io.Reader) (io.Reader, error) {
// Make the cipher
block, err := aes.NewCipher(a.key)
if err != nil {
return nil, err
}
// Read the IV from the source
iv := make([]byte, aes.BlockSize)
_, err = source.Read(iv)
if err != nil {
return nil, err
}
// Get the stream
stream := cipher.NewCFBDecrypter(block, iv)
// Return the decrypter
return &AESDecryptionReader{
Source: source,
Stream: stream,
}, nil
}
// AESEncyptionReader is an io.Reader which provides the encrypted version of a source io.Reader when read
type AESEncryptionReader struct {
Source io.Reader
Stream cipher.Stream
IV []byte
cursor int
}
// Read returns the encrypted bytes of the source io.Reader, starting with the IV
func (e *AESEncryptionReader) Read(p []byte) (int, error) {
offset := 0
// Check if we're still in the IV block at the beginning of the read
// If we are, we need to finish returning that before we begin reading from `Source`
if e.cursor < len(e.IV) {
part := len(e.IV) - e.cursor
if len(p) <= part {
copy(p, e.IV[e.cursor:e.cursor+len(p)])
e.cursor += len(p)
return len(p), nil
}
copy(p[:part], e.IV[e.cursor:])
e.cursor += part
offset = part
}
// Read from `Source`, and encrypt those bytes before returning them
n, readErr := e.Source.Read(p[offset:])
if n > 0 {
e.Stream.XORKeyStream(p[offset:offset+n], p[offset:offset+n])
return n + offset, readErr
}
return 0, io.EOF
}
// AESDecryptionReader is an io.Reader which provides the decrypted version of a source io.Reader when read
// The source io.Reader should be positioned at the start of the ciphertext when initialized
type AESDecryptionReader struct {
Source io.Reader
Stream cipher.Stream
}
// Read returns the decrypted bytes of the source io.Reader
func (d *AESDecryptionReader) Read(p []byte) (int, error) {
n, readErr := d.Source.Read(p)
if n > 0 {
d.Stream.XORKeyStream(p[:n], p[:n])
return n, readErr
}
return 0, io.EOF
}