-
Notifications
You must be signed in to change notification settings - Fork 6
/
encrypt.go
174 lines (141 loc) · 5.39 KB
/
encrypt.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
174
/*
Package encrypt contains a collection of utility functions to encrypt and decrypt data.
*/
package encrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"encoding/base64"
"encoding/gob"
"encoding/json"
"errors"
"fmt"
"io"
"github.com/Vonage/gosrvlib/pkg/random"
)
// randReader is the default random number generator.
var randReader io.Reader //nolint:gochecknoglobals
func newAESGCM(key []byte) (cipher.AEAD, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err //nolint:wrapcheck
}
return cipher.NewGCM(block) //nolint:wrapcheck
}
// Encrypt encrypts the byte-slice input msg with the specified key.
// The key argument must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func Encrypt(key, msg []byte) ([]byte, error) {
aesgcm, err := newAESGCM(key)
if err != nil {
return nil, err
}
nonce, err := random.New(randReader).RandomBytes(aesgcm.NonceSize())
if err != nil {
return nil, err //nolint:wrapcheck
}
return aesgcm.Seal(nonce, nonce, msg, nil), nil
}
// Decrypt decrypts a byte-slice data encrypted with the Encrypt function.
// The key argument must be the same used to encrypt the data:
// either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func Decrypt(key, msg []byte) ([]byte, error) {
aesgcm, err := newAESGCM(key)
if err != nil {
return nil, err
}
ns := aesgcm.NonceSize()
if len(msg) < ns {
return nil, errors.New("invalid input size")
}
return aesgcm.Open(nil, msg[:ns], msg[ns:], nil) //nolint:wrapcheck
}
func byteEncryptEncoded(key []byte, data []byte) ([]byte, error) {
msg, err := Encrypt(key, data)
if err != nil {
return nil, fmt.Errorf("encrypt: %w", err)
}
dst := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
base64.StdEncoding.Encode(dst, msg)
return dst, nil
}
func byteDecryptEncoded(key, msg []byte) ([]byte, error) {
dst := make([]byte, base64.StdEncoding.DecodedLen(len(msg)))
n, err := base64.StdEncoding.Decode(dst, msg)
if err != nil {
return nil, fmt.Errorf("decode base64: %w", err)
}
return Decrypt(key, dst[:n])
}
// ByteEncryptAny encrypts the input data with the specified key and returns a base64 byte slice.
// The input data is serialized using gob, encrypted with the Encrypt method and encoded as base64.
// The key argument must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func ByteEncryptAny(key []byte, data any) ([]byte, error) {
buf := &bytes.Buffer{}
if err := gob.NewEncoder(buf).Encode(data); err != nil {
return nil, fmt.Errorf("encode gob: %w", err)
}
return byteEncryptEncoded(key, buf.Bytes())
}
// ByteDecryptAny decrypts a byte-slice message produced with the ByteEncryptAny function to the provided data object.
// The value underlying data must be a pointer to the correct type for the next data item received.
// The key argument must be the same used to encrypt the data:
// either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func ByteDecryptAny(key, msg []byte, data any) error {
dec, err := byteDecryptEncoded(key, msg)
if err != nil {
return err
}
if err := gob.NewDecoder(bytes.NewBuffer(dec)).Decode(data); err != nil {
return fmt.Errorf("decode gob: %w", err)
}
return nil
}
// EncryptAny wraps the ByteEncryptAny function to return a string instead of a byte slice.
func EncryptAny(key []byte, data any) (string, error) { //nolint:revive
b, err := ByteEncryptAny(key, data)
if err != nil {
return "", fmt.Errorf("decrypt: %w", err)
}
return string(b), nil
}
// DecryptAny wraps the ByteDecryptAny function to accept a msg string instead of a byte slice.
func DecryptAny(key []byte, msg string, data any) error {
return ByteDecryptAny(key, []byte(msg), data)
}
// ByteEncryptSerializeAny encrypts the input data with the specified key and returns a base64 byte slice.
// The input data is serialized using json, encrypted with the Encrypt method and encoded as base64.
// The key argument must be either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func ByteEncryptSerializeAny(key []byte, data any) ([]byte, error) {
buf := &bytes.Buffer{}
if err := json.NewEncoder(buf).Encode(data); err != nil {
return nil, fmt.Errorf("encode gob: %w", err)
}
return byteEncryptEncoded(key, buf.Bytes())
}
// ByteDecryptSerializeAny decrypts a byte-slice message produced with the ByteEncryptSerializeAny function to the provided data object.
// The value underlying data must be a pointer to the correct type for the next data item received.
// The key argument must be the same used to encrypt the data:
// either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
func ByteDecryptSerializeAny(key, msg []byte, data any) error {
dec, err := byteDecryptEncoded(key, msg)
if err != nil {
return err
}
if err := json.NewDecoder(bytes.NewBuffer(dec)).Decode(data); err != nil {
return fmt.Errorf("decode gob: %w", err)
}
return nil
}
// EncryptSerializeAny wraps the ByteEncrypSerializetAny function to return a string instead of a byte slice.
func EncryptSerializeAny(key []byte, data any) (string, error) { //nolint:revive
b, err := ByteEncryptSerializeAny(key, data)
if err != nil {
return "", fmt.Errorf("decrypt: %w", err)
}
return string(b), nil
}
// DecryptSerializeAny wraps the ByteDecryptSerializeAny function to accept a msg string instead of a byte slice.
func DecryptSerializeAny(key []byte, msg string, data any) error {
return ByteDecryptSerializeAny(key, []byte(msg), data)
}