diff --git a/bin/validity-led-dance b/bin/validity-led-dance index 4612938..7a56f30 100755 --- a/bin/validity-led-dance +++ b/bin/validity-led-dance @@ -21,10 +21,9 @@ if __name__ == "__main__": glow_end_scan() sleep(0.05) - led_script = unhexlify( - '39ff100000ff03000001ff002000000000ffff0000ffff0000ff03000001ff00' - '200000000000000000ffff0000ff03000001ff002000000000ffff0000000000' - '0000000000000000000000000000000000000000000000000000000000000000' - '0000000000000000000000000000000000000000000000000000000000') + led_script = unhexlify('39ff100000ff03000001ff002000000000ffff0000ffff0000ff03000001ff00' + '200000000000000000ffff0000ff03000001ff002000000000ffff0000000000' + '0000000000000000000000000000000000000000000000000000000000000000' + '0000000000000000000000000000000000000000000000000000000000') assert_status(tls.app(led_script)) diff --git a/validitysensor/db.py b/validitysensor/db.py index 6853e1c..e55cbd9 100644 --- a/validitysensor/db.py +++ b/validitysensor/db.py @@ -1,15 +1,17 @@ from binascii import hexlify +from struct import pack, unpack +import typing from .blobs import db_write_enable from .flash import call_cleanups -from .sid import * +from .sid import SidIdentity, sid_from_bytes from .tls import tls from .util import assert_status from .winbio_constants import finger_names class UserStorage: - def __init__(self, dbid, name): + def __init__(self, dbid: int, name: str): self.dbid = dbid self.name = name self.users = [] @@ -20,10 +22,10 @@ class UserStorage: class User: - def __init__(self, dbid, identity): + def __init__(self, dbid: int, identity: str): self.dbid = dbid self.identity = identity - self.fingers = [] + self.fingers: typing.List[typing.Mapping[str, int]] = [] def __repr__(self): return '' % (self.dbid, repr( @@ -35,7 +37,7 @@ def subtype_to_string(s: int): return finger_name or 'Unknown' -def parse_user_storage(rsp): +def parse_user_storage(rsp: bytes): rc, = unpack(' typing.Optional[User]: @@ -169,7 +171,7 @@ class Db: else: return parse_user(rsp) - def get_record_value(self, dbid): + def get_record_value(self, dbid: int): rsp = tls.cmd(pack(' bytes: cmd = pack(' 0: chunk, buf = buf[:bs], buf[bs:] @@ -148,13 +154,13 @@ def write_flash_all(partition, ptr, buf): ptr += len(chunk) -def read_flash_all(partition, start, size): +def read_flash_all(partition: int, start: int, size: int): bs = 0x1000 blocks = [read_flash(partition, addr, bs) for addr in range(start, start + size, bs)] return b''.join(blocks)[:size] -def write_fw_signature(partition, signature): +def write_fw_signature(partition: int, signature: bytes): rsp = tls.cmd(pack(' typing.Tuple[int, int, int, int]: try: assert_status(tls.app(self.build_cmd_02(mode))) @@ -733,7 +734,7 @@ class Sensor: finally: tls.app(unhexlify('04')) # capture stop if still running, cleanup - def enrollment_update_start(self, key): + def enrollment_update_start(self, key: int) -> int: rsp = tls.app(pack(' 0: @@ -890,7 +891,7 @@ class Sensor: # cleanup, ignore any errors tls.app(unhexlify('6200000000')) - def identify(self, update_cb): + def identify(self, update_cb: typing.Callable[[Exception], None]): while True: try: glow_start_scan() @@ -908,7 +909,7 @@ class Sensor: return self.match_finger() - def get_finger_blobs(self, usrid, subtype): + def get_finger_blobs(self, usrid: int, subtype: int): usr = db.get_user(usrid) fingerids = [f['dbid'] for f in usr.fingers if f['subtype'] == subtype] diff --git a/validitysensor/table_types.py b/validitysensor/table_types.py index 1c1fdde..9c0907d 100644 --- a/validitysensor/table_types.py +++ b/validitysensor/table_types.py @@ -1,18 +1,20 @@ +import typing from binascii import hexlify, unhexlify class SensorTypeInfo: - table = [] + table: typing.List["SensorTypeInfo"] = [] @classmethod - def get_by_type(cls, sensor_type): + def get_by_type(cls, sensor_type: int) -> typing.Optional["SensorTypeInfo"]: + # noinspection PyUnresolvedReferences from . import generated_tables for i in cls.table: if i.sensor_type == sensor_type: return i - def __init__(self, sensor_type, bytes_per_line, repeat_multiplier, lines_per_calibration_data, - line_width, calibration_blob): + def __init__(self, sensor_type: int, bytes_per_line: int, repeat_multiplier: int, lines_per_calibration_data: int, + line_width: int, calibration_blob: str): self.sensor_type = sensor_type self.repeat_multiplier = repeat_multiplier self.lines_per_calibration_data = lines_per_calibration_data @@ -50,10 +52,11 @@ def metric(i, rominfo): class SensorCaptureProg: - table = [] + table: typing.List["SensorCaptureProg"] = [] @classmethod - def get(cls, rominfo, sensor_type, a0, a1): + def get(cls, rominfo, sensor_type: int, a0: int, a1: int): + # noinspection PyUnresolvedReferences from . import generated_tables maximum = 0 @@ -80,7 +83,8 @@ class SensorCaptureProg: if found is not None: return b''.join(found.blobs) - def __init__(self, major, minor, build, u1, dev_type, a0, a1, blobs): + def __init__(self, major: int, minor: int, build: int, u1: int, dev_type: int, a0: int, a1: int, + blobs: typing.Sequence[str]): self.major = major self.minor = minor self.build = build @@ -88,8 +92,7 @@ class SensorCaptureProg: self.dev_type = dev_type self.a0 = a0 self.a1 = a1 - blobs = [unhexlify(b) for b in blobs] - self.blobs = blobs + self.blobs = [unhexlify(b) for b in blobs] def __repr__(self): blobs = [hexlify(b).decode() for b in self.blobs] diff --git a/validitysensor/timeslot.py b/validitysensor/timeslot.py index 265d312..46d50c2 100644 --- a/validitysensor/timeslot.py +++ b/validitysensor/timeslot.py @@ -1,5 +1,6 @@ from binascii import hexlify from struct import unpack, pack +import typing codes = {} codes[0x0] = "No Operation" @@ -98,7 +99,7 @@ insn_to_string = [ ] -def decode_insn(b): +def decode_insn(b: bytes): if b[0] == 0: return 0, 1 elif b[0] == 1: @@ -135,7 +136,7 @@ def decode_insn(b): raise Exception('Unhandled instruction %02x' % b) -def disassm_timeslot_table(b, off): +def disassm_timeslot_table(b: bytes, off: int): pc = off while len(b) > 0: op, sz, *operands = decode_insn(b) @@ -147,7 +148,7 @@ def disassm_timeslot_table(b, off): pc += sz -def find_nth_insn(b, opcode, n): +def find_nth_insn(b: bytes, opcode: int, n: int): pc = 0 while len(b) > 0: op, sz, *_ = decode_insn(b) @@ -164,7 +165,7 @@ def find_nth_insn(b, opcode, n): pc += sz -def find_nth_regwrite(b, reg_addr, n): +def find_nth_regwrite(b: bytes, reg_addr: int, n: int): pc = 0 while len(b) > 0: op, sz, *operands = decode_insn(b) @@ -183,20 +184,20 @@ def find_nth_regwrite(b, reg_addr, n): pc += sz -def split_chunks(b): +def split_chunks(b: bytes) -> typing.Generator[typing.List[typing.Union[int, bytes]], None, None]: while len(b) > 0: (typ, sz), b = unpack(' 0: (typ, sz), b = unpack('H', len(chunk)) + chunk -def with_3bytes_size(chunk): +def with_3bytes_size(chunk: bytes): return pack('>BH', len(chunk) >> 16, len(chunk)) + chunk -def with_1byte_size(chunk): +def with_1byte_size(chunk: bytes): return pack('>B', len(chunk)) + chunk @@ -76,18 +77,18 @@ def to_bytes(n): return b -def pad(b): +def pad(b: bytes): l = 16 - (len(b) % 16) return b + bytes([l - 1]) * l -def unpad(b): +def unpad(b: bytes): return b[:-1 - b[-1]] # TODO assert the right state transitions class Tls: - def __init__(self, usb): + def __init__(self, usb: Usb): self.usb = usb self.reset() try: @@ -107,7 +108,7 @@ class Tls: self.secure_tx = False # Info about the host computer - def set_hwkey(self, product_name, serial_number): + def set_hwkey(self, product_name: str, serial_number: str): hw_key = bytes(product_name, 'ascii') + b'\0' + \ bytes(serial_number, 'ascii') + b'\0' @@ -116,7 +117,7 @@ class Tls: self.psk_validation_key = prf(self.psk_encryption_key, b'GWK_SIGN' + gwk_sign_hardcoded, 0x20) - def cmd(self, cmd): + def cmd(self, cmd: typing.Union[bytes, typing.Callable[[], bytes]]): if self.secure_rx and self.secure_tx: rsp = self.app(cmd) else: @@ -142,15 +143,15 @@ class Tls: self.parse_tls_response(rsp) - def trace(self, s): + def trace(self, s: str): if self.trace_enabled: logging.debug(s) - def app(self, b): + def app(self, b: typing.Union[bytes, typing.Callable[[], bytes]]): b = b() if callable(b) else b return self.parse_tls_response(self.usb.cmd(self.make_app_data(b))) - def update_neg(self, b): + def update_neg(self, b: bytes): self.handshake_hash.update(b) def make_keys(self): @@ -187,7 +188,7 @@ class Tls: self.secure_rx = d['secure_rx'] self.secure_tx = d['secure_tx'] - def decrypt(self, c): + def decrypt(self, c: bytes): iv, c = c[:0x10], c[0x10:] cipher = Cipher(algorithms.AES(self.decryption_key), modes.CBC(iv), backend=crypto_backend) decryptor = cipher.decryptor() @@ -195,7 +196,7 @@ class Tls: m = unpad(m) return m - def encrypt(self, b): + def encrypt(self, b: bytes): #iv = unhexlify('454849acdd075174d6b9e713a957c2e7') iv = os.urandom(0x10) cipher = Cipher(algorithms.AES(self.encryption_key), modes.CBC(iv), backend=crypto_backend) @@ -204,7 +205,7 @@ class Tls: c = encryptor.update(b) + encryptor.finalize() return iv + c - def validate(self, t, b): + def validate(self, t: int, b: bytes): b, hs = b[:-0x20], b[-0x20:] hdr = pack('>BBBH', t, 3, 3, len(b)) @@ -216,7 +217,7 @@ class Tls: self.trace('tls> %02x: %s' % (t, hexlify(b).decode())) hdr = pack('>BBBH', t, 3, 3, len(b)) @@ -240,7 +241,7 @@ class Tls: cert = pack('>BH', 0, len(self.tls_cert)) + cert # same return self.with_neg_hdr(0x0b, cert) - def with_neg_hdr(self, t, b): + def with_neg_hdr(self, t: int, b: bytes): b = pack('>B', t) + with_3bytes_size(b) self.update_neg(b) return b @@ -254,7 +255,7 @@ class Tls: b = self.priv_key.sign(buf, ec.ECDSA(Prehashed(hashes.SHA256()))) return self.with_neg_hdr(0x0f, b) - def handle_server_hello(self, p): + def handle_server_hello(self, p: bytes): if p[:2] != unhexlify('0303'): raise Exception('unexpected TLS version %s' % hexlify(p[:2]).decode()) @@ -278,7 +279,7 @@ class Tls: if p != b'': raise Exception('Not expecting any more data') - def handle_cert_req(self, p): + def handle_cert_req(self, p: bytes): (sign_and_hash_algo, ), p = unpack('>H', p[:2]), p[2:] if sign_and_hash_algo != 0x140: raise Exception( @@ -292,24 +293,24 @@ class Tls: if p != b'': raise Exception('Not expecting any more data') - def handle_server_hello_done(self, p): + def handle_server_hello_done(self, p: bytes): if p != b'': raise Exception('Not expecting any body for "server hello done" pkt: %s' % hexlify(p).decode()) - def handle_finish(self, b): + def handle_finish(self, b: bytes): hs_hash = self.handshake_hash.copy().digest() verify_data = prf(self.master_secret, b'server finished' + hs_hash, 0xc) if verify_data != b: raise Exception('Final handshake check failed') - def handle_app_data(self, b): + def handle_app_data(self, b: bytes): if not self.secure_rx: raise Exception('App payload before secure connection established') return self.validate(0x17, self.decrypt(b)) - def handle_handshake(self, handshake): + def handle_handshake(self, handshake: bytes) -> None: if self.secure_rx: handshake = self.validate(0x16, self.decrypt(handshake)) @@ -335,7 +336,7 @@ class Tls: self.update_neg(hdr + p) - def parse_tls_response(self, rsp): + def parse_tls_response(self, rsp: bytes): app_data = b'' while len(rsp) > 0: @@ -366,7 +367,7 @@ class Tls: return app_data - def make_app_data(self, b): + def make_app_data(self, b: bytes): if not self.secure_tx: raise Exception('App payload before secure connection established') @@ -374,7 +375,7 @@ class Tls: return unhexlify('170303') + with_2bytes_size(b) - def make_handshake(self, b): + def make_handshake(self, b: bytes): if self.secure_tx: b = self.encrypt(self.sign(0x16, b)) @@ -404,10 +405,10 @@ class Tls: return self.with_neg_hdr(0x01, h) - def make_ext(self, id, b): + def make_ext(self, id: int, b: bytes): return pack('>H', id) + with_2bytes_size(b) - def parse_tls_flash(self, reply): + def parse_tls_flash(self, reply: bytes): while len(reply) > 0: hdr, reply = reply[:4], reply[4:] hs, reply = reply[:0x20], reply[0x20:] @@ -440,7 +441,7 @@ class Tls: else: self.trace('unhandled block id %04x (%d bytes): %s' % (id, sz, hexlify(body))) - def make_tls_flash_block(self, id, body): + def make_tls_flash_block(self, id: int, body: bytes): m = sha256() m.update(body) hdr = pack('