-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcrypt.go
More file actions
150 lines (130 loc) · 4.45 KB
/
crypt.go
File metadata and controls
150 lines (130 loc) · 4.45 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
// Provides basic encryption and decryption of any kind of data
package crypter
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"encoding/hex"
"errors"
"io"
)
// Crypt stores a collection of encrypted data
// Along with its plain text and encryption key
type Crypt struct {
UnencryptedData []byte
CipherData []byte
Key []byte
}
// Error when the key provided is not valid
var ErrInvalidCryptKey = errors.New("the given key is invalid")
// NewCryptFromPlainText creates a new crypt from plain text
// To create from Bytes look at NewCryptFromUnencryptedData
func NewCryptFromPlainText(plainText, key string) (*Crypt, error) {
return NewCryptFromUnencryptedData([]byte(plainText), key)
}
// NewCryptFromUnencryptedData creates a new crypt from an array of bytes
func NewCryptFromUnencryptedData(data []byte, key string) (*Crypt, error) {
if (!ValidateCryptKey(key)) {
return nil, ErrInvalidCryptKey
}
crypt := Crypt {
UnencryptedData: data,
Key: []byte(key)}
return &crypt, nil
}
// NewCryptFromHexCipherText creates a new crypt from hex encoded encrypted text
// It returns an error on failure
func NewCryptFromHexCipherText(cipherText, key string) (*Crypt, error) {
decodedString, err := DecodeHexString(cipherText)
if (err != nil) {
return nil, err
}
return NewCryptFromCipherData(decodedString, key)
}
// NewCryptFromCipherData creates a new crypt from an array of bytes that have encrypted data
func NewCryptFromCipherData(cipherData []byte, key string) (*Crypt, error) {
if (!ValidateCryptKey(key)) {
return nil, ErrInvalidCryptKey
}
crypt := Crypt {
CipherData: cipherData,
Key: []byte(key)}
return &crypt, nil
}
// Encrypt encrypts the plain data using the given key
// Error is nil if the method successfully encrypts the data
func (crypt *Crypt) Encrypt() ([]byte, error) {
block, err := aes.NewCipher(crypt.Key)
if (err != nil) {
return nil, err
}
crypt.CipherData = make([]byte, aes.BlockSize + len(crypt.UnencryptedData))
// Generate initialization vector
// This will generate a random vector
iv := crypt.CipherData[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
}
// Use a stream cipher to encrypt the data
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(crypt.CipherData[aes.BlockSize:], crypt.UnencryptedData)
return crypt.CipherData, nil
}
// EncryptToString encrypts the data and encodes it to a hex string
// Error is nil if the method successfully encrypts the data
// It returns a hex encoded string for the encrypted data
func (crypt *Crypt) EncryptToString() (string, error) {
data, err := crypt.Encrypt()
if (err != nil) {
return "", err
}
return hex.EncodeToString(data), nil
}
// Decrypt tries to decrypt the given encrypted data into plain data
// Error is nil if the decrypt was successful
func (crypt *Crypt) Decrypt() ([]byte, error) {
block, err := aes.NewCipher(crypt.Key)
if (err != nil) {
return nil, err
}
if (len(crypt.CipherData) < aes.BlockSize) {
return nil, errors.New("invalid cipher text")
}
// Retrieve the cipher
iv := crypt.CipherData[:aes.BlockSize]
cipherText := crypt.CipherData[aes.BlockSize:]
crypt.UnencryptedData = make([]byte, len(cipherText))
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(crypt.UnencryptedData, cipherText)
return crypt.UnencryptedData, nil
}
// DecryptToString decrypts the data and converts it to a string
// Tries to convert the decrypted data into a string and returns it
func (crypt *Crypt) DecryptToString() (string, error) {
data, err := crypt.Decrypt()
if (err != nil) {
return "", err
}
return string(data), nil
}
// DecodeHexString decodes the string from hex to a byte array
func DecodeHexString(text string) ([]byte, error) {
textBytes, err := hex.DecodeString(text)
if (err != nil) {
return nil, err
}
return textBytes, nil
}
// ValidateCryptKey checks for the validity of the given key
// The cryptographic system requires a key size of 16, 24 or 32 only
// All other keys will be rejected
func ValidateCryptKey(key string) bool {
keyLength := len(key)
validSizes := []int {16, 24, 32}
for _, size := range validSizes {
if (keyLength == size) {
return true
}
}
return false
}