-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathcipher.go
173 lines (141 loc) · 4.93 KB
/
cipher.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
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
package stream
import (
"crypto/aes"
"crypto/cipher"
"errors"
"fmt"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/nacl/secretbox"
)
// Cipher provides encrypt and decrypt function of a slice data.
type Cipher interface {
// Encrypt encrypts a plaintext to ciphertext. Returns ciphertext slice
// whose length should be equal to ciphertext length. Input buffer ciphertext
// has enough length for encrypted plaintext, and the length satisfy:
// len(ciphertext) == MaxChunkSize + MaxOverheadSize
// len(plaintext) <= MaxChunkSize
Encrypt(ciphertext, plaintext, nonce []byte) ([]byte, error)
// Decrypt decrypts a ciphertext to plaintext. Returns plaintext slice
// whose length should be equal to plaintext length. Input buffer plaintext
// has enough length for decrypted ciphertext, and the length satisfy:
// len(plaintext) == MaxChunkSize
// len(ciphertext) <= MaxChunkSize + MaxOverheadSize
Decrypt(plaintext, ciphertext, nonce []byte) ([]byte, error)
// MaxOverhead is the max number of bytes overhead of ciphertext compared to
// plaintext. It is only used to determine internal buffer size, so
// overestimate is ok.
MaxOverhead() int
// NonceSize is the nonce size in bytes.
NonceSize() int
}
// XSalsa20Poly1305Cipher is an AEAD cipher that uses XSalsa20 and Poly1305 to
// encrypt and authenticate messages. The ciphertext it produces contains 24
// bytes of random nonce, followed by n+16 bytes of authenticated encrypted
// data, where n is the plaintext size.
type XSalsa20Poly1305Cipher struct {
key *[32]byte
}
// NewXSalsa20Poly1305Cipher creates a XSalsa20Poly1305Cipher with a given key.
// For best security, every stream should have a unique key.
func NewXSalsa20Poly1305Cipher(key *[32]byte) *XSalsa20Poly1305Cipher {
return &XSalsa20Poly1305Cipher{
key: key,
}
}
// Encrypt implements Cipher.
func (c *XSalsa20Poly1305Cipher) Encrypt(ciphertext, plaintext, nonce []byte) ([]byte, error) {
var n [24]byte
copy(n[:], nonce[:24])
encrypted := secretbox.Seal(ciphertext[:0], plaintext, &n, c.key)
return ciphertext[:len(encrypted)], nil
}
// Decrypt implements Cipher.
func (c *XSalsa20Poly1305Cipher) Decrypt(plaintext, ciphertext, nonce []byte) ([]byte, error) {
var n [24]byte
copy(n[:], nonce[:24])
plaintext, ok := secretbox.Open(plaintext[:0], ciphertext, &n, c.key)
if !ok {
return nil, errors.New("decrypt failed")
}
return plaintext, nil
}
// overhead returns Cipher's overhead including nonce size.
func (c *XSalsa20Poly1305Cipher) overhead() int {
return secretbox.Overhead
}
// MaxOverhead implements Cipher.
func (c *XSalsa20Poly1305Cipher) MaxOverhead() int {
return c.overhead()
}
// NonceSize implements Cipher.
func (c *XSalsa20Poly1305Cipher) NonceSize() int {
return 24
}
// CryptoAEADCipher is a wrapper to crypto/cipher AEAD interface and implements
// Cipher interface.
type CryptoAEADCipher struct {
aead cipher.AEAD
}
// NewCryptoAEADCipher converts a crypto/cipher AEAD to Cipher.
func NewCryptoAEADCipher(aead cipher.AEAD) *CryptoAEADCipher {
return &CryptoAEADCipher{
aead: aead,
}
}
// Encrypt implements Cipher.
func (c *CryptoAEADCipher) Encrypt(ciphertext, plaintext, nonce []byte) ([]byte, error) {
encrypted := c.aead.Seal(ciphertext[:0], nonce, plaintext, nil)
return ciphertext[:len(encrypted)], nil
}
// Decrypt implements Cipher.
func (c *CryptoAEADCipher) Decrypt(plaintext, ciphertext, nonce []byte) ([]byte, error) {
plaintext, err := c.aead.Open(plaintext[:0], nonce, ciphertext, nil)
if err != nil {
return nil, fmt.Errorf("decrypt failed: %v", err)
}
return plaintext, nil
}
// overhead returns Cipher's overhead including nonce size.
func (c *CryptoAEADCipher) overhead() int {
return c.aead.Overhead()
}
// MaxOverhead implements Cipher.
func (c *CryptoAEADCipher) MaxOverhead() int {
return c.overhead()
}
// NonceSize implements Cipher.
func (c *CryptoAEADCipher) NonceSize() int {
return c.aead.NonceSize()
}
// NewAESGCMCipher creates a 128-bit (16 bytes key) or 256-bit (32 bytes key)
// AES block cipher wrapped in Galois Counter Mode with the standard nonce
// length. For best security, every stream should have a unique key.
func NewAESGCMCipher(key []byte) (*CryptoAEADCipher, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
return NewCryptoAEADCipher(aesgcm), nil
}
// NewChaCha20Poly1305Cipher creates a ChaCha20-Poly1305 AEAD that uses the
// given 256-bit key.
func NewChaCha20Poly1305Cipher(key []byte) (*CryptoAEADCipher, error) {
cipher, err := chacha20poly1305.New(key)
if err != nil {
return nil, err
}
return NewCryptoAEADCipher(cipher), nil
}
// NewXChaCha20Poly1305Cipher creates a XChaCha20-Poly1305 AEAD that uses the
// given 256-bit key.
func NewXChaCha20Poly1305Cipher(key []byte) (*CryptoAEADCipher, error) {
cipher, err := chacha20poly1305.NewX(key)
if err != nil {
return nil, err
}
return NewCryptoAEADCipher(cipher), nil
}