/
alg_aes256_ctr.go
107 lines (86 loc) · 2.19 KB
/
alg_aes256_ctr.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
package gfc
// This file provides AES256-CTR encryption for gfc.
// CTR converts a block cipher into a stream cipher by
// repeatedly encrypting an incrementing counter and
// xoring the resulting stream of data with the input.
// In gfc, this mode does not authenticate decrypted message
// so I recommend you use GCM (default mode for gfc).
// See https://golang.org/src/crypto/cipher/ctr.go
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"github.com/pkg/errors"
)
const blockSizeAES256CTR = 16
func EncryptCTR(plaintext Buffer, aesKey []byte) (Buffer, error) {
key, salt, err := keySaltPBKDF2(aesKey, nil)
if err != nil {
err = errors.Wrap(err, ErrPBKDF2KeySalt.Error())
return nil, errors.Wrap(err, "AES256-CTR encryption")
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, errors.Wrap(err, ErrNewCipherCTR.Error())
}
// blockSize is 16
iv := make([]byte, blockSizeAES256CTR)
rand.Read(iv)
stream := cipher.NewCTR(block, iv)
ciphertext := new(bytes.Buffer)
// We will be using a byte buffer of size 1024
buf := make([]byte, 1024)
for {
// Read n bytes from plaintext to buf
n, err := plaintext.Read(buf)
if n > 0 {
stream.XORKeyStream(buf, buf[:n])
// Write buf[:n] to ciphertext
ciphertext.Write(buf[:n])
}
if err == io.EOF {
break
}
if err != nil {
return nil, errors.Wrap(err, ErrReadCTR.Error())
}
}
return formatOutputGfcSymm(
ciphertext.Bytes(),
iv,
salt,
)
}
func DecryptCTR(ciphertext Buffer, aesKey []byte) (Buffer, error) {
lenMsg, _, key, iv, err := decodeOutputGfcSymm(ciphertext, aesKey, blockSizeAES256CTR)
if err != nil {
return nil, errors.Wrap(err, ErrUnmarshalSymmAEAD.Error())
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, errors.Wrap(err, ErrNewCipherCTR.Error())
}
stream := cipher.NewCTR(block, iv)
buf := make([]byte, 1024)
plaintext := new(bytes.Buffer)
for {
n, err := ciphertext.Read(buf)
if n > 0 {
if n > lenMsg {
n = lenMsg
}
lenMsg -= n
stream.XORKeyStream(buf, buf[:n])
plaintext.Write(buf[:n])
}
if err == io.EOF {
break
}
if err != nil {
return nil, errors.Wrap(err, ErrReadCTR.Error())
}
}
return plaintext, nil
}