key_store_passphrase.go 7.6 KB

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