rewrite the GCM encrypt and decrypt function.

This commit is contained in:
19byte 2024-03-02 17:32:01 +08:00 committed by GitHub
parent 0a2f33946b
commit b464391a45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 33 deletions

View file

@ -21,7 +21,7 @@ import (
"crypto/cipher" "crypto/cipher"
"crypto/rand" "crypto/rand"
"encoding/json" "encoding/json"
"io" "errors"
"os" "os"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -41,14 +41,32 @@ type AESEncryptedStorage struct {
filename string filename string
// Key stored in base64 // Key stored in base64
key []byte key []byte
gcm cipher.AEAD
gcmNS int // NonceSize
} }
// NewAESEncryptedStorage creates a new encrypted storage backed by the given file/key // NewAESEncryptedStorage creates a new encrypted storage backed by the given file/key
func NewAESEncryptedStorage(filename string, key []byte) *AESEncryptedStorage { func NewAESEncryptedStorage(filename string, key []byte) *AESEncryptedStorage {
return &AESEncryptedStorage{ aesStore := &AESEncryptedStorage{
filename: filename, filename: filename,
key: key, key: key,
} }
blk, err := aes.NewCipher(key)
if err != nil {
log.Warn("reading AES key", "err", err)
return nil
}
aesStore.gcm, err = cipher.NewGCM(blk)
if err != nil {
log.Warn("initializing AES AEAD", "err", err)
return nil
}
aesStore.gcmNS = aesStore.gcm.NonceSize()
return aesStore
} }
// Put stores a value by key. 0-length keys results in noop. // Put stores a value by key. 0-length keys results in noop.
@ -61,7 +79,7 @@ func (s *AESEncryptedStorage) Put(key, value string) {
log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename) log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
return return
} }
ciphertext, iv, err := encrypt(s.key, []byte(value), []byte(key)) ciphertext, iv, err := s.encrypt([]byte(value), []byte(key))
if err != nil { if err != nil {
log.Warn("Failed to encrypt entry", "err", err) log.Warn("Failed to encrypt entry", "err", err)
return return
@ -89,7 +107,7 @@ func (s *AESEncryptedStorage) Get(key string) (string, error) {
log.Warn("Key does not exist", "key", key) log.Warn("Key does not exist", "key", key)
return "", ErrNotFound return "", ErrNotFound
} }
entry, err := decrypt(s.key, encrypted.Iv, encrypted.CipherText, []byte(key)) entry, err := s.decrypt(encrypted.CipherText, []byte(key))
if err != nil { if err != nil {
log.Warn("Failed to decrypt key", "key", key) log.Warn("Failed to decrypt key", "key", key)
return "", err return "", err
@ -141,38 +159,29 @@ func (s *AESEncryptedStorage) writeEncryptedStorage(creds map[string]storedCrede
return nil return nil
} }
func randBytes(size int) (blk []byte, err error) {
blk = make([]byte, size)
_, err = rand.Read(blk)
return
}
// encrypt encrypts plaintext with the given key, with additional data // encrypt encrypts plaintext with the given key, with additional data
// The 'additionalData' is used to place the (plaintext) KV-store key into the V, // The 'additionalData' is used to place the (plaintext) KV-store key into the V,
// to prevent the possibility to alter a K, or swap two entries in the KV store with each other. // to prevent the possibility to alter a K, or swap two entries in the KV store with each other.
func encrypt(key []byte, plaintext []byte, additionalData []byte) ([]byte, []byte, error) { func (s *AESEncryptedStorage) encrypt(plaintext []byte, additionalData []byte) (_ []byte, _ []byte, err error) {
block, err := aes.NewCipher(key) // Never use more than 2^32 random nonce's with a given
if err != nil { // key because of the risk of a repeat.
return nil, nil, err var n []byte
if n, err = randBytes(s.gcmNS); err != nil {
return
} }
aesgcm, err := cipher.NewGCM(block) return append(n, s.gcm.Seal(nil, n, plaintext, additionalData)...), n, nil
if err != nil {
return nil, nil, err
}
nonce := make([]byte, aesgcm.NonceSize())
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return nil, nil, err
}
ciphertext := aesgcm.Seal(nil, nonce, plaintext, additionalData)
return ciphertext, nonce, nil
} }
func decrypt(key []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) { func (s *AESEncryptedStorage) decrypt(ciphertext []byte, additionalData []byte) ([]byte, error) {
block, err := aes.NewCipher(key) if len(ciphertext) < s.gcmNS {
if err != nil { return nil, errors.New("cipher data too short")
return nil, err
} }
aesgcm, err := cipher.NewGCM(block) return s.gcm.Open(nil, ciphertext[0:s.gcmNS], ciphertext[s.gcmNS:], additionalData)
if err != nil {
return nil, err
}
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, additionalData)
if err != nil {
return nil, err
}
return plaintext, nil
} }

View file

@ -36,13 +36,15 @@ func TestEncryption(t *testing.T) {
key := []byte("AES256Key-32Characters1234567890") key := []byte("AES256Key-32Characters1234567890")
plaintext := []byte("exampleplaintext") plaintext := []byte("exampleplaintext")
c, iv, err := encrypt(key, plaintext, nil) aesStore := NewAESEncryptedStorage("", key)
c, iv, err := aesStore.encrypt(plaintext, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
t.Logf("Ciphertext %x, nonce %x\n", c, iv) t.Logf("Ciphertext %x, nonce %x\n", c, iv)
p, err := decrypt(key, iv, c, nil) p, err := aesStore.decrypt(c, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }