Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
6b2a03fa
Commit
6b2a03fa
authored
Jun 25, 2015
by
Jeffrey Wilcke
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1085 from Gustav-Simonsson/key_store_v3
crypto: key store v3
parents
8774fdcd
d23ec6c4
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
381 additions
and
91 deletions
+381
-91
test_utils.go
common/test_utils.go
+37
-0
crypto.go
crypto/crypto.go
+19
-7
key.go
crypto/key.go
+16
-10
key_store_passphrase.go
crypto/key_store_passphrase.go
+119
-72
key_store_test.go
crypto/key_store_test.go
+112
-2
cb61d5a9c4896fb9658090b597ef0e7be6f7b67e
...97ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e
+1
-0
v1_test_vector.json
crypto/tests/v1_test_vector.json
+28
-0
v3_test_vector.json
crypto/tests/v3_test_vector.json
+49
-0
No files found.
common/test_utils.go
0 → 100644
View file @
6b2a03fa
package
common
import
(
"encoding/json"
"fmt"
"io/ioutil"
)
// LoadJSON reads the given file and unmarshals its content.
func
LoadJSON
(
file
string
,
val
interface
{})
error
{
content
,
err
:=
ioutil
.
ReadFile
(
file
)
if
err
!=
nil
{
return
err
}
if
err
:=
json
.
Unmarshal
(
content
,
val
);
err
!=
nil
{
if
syntaxerr
,
ok
:=
err
.
(
*
json
.
SyntaxError
);
ok
{
line
:=
findLine
(
content
,
syntaxerr
.
Offset
)
return
fmt
.
Errorf
(
"JSON syntax error at %v:%v: %v"
,
file
,
line
,
err
)
}
return
fmt
.
Errorf
(
"JSON unmarshal error in %v: %v"
,
file
,
err
)
}
return
nil
}
// findLine returns the line number for the given offset into data.
func
findLine
(
data
[]
byte
,
offset
int64
)
(
line
int
)
{
line
=
1
for
i
,
r
:=
range
string
(
data
)
{
if
int64
(
i
)
>=
offset
{
return
}
if
r
==
'\n'
{
line
++
}
}
return
}
crypto/crypto.go
View file @
6b2a03fa
...
@@ -258,19 +258,31 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
...
@@ -258,19 +258,31 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
return
key
,
err
return
key
,
err
}
}
func
aesCBCDecrypt
(
key
[]
byte
,
cipherText
[]
byte
,
iv
[]
byte
)
(
plainText
[]
byte
,
err
error
)
{
// AES-128 is selected due to size of encryptKey
func
aesCTRXOR
(
key
,
inText
,
iv
[]
byte
)
([]
byte
,
error
)
{
aesBlock
,
err
:=
aes
.
NewCipher
(
key
)
aesBlock
,
err
:=
aes
.
NewCipher
(
key
)
if
err
!=
nil
{
if
err
!=
nil
{
return
plainText
,
err
return
nil
,
err
}
stream
:=
cipher
.
NewCTR
(
aesBlock
,
iv
)
outText
:=
make
([]
byte
,
len
(
inText
))
stream
.
XORKeyStream
(
outText
,
inText
)
return
outText
,
err
}
func
aesCBCDecrypt
(
key
,
cipherText
,
iv
[]
byte
)
([]
byte
,
error
)
{
aesBlock
,
err
:=
aes
.
NewCipher
(
key
)
if
err
!=
nil
{
return
nil
,
err
}
}
decrypter
:=
cipher
.
NewCBCDecrypter
(
aesBlock
,
iv
)
decrypter
:=
cipher
.
NewCBCDecrypter
(
aesBlock
,
iv
)
paddedPlain
T
ext
:=
make
([]
byte
,
len
(
cipherText
))
paddedPlain
t
ext
:=
make
([]
byte
,
len
(
cipherText
))
decrypter
.
CryptBlocks
(
paddedPlain
T
ext
,
cipherText
)
decrypter
.
CryptBlocks
(
paddedPlain
t
ext
,
cipherText
)
plain
Text
=
PKCS7Unpad
(
paddedPlainT
ext
)
plain
text
:=
PKCS7Unpad
(
paddedPlaint
ext
)
if
plain
T
ext
==
nil
{
if
plain
t
ext
==
nil
{
err
=
errors
.
New
(
"Decryption failed: PKCS7Unpad failed after AES decryption"
)
err
=
errors
.
New
(
"Decryption failed: PKCS7Unpad failed after AES decryption"
)
}
}
return
plain
T
ext
,
err
return
plain
t
ext
,
err
}
}
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
// From https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
...
...
crypto/key.go
View file @
6b2a03fa
...
@@ -35,7 +35,7 @@ import (
...
@@ -35,7 +35,7 @@ import (
)
)
const
(
const
(
version
=
"1"
version
=
3
)
)
type
Key
struct
{
type
Key
struct
{
...
@@ -51,10 +51,17 @@ type plainKeyJSON struct {
...
@@ -51,10 +51,17 @@ type plainKeyJSON struct {
Address
string
`json:"address"`
Address
string
`json:"address"`
PrivateKey
string
`json:"privatekey"`
PrivateKey
string
`json:"privatekey"`
Id
string
`json:"id"`
Id
string
`json:"id"`
Version
string
`json:"version"`
Version
int
`json:"version"`
}
}
type
encryptedKeyJSON
struct
{
type
encryptedKeyJSONV3
struct
{
Address
string
`json:"address"`
Crypto
cryptoJSON
Id
string
`json:"id"`
Version
int
`json:"version"`
}
type
encryptedKeyJSONV1
struct
{
Address
string
`json:"address"`
Address
string
`json:"address"`
Crypto
cryptoJSON
Crypto
cryptoJSON
Id
string
`json:"id"`
Id
string
`json:"id"`
...
@@ -66,9 +73,8 @@ type cryptoJSON struct {
...
@@ -66,9 +73,8 @@ type cryptoJSON struct {
CipherText
string
`json:"ciphertext"`
CipherText
string
`json:"ciphertext"`
CipherParams
cipherparamsJSON
`json:"cipherparams"`
CipherParams
cipherparamsJSON
`json:"cipherparams"`
KDF
string
`json:"kdf"`
KDF
string
`json:"kdf"`
KDFParams
scryptParamsJSON
`json:"kdfparams"`
KDFParams
map
[
string
]
interface
{}
`json:"kdfparams"`
MAC
string
`json:"mac"`
MAC
string
`json:"mac"`
Version
string
`json:"version"`
}
}
type
cipherparamsJSON
struct
{
type
cipherparamsJSON
struct
{
...
...
crypto/key_store_passphrase.go
View file @
6b2a03fa
...
@@ -26,40 +26,7 @@
...
@@ -26,40 +26,7 @@
This key store behaves as KeyStorePlain with the difference that
This key store behaves as KeyStorePlain with the difference that
the private key is encrypted and on disk uses another JSON encoding.
the private key is encrypted and on disk uses another JSON encoding.
Cryptography:
The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
1. Encryption key is first 16 bytes of scrypt derived key
from user passphrase. Scrypt parameters
(work factors) [1][2] are defined as constants below.
2. Scrypt salt is 32 random bytes from CSPRNG.
It's stored in plain next in the key file.
3. MAC is SHA3-256 of concatenation of ciphertext and
last 16 bytes of scrypt derived key.
4. Plaintext is the EC private key bytes.
5. Encryption algo is AES 128 CBC [3][4]
6. CBC IV is 16 random bytes from CSPRNG.
It's stored in plain next in the key file.
7. Plaintext padding is PKCS #7 [5][6]
Encoding:
1. On disk, the ciphertext, MAC, salt and IV are encoded in a JSON object.
cat a key file to see the structure.
2. byte arrays are base64 JSON strings.
3. The EC private key bytes are in uncompressed form [7].
They are a big-endian byte slice of the absolute value of D [8][9].
References:
1. http://www.tarsnap.com/scrypt/scrypt-slides.pdf
2. http://stackoverflow.com/questions/11126315/what-are-optimal-scrypt-work-factors
3. http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
4. http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
5. https://leanpub.com/gocrypto/read#leanpub-auto-block-cipher-modes
6. http://tools.ietf.org/html/rfc2315
7. http://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key
8. http://golang.org/pkg/crypto/ecdsa/#PrivateKey
9. https://golang.org/pkg/math/big/#Int.Bytes
*/
*/
...
@@ -68,22 +35,24 @@ package crypto
...
@@ -68,22 +35,24 @@ package crypto
import
(
import
(
"bytes"
"bytes"
"crypto/aes"
"crypto/aes"
"crypto/
cipher
"
"crypto/
sha256
"
"encoding/hex"
"encoding/hex"
"encoding/json"
"encoding/json"
"errors"
"errors"
"fmt"
"io"
"io"
"os"
"os"
"path/filepath"
"path/filepath"
"reflect"
"code.google.com/p/go-uuid/uuid"
"code.google.com/p/go-uuid/uuid"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/randentropy"
"github.com/ethereum/go-ethereum/crypto/randentropy"
"golang.org/x/crypto/pbkdf2"
"golang.org/x/crypto/scrypt"
"golang.org/x/crypto/scrypt"
)
)
const
(
const
(
keyHeaderVersion
=
"1"
keyHeaderKDF
=
"scrypt"
keyHeaderKDF
=
"scrypt"
// 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
// 2^18 / 8 / 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
scryptN
=
1
<<
18
scryptN
=
1
<<
18
...
@@ -105,7 +74,7 @@ func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *K
...
@@ -105,7 +74,7 @@ func (ks keyStorePassphrase) GenerateNewKey(rand io.Reader, auth string) (key *K
}
}
func
(
ks
keyStorePassphrase
)
GetKey
(
keyAddr
common
.
Address
,
auth
string
)
(
key
*
Key
,
err
error
)
{
func
(
ks
keyStorePassphrase
)
GetKey
(
keyAddr
common
.
Address
,
auth
string
)
(
key
*
Key
,
err
error
)
{
keyBytes
,
keyId
,
err
:=
DecryptKey
(
ks
,
keyAddr
,
auth
)
keyBytes
,
keyId
,
err
:=
DecryptKey
FromFile
(
ks
,
keyAddr
,
auth
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
...
@@ -129,51 +98,43 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
...
@@ -129,51 +98,43 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
return
err
return
err
}
}
encryptKey
:=
Sha3
(
derivedKey
[
:
16
])[
:
16
]
encryptKey
:=
derivedKey
[
:
16
]
keyBytes
:=
FromECDSA
(
key
.
PrivateKey
)
keyBytes
:=
FromECDSA
(
key
.
PrivateKey
)
toEncrypt
:=
PKCS7Pad
(
keyBytes
)
AES128Block
,
err
:=
aes
.
NewCipher
(
encryptKey
)
iv
:=
randentropy
.
GetEntropyCSPRNG
(
aes
.
BlockSize
)
// 16
cipherText
,
err
:=
aesCTRXOR
(
encryptKey
,
keyBytes
,
iv
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
iv
:=
randentropy
.
GetEntropyCSPRNG
(
aes
.
BlockSize
)
// 16
AES128CBCEncrypter
:=
cipher
.
NewCBCEncrypter
(
AES128Block
,
iv
)
cipherText
:=
make
([]
byte
,
len
(
toEncrypt
))
AES128CBCEncrypter
.
CryptBlocks
(
cipherText
,
toEncrypt
)
mac
:=
Sha3
(
derivedKey
[
16
:
32
],
cipherText
)
mac
:=
Sha3
(
derivedKey
[
16
:
32
],
cipherText
)
scryptParamsJSON
:=
scryptParamsJSON
{
scryptParamsJSON
:=
make
(
map
[
string
]
interface
{},
5
)
N
:
scryptN
,
scryptParamsJSON
[
"n"
]
=
scryptN
R
:
scryptr
,
scryptParamsJSON
[
"r"
]
=
scryptr
P
:
scryptp
,
scryptParamsJSON
[
"p"
]
=
scryptp
DkLen
:
scryptdkLen
,
scryptParamsJSON
[
"dklen"
]
=
scryptdkLen
Salt
:
hex
.
EncodeToString
(
salt
),
scryptParamsJSON
[
"salt"
]
=
hex
.
EncodeToString
(
salt
)
}
cipherParamsJSON
:=
cipherparamsJSON
{
cipherParamsJSON
:=
cipherparamsJSON
{
IV
:
hex
.
EncodeToString
(
iv
),
IV
:
hex
.
EncodeToString
(
iv
),
}
}
cryptoStruct
:=
cryptoJSON
{
cryptoStruct
:=
cryptoJSON
{
Cipher
:
"aes-128-c
bc
"
,
Cipher
:
"aes-128-c
tr
"
,
CipherText
:
hex
.
EncodeToString
(
cipherText
),
CipherText
:
hex
.
EncodeToString
(
cipherText
),
CipherParams
:
cipherParamsJSON
,
CipherParams
:
cipherParamsJSON
,
KDF
:
"scrypt"
,
KDF
:
"scrypt"
,
KDFParams
:
scryptParamsJSON
,
KDFParams
:
scryptParamsJSON
,
MAC
:
hex
.
EncodeToString
(
mac
),
MAC
:
hex
.
EncodeToString
(
mac
),
Version
:
"1"
,
}
}
encryptedKeyJSON
:=
encryptedKeyJSON
{
encryptedKeyJSON
V3
:=
encryptedKeyJSONV3
{
hex
.
EncodeToString
(
key
.
Address
[
:
]),
hex
.
EncodeToString
(
key
.
Address
[
:
]),
cryptoStruct
,
cryptoStruct
,
key
.
Id
.
String
(),
key
.
Id
.
String
(),
version
,
version
,
}
}
keyJSON
,
err
:=
json
.
Marshal
(
encryptedKeyJSON
)
keyJSON
,
err
:=
json
.
Marshal
(
encryptedKeyJSON
V3
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -183,7 +144,7 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
...
@@ -183,7 +144,7 @@ func (ks keyStorePassphrase) StoreKey(key *Key, auth string) (err error) {
func
(
ks
keyStorePassphrase
)
DeleteKey
(
keyAddr
common
.
Address
,
auth
string
)
(
err
error
)
{
func
(
ks
keyStorePassphrase
)
DeleteKey
(
keyAddr
common
.
Address
,
auth
string
)
(
err
error
)
{
// only delete if correct passphrase is given
// only delete if correct passphrase is given
_
,
_
,
err
=
DecryptKey
(
ks
,
keyAddr
,
auth
)
_
,
_
,
err
=
DecryptKey
FromFile
(
ks
,
keyAddr
,
auth
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -192,17 +153,43 @@ func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err
...
@@ -192,17 +153,43 @@ func (ks keyStorePassphrase) DeleteKey(keyAddr common.Address, auth string) (err
return
os
.
RemoveAll
(
keyDirPath
)
return
os
.
RemoveAll
(
keyDirPath
)
}
}
func
DecryptKey
(
ks
keyStorePassphrase
,
keyAddr
common
.
Address
,
auth
string
)
(
keyBytes
[]
byte
,
keyId
[]
byte
,
err
error
)
{
func
DecryptKey
FromFile
(
ks
keyStorePassphrase
,
keyAddr
common
.
Address
,
auth
string
)
(
keyBytes
[]
byte
,
keyId
[]
byte
,
err
error
)
{
fileContent
,
err
:=
GetKeyFile
(
ks
.
keysDirPath
,
keyAddr
)
fileContent
,
err
:=
GetKeyFile
(
ks
.
keysDirPath
,
keyAddr
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
err
}
}
keyProtected
:=
new
(
encryptedKeyJSON
)
m
:=
make
(
map
[
string
]
interface
{}
)
err
=
json
.
Unmarshal
(
fileContent
,
keyProtected
)
err
=
json
.
Unmarshal
(
fileContent
,
&
m
)
keyId
=
uuid
.
Parse
(
keyProtected
.
Id
)
v
:=
reflect
.
ValueOf
(
m
[
"version"
])
if
v
.
Kind
()
==
reflect
.
String
&&
v
.
String
()
==
"1"
{
k
:=
new
(
encryptedKeyJSONV1
)
err
:=
json
.
Unmarshal
(
fileContent
,
k
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
return
decryptKeyV1
(
k
,
auth
)
}
else
{
k
:=
new
(
encryptedKeyJSONV3
)
err
:=
json
.
Unmarshal
(
fileContent
,
k
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
return
decryptKeyV3
(
k
,
auth
)
}
}
func
decryptKeyV3
(
keyProtected
*
encryptedKeyJSONV3
,
auth
string
)
(
keyBytes
[]
byte
,
keyId
[]
byte
,
err
error
)
{
if
keyProtected
.
Version
!=
version
{
return
nil
,
nil
,
fmt
.
Errorf
(
"Version not supported: %v"
,
keyProtected
.
Version
)
}
if
keyProtected
.
Crypto
.
Cipher
!=
"aes-128-ctr"
{
return
nil
,
nil
,
fmt
.
Errorf
(
"Cipher not supported: %v"
,
keyProtected
.
Crypto
.
Cipher
)
}
keyId
=
uuid
.
Parse
(
keyProtected
.
Id
)
mac
,
err
:=
hex
.
DecodeString
(
keyProtected
.
Crypto
.
MAC
)
mac
,
err
:=
hex
.
DecodeString
(
keyProtected
.
Crypto
.
MAC
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
err
...
@@ -218,26 +205,48 @@ func DecryptKey(ks keyStorePassphrase, keyAddr common.Address, auth string) (key
...
@@ -218,26 +205,48 @@ func DecryptKey(ks keyStorePassphrase, keyAddr common.Address, auth string) (key
return
nil
,
nil
,
err
return
nil
,
nil
,
err
}
}
salt
,
err
:=
hex
.
DecodeString
(
keyProtected
.
Crypto
.
KDFParams
.
Salt
)
derivedKey
,
err
:=
getKDFKey
(
keyProtected
.
Crypto
,
auth
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
err
}
}
n
:=
keyProtected
.
Crypto
.
KDFParams
.
N
calculatedMAC
:=
Sha3
(
derivedKey
[
16
:
32
],
cipherText
)
r
:=
keyProtected
.
Crypto
.
KDFParams
.
R
if
!
bytes
.
Equal
(
calculatedMAC
,
mac
)
{
p
:=
keyProtected
.
Crypto
.
KDFParams
.
P
return
nil
,
nil
,
errors
.
New
(
"Decryption failed: MAC mismatch"
)
dkLen
:=
keyProtected
.
Crypto
.
KDFParams
.
DkLen
}
plainText
,
err
:=
aesCTRXOR
(
derivedKey
[
:
16
],
cipherText
,
iv
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
return
plainText
,
keyId
,
err
}
authArray
:=
[]
byte
(
auth
)
func
decryptKeyV1
(
keyProtected
*
encryptedKeyJSONV1
,
auth
string
)
(
keyBytes
[]
byte
,
keyId
[]
byte
,
err
error
)
{
derivedKey
,
err
:=
scrypt
.
Key
(
authArray
,
salt
,
n
,
r
,
p
,
dkLen
)
keyId
=
uuid
.
Parse
(
keyProtected
.
Id
)
mac
,
err
:=
hex
.
DecodeString
(
keyProtected
.
Crypto
.
MAC
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
iv
,
err
:=
hex
.
DecodeString
(
keyProtected
.
Crypto
.
CipherParams
.
IV
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
cipherText
,
err
:=
hex
.
DecodeString
(
keyProtected
.
Crypto
.
CipherText
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
derivedKey
,
err
:=
getKDFKey
(
keyProtected
.
Crypto
,
auth
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
nil
,
err
return
nil
,
nil
,
err
}
}
calculatedMAC
:=
Sha3
(
derivedKey
[
16
:
32
],
cipherText
)
calculatedMAC
:=
Sha3
(
derivedKey
[
16
:
32
],
cipherText
)
if
!
bytes
.
Equal
(
calculatedMAC
,
mac
)
{
if
!
bytes
.
Equal
(
calculatedMAC
,
mac
)
{
err
=
errors
.
New
(
"Decryption failed: MAC mismatch"
)
return
nil
,
nil
,
errors
.
New
(
"Decryption failed: MAC mismatch"
)
return
nil
,
nil
,
err
}
}
plainText
,
err
:=
aesCBCDecrypt
(
Sha3
(
derivedKey
[
:
16
])[
:
16
],
cipherText
,
iv
)
plainText
,
err
:=
aesCBCDecrypt
(
Sha3
(
derivedKey
[
:
16
])[
:
16
],
cipherText
,
iv
)
...
@@ -246,3 +255,41 @@ func DecryptKey(ks keyStorePassphrase, keyAddr common.Address, auth string) (key
...
@@ -246,3 +255,41 @@ func DecryptKey(ks keyStorePassphrase, keyAddr common.Address, auth string) (key
}
}
return
plainText
,
keyId
,
err
return
plainText
,
keyId
,
err
}
}
func
getKDFKey
(
cryptoJSON
cryptoJSON
,
auth
string
)
([]
byte
,
error
)
{
authArray
:=
[]
byte
(
auth
)
salt
,
err
:=
hex
.
DecodeString
(
cryptoJSON
.
KDFParams
[
"salt"
]
.
(
string
))
if
err
!=
nil
{
return
nil
,
err
}
dkLen
:=
ensureInt
(
cryptoJSON
.
KDFParams
[
"dklen"
])
if
cryptoJSON
.
KDF
==
"scrypt"
{
n
:=
ensureInt
(
cryptoJSON
.
KDFParams
[
"n"
])
r
:=
ensureInt
(
cryptoJSON
.
KDFParams
[
"r"
])
p
:=
ensureInt
(
cryptoJSON
.
KDFParams
[
"p"
])
return
scrypt
.
Key
(
authArray
,
salt
,
n
,
r
,
p
,
dkLen
)
}
else
if
cryptoJSON
.
KDF
==
"pbkdf2"
{
c
:=
ensureInt
(
cryptoJSON
.
KDFParams
[
"c"
])
prf
:=
cryptoJSON
.
KDFParams
[
"prf"
]
.
(
string
)
if
prf
!=
"hmac-sha256"
{
return
nil
,
fmt
.
Errorf
(
"Unsupported PBKDF2 PRF: "
,
prf
)
}
key
:=
pbkdf2
.
Key
(
authArray
,
salt
,
c
,
dkLen
,
sha256
.
New
)
return
key
,
nil
}
return
nil
,
fmt
.
Errorf
(
"Unsupported KDF: "
,
cryptoJSON
.
KDF
)
}
// TODO: can we do without this when unmarshalling dynamic JSON?
// why do integers in KDF params end up as float64 and not int after
// unmarshal?
func
ensureInt
(
x
interface
{})
int
{
res
,
ok
:=
x
.
(
int
)
if
!
ok
{
res
=
int
(
x
.
(
float64
))
}
return
res
}
crypto/key_store_test.go
View file @
6b2a03fa
package
crypto
package
crypto
import
(
import
(
"
github.com/ethereum/go-ethereum/common
"
"
encoding/hex
"
"
github.com/ethereum/go-ethereum/crypto/randentropy
"
"
fmt
"
"reflect"
"reflect"
"testing"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto/randentropy"
)
)
func
TestKeyStorePlain
(
t
*
testing
.
T
)
{
func
TestKeyStorePlain
(
t
*
testing
.
T
)
{
...
@@ -97,3 +100,110 @@ func TestImportPreSaleKey(t *testing.T) {
...
@@ -97,3 +100,110 @@ func TestImportPreSaleKey(t *testing.T) {
t
.
Fatal
(
err
)
t
.
Fatal
(
err
)
}
}
}
}
// Test and utils for the key store tests in the Ethereum JSON tests;
// tests/KeyStoreTests/basic_tests.json
type
KeyStoreTestV3
struct
{
Json
encryptedKeyJSONV3
Password
string
Priv
string
}
type
KeyStoreTestV1
struct
{
Json
encryptedKeyJSONV1
Password
string
Priv
string
}
func
TestV3_PBKDF2_1
(
t
*
testing
.
T
)
{
tests
:=
loadKeyStoreTestV3
(
"tests/v3_test_vector.json"
,
t
)
testDecryptV3
(
tests
[
"wikipage_test_vector_pbkdf2"
],
t
)
}
func
TestV3_PBKDF2_2
(
t
*
testing
.
T
)
{
tests
:=
loadKeyStoreTestV3
(
"../tests/files/KeyStoreTests/basic_tests.json"
,
t
)
testDecryptV3
(
tests
[
"test1"
],
t
)
}
func
TestV3_PBKDF2_3
(
t
*
testing
.
T
)
{
tests
:=
loadKeyStoreTestV3
(
"../tests/files/KeyStoreTests/basic_tests.json"
,
t
)
testDecryptV3
(
tests
[
"python_generated_test_with_odd_iv"
],
t
)
}
func
TestV3_PBKDF2_4
(
t
*
testing
.
T
)
{
tests
:=
loadKeyStoreTestV3
(
"../tests/files/KeyStoreTests/basic_tests.json"
,
t
)
testDecryptV3
(
tests
[
"evilnonce"
],
t
)
}
func
TestV3_Scrypt_1
(
t
*
testing
.
T
)
{
tests
:=
loadKeyStoreTestV3
(
"tests/v3_test_vector.json"
,
t
)
testDecryptV3
(
tests
[
"wikipage_test_vector_scrypt"
],
t
)
}
func
TestV3_Scrypt_2
(
t
*
testing
.
T
)
{
tests
:=
loadKeyStoreTestV3
(
"../tests/files/KeyStoreTests/basic_tests.json"
,
t
)
testDecryptV3
(
tests
[
"test2"
],
t
)
}
func
TestV1_1
(
t
*
testing
.
T
)
{
tests
:=
loadKeyStoreTestV1
(
"tests/v1_test_vector.json"
,
t
)
testDecryptV1
(
tests
[
"test1"
],
t
)
}
func
TestV1_2
(
t
*
testing
.
T
)
{
ks
:=
NewKeyStorePassphrase
(
"tests/v1"
)
addr
:=
common
.
HexToAddress
(
"cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
)
k
,
err
:=
ks
.
GetKey
(
addr
,
"g"
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
if
k
.
Address
!=
addr
{
t
.
Fatal
(
fmt
.
Errorf
(
"Unexpected address: %v, expected %v"
,
k
.
Address
,
addr
))
}
privHex
:=
hex
.
EncodeToString
(
FromECDSA
(
k
.
PrivateKey
))
expectedHex
:=
"d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
if
privHex
!=
expectedHex
{
t
.
Fatal
(
fmt
.
Errorf
(
"Unexpected privkey: %v, expected %v"
,
privHex
,
expectedHex
))
}
}
func
testDecryptV3
(
test
KeyStoreTestV3
,
t
*
testing
.
T
)
{
privBytes
,
_
,
err
:=
decryptKeyV3
(
&
test
.
Json
,
test
.
Password
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
privHex
:=
hex
.
EncodeToString
(
privBytes
)
if
test
.
Priv
!=
privHex
{
t
.
Fatal
(
fmt
.
Errorf
(
"Decrypted bytes not equal to test, expected %v have %v"
,
test
.
Priv
,
privHex
))
}
}
func
testDecryptV1
(
test
KeyStoreTestV1
,
t
*
testing
.
T
)
{
privBytes
,
_
,
err
:=
decryptKeyV1
(
&
test
.
Json
,
test
.
Password
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
privHex
:=
hex
.
EncodeToString
(
privBytes
)
if
test
.
Priv
!=
privHex
{
t
.
Fatal
(
fmt
.
Errorf
(
"Decrypted bytes not equal to test, expected %v have %v"
,
test
.
Priv
,
privHex
))
}
}
func
loadKeyStoreTestV3
(
file
string
,
t
*
testing
.
T
)
map
[
string
]
KeyStoreTestV3
{
tests
:=
make
(
map
[
string
]
KeyStoreTestV3
)
err
:=
common
.
LoadJSON
(
file
,
&
tests
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
return
tests
}
func
loadKeyStoreTestV1
(
file
string
,
t
*
testing
.
T
)
map
[
string
]
KeyStoreTestV1
{
tests
:=
make
(
map
[
string
]
KeyStoreTestV1
)
err
:=
common
.
LoadJSON
(
file
,
&
tests
)
if
err
!=
nil
{
t
.
Fatal
(
err
)
}
return
tests
}
crypto/tests/v1/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e/cb61d5a9c4896fb9658090b597ef0e7be6f7b67e
0 → 100644
View file @
6b2a03fa
{"address":"cb61d5a9c4896fb9658090b597ef0e7be6f7b67e","Crypto":{"cipher":"aes-128-cbc","ciphertext":"6143d3192db8b66eabd693d9c4e414dcfaee52abda451af79ccf474dafb35f1bfc7ea013aa9d2ee35969a1a2e8d752d0","cipherparams":{"iv":"35337770fc2117994ecdcad026bccff4"},"kdf":"scrypt","kdfparams":{"n":262144,"r":8,"p":1,"dklen":32,"salt":"9afcddebca541253a2f4053391c673ff9fe23097cd8555d149d929e4ccf1257f"},"mac":"3f3d5af884b17a100b0b3232c0636c230a54dc2ac8d986227219b0dd89197644","version":"1"},"id":"e25f7c1f-d318-4f29-b62c-687190d4d299","version":"1"}
\ No newline at end of file
crypto/tests/v1_test_vector.json
0 → 100644
View file @
6b2a03fa
{
"test1"
:
{
"json"
:
{
"Crypto"
:
{
"cipher"
:
"aes-128-cbc"
,
"cipherparams"
:
{
"iv"
:
"35337770fc2117994ecdcad026bccff4"
},
"ciphertext"
:
"6143d3192db8b66eabd693d9c4e414dcfaee52abda451af79ccf474dafb35f1bfc7ea013aa9d2ee35969a1a2e8d752d0"
,
"kdf"
:
"scrypt"
,
"kdfparams"
:
{
"dklen"
:
32
,
"n"
:
262144
,
"p"
:
1
,
"r"
:
8
,
"salt"
:
"9afcddebca541253a2f4053391c673ff9fe23097cd8555d149d929e4ccf1257f"
},
"mac"
:
"3f3d5af884b17a100b0b3232c0636c230a54dc2ac8d986227219b0dd89197644"
,
"version"
:
"1"
},
"address"
:
"cb61d5a9c4896fb9658090b597ef0e7be6f7b67e"
,
"id"
:
"e25f7c1f-d318-4f29-b62c-687190d4d299"
,
"version"
:
"1"
},
"password"
:
"g"
,
"priv"
:
"d1b1178d3529626a1a93e073f65028370d14c7eb0936eb42abef05db6f37ad7d"
}
}
crypto/tests/v3_test_vector.json
0 → 100644
View file @
6b2a03fa
{
"wikipage_test_vector_scrypt"
:
{
"json"
:
{
"crypto"
:
{
"cipher"
:
"aes-128-ctr"
,
"cipherparams"
:
{
"iv"
:
"83dbcc02d8ccb40e466191a123791e0e"
},
"ciphertext"
:
"d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c"
,
"kdf"
:
"scrypt"
,
"kdfparams"
:
{
"dklen"
:
32
,
"n"
:
262144
,
"r"
:
1
,
"p"
:
8
,
"salt"
:
"ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"
},
"mac"
:
"2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"
},
"id"
:
"3198bc9c-6672-5ab3-d995-4942343ae5b6"
,
"version"
:
3
},
"password"
:
"testpassword"
,
"priv"
:
"7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"
},
"wikipage_test_vector_pbkdf2"
:
{
"json"
:
{
"crypto"
:
{
"cipher"
:
"aes-128-ctr"
,
"cipherparams"
:
{
"iv"
:
"6087dab2f9fdbbfaddc31a909735c1e6"
},
"ciphertext"
:
"5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46"
,
"kdf"
:
"pbkdf2"
,
"kdfparams"
:
{
"c"
:
262144
,
"dklen"
:
32
,
"prf"
:
"hmac-sha256"
,
"salt"
:
"ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"
},
"mac"
:
"517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2"
},
"id"
:
"3198bc9c-6672-5ab3-d995-4942343ae5b6"
,
"version"
:
3
},
"password"
:
"testpassword"
,
"priv"
:
"7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment