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