mirror of
https://github.com/muun/recovery.git
synced 2025-07-20 22:11:16 -04:00
161 lines
4.6 KiB
Go
Executable File
161 lines
4.6 KiB
Go
Executable File
package libwallet
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/btcsuite/btcutil/base58"
|
|
)
|
|
|
|
func TestNewChallengePrivateKey(t *testing.T) {
|
|
type args struct {
|
|
input []byte
|
|
salt []byte
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want *ChallengePrivateKey
|
|
}{
|
|
// TODO: Add test cases.
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := NewChallengePrivateKey(tt.args.input, tt.args.salt); !reflect.DeepEqual(got, tt.want) {
|
|
t.Errorf("NewChallengePrivateKey() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestChallengeKeySignSha(t *testing.T) {
|
|
input := randomBytes(32)
|
|
salt := randomBytes(32)
|
|
challengePrivKey := NewChallengePrivateKey(input, salt)
|
|
|
|
payload := []byte("foobar")
|
|
_, err := challengePrivKey.SignSha(payload)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// TODO(federicobond): assert that signature verifies
|
|
}
|
|
|
|
func TestChallengeKeyCrypto(t *testing.T) {
|
|
|
|
const birthday = 376
|
|
network := Regtest()
|
|
salt := randomBytes(8)
|
|
|
|
privKey, _ := NewHDPrivateKey(randomBytes(32), network)
|
|
challengePrivKey := NewChallengePrivateKey([]byte("a very good password"), salt)
|
|
|
|
encryptedKey, err := challengePrivKey.PubKey().EncryptKey(privKey, salt, birthday)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
decryptedKey, err := challengePrivKey.DecryptRawKey(encryptedKey, network)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if privKey.String() != decryptedKey.Key.String() {
|
|
t.Fatalf("keys dont match: orig %v vs decrypted %v", privKey.String(), decryptedKey.Key.String())
|
|
}
|
|
if birthday != decryptedKey.Birthday {
|
|
t.Fatalf("birthdays dont match: expected %v got %v", birthday, decryptedKey.Birthday)
|
|
}
|
|
}
|
|
|
|
func TestChallengeKeyCryptoV2(t *testing.T) {
|
|
|
|
const (
|
|
encodedKey = "tprv8ZgxMBicQKsPcxg1GFGZgL5zALjPwijrYNUqTi2s9JsVqDLzbpX55U9JH2PKAQKExtpdTyboZmV2ytaqr9pAHuxE1hX8k9bQgZAjq25E6P7"
|
|
encryptedKey = "4LbSKwcepbbx4dPetoxvTWszb6mLyJHFhumzmdPRVprbn8XZBvFa6Ffarm6R3WGKutFzdxxJgQDdSHuYdjhDp1EZfSNbj12gXMND1AgmNijSxEua3LwVURU3nzWsvV5b1AsWEjJca24CaFY6T3C"
|
|
password = "a very good password"
|
|
saltLength = 8
|
|
birthday = 376
|
|
)
|
|
|
|
extractSalt := func(rawKey string) []byte {
|
|
bytes := base58.Decode(rawKey)
|
|
return bytes[len(bytes)-saltLength:]
|
|
}
|
|
|
|
challengeKey := NewChallengePrivateKey([]byte(password), extractSalt(encryptedKey))
|
|
decryptedKey, err := challengeKey.DecryptRawKey(encryptedKey, Regtest())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if decryptedKey.Birthday != birthday {
|
|
t.Fatalf("decrypted birthday %v differs from expected %v", decryptedKey.Birthday, birthday)
|
|
}
|
|
|
|
if decryptedKey.Key.String() != encodedKey {
|
|
t.Fatalf("key doesnt match\ngot %v\nexpected %v\n", decryptedKey.Key.String(), encodedKey)
|
|
}
|
|
|
|
_, err = challengeKey.PubKey().EncryptKey(decryptedKey.Key, extractSalt(encryptedKey), birthday)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestDecodeKeyWithOrWithoutSalt(t *testing.T) {
|
|
const (
|
|
// The same encoded key, with one version missing the salt field:
|
|
saltedKey = "4LbSKwcepbbx4dPetoxvTWszb6mLyJHFhumzmdPRVprbn8XZBvFa6Ffarm6R3WGKutFzdxxJgQDdSHuYdjhDp1EZfSNbj12gXMND1AgmNijSxEua3LwVURU3nzWsvV5b1AsWEjJca24CaFY6T3C"
|
|
unsaltedKey = "5XEEts6mc9WV34krDWsqmpLcPCw2JkK8qJu3gFdZpP8ngkERuQEsaDvYrGkhXUpM6jQRtimTYm4XnBPujpo3MsdYBedsNVxvT3WC6uCCFuzNUZCoydVY39yJXbxva7naDxH5iTra"
|
|
)
|
|
|
|
expected := &EncryptedPrivateKeyInfo{
|
|
Version: 2,
|
|
Birthday: 376,
|
|
CipherText: "f6af1ecd17052a81b75902c1712567cf1c650329875feb7e24af3e27235f384054ea549025e99dc2659f95bb6447cf861aa2ec0407ea74baf5a9d6a885ae184b",
|
|
EphPublicKey: "020a8d322dda8ff685d80b16681d4e87c109664cdc246a9d3625adfe0de203e71e",
|
|
Salt: "e3305526d0cd675f",
|
|
}
|
|
|
|
// Verify the salted version:
|
|
actual, err := DecodeEncryptedPrivateKey(saltedKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
assertDecodedKeysEqual(t, actual, expected)
|
|
|
|
// Verify the unsalted version:
|
|
actual, err = DecodeEncryptedPrivateKey(unsaltedKey)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
expected.Salt = "0000000000000000" // unsalted key should decode with zeroed field
|
|
|
|
assertDecodedKeysEqual(t, actual, expected)
|
|
}
|
|
|
|
func assertDecodedKeysEqual(t *testing.T, actual, expected *EncryptedPrivateKeyInfo) {
|
|
if actual.Version != expected.Version {
|
|
t.Fatalf("version %v expected %v", actual.Version, expected.Version)
|
|
}
|
|
|
|
if actual.Birthday != expected.Birthday {
|
|
t.Fatalf("birthday %v, expected %v", actual.Birthday, expected.Birthday)
|
|
}
|
|
|
|
if actual.CipherText != expected.CipherText {
|
|
t.Fatalf("cipherText %x expected %x", actual.CipherText, expected.CipherText)
|
|
}
|
|
|
|
if actual.EphPublicKey != expected.EphPublicKey {
|
|
t.Fatalf("ephPublicKey %x expected %x", actual.EphPublicKey, expected.EphPublicKey)
|
|
}
|
|
|
|
if actual.Salt != expected.Salt {
|
|
t.Fatalf("salt %x expected %x", actual.Salt, expected.Salt)
|
|
}
|
|
}
|