forked from fireblocks/fireblocks-key-recovery-tool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
fb_recover_keys.py
executable file
·128 lines (109 loc) · 5.05 KB
/
fb_recover_keys.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
from utils import recover
import argparse
import getpass
import sys
from termcolor import colored
pubkey_descriptions = {
'MPC_ECDSA_SECP256K1': 'MPC_ECDSA_SECP256K1 XPUB',
'MPC_CMP_ECDSA_SECP256K1': 'MPC_ECDSA_SECP256K1 XPUB',
'MPC_EDDSA_ED25519': 'MPC_EdDSA_ED25519 extended public key (Fireblocks format)',
'MPC_CMP_EDDSA_ED25519': 'MPC_EdDSA_ED25519 extended public key (Fireblocks format)',
}
privkey_descriptions = {
'MPC_ECDSA_SECP256K1': 'MPC_ECDSA_SECP256K1 XPRV',
'MPC_CMP_ECDSA_SECP256K1': 'MPC_ECDSA_SECP256K1 XPRV',
'MPC_EDDSA_ED25519': 'MPC_EdDSA_ED25519 extended private key (Fireblocks format)',
'MPC_CMP_EDDSA_ED25519': 'MPC_EdDSA_ED25519 extended private key (Fireblocks format)',
}
def query_yes_no(question, default="yes"):
"""Ask a yes/no question via input() and return their answer.
"question" is a string that is presented to the user.
"default" is the presumed answer if the user just hits <Enter>.
It must be "yes" (the default), "no" or None (meaning
an answer is required of the user).
The "answer" return value is True for "yes" or False for "no".
"""
valid = {"yes": True, "y": True, "ye": True,
"no": False, "n": False}
if default is None:
prompt = " [y/n] "
elif default == "yes":
prompt = " [Y/n] "
elif default == "no":
prompt = " [y/N] "
else:
raise ValueError("invalid default answer: '%s'" % default)
while True:
sys.stdout.write(question + prompt)
choice = input().lower()
if default is not None and choice == '':
return valid[default]
elif choice in valid:
return valid[choice]
else:
sys.stdout.write("Please respond with 'yes' or 'no' "
"(or 'y' or 'n').\n")
def main():
parser = argparse.ArgumentParser()
parser.add_argument('backup', help='Backup zip file')
parser.add_argument('key', help='RSA private key file')
parser.add_argument('--prv', default=False,
action='store_const', const=True,
help='Reveal private key')
parser.add_argument('--mobile-key', help='mobile RSA private key file', default=None)
args = parser.parse_args()
if not os.path.exists(args.backup):
print('Backupfile: {} not found.'.format(args.backup))
exit(- 1)
if not os.path.exists(args.key):
print('RSA key: {} not found.'.format(args.key))
exit(-1)
mobile_key_pass = None
passphrase = None
if args.mobile_key is None:
passphrase = getpass.getpass(prompt='Please enter mobile recovery passphrase:')
else:
with open(args.mobile_key, 'r') as _key:
if 'ENCRYPTED' in _key.readlines()[1]:
mobile_key_pass = getpass.getpass(prompt='Please enter mobile recovery RSA private key passphrase:')
with open(args.key, 'r') as _key:
if 'ENCRYPTED' in _key.readlines()[1]:
key_pass = getpass.getpass(prompt='Please enter recovery RSA private key passphrase:')
else:
key_pass = None
try:
privkeys = recover.restore_key_and_chaincode(
args.backup, args.key, passphrase, key_pass, args.mobile_key, mobile_key_pass)
except recover.RecoveryErrorMobileKeyDecrypt:
print(colored("Failed to decrypt mobile Key. " + colored("Please make sure you have the mobile passphrase entered correctly.", attrs = ["bold"]), "cyan"))
exit(-1)
except recover.RecoveryErrorRSAKeyImport:
print(colored("Failed to import RSA Key. " + colored("Please make sure you have the RSA passphrase entered correctly.", attrs = ["bold"]), "cyan"))
exit(-1)
except recover.RecoveryErrorMobileRSAKeyImport:
print(colored("Failed to import mobile RSA Key. " + colored("Please make sure you have the RSA passphrase entered correctly.", attrs = ["bold"]), "cyan"))
exit(-1)
except recover.RecoveryErrorMobileRSADecrypt:
print(colored("Failed to decrypt mobile Key. " + colored("Please make sure you have the mobile private key entered correctly.", attrs = ["bold"]), "cyan"))
exit(-1)
show_xprv = False
if args.prv:
show_xprv = query_yes_no('''
Are you sure you want to show the extended private key of the Vault?
Be sure you are in a private location and no one can see your screen.'''
, default = "no")
for algo, info in privkeys.items():
# info may be either None or tuple
if info:
privkey, chaincode = info
pub = recover.get_public_key(algo, privkey)
if show_xprv:
print(privkey_descriptions[algo] + ":\t" + recover.encode_extended_key(algo, privkey, chaincode, False))
print(pubkey_descriptions[algo] + ":\t%s\t%s" % (recover.encode_extended_key(algo, pub, chaincode, True), colored("Verified!","green")))
else:
print(pubkey_descriptions[algo] + ":\t%s" % (colored("Verification failed","red")))
if __name__ == "__main__" :
main()