Skip to content

Commit 88946e8

Browse files
mergify[bot]simitt
andauthored
Switch to NewGCMWithRandomNonce for fips (#7474) (#7549)
* Switch to NewGCMWithRandomNonce for fips (cherry picked from commit 7f1599a) Co-authored-by: simitt <[email protected]>
1 parent b1c867e commit 88946e8

File tree

10 files changed

+332
-213
lines changed

10 files changed

+332
-213
lines changed

internal/pkg/agent/vault/aesgcm/aesgcm.go

Lines changed: 0 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,8 @@
55
package aesgcm
66

77
import (
8-
"crypto/aes"
9-
"crypto/cipher"
108
"crypto/rand"
119
"encoding/hex"
12-
"syscall"
1310
)
1411

1512
// AESKeyType indicates the AES key length.
@@ -55,29 +52,6 @@ func NewKeyHexString(kt AESKeyType) (string, error) {
5552
return hex.EncodeToString(key), nil
5653
}
5754

58-
// Encrypt encrypts the data with AES-GCM
59-
func Encrypt(key, data []byte) ([]byte, error) {
60-
block, err := aes.NewCipher(key)
61-
if err != nil {
62-
return nil, err
63-
}
64-
65-
aesGCM, err := cipher.NewGCM(block)
66-
if err != nil {
67-
return nil, err
68-
}
69-
70-
nonce := make([]byte, aesGCM.NonceSize())
71-
if _, err = rand.Read(nonce); err != nil {
72-
return nil, err
73-
}
74-
75-
// The first parameter is nonce in order to get the ciphertext as concatenation of nonce and encrypted data
76-
ciphertext := aesGCM.Seal(nonce, nonce, data, nil)
77-
78-
return ciphertext, nil
79-
}
80-
8155
// EncryptHex encrypts with hex string key, producing hex encoded result
8256
func EncryptHex(key string, data []byte) (string, error) {
8357
bkey, err := hex.DecodeString(key)
@@ -91,27 +65,6 @@ func EncryptHex(key string, data []byte) (string, error) {
9165
return hex.EncodeToString(enc), nil
9266
}
9367

94-
// Decrypt decrypts the data with AES-GCM
95-
func Decrypt(key, data []byte) ([]byte, error) {
96-
block, err := aes.NewCipher(key)
97-
if err != nil {
98-
return nil, err
99-
}
100-
101-
aesGCM, err := cipher.NewGCM(block)
102-
if err != nil {
103-
return nil, err
104-
}
105-
106-
nonceSize := aesGCM.NonceSize()
107-
if len(data) < nonceSize {
108-
return nil, syscall.EINVAL
109-
}
110-
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
111-
112-
return aesGCM.Open(nil, nonce, ciphertext, nil)
113-
}
114-
11568
// DecryptHex decrypts with hex string key and data
11669
func DecryptHex(key string, data string) ([]byte, error) {
11770
bkey, err := hex.DecodeString(key)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License 2.0;
3+
// you may not use this file except in compliance with the Elastic License 2.0.
4+
5+
//go:build requirefips
6+
7+
package aesgcm
8+
9+
import (
10+
"crypto/aes"
11+
"crypto/cipher"
12+
)
13+
14+
// Encrypt encrypts the data with AES-GCM with random nonce
15+
func Encrypt(key, data []byte) ([]byte, error) {
16+
block, err := aes.NewCipher(key)
17+
if err != nil {
18+
return nil, err
19+
}
20+
21+
aesGCM, err := cipher.NewGCMWithRandomNonce(block)
22+
if err != nil {
23+
return nil, err
24+
}
25+
ciphertext := aesGCM.Seal(nil, nil, data, nil)
26+
return ciphertext, nil
27+
}
28+
29+
// Decrypt decrypts the data with AES-GCM with random nonce
30+
func Decrypt(key, data []byte) ([]byte, error) {
31+
block, err := aes.NewCipher(key)
32+
if err != nil {
33+
return nil, err
34+
}
35+
36+
aesGCM, err := cipher.NewGCMWithRandomNonce(block)
37+
if err != nil {
38+
return nil, err
39+
}
40+
return aesGCM.Open(nil, nil, data, nil)
41+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License 2.0;
3+
// you may not use this file except in compliance with the Elastic License 2.0.
4+
5+
//go:build !requirefips
6+
7+
package aesgcm
8+
9+
import (
10+
"crypto/aes"
11+
"crypto/cipher"
12+
"crypto/rand"
13+
"syscall"
14+
)
15+
16+
// Encrypt encrypts the data with AES-GCM
17+
func Encrypt(key, data []byte) ([]byte, error) {
18+
block, err := aes.NewCipher(key)
19+
if err != nil {
20+
return nil, err
21+
}
22+
23+
aesGCM, err := cipher.NewGCM(block)
24+
if err != nil {
25+
return nil, err
26+
}
27+
28+
nonce := make([]byte, aesGCM.NonceSize())
29+
if _, err = rand.Read(nonce); err != nil {
30+
return nil, err
31+
}
32+
33+
// The first parameter is nonce in order to get the ciphertext as concatenation of nonce and encrypted data
34+
ciphertext := aesGCM.Seal(nonce, nonce, data, nil)
35+
return ciphertext, nil
36+
}
37+
38+
// Decrypt decrypts the data with AES-GCM
39+
func Decrypt(key, data []byte) ([]byte, error) {
40+
block, err := aes.NewCipher(key)
41+
if err != nil {
42+
return nil, err
43+
}
44+
45+
aesGCM, err := cipher.NewGCM(block)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
nonceSize := aesGCM.NonceSize()
51+
if len(data) < nonceSize {
52+
return nil, syscall.EINVAL
53+
}
54+
nonce, ciphertext := data[:nonceSize], data[nonceSize:]
55+
return aesGCM.Open(nil, nonce, ciphertext, nil)
56+
}

internal/pkg/crypto/io.go

Lines changed: 2 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,11 @@ import (
1111
"crypto/pbkdf2"
1212
"crypto/rand"
1313
"crypto/sha512"
14-
"encoding/binary"
1514
"errors"
1615
"fmt"
1716
"io"
1817
)
1918

20-
// Option is the default options used to generate the encrypt and decrypt writer.
21-
// NOTE: the defined options need to be same for both the Reader and the writer.
22-
type Option struct {
23-
Generator bytesGen
24-
IterationsCount int
25-
KeyLength int
26-
SaltLength int
27-
IVLength int
28-
29-
// BlockSize must be a factor of aes.BlockSize
30-
BlockSize int
31-
}
32-
33-
// DefaultOptions is the default options to use when creating the writer, changing might decrease
34-
// the efficacity of the encryption.
35-
var DefaultOptions = &Option{
36-
IterationsCount: 10000,
37-
KeyLength: 32,
38-
SaltLength: 64,
39-
IVLength: 12,
40-
Generator: randomBytes,
41-
BlockSize: bytes.MinRead,
42-
}
43-
4419
// versionMagicHeader is the format version that will be added at the beginning of the header and
4520
// can be used to change how the decryption work in future version.
4621
var versionMagicHeader = []byte("v2")
@@ -122,7 +97,7 @@ func (w *Writer) Write(b []byte) (int, error) {
12297
return 0, w.err
12398
}
12499

125-
aesgcm, err := cipher.NewGCM(block)
100+
aesgcm, err := getCipherAEAD(block)
126101
if err != nil {
127102
w.err = fmt.Errorf("could not create the GCM to encrypt: %w", err)
128103
return 0, w.err
@@ -160,33 +135,6 @@ func (w *Writer) Write(b []byte) (int, error) {
160135
return len(b), nil
161136
}
162137

163-
func (w *Writer) writeBlock(b []byte) error {
164-
// randomly generate the salt and the initialization vector, this information will be saved
165-
// on disk in the file as part of the header
166-
iv, err := w.generator(w.option.IVLength)
167-
if err != nil {
168-
w.err = fmt.Errorf("fail to generate random IV: %w", err)
169-
return w.err
170-
}
171-
172-
//nolint:errcheck // Ignore the error at this point.
173-
w.writer.Write(iv)
174-
175-
encodedBytes := w.gcm.Seal(nil, iv, b, nil)
176-
177-
l := make([]byte, 4)
178-
binary.LittleEndian.PutUint32(l, uint32(len(encodedBytes))) //nolint:gosec // ignoring unsafe type conversion
179-
//nolint:errcheck // Ignore the error at this point.
180-
w.writer.Write(l)
181-
182-
_, err = w.writer.Write(encodedBytes)
183-
if err != nil {
184-
return fmt.Errorf("fail to encode data: %w", err)
185-
}
186-
187-
return nil
188-
}
189-
190138
// Reader implements the io.Reader interface and allow to decrypt bytes from the Writer. The reader
191139
// will lazy read the header from the wrapper reader to initialize everything required to decrypt
192140
// the data.
@@ -262,7 +210,7 @@ func (r *Reader) Read(b []byte) (int, error) {
262210
return 0, r.err
263211
}
264212

265-
aesgcm, err := cipher.NewGCM(block)
213+
aesgcm, err := getCipherAEAD(block)
266214
if err != nil {
267215
r.err = fmt.Errorf("could not create the GCM to decrypt the data: %w", err)
268216
return 0, r.err
@@ -300,43 +248,6 @@ func (r *Reader) readTo(b []byte) (int, error) {
300248
return n, r.err
301249
}
302250

303-
func (r *Reader) consumeBlock() error {
304-
// Retrieve block information:
305-
// - Initialization vector
306-
// - Length of the block
307-
iv, l, err := r.readBlockInfo()
308-
if err != nil {
309-
return err
310-
}
311-
312-
encodedBytes := make([]byte, l)
313-
_, err = io.ReadAtLeast(r.reader, encodedBytes, l)
314-
if err != nil {
315-
r.err = fmt.Errorf("fail read the block of %d bytes: %w", l, err)
316-
}
317-
318-
decodedBytes, err := r.gcm.Open(nil, iv, encodedBytes, nil)
319-
if err != nil {
320-
return fmt.Errorf("fail to decode bytes: %w", err)
321-
}
322-
r.buf = append(r.buf[:], decodedBytes...)
323-
324-
return nil
325-
}
326-
327-
func (r *Reader) readBlockInfo() ([]byte, int, error) {
328-
buf := make([]byte, r.option.IVLength+4)
329-
_, err := io.ReadAtLeast(r.reader, buf, len(buf))
330-
if err != nil {
331-
return nil, 0, err
332-
}
333-
334-
iv := buf[0:r.option.IVLength]
335-
l := binary.LittleEndian.Uint32(buf[r.option.IVLength:])
336-
337-
return iv, int(l), nil
338-
}
339-
340251
// Close will propagate the Close call to the wrapped reader.
341252
func (r *Reader) Close() error {
342253
a, ok := r.reader.(io.ReadCloser)

0 commit comments

Comments
 (0)