key_store_passphrase.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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. Cryptography:
  24. 1. Encryption key is scrypt derived key from user passphrase. Scrypt parameters
  25. (work factors) [1][2] are defined as constants below.
  26. 2. Scrypt salt is 32 random bytes from CSPRNG. It is appended to ciphertext.
  27. 3. Checksum is SHA3 of the private key bytes.
  28. 4. Plaintext is concatenation of private key bytes and checksum.
  29. 5. Encryption algo is AES 256 CBC [3][4]
  30. 6. CBC IV is 16 random bytes from CSPRNG. It is appended to ciphertext.
  31. 7. Plaintext padding is PKCS #7 [5][6]
  32. Encoding:
  33. 1. On disk, ciphertext, salt and IV are encoded in a nested JSON object.
  34. cat a key file to see the structure.
  35. 2. byte arrays are base64 JSON strings.
  36. 3. The EC private key bytes are in uncompressed form [7].
  37. They are a big-endian byte slice of the absolute value of D [8][9].
  38. 4. The checksum is the last 32 bytes of the plaintext byte array and the
  39. private key is the preceeding bytes.
  40. References:
  41. 1. http://www.tarsnap.com/scrypt/scrypt-slides.pdf
  42. 2. http://stackoverflow.com/questions/11126315/what-are-optimal-scrypt-work-factors
  43. 3. http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
  44. 4. http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
  45. 5. https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
  46. 6. http://tools.ietf.org/html/rfc2315
  47. 7. http://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key
  48. 8. http://golang.org/pkg/crypto/ecdsa/#PrivateKey
  49. 9. https://golang.org/pkg/math/big/#Int.Bytes
  50. */
  51. package crypto
  52. import (
  53. "bytes"
  54. "crypto/aes"
  55. "crypto/cipher"
  56. "encoding/hex"
  57. "encoding/json"
  58. "errors"
  59. "io"
  60. "os"
  61. "path/filepath"
  62. "code.google.com/p/go-uuid/uuid"
  63. "github.com/ethereum/go-ethereum/crypto/randentropy"
  64. "golang.org/x/crypto/scrypt"
  65. )
  66. const (
  67. // 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
  68. scryptN = 1 << 18
  69. scryptr = 8
  70. scryptp = 1
  71. scryptdkLen = 32
  72. )
  73. type keyStorePassphrase struct {
  74. keysDirPath string
  75. }
  76. func NewKeyStorePassphrase(path string) KeyStore2 {
  77. return &keyStorePassphrase{path}
  78. }
  79. func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
  80. return GenerateNewKeyDefault(ks, rand, auth)
  81. }
  82. func (ks keyStorePassphrase) GetKey(keyAddr []byte, auth string) (key *Key, err error) {
  83. keyBytes, keyId, err := DecryptKey(ks, keyAddr, auth)
  84. if err != nil {
  85. return nil, err
  86. }
  87. key = &Key{
  88. Id: uuid.UUID(keyId),
  89. Address: keyAddr,
  90. PrivateKey: ToECDSA(keyBytes),
  91. }
  92. return key, err
  93. }
  94. func (ks keyStorePassphrase) GetKeyAddresses() (addresses [][]byte, err error) {
  95. return GetKeyAddresses(ks.keysDirPath)
  96. }
  97. func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
  98. authArray := []byte(auth)
  99. salt := randentropy.GetEntropyMixed(32)
  100. derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
  101. if err != nil {
  102. return err
  103. }
  104. keyBytes := FromECDSA(key.PrivateKey)
  105. keyBytesHash := Sha3(keyBytes)
  106. toEncrypt := PKCS7Pad(append(keyBytes, keyBytesHash...))
  107. AES256Block, err := aes.NewCipher(derivedKey)
  108. if err != nil {
  109. return err
  110. }
  111. iv := randentropy.GetEntropyMixed(aes.BlockSize) // 16
  112. AES256CBCEncrypter := cipher.NewCBCEncrypter(AES256Block, iv)
  113. cipherText := make([]byte, len(toEncrypt))
  114. AES256CBCEncrypter.CryptBlocks(cipherText, toEncrypt)
  115. cipherStruct := cipherJSON{
  116. salt,
  117. iv,
  118. cipherText,
  119. }
  120. keyStruct := encryptedKeyJSON{
  121. key.Id,
  122. key.Address,
  123. cipherStruct,
  124. }
  125. keyJSON, err := json.Marshal(keyStruct)
  126. if err != nil {
  127. return err
  128. }
  129. return WriteKeyFile(key.Address, ks.keysDirPath, keyJSON)
  130. }
  131. func (ks keyStorePassphrase) DeleteKey(keyAddr []byte, auth string) (err error) {
  132. // only delete if correct passphrase is given
  133. _, _, err = DecryptKey(ks, keyAddr, auth)
  134. if err != nil {
  135. return err
  136. }
  137. keyDirPath := filepath.Join(ks.keysDirPath, hex.EncodeToString(keyAddr))
  138. return os.RemoveAll(keyDirPath)
  139. }
  140. func DecryptKey(ks keyStorePassphrase, keyAddr []byte, auth string) (keyBytes []byte, keyId []byte, err error) {
  141. fileContent, err := GetKeyFile(ks.keysDirPath, keyAddr)
  142. if err != nil {
  143. return nil, nil, err
  144. }
  145. keyProtected := new(encryptedKeyJSON)
  146. err = json.Unmarshal(fileContent, keyProtected)
  147. keyId = keyProtected.Id
  148. salt := keyProtected.Crypto.Salt
  149. iv := keyProtected.Crypto.IV
  150. cipherText := keyProtected.Crypto.CipherText
  151. authArray := []byte(auth)
  152. derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptr, scryptp, scryptdkLen)
  153. if err != nil {
  154. return nil, nil, err
  155. }
  156. plainText, err := aesCBCDecrypt(derivedKey, cipherText, iv)
  157. if err != nil {
  158. return nil, nil, err
  159. }
  160. keyBytes = plainText[:len(plainText)-32]
  161. keyBytesHash := plainText[len(plainText)-32:]
  162. if !bytes.Equal(Sha3(keyBytes), keyBytesHash) {
  163. err = errors.New("Decryption failed: checksum mismatch")
  164. return nil, nil, err
  165. }
  166. return keyBytes, keyId, err
  167. }