mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
rewrite the GCM encrypt and decrypt function.
This commit is contained in:
parent
0a2f33946b
commit
b464391a45
2 changed files with 44 additions and 33 deletions
|
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue