-
Notifications
You must be signed in to change notification settings - Fork 15
/
crypt.go
117 lines (101 loc) · 3.13 KB
/
crypt.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
/*
* Copyright 2018-2023, CS Systemes d'Information, http://csgroup.eu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// code heavily inspired by cryptopasta: https://raw.githubusercontent.com/gtank/cryptopasta/master/encrypt.go
package crypt
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"io"
"github.com/CS-SI/SafeScale/v22/lib/utils/fail"
)
// Key ...
type Key [32]byte
// NewEncryptionKey generates a random 256-bit key for Encrypt() and
// Decrypt().
// If text is nil or empty, creates a random key. It panics if the source of randomness fails.
// If text is not nil and not empty, and the length of text is lower than 32, the key is completed
// with spaces.
// If text is not nil and not empty, and the length of text us greater than 32, the 32 first bytes
// are used as key.
func NewEncryptionKey(text []byte) (*Key, error) {
key := Key{}
nBytes := len(text)
if len(text) == 0 {
_, err := io.ReadFull(rand.Reader, key[:])
if err != nil {
return nil, fail.Wrap(err, "cannot read enough random bytes (you should consider to stop using this computer)")
}
} else {
n := nBytes
if nBytes > 32 {
n = 32
}
for i := 0; i < n; i++ {
key[i] = text[i]
}
for i := n; i < 32; i++ {
key[i] = ' '
}
}
return &key, nil
}
// Encrypt encrypts data using 256-bit AES-GCM. This both hides the content of
// the data and provides a check that it hasn't been altered. output takes the
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Encrypt(plaintext []byte, key *Key) ([]byte, error) {
if key == nil {
return nil, fail.InvalidParameterCannotBeNilError("key")
}
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonce := make([]byte, gcm.NonceSize())
_, err = io.ReadFull(rand.Reader, nonce)
if err != nil {
return nil, err
}
return gcm.Seal(nonce, nonce, plaintext, nil), nil
}
// Decrypt decrypts data using 256-bit AES-GCM. This both hides the content of
// the data and provides a check that it hasn't been altered. Expects input
// form nonce|ciphertext|tag where '|' indicates concatenation.
func Decrypt(ciphertext []byte, key *Key) ([]byte, error) {
if key == nil {
return nil, fail.InvalidParameterCannotBeNilError("key")
}
block, err := aes.NewCipher(key[:])
if err != nil {
return nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
if len(ciphertext) < gcm.NonceSize() {
return nil, fail.InvalidParameterError("ciphertext", "malformed (corrupted?)")
}
return gcm.Open(nil,
ciphertext[:gcm.NonceSize()],
ciphertext[gcm.NonceSize():],
nil,
)
}