@@ -21,6 +21,7 @@ type argon2dParameters struct {
21
21
iterations uint32
22
22
memory uint32
23
23
parallelism uint8
24
+ keyLen uint32
24
25
}
25
26
26
27
type Option func (p * argon2dParameters )
@@ -47,11 +48,20 @@ const (
47
48
nameParamIterations = "iterations"
48
49
nameParamMemory = "memory"
49
50
nameParamParallelism = "parallelism"
51
+ nameParamKeyLen = "keylen"
50
52
51
53
nameFuncNope = ""
52
54
nameFuncArgon2ID = "ARGON2ID"
53
55
nameFuncAES256CTR = "AES_256_CTR"
56
+ nameFuncAES256CBC = "AES_256_CBC"
54
57
nameFuncMACv1 = "MACV1"
58
+
59
+ // Parameter Choice
60
+ // https://www.rfc-editor.org/rfc/rfc9106.html#section-4
61
+ defaultIterations = 3
62
+ defaultMemory = 65536 // 2 ^ 16
63
+ defaultParallelism = 4
64
+ defaultKeyLen = 48
55
65
)
56
66
57
67
// ErrNotSupported describes an error in which the encrypted method is no
@@ -75,17 +85,17 @@ func NopeEncrypter() Encrypter {
75
85
}
76
86
}
77
87
78
- // DefaultEncrypter creates a default encrypter instance.
88
+ // DefaultEncrypter creates a new encrypter instance.
89
+ // If no option sets it uses the default parameters.
79
90
//
80
91
// The default encrypter uses Argon2ID as password hasher and AES_256_CTR as
81
92
// encryption algorithm.
82
93
func DefaultEncrypter (opts ... Option ) Encrypter {
83
- // Parameter Choice
84
- // https://www.rfc-editor.org/rfc/rfc9106.html#section-4
85
94
argon2dParameters := & argon2dParameters {
86
- iterations : uint32 (3 ),
87
- memory : uint32 (65536 ), // 2 ^ 16
88
- parallelism : uint8 (4 ),
95
+ iterations : defaultIterations ,
96
+ memory : defaultMemory ,
97
+ parallelism : defaultParallelism ,
98
+ keyLen : defaultKeyLen ,
89
99
}
90
100
for _ , opt := range opts {
91
101
opt (argon2dParameters )
@@ -98,6 +108,7 @@ func DefaultEncrypter(opts ...Option) Encrypter {
98
108
encParams .SetUint32 (nameParamIterations , argon2dParameters .iterations )
99
109
encParams .SetUint32 (nameParamMemory , argon2dParameters .memory )
100
110
encParams .SetUint8 (nameParamParallelism , argon2dParameters .parallelism )
111
+ encParams .SetUint32 (nameParamKeyLen , argon2dParameters .keyLen )
101
112
102
113
return Encrypter {
103
114
Method : method ,
@@ -140,22 +151,23 @@ func (e *Encrypter) Encrypt(message, password string) (string, error) {
140
151
return "" , err
141
152
}
142
153
143
- iterations := e .Params .GetUint32 (nameParamIterations )
144
- memory := e .Params .GetUint32 (nameParamMemory )
145
- parallelism := e .Params .GetUint8 (nameParamParallelism )
154
+ iterations := e .Params .GetUint32 (nameParamIterations , defaultIterations )
155
+ memory := e .Params .GetUint32 (nameParamMemory , defaultMemory )
156
+ parallelism := e .Params .GetUint8 (nameParamParallelism , defaultParallelism )
157
+ keyLen := e .Params .GetUint32 (nameParamKeyLen , defaultKeyLen )
146
158
147
159
// Argon2 currently has three modes:
148
160
// - data-dependent Argon2d,
149
161
// - data-independent Argon2i,
150
162
// - a mix of the two, Argon2id.
151
- cipherKey := argon2 .IDKey ([]byte (password ), salt , iterations , memory , parallelism , 32 )
163
+ derivedBytes := argon2 .IDKey ([]byte (password ), salt , iterations , memory , parallelism , keyLen )
152
164
153
165
// Encrypter method
154
166
switch funcs [1 ] {
155
167
case nameFuncAES256CTR :
156
- // Using salt for Initialization Vector (IV)
157
- iv := salt
158
- cipher := aesCrypt ([]byte (message ), iv , cipherKey )
168
+ cipherKey := derivedBytes [: 32 ]
169
+ iv := derivedBytes [ 32 :]
170
+ cipher := aesCTRCrypt ([]byte (message ), iv , cipherKey )
159
171
160
172
// MAC method
161
173
switch funcs [2 ] {
@@ -215,18 +227,35 @@ func (e *Encrypter) Decrypt(cipherText, password string) (string, error) {
215
227
case nameFuncArgon2ID :
216
228
salt := data [0 :16 ]
217
229
218
- iterations := e .Params .GetUint32 (nameParamIterations )
219
- memory := e .Params .GetUint32 (nameParamMemory )
220
- parallelism := e .Params .GetUint8 (nameParamParallelism )
230
+ iterations := e .Params .GetUint32 (nameParamIterations , defaultIterations )
231
+ memory := e .Params .GetUint32 (nameParamMemory , defaultMemory )
232
+ parallelism := e .Params .GetUint8 (nameParamParallelism , defaultParallelism )
233
+ keyLen := e .Params .GetUint32 (nameParamKeyLen , defaultKeyLen )
221
234
222
- cipherKey := argon2 .IDKey ([]byte (password ), salt , iterations , memory , parallelism , 32 )
235
+ derivedByte := argon2 .IDKey ([]byte (password ), salt , iterations , memory , parallelism , keyLen )
223
236
224
237
// Encrypter method
225
238
switch funcs [1 ] {
226
239
case nameFuncAES256CTR :
227
- iv := salt
240
+ var initVec , cipherKey []byte
241
+
242
+ switch keyLen {
243
+ case 0 :
244
+ // This case supports legacy encryption methods where the same salt is reused as the IV.
245
+ cipherKey = derivedByte
246
+ initVec = salt
247
+
248
+ case 48 :
249
+ // The first 32 bytes are used as the encryption key, and the last 16 bytes are used as the IV.
250
+ cipherKey = derivedByte [:32 ]
251
+ initVec = derivedByte [32 :]
252
+
253
+ default :
254
+ return "" , ErrInvalidParam
255
+ }
256
+
228
257
enc := data [16 : len (data )- 4 ]
229
- text = string (aesCrypt (enc , iv , cipherKey ))
258
+ text = string (aesCTRCrypt (enc , initVec , cipherKey ))
230
259
231
260
// MAC method
232
261
switch funcs [2 ] {
@@ -249,9 +278,9 @@ func (e *Encrypter) Decrypt(cipherText, password string) (string, error) {
249
278
return text , nil
250
279
}
251
280
252
- // aesCrypt encrypts/decrypts a message using AES-256-CTR and
281
+ // aesCTRCrypt encrypts/decrypts a message using AES-256-CTR and
253
282
// returns the encoded/decoded bytes.
254
- func aesCrypt (message , initVec , cipherKey []byte ) []byte {
283
+ func aesCTRCrypt (message , initVec , cipherKey []byte ) []byte {
255
284
// Generate the cipher message
256
285
cipherMsg := make ([]byte , len (message ))
257
286
aesCipher , err := aes .NewCipher (cipherKey )
0 commit comments