diff --git a/crypto/kms/privatekeystore.go b/crypto/kms/privatekeystore.go index ef4daf926..64197d821 100644 --- a/crypto/kms/privatekeystore.go +++ b/crypto/kms/privatekeystore.go @@ -27,6 +27,7 @@ import ( "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/crypto/symmetric" "github.com/CovenantSQL/CovenantSQL/utils/log" + "github.com/btcsuite/btcutil/base58" ) var ( @@ -34,6 +35,12 @@ var ( ErrNotKeyFile = errors.New("private key file empty") // ErrHashNotMatch indicates specified key hash is wrong ErrHashNotMatch = errors.New("private key hash not match") + // ErrPrivateKeyVersion indicates specified key is not base58 version + ErrInvalidBase58Version = errors.New("invalid base58 version") + // ErrPrivateKeyChecksum indicates specified key is not base58 checksum + ErrInvalidBase58Checksum = errors.New("invalid base58 checksum") + + PrivateKeyStoreVersion byte = 0x23 ) // LoadPrivateKey loads private key from keyFilePath, and verifies the hash @@ -45,7 +52,21 @@ func LoadPrivateKey(keyFilePath string, masterKey []byte) (key *asymmetric.Priva return } - decData, err := symmetric.DecryptWithPassword(fileContent, masterKey) + encData, version, err := base58.CheckDecode(string(fileContent)) + switch err { + case base58.ErrChecksum: + return + + case base58.ErrInvalidFormat: + // be compatible with the original binary private key format + encData = fileContent + } + + if version != 0 && version != PrivateKeyStoreVersion { + return nil, ErrInvalidBase58Version + } + + decData, err := symmetric.DecryptWithPassword(encData, masterKey) if err != nil { log.Error("decrypt private key error") return @@ -79,7 +100,10 @@ func SavePrivateKey(keyFilePath string, key *asymmetric.PrivateKey, masterKey [] if err != nil { return } - return ioutil.WriteFile(keyFilePath, encKey, 0400) + + base58EncKey := base58.CheckEncode(encKey, PrivateKeyStoreVersion) + + return ioutil.WriteFile(keyFilePath, []byte(base58EncKey), 0600) } // InitLocalKeyPair initializes local private key diff --git a/crypto/kms/privatekeystore_test.go b/crypto/kms/privatekeystore_test.go index 0485552af..32710e0df 100644 --- a/crypto/kms/privatekeystore_test.go +++ b/crypto/kms/privatekeystore_test.go @@ -25,7 +25,9 @@ import ( "github.com/CovenantSQL/CovenantSQL/conf" "github.com/CovenantSQL/CovenantSQL/crypto/asymmetric" + "github.com/CovenantSQL/CovenantSQL/crypto/hash" "github.com/CovenantSQL/CovenantSQL/crypto/symmetric" + "github.com/btcsuite/btcutil/base58" . "github.com/smartystreets/goconvey/convey" ) @@ -95,6 +97,29 @@ func TestLoadPrivateKey(t *testing.T) { So(err, ShouldEqual, ErrHashNotMatch) So(lk, ShouldBeNil) }) + Convey("invalid base58 version", t, func() { + defer os.Remove("./.Base58VersionNotMatch") + var invalidPrivateKeyStoreVersion byte = 0x1 + privateKeyBytes, _ := hex.DecodeString("f7c0bc718eb0df81e796a11e6f62e23cd2be0a4bdcca30df40d4d915cc3be3ff") + privateKey, _ := asymmetric.PrivKeyFromBytes(privateKeyBytes) + serializedKey := privateKey.Serialize() + keyHash := hash.DoubleHashB(serializedKey) + rawData := append(keyHash, serializedKey...) + encKey, _ := symmetric.EncryptWithPassword(rawData, []byte(password)) + invalidBase58EncKey := base58.CheckEncode(encKey, invalidPrivateKeyStoreVersion) + ioutil.WriteFile("./.Base58VersionNotMatch", []byte(invalidBase58EncKey), 0600) + lk, err := LoadPrivateKey("./.Base58VersionNotMatch", []byte(password)) + So(err, ShouldEqual, ErrInvalidBase58Version) + So(lk, ShouldBeNil) + }) + Convey("invalid base58 checksum", t, func() { + defer os.Remove("./.Base58InvalidChecksum") + invalidBase58Str := "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" + ioutil.WriteFile("./.Base58InvalidChecksum", []byte(invalidBase58Str), 0600) + lk, err := LoadPrivateKey("./.Base58InvalidChecksum", []byte(password)) + So(err, ShouldEqual, base58.ErrChecksum) + So(lk, ShouldBeNil) + }) } func TestInitLocalKeyPair(t *testing.T) {