github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/signer/storage/aes_gcm_storage.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:42</date>
    10  //</624450111014965248>
    11  
    12  //
    13  
    14  package storage
    15  
    16  import (
    17  	"crypto/aes"
    18  	"crypto/cipher"
    19  	"crypto/rand"
    20  	"encoding/json"
    21  	"io"
    22  	"io/ioutil"
    23  	"os"
    24  
    25  	"github.com/ethereum/go-ethereum/log"
    26  )
    27  
    28  type storedCredential struct {
    29  //四维
    30  	Iv []byte `json:"iv"`
    31  //密文
    32  	CipherText []byte `json:"c"`
    33  }
    34  
    35  //AESEncryptedStorage是一种由JSON文件支持的存储类型。json文件包含
    36  //密钥值映射,其中密钥没有加密,只有值是加密的。
    37  type AESEncryptedStorage struct {
    38  //要读取/写入凭据的文件
    39  	filename string
    40  //密钥存储在base64中
    41  	key []byte
    42  }
    43  
    44  //newaesEncryptedStorage创建由给定文件/密钥支持的新加密存储
    45  func NewAESEncryptedStorage(filename string, key []byte) *AESEncryptedStorage {
    46  	return &AESEncryptedStorage{
    47  		filename: filename,
    48  		key:      key,
    49  	}
    50  }
    51  
    52  //按键存储值。0长度键导致无操作
    53  func (s *AESEncryptedStorage) Put(key, value string) {
    54  	if len(key) == 0 {
    55  		return
    56  	}
    57  	data, err := s.readEncryptedStorage()
    58  	if err != nil {
    59  		log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
    60  		return
    61  	}
    62  	ciphertext, iv, err := encrypt(s.key, []byte(value), []byte(key))
    63  	if err != nil {
    64  		log.Warn("Failed to encrypt entry", "err", err)
    65  		return
    66  	}
    67  	encrypted := storedCredential{Iv: iv, CipherText: ciphertext}
    68  	data[key] = encrypted
    69  	if err = s.writeEncryptedStorage(data); err != nil {
    70  		log.Warn("Failed to write entry", "err", err)
    71  	}
    72  }
    73  
    74  //get返回以前存储的值,如果该值不存在或键的长度为0,则返回空字符串
    75  func (s *AESEncryptedStorage) Get(key string) string {
    76  	if len(key) == 0 {
    77  		return ""
    78  	}
    79  	data, err := s.readEncryptedStorage()
    80  	if err != nil {
    81  		log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
    82  		return ""
    83  	}
    84  	encrypted, exist := data[key]
    85  	if !exist {
    86  		log.Warn("Key does not exist", "key", key)
    87  		return ""
    88  	}
    89  	entry, err := decrypt(s.key, encrypted.Iv, encrypted.CipherText, []byte(key))
    90  	if err != nil {
    91  		log.Warn("Failed to decrypt key", "key", key)
    92  		return ""
    93  	}
    94  	return string(entry)
    95  }
    96  
    97  //ReadEncryptedStorage使用加密的凭据读取文件
    98  func (s *AESEncryptedStorage) readEncryptedStorage() (map[string]storedCredential, error) {
    99  	creds := make(map[string]storedCredential)
   100  	raw, err := ioutil.ReadFile(s.filename)
   101  
   102  	if err != nil {
   103  		if os.IsNotExist(err) {
   104  //还不存在
   105  			return creds, nil
   106  		}
   107  		log.Warn("Failed to read encrypted storage", "err", err, "file", s.filename)
   108  	}
   109  	if err = json.Unmarshal(raw, &creds); err != nil {
   110  		log.Warn("Failed to unmarshal encrypted storage", "err", err, "file", s.filename)
   111  		return nil, err
   112  	}
   113  	return creds, nil
   114  }
   115  
   116  //WriteEncryptedStorage使用加密的凭据写入文件
   117  func (s *AESEncryptedStorage) writeEncryptedStorage(creds map[string]storedCredential) error {
   118  	raw, err := json.Marshal(creds)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	if err = ioutil.WriteFile(s.filename, raw, 0600); err != nil {
   123  		return err
   124  	}
   125  	return nil
   126  }
   127  
   128  //加密用给定的密钥加密明文,并附加数据
   129  //“附加数据”用于将(明文)kv存储密钥放入v,
   130  //以防止改变一个k,或相互交换kv存储中的两个条目。
   131  func encrypt(key []byte, plaintext []byte, additionalData []byte) ([]byte, []byte, error) {
   132  	block, err := aes.NewCipher(key)
   133  	if err != nil {
   134  		return nil, nil, err
   135  	}
   136  	aesgcm, err := cipher.NewGCM(block)
   137  	nonce := make([]byte, aesgcm.NonceSize())
   138  	if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
   139  		return nil, nil, err
   140  	}
   141  	if err != nil {
   142  		return nil, nil, err
   143  	}
   144  	ciphertext := aesgcm.Seal(nil, nonce, plaintext, additionalData)
   145  	return ciphertext, nonce, nil
   146  }
   147  
   148  func decrypt(key []byte, nonce []byte, ciphertext []byte, additionalData []byte) ([]byte, error) {
   149  	block, err := aes.NewCipher(key)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  	aesgcm, err := cipher.NewGCM(block)
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	plaintext, err := aesgcm.Open(nil, nonce, ciphertext, additionalData)
   158  	if err != nil {
   159  		return nil, err
   160  	}
   161  	return plaintext, nil
   162  }
   163