forked from Yubico/yubiclip-android
/
xorsetup.py
154 lines (130 loc) · 5.28 KB
/
xorsetup.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import sys
import pwinput
import base64
import secrets
import time
from yubikit.core.otp import OtpConnection
from yubikit.yubiotp import (
YubiOtpSession,
SLOT,
NDEF_TYPE,
StaticPasswordSlotConfiguration,
)
from ykman.device import connect_to_device, scan_devices, list_all_devices
slot = None
xorKeyGenerated = False
didProvision = False
if(len(sys.argv) == 1):
print("Usage: py xorsetup.py <slot 1|2> [XOR key]")
print("If no XOR key is provided, a cryptographically secure one will be generated")
sys.exit(1)
if(len(sys.argv) > 2):
xorKey = sys.argv[2]
else:
xorKey = secrets.token_hex(30)
xorKeyGenerated = True
print("Generated XOR key: " + xorKey)
print("Note this in a secure place, if you lose it you will not be able to recover your password!")
def xorBytes(data,key):
result = bytearray()
for i in range(min(len(data),30)):
result.append(data[i] ^ key[i])
return result
def waitForDevice():
state = None
got_Device = False
print("Waiting for YubiKey insertion...")
while True:
pids, new_state = scan_devices()
if new_state != state:
state = new_state
for device, info in list_all_devices():
got_Device = True
if got_Device:
break
else:
time.sleep(1.0) # No change, sleep for 1 second.
waitForDevice()
connection, device, info = connect_to_device(
connection_types=[OtpConnection],
)
slot = SLOT.ONE if sys.argv[1] == "1" else SLOT.TWO if sys.argv[1] == "2" else None
print("YubiKey inserted!")
#ask if they need to provision
if xorKeyGenerated == False:
print("You have provided an XOR key, do you want to use automatic key provisioning? (y/n)")
if(input() == "y"):
xorKeyGenerated = True
if xorKeyGenerated:
with connection:
session = YubiOtpSession(connection)
if slot is None:
raise ValueError("Slot must be 1 or 2")
if slot is SLOT.ONE:
print("!!!!! CONFIRM !!!!!")
print("This will overwrite the SLOT 1")
print("Slot 1 stores FACTORY PROGRAMMED (cc prefix) YubiOTP credentials (ex, cccccbcbrigfcdnudidhjcvhbkdulvvibgedbjdbljvl)")
print("If you have used YubiOTP on any accounts (ie, LastPass), you may lose access to those accounts!")
print("Some services may not accept vv prefix YubiOTP credentials. You CANNOT get the cc prefix back later!")
print("Do you wish to continue? y/n")
answer = input()
if answer != "y":
print("ABORT")
sys.exit()
print("!!!!! CONFIRM !!!!!")
print(f"This will overwrite the SLOT {sys.argv[1]}")
print("Do you wish to continue? y/n")
answer = input()
if answer == "y":
print("Continuing...")
else:
print("ABORT")
sys.exit()
session.put_configuration(slot, StaticPasswordSlotConfiguration(base64.a85encode(bytes.fromhex(xorKey))))
session.set_ndef_configuration(slot,"x-yubixor-provision://#", None, NDEF_TYPE.URI)
print("Loaded provision key. Remove your YubiKey and scan it with the Yubiclip-XOR app before continuing.")
didProvision = True
print("Continue setup? y/n")
answer = input()
if answer != "y":
sys.exit()
waitForDevice()
connection, device, info = connect_to_device(
connection_types=[OtpConnection],
)
with connection:
session = YubiOtpSession(connection)
if slot is SLOT.ONE and didProvision is False:
print("!!!!! CONFIRM !!!!!")
print("This will overwrite the SLOT 1")
print("Slot 1 stores FACTORY PROGRAMMED (cc prefix) YubiOTP credentials (ex, cccccbcbrigfcdnudidhjcvhbkdulvvibgedbjdbljvl)")
print("If you have used YubiOTP on any accounts (ie, LastPass), you may lose access to those accounts!")
print("Some services may not accept vv prefix YubiOTP credentials. You CANNOT get the cc prefix back later!")
print("Do you wish to continue? y/n")
answer = input()
if answer != "y":
print("ABORT")
sys.exit()
while True:
password = pwinput.pwinput("Enter password (max 30 bytes, min 8): ")
passconf = pwinput.pwinput("Confirm password: ")
if password != passconf:
print("Passwords do not match, Try again.")
elif len(password.encode("ascii")) > 30:
print("Password too long, Try again.")
elif(len(password.encode("ascii")) < 8): # this is arbitrary, if we really wanted to we could store a single byte, but I cant think of a use case for less than 8.
print("Password too short (min 8 bytes), Try again.")
else:
break
print("!!!!! CONFIRM !!!!!")
print(f"This will overwrite the SLOT {sys.argv[1]}")
print("Do you wish to continue? y/n")
answer = input()
if answer == "y":
print("Continuing...")
else:
print("ABORT")
sys.exit()
session.put_configuration(slot, StaticPasswordSlotConfiguration(base64.a85encode(xorBytes(password.encode("ascii"),bytes.fromhex(xorKey)))))
session.set_ndef_configuration(slot,"x-yubixor://#", None, NDEF_TYPE.URI)
print("Setup complete. Remove your YubiKey and scan it with the Yubiclip-XOR app.")