Last active
December 30, 2016 03:43
-
-
Save otms61/bdbfc2736de71f18b5d2994bb82e613b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from Crypto.Cipher import AES | |
from binascii import hexlify, unhexlify | |
d = {'b': '1', 'c': '0', 'd': '2', 'e': '3', 'f': '4', 'g': '5', 'h': '6', 'i': '7', 'j': '8', 'k': '9', 'l': 'a', 'n': 'b', 'r': 'c', 't': 'd', 'u': 'e', 'v': 'f'} | |
rd = {'0': 'c', '1': 'b', '2': 'd', '3': 'e', '4': 'f', '5': 'g', '6': 'h', '7': 'i', '8': 'j', '9': 'k', 'a': 'l', 'b': 'n', 'c': 'r', 'd': 't', 'e': 'u', 'f': 'v'} | |
def modhex2hex(x): | |
return ''.join([d[i] for i in x]) | |
def hex2modhex(x): | |
return ''.join([rd[i] for i in x]) | |
def update_crc(crc, x): | |
crc ^= x | |
for _ in range(8): | |
flag = crc & 1 | |
crc >>= 1 | |
if flag != 0: | |
crc ^= 0x8408 | |
return crc & 0xffff | |
def get_crc(s): | |
assert len(s) == 14, "Invalid length" | |
crc = 0x5af0 | |
for i in s: | |
crc = update_crc(crc, i) | |
return crc | |
def verify_crc(s): | |
assert len(s) == 16, "Invalid length" | |
crc = 0xffff | |
for i in s: | |
crc = update_crc(crc, i) | |
return crc == 0xf0b8 | |
class Yubico(object): | |
def __init__(self, key): | |
self.key = key | |
self.otp = 0 | |
self.public_id = 0 | |
self.plain = b'' | |
self.uid = 0 | |
self.useCtr = 0 | |
self.tstp = 0 | |
self.sessionCtr = 0 | |
self.rnd = 0 | |
self.crc = 0 | |
def __repr__(self): | |
return f'< public_id:{self.public_id:012x} private_id:{self.uid:012x} useCtr:{self.useCtr:04x} tstp:{self.tstp:06x} sessionCtr:{self.sessionCtr:02x} rnd:{self.rnd:04x} crc:{self.crc:04x} >' | |
def calc_crc(self): | |
r = \ | |
self.uid.to_bytes(6, 'big') + \ | |
self.useCtr.to_bytes(2, 'little') + \ | |
self.tstp.to_bytes(3, 'big') + \ | |
self.sessionCtr.to_bytes(1, 'big') + \ | |
self.rnd.to_bytes(2, 'big') | |
return get_crc(r) | |
@classmethod | |
def parse_otp(cls, key, otp): | |
yubico = cls(key) | |
yubico.key = key | |
yubico.otp = otp | |
otp_hex = modhex2hex(yubico.otp) | |
yubico.public_id = int(otp_hex[:12], 16) | |
crypted = unhexlify(otp_hex[12:]) | |
yubico.plain = AES.new(key).decrypt(crypted) | |
yubico.uid = int.from_bytes(yubico.plain[:6], 'big') | |
yubico.useCtr = int.from_bytes(yubico.plain[6:8], 'little') | |
yubico.tstp = int.from_bytes(yubico.plain[8:11], 'big') | |
yubico.sessionCtr = int.from_bytes(yubico.plain[11:12], 'big') | |
yubico.rnd = int.from_bytes(yubico.plain[12:14], 'big') | |
yubico.crc = int.from_bytes(yubico.plain[14:16], 'little') | |
return yubico | |
@classmethod | |
def calc_otp(cls, key, public_id, private_id, useCtr, sessionCtr, tstp=0, rnd=0): | |
yubico = cls(key) | |
yubico.public_id = public_id | |
yubico.uid = private_id | |
yubico.useCtr = useCtr | |
yubico.sessionCtr = sessionCtr | |
yubico.tstp = tstp | |
yubico.rnd = rnd | |
yubico.crc = yubico.calc_crc() | |
plain = \ | |
yubico.uid.to_bytes(6, 'big') + \ | |
yubico.useCtr.to_bytes(2, 'little') + \ | |
yubico.tstp.to_bytes(3, 'big') + \ | |
yubico.sessionCtr.to_bytes(1, 'big') + \ | |
yubico.rnd.to_bytes(2, 'big') + \ | |
yubico.crc.to_bytes(2, 'little') | |
crypted = AES.new(key).encrypt(plain) | |
otp = yubico.public_id.to_bytes(6, 'big') + crypted | |
yubico.otp = hex2modhex(otp.hex()) | |
return yubico | |
key = b"\xa9\xe2\x29\x33\x2e\x87\x0f\x26\x1e\xa5\x5a\x2a\xbd\xef\xda\xe0" | |
s = '''vvntibfekfkkuvrvubtictldndbenurgrgbukhkutild | |
vvntibfekfkkcgfeljervjjcejvjkvttthndftrtbdrf | |
vvntibfekfkkbnkhcdiuhbbbflbuitdnecbkbnlkchgv | |
vvntibfekfkkbevrttebkucvbdrntikdicluudifdgil | |
vvntibfekfkkjfvttcrfvdkrrrvdidrrrdlcdefvhege''' | |
for i in s.split('\n'): | |
y = Yubico.parse_otp(key, i) | |
print(y) | |
print() | |
y1 = Yubico.calc_otp(key, 0xffbd71439499, 0x8a00555dd7db, 0x01, 0x0, 0xf011a4, 0xadfd) | |
print(y1) | |
print(y1.otp) | |
y2 = Yubico.parse_otp(key, y1.otp) | |
print(y2) | |
print(y2.otp) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment