github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/signer/storage/aes_gcm_storage.go (about)

     1  //
     2  package storage
     3  
     4  import (
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"crypto/rand"
     8  	"encoding/json"
     9  	"io"
    10  	"io/ioutil"
    11  	"os"
    12  
    13  	"github.com/quickchainproject/quickchain/log"
    14  )
    15  
    16  type storedCredential struct {
    17  	// The iv
    18  	Iv []byte `json:"iv"`
    19  	// The ciphertext
    20  	CipherText []byte `json:"c"`
    21  }
    22  
    23  // AESEncryptedStorage is a storage type which is backed by a json-faile. The json-file contains
    24  // key-value mappings, where the keys are _not_ encrypted, only the values are.
    25  type AESEncryptedStorage struct {
    26  	// File to read/write credentials
    27  	filename string
    28  	// Key stored in base64
    29  	key []byte
    30  }
    31  
    32  // NewAESEncryptedStorage creates a new encrypted storage backed by the given file/key
    33  func NewAESEncryptedStorage(filename string, key []byte) *AESEncryptedStorage {
    34  	return &AESEncryptedStorage{
    35  		filename: filename,
    36  		key:      key,
    37  	}
    38  }
    39  
    40  // Put stores a value by key. 0-length keys results in no-op
    41  func (s *AESEncryptedStorage) Put(key, value string) {
    42  	if len(key) == 0 {
    43  		return
    44  	}
    45  	data, err := s.readEncryptedStorage()
    46  	if err != nil {
    47  		log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
    48  		return
    49  	}
    50  	ciphertext, iv, err := encrypt(s.key, []byte(value))
    51  	if err != nil {
    52  		log.Warn("Failed to encrypt entry", "err", err)
    53  		return
    54  	}
    55  	encrypted := storedCredential{Iv: iv, CipherText: ciphertext}
    56  	data[key] = encrypted
    57  	if err = s.writeEncryptedStorage(data); err != nil {
    58  		log.Warn("Failed to write entry", "err", err)
    59  	}
    60  }
    61  
    62  // Get returns the previously stored value, or the empty string if it does not exist or key is of 0-length
    63  func (s *AESEncryptedStorage) Get(key string) string {
    64  	if len(key) == 0 {
    65  		return ""
    66  	}
    67  	data, err := s.readEncryptedStorage()
    68  	if err != nil {
    69  		log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
    70  		return ""
    71  	}
    72  	encrypted, exist := data[key]
    73  	if !exist {
    74  		log.Warn("Key does not exist", "key", key)
    75  		return ""
    76  	}
    77  	entry, err := decrypt(s.key, encrypted.Iv, encrypted.CipherText)
    78  	if err != nil {
    79  		log.Warn("Failed to decrypt key", "key", key)
    80  		return ""
    81  	}
    82  	return string(entry)
    83  }
    84  
    85  // readEncryptedStorage reads the file with encrypted creds
    86  func (s *AESEncryptedStorage) readEncryptedStorage() (map[string]storedCredential, error) {
    87  	creds := make(map[string]storedCredential)
    88  	raw, err := ioutil.ReadFile(s.filename)
    89  
    90  	if err != nil {
    91  		if os.IsNotExist(err) {
    92  			// Doesn't exist yet
    93  			return creds, nil
    94  
    95  		} else {
    96  			log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
    97  		}
    98  	}
    99  	if err = json.Unmarshal(raw, &creds); err != nil {
   100  		log.Warn("Failed to unmarshal encrypted storage", "err", err, "file", s.filename)
   101  		return nil, err
   102  	}
   103  	return creds, nil
   104  }
   105  
   106  // writeEncryptedStorage write the file with encrypted creds
   107  func (s *AESEncryptedStorage) writeEncryptedStorage(creds map[string]storedCredential) error {
   108  	raw, err := json.Marshal(creds)
   109  	if err != nil {
   110  		return err
   111  	}
   112  	if err = ioutil.WriteFile(s.filename, raw, 0600); err != nil {
   113  		return err
   114  	}
   115  	return nil
   116  }
   117  
   118  func encrypt(key []byte, plaintext []byte) ([]byte, []byte, error) {
   119  	block, err := aes.NewCipher(key)
   120  	if err != nil {
   121  		return nil, nil, err
   122  	}
   123  	aesgcm, err := cipher.NewGCM(block)
   124  	nonce := make([]byte, aesgcm.NonceSize())
   125  	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
   126  		return nil, nil, err
   127  	}
   128  	if err != nil {
   129  		return nil, nil, err
   130  	}
   131  	ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
   132  	return ciphertext, nonce, nil
   133  }
   134  
   135  func decrypt(key []byte, nonce []byte, ciphertext []byte) ([]byte, error) {
   136  	block, err := aes.NewCipher(key)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  	aesgcm, err := cipher.NewGCM(block)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	return plaintext, nil
   149  }