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/rand"
"encoding/json"
"io"
"errors"
"os"
"github.com/ethereum/go-ethereum/log"
@ -41,14 +41,32 @@ type AESEncryptedStorage struct {
filename string
// Key stored in base64
key []byte
gcm cipher.AEAD
gcmNS int // NonceSize
}
// NewAESEncryptedStorage creates a new encrypted storage backed by the given file/key
func NewAESEncryptedStorage(filename string, key []byte) *AESEncryptedStorage {
return &AESEncryptedStorage{
aesStore := &AESEncryptedStorage{
filename: filename,
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.
@ -61,7 +79,7 @@ func (s *AESEncryptedStorage) Put(key, value string) {
log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
return
}
ciphertext, iv, err := encrypt(s.key, []byte(value), []byte(key))
ciphertext, iv, err := s.encrypt([]byte(value), []byte(key))
if err != nil {
log.Warn("Failed to encrypt entry", "err", err)
return
@ -89,7 +107,7 @@ func (s *AESEncryptedStorage) Get(key string) (string, error) {
log.Warn("Key does not exist", "key", key)
return "", ErrNotFound
}
entry, err := decrypt(s.key, encrypted.Iv, encrypted.CipherText, []byte(key))
entry, err := s.decrypt(encrypted.CipherText, []byte(key))
if err != nil {
log.Warn("Failed to decrypt key", "key", key)
return "", err
@ -141,38 +159,29 @@ func (s *AESEncryptedStorage) writeEncryptedStorage(creds map[string]storedCrede
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
// 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.
func encrypt(key []byte, plaintext []byte, additionalData []byte) ([]byte, []byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, nil, err
func (s *AESEncryptedStorage) encrypt(plaintext []byte, additionalData []byte) (_ []byte, _ []byte, err error) {
// Never use more than 2^32 random nonce's with a given
// key because of the risk of a repeat.
var n []byte
if n, err = randBytes(s.gcmNS); err != nil {
return
}
aesgcm, err := cipher.NewGCM(block)
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
return append(n, s.gcm.Seal(nil, n, plaintext, additionalData)...), n, nil
}
func decrypt(key []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
func (s *AESEncryptedStorage) decrypt(ciphertext []byte, additionalData []byte) ([]byte, error) {
if len(ciphertext) < s.gcmNS {
return nil, errors.New("cipher data too short")
}
aesgcm, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
plaintext, err := aesgcm.Open(nil, nonce, ciphertext, additionalData)
if err != nil {
return nil, err
}
return plaintext, nil
return s.gcm.Open(nil, ciphertext[0:s.gcmNS], ciphertext[s.gcmNS:], additionalData)
}

View file

@ -36,13 +36,15 @@ func TestEncryption(t *testing.T) {
key := []byte("AES256Key-32Characters1234567890")
plaintext := []byte("exampleplaintext")
c, iv, err := encrypt(key, plaintext, nil)
aesStore := NewAESEncryptedStorage("", key)
c, iv, err := aesStore.encrypt(plaintext, nil)
if err != nil {
t.Fatal(err)
}
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 {
t.Fatal(err)
}