key_store_passphrase.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. // Copyright 2014 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. /*
  17. This key store behaves as KeyStorePlain with the difference that
  18. the private key is encrypted and on disk uses another JSON encoding.
  19. The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
  20. */
  21. package crypto
  22. import (
  23. "bytes"
  24. "crypto/aes"
  25. "crypto/sha256"
  26. "encoding/hex"
  27. "encoding/json"
  28. "errors"
  29. "fmt"
  30. "io"
  31. "reflect"
  32. "github.com/ethereum/go-ethereum/common"
  33. "github.com/ethereum/go-ethereum/crypto/randentropy"
  34. "github.com/pborman/uuid"
  35. "golang.org/x/crypto/pbkdf2"
  36. "golang.org/x/crypto/scrypt"
  37. )
  38. const (
  39. keyHeaderKDF = "scrypt"
  40. // n,r,p = 2^18, 8, 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
  41. StandardScryptN = 1 << 18
  42. StandardScryptP = 1
  43. // n,r,p = 2^12, 8, 6 uses 4MB memory and approx 100ms CPU time on a modern CPU.
  44. LightScryptN = 1 << 12
  45. LightScryptP = 6
  46. scryptR = 8
  47. scryptDKLen = 32
  48. )
  49. type keyStorePassphrase struct {
  50. keysDirPath string
  51. scryptN int
  52. scryptP int
  53. scryptR int
  54. scryptDKLen int
  55. }
  56. func NewKeyStorePassphrase(path string, scryptN int, scryptP int) KeyStore {
  57. return &keyStorePassphrase{path, scryptN, scryptP, scryptR, scryptDKLen}
  58. }
  59. func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
  60. return GenerateNewKeyDefault(ks, rand, auth)
  61. }
  62. func (ks keyStorePassphrase) GetKey(keyAddr common.Address, auth string) (key *Key, err error) {
  63. keyBytes, keyId, err := decryptKeyFromFile(ks.keysDirPath, keyAddr, auth)
  64. if err == nil {
  65. key = &Key{
  66. Id: uuid.UUID(keyId),
  67. Address: keyAddr,
  68. PrivateKey: ToECDSA(keyBytes),
  69. }
  70. }
  71. return
  72. }
  73. func (ks keyStorePassphrase) Cleanup(keyAddr common.Address) (err error) {
  74. return cleanup(ks.keysDirPath, keyAddr)
  75. }
  76. func (ks keyStorePassphrase) GetKeyAddresses() (addresses []common.Address, err error) {
  77. return getKeyAddresses(ks.keysDirPath)
  78. }
  79. func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
  80. authArray := []byte(auth)
  81. salt := randentropy.GetEntropyCSPRNG(32)
  82. derivedKey, err := scrypt.Key(authArray, salt, ks.scryptN, ks.scryptR, ks.scryptP, ks.scryptDKLen)
  83. if err != nil {
  84. return err
  85. }
  86. encryptKey := derivedKey[:16]
  87. keyBytes := FromECDSA(key.PrivateKey)
  88. iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
  89. cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
  90. if err != nil {
  91. return err
  92. }
  93. mac := Keccak256(derivedKey[16:32], cipherText)
  94. scryptParamsJSON := make(map[string]interface{}, 5)
  95. scryptParamsJSON["n"] = ks.scryptN
  96. scryptParamsJSON["r"] = ks.scryptR
  97. scryptParamsJSON["p"] = ks.scryptP
  98. scryptParamsJSON["dklen"] = ks.scryptDKLen
  99. scryptParamsJSON["salt"] = hex.EncodeToString(salt)
  100. cipherParamsJSON := cipherparamsJSON{
  101. IV: hex.EncodeToString(iv),
  102. }
  103. cryptoStruct := cryptoJSON{
  104. Cipher: "aes-128-ctr",
  105. CipherText: hex.EncodeToString(cipherText),
  106. CipherParams: cipherParamsJSON,
  107. KDF: "scrypt",
  108. KDFParams: scryptParamsJSON,
  109. MAC: hex.EncodeToString(mac),
  110. }
  111. encryptedKeyJSONV3 := encryptedKeyJSONV3{
  112. hex.EncodeToString(key.Address[:]),
  113. cryptoStruct,
  114. key.Id.String(),
  115. version,
  116. }
  117. keyJSON, err := json.Marshal(encryptedKeyJSONV3)
  118. if err != nil {
  119. return err
  120. }
  121. return writeKeyFile(key.Address, ks.keysDirPath, keyJSON)
  122. }
  123. func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err error) {
  124. // only delete if correct passphrase is given
  125. _, _, err = decryptKeyFromFile(ks.keysDirPath, keyAddr, auth)
  126. if err != nil {
  127. return err
  128. }
  129. return deleteKey(ks.keysDirPath, keyAddr)
  130. }
  131. func decryptKeyFromFile(keysDirPath string, keyAddr common.Address, auth string) (keyBytes []byte, keyId []byte, err error) {
  132. m := make(map[string]interface{})
  133. err = getKey(keysDirPath, keyAddr, &m)
  134. if err != nil {
  135. return
  136. }
  137. v := reflect.ValueOf(m["version"])
  138. if v.Kind() == reflect.String && v.String() == "1" {
  139. k := new(encryptedKeyJSONV1)
  140. err = getKey(keysDirPath, keyAddr, &k)
  141. if err != nil {
  142. return
  143. }
  144. return decryptKeyV1(k, auth)
  145. } else {
  146. k := new(encryptedKeyJSONV3)
  147. err = getKey(keysDirPath, keyAddr, &k)
  148. if err != nil {
  149. return
  150. }
  151. return decryptKeyV3(k, auth)
  152. }
  153. }
  154. func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) {
  155. if keyProtected.Version != version {
  156. return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
  157. }
  158. if keyProtected.Crypto.Cipher != "aes-128-ctr" {
  159. return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher)
  160. }
  161. keyId = uuid.Parse(keyProtected.Id)
  162. mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
  163. if err != nil {
  164. return nil, nil, err
  165. }
  166. iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
  167. if err != nil {
  168. return nil, nil, err
  169. }
  170. cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
  171. if err != nil {
  172. return nil, nil, err
  173. }
  174. derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
  175. if err != nil {
  176. return nil, nil, err
  177. }
  178. calculatedMAC := Keccak256(derivedKey[16:32], cipherText)
  179. if !bytes.Equal(calculatedMAC, mac) {
  180. return nil, nil, errors.New("Decryption failed: MAC mismatch")
  181. }
  182. plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
  183. if err != nil {
  184. return nil, nil, err
  185. }
  186. return plainText, keyId, err
  187. }
  188. func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
  189. keyId = uuid.Parse(keyProtected.Id)
  190. mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
  191. if err != nil {
  192. return nil, nil, err
  193. }
  194. iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
  195. if err != nil {
  196. return nil, nil, err
  197. }
  198. cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
  199. if err != nil {
  200. return nil, nil, err
  201. }
  202. derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
  203. if err != nil {
  204. return nil, nil, err
  205. }
  206. calculatedMAC := Keccak256(derivedKey[16:32], cipherText)
  207. if !bytes.Equal(calculatedMAC, mac) {
  208. return nil, nil, errors.New("Decryption failed: MAC mismatch")
  209. }
  210. plainText, err := aesCBCDecrypt(Keccak256(derivedKey[:16])[:16], cipherText, iv)
  211. if err != nil {
  212. return nil, nil, err
  213. }
  214. return plainText, keyId, err
  215. }
  216. func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
  217. authArray := []byte(auth)
  218. salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
  219. if err != nil {
  220. return nil, err
  221. }
  222. dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])
  223. if cryptoJSON.KDF == "scrypt" {
  224. n := ensureInt(cryptoJSON.KDFParams["n"])
  225. r := ensureInt(cryptoJSON.KDFParams["r"])
  226. p := ensureInt(cryptoJSON.KDFParams["p"])
  227. return scrypt.Key(authArray, salt, n, r, p, dkLen)
  228. } else if cryptoJSON.KDF == "pbkdf2" {
  229. c := ensureInt(cryptoJSON.KDFParams["c"])
  230. prf := cryptoJSON.KDFParams["prf"].(string)
  231. if prf != "hmac-sha256" {
  232. return nil, fmt.Errorf("Unsupported PBKDF2 PRF: ", prf)
  233. }
  234. key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
  235. return key, nil
  236. }
  237. return nil, fmt.Errorf("Unsupported KDF: ", cryptoJSON.KDF)
  238. }
  239. // TODO: can we do without this when unmarshalling dynamic JSON?
  240. // why do integers in KDF params end up as float64 and not int after
  241. // unmarshal?
  242. func ensureInt(x interface{}) int {
  243. res, ok := x.(int)
  244. if !ok {
  245. res = int(x.(float64))
  246. }
  247. return res
  248. }