def InternalInit(self): """Initializes the device and obtains channel id.""" self.cid = UsbHidTransport.U2FHID_BROADCAST_CID nonce = bytearray(os.urandom(8)) r = self.InternalExchange(UsbHidTransport.U2FHID_INIT, nonce) if len(r) < 17: raise errors.HidError('unexpected init reply len') if r[0:8] != nonce: raise errors.HidError('nonce mismatch') self.cid = bytearray(r[8:12]) self.u2fhid_version = r[12]
def Write(self, packet): """See base class.""" if len(packet) != self.GetOutReportDataLength(): raise errors.HidError( "Packet length must match report data length.") packet_data = [0] + packet # Prepend the zero-byte (report ID) out = bytes(bytearray(packet_data)) num_written = wintypes.DWORD() ret = (kernel32.WriteFile(self.dev, out, len(out), ctypes.byref(num_written), None)) if num_written.value != len(out): raise errors.HidError("Failed to write complete packet. " + "Expected %d, but got %d" % (len(out), num_written.value)) if not ret: raise ctypes.WinError()
def InternalExchange(self, cmd, payload_in): """Sends and receives a message from the device.""" # make a copy because we destroy it below self.logger.debug('payload: ' + str(list(payload_in))) payload = bytearray() payload[:] = payload_in for _ in range(2): self.InternalSend(cmd, payload) ret_cmd, ret_payload = self.InternalRecv() if ret_cmd == UsbHidTransport.U2FHID_ERROR: if ret_payload == UsbHidTransport.ERR_CHANNEL_BUSY: time.sleep(0.5) continue raise errors.HidError('Device error: %d' % int(ret_payload[0])) elif ret_cmd != cmd: raise errors.HidError('Command mismatch!') return ret_payload raise errors.HidError('Device Busy. Please retry')
def GetValueLength(rd, pos): """Get value length for a key in rd. For a key at position pos in the Report Descriptor rd, return the length of the associated value. This supports both short and long format values. Args: rd: Report Descriptor pos: The position of the key in rd. Returns: (key_size, data_len) where key_size is the number of bytes occupied by the key and data_len is the length of the value associated by the key. """ rd = bytearray(rd) key = rd[pos] if key == LONG_ITEM_ENCODING: # If the key is tagged as a long item (0xfe), then the format is # [key (1 byte)] [data len (1 byte)] [item tag (1 byte)] [data (n # bytes)]. # Thus, the entire key record is 3 bytes long. if pos + 1 < len(rd): return (3, rd[pos + 1]) else: raise errors.HidError('Malformed report descriptor') else: # If the key is tagged as a short item, then the item tag and data len are # packed into one byte. The format is thus: # [tag (high 4 bits)] [type (2 bits)] [size code (2 bits)] [data (n bytes)]. # The size code specifies 1,2, or 4 bytes (0x03 means 4 bytes). code = key & 0x03 if code <= 0x02: return (1, code) elif code == 0x03: return (1, 4) raise errors.HidError('Cannot happen')
def ReadLsbBytes(rd, offset, value_size): """Reads value_size bytes from rd at offset, least signifcant byte first.""" encoding = None if value_size == 1: encoding = '<B' elif value_size == 2: encoding = '<H' elif value_size == 4: encoding = '<L' else: raise errors.HidError('Invalid value size specified') ret, = struct.unpack(encoding, rd[offset:offset + value_size]) return ret
def Read(self): """See base class.""" buf = ctypes.create_string_buffer(self.desc.internal_max_in_report_len) num_read = wintypes.DWORD() ret = kernel32.ReadFile( self.dev, buf, len(buf), ctypes.byref(num_read), None) if num_read.value != self.desc.internal_max_in_report_len: raise errors.HidError("Failed to read full length report from device.") if not ret: raise ctypes.WinError() # Convert the string buffer to a list of numbers. Throw away the first # byte, which is the report id (which we don't care about). return list(bytearray(buf[1:]))
class GUID(ctypes.Structure): _fields_ = [("Data1", ctypes.c_ulong), ("Data2", ctypes.c_ushort), ("Data3", ctypes.c_ushort), ("Data4", ctypes.c_ubyte * 8)] # On Windows, SetupAPI.h packs structures differently in 64bit and # 32bit mode. In 64bit mode, thestructures are packed on 8 byte # boundaries, while in 32bit mode, they are packed on 1 byte boundaries. # This is important to get right for some API calls that fill out these # structures. if platform.architecture()[0] == "64bit": SETUPAPI_PACK = 8 elif platform.architecture()[0] == "32bit": SETUPAPI_PACK = 1 else: raise errors.HidError("Unknown architecture: %s" % platform.architecture()[0]) class DeviceInterfaceData(ctypes.Structure): _fields_ = [("cbSize", wintypes.DWORD), ("InterfaceClassGuid", GUID), ("Flags", wintypes.DWORD), ("Reserved", ctypes.POINTER(ctypes.c_ulong))] _pack_ = SETUPAPI_PACK class DeviceInterfaceDetailData(ctypes.Structure): _fields_ = [("cbSize", wintypes.DWORD), ("DevicePath", ctypes.c_byte * 1)] _pack_ = SETUPAPI_PACK class HidAttributes(ctypes.Structure):