diff --git a/.gitignore b/.gitignore index b135afe..3b213bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /python-yubico-1.3.2.tar.gz +/python-yubico-1.3.3.tar.gz diff --git a/python-yubico-py3.patch b/python-yubico-py3.patch deleted file mode 100644 index 4a6588a..0000000 --- a/python-yubico-py3.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 7e6e424ed579c53a0767ba71eb47345ae1e472ca Mon Sep 17 00:00:00 2001 -From: minus -Date: Sat, 12 Mar 2016 12:18:44 +0100 -Subject: [PATCH] fixed Python 3 compatibility for Yubikey 4 - ---- - yubico/yubikey_4_usb_hid.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/yubico/yubikey_4_usb_hid.py b/yubico/yubikey_4_usb_hid.py -index 31c6f5d..b44bb90 100644 ---- a/yubico/yubikey_4_usb_hid.py -+++ b/yubico/yubikey_4_usb_hid.py -@@ -104,7 +104,7 @@ def _read_capabilities(self): - frame = yubikey_frame.YubiKeyFrame(command=SLOT.YK4_CAPABILITIES) - self._device._write(frame) - response = self._device._read_response() -- r_len = ord(response[0]) -+ r_len = yubico_util.ord_byte(response[0]) - - # 1 byte length, 2 byte CRC. - if not yubico_util.validate_crc16(response[:r_len+3]): diff --git a/python-yubico-python3.patch b/python-yubico-python3.patch deleted file mode 100644 index 88adead..0000000 --- a/python-yubico-python3.patch +++ /dev/null @@ -1,2115 +0,0 @@ -From 1d38bede51448043ccda379adc6a254ddd313893 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 1 Jul 2015 15:04:18 +0200 -Subject: [PATCH 1/6] Breaking circular imports: Move __version__ to a - dedicated module - ---- - setup.py | 2 +- - yubico/__init__.py | 2 +- - yubico/yubico_exception.py | 2 +- - yubico/yubico_util.py | 2 +- - yubico/yubico_version.py | 1 + - yubico/yubikey.py | 2 +- - yubico/yubikey_config.py | 2 +- - yubico/yubikey_defs.py | 2 +- - yubico/yubikey_frame.py | 2 +- - yubico/yubikey_neo_usb_hid.py | 2 +- - yubico/yubikey_usb_hid.py | 2 +- - 11 files changed, 11 insertions(+), 10 deletions(-) - create mode 100644 yubico/yubico_version.py - -diff --git a/setup.py b/setup.py -index cc3e92e..0b08fec 100644 ---- a/setup.py -+++ b/setup.py -@@ -10,7 +10,7 @@ - def get_version(): - """Return the current version as defined by yubico/__init__.py.""" - -- with open('yubico/__init__.py', 'r') as f: -+ with open('yubico/yubico_version.py', 'r') as f: - match = VERSION_PATTERN.search(f.read()) - return match.group(1) - -diff --git a/yubico/__init__.py b/yubico/__init__.py -index 0f868b2..738897e 100644 ---- a/yubico/__init__.py -+++ b/yubico/__init__.py -@@ -20,7 +20,7 @@ - # Copyright (c) 2010, 2011, 2012 Yubico AB - # See the file COPYING for licence statement. - --__version__ = "1.2.3" -+from yubico_version import __version__ - - __all__ = [ - # classes -diff --git a/yubico/yubico_exception.py b/yubico/yubico_exception.py -index bb36f0d..3adba6c 100644 ---- a/yubico/yubico_exception.py -+++ b/yubico/yubico_exception.py -@@ -22,7 +22,7 @@ class for exceptions used in the other Yubico modules - 'YubiKeyTimeout', - ] - --from yubico import __version__ -+from yubico_version import __version__ - - class YubicoError(Exception): - """ -diff --git a/yubico/yubico_util.py b/yubico/yubico_util.py -index 2f3f1bc..8e13f32 100644 ---- a/yubico/yubico_util.py -+++ b/yubico/yubico_util.py -@@ -15,7 +15,7 @@ - # classes - ] - --from yubico import __version__ -+from yubico_version import __version__ - import yubikey_defs - import yubico_exception - import string -diff --git a/yubico/yubico_version.py b/yubico/yubico_version.py -new file mode 100644 -index 0000000..10aa336 ---- /dev/null -+++ b/yubico/yubico_version.py -@@ -0,0 +1 @@ -+__version__ = "1.2.3" -diff --git a/yubico/yubikey.py b/yubico/yubikey.py -index a44dabc..c576e80 100644 ---- a/yubico/yubikey.py -+++ b/yubico/yubikey.py -@@ -31,7 +31,7 @@ - 'YubiKeyTimeout', - ] - --from yubico import __version__ -+from yubico_version import __version__ - import yubico_exception - - class YubiKeyError(yubico_exception.YubicoError): -diff --git a/yubico/yubikey_config.py b/yubico/yubikey_config.py -index 0f08e3f..4f9ae29 100644 ---- a/yubico/yubikey_config.py -+++ b/yubico/yubikey_config.py -@@ -15,7 +15,7 @@ - 'YubiKeyConfig', - ] - --from yubico import __version__ -+from yubico_version import __version__ - - import struct - import binascii -diff --git a/yubico/yubikey_defs.py b/yubico/yubikey_defs.py -index 74f5bb8..843b8d9 100644 ---- a/yubico/yubikey_defs.py -+++ b/yubico/yubikey_defs.py -@@ -18,7 +18,7 @@ - # classes - ] - --from yubico import __version__ -+from yubico_version import __version__ - - # Yubikey Low level interface #2.3 - RESP_TIMEOUT_WAIT_MASK = 0x1f # Mask to get timeout value -diff --git a/yubico/yubikey_frame.py b/yubico/yubikey_frame.py -index 018f9c7..c34b4ec 100644 ---- a/yubico/yubikey_frame.py -+++ b/yubico/yubikey_frame.py -@@ -17,7 +17,7 @@ - import yubikey_defs - import yubico_exception - import yubikey_config --from yubico import __version__ -+from yubico_version import __version__ - - class YubiKeyFrame: - """ -diff --git a/yubico/yubikey_neo_usb_hid.py b/yubico/yubikey_neo_usb_hid.py -index f7913c7..7711779 100644 ---- a/yubico/yubikey_neo_usb_hid.py -+++ b/yubico/yubikey_neo_usb_hid.py -@@ -16,7 +16,7 @@ - - import struct - --from yubico import __version__ -+from yubico_version import __version__ - import yubikey_usb_hid - import yubikey_frame - import yubico_exception -diff --git a/yubico/yubikey_usb_hid.py b/yubico/yubikey_usb_hid.py -index e808804..716ddaf 100644 ---- a/yubico/yubikey_usb_hid.py -+++ b/yubico/yubikey_usb_hid.py -@@ -14,7 +14,7 @@ - 'YubiKeyUSBHIDStatus', - ] - --from yubico import __version__ -+from yubico_version import __version__ - - import yubico_util - import yubico_exception - -From 8061cb91bb582f7000e7432bb2319b9f70add306 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 1 Jul 2015 15:12:45 +0200 -Subject: [PATCH 2/6] Breaking circular imports: Move command definitions to - yubikey_defs - -This breaks the yubikey_config <-> yubikey_frame circular import. ---- - yubico/yubikey_config.py | 22 ++++------------------ - yubico/yubikey_defs.py | 18 ++++++++++++++++++ - yubico/yubikey_frame.py | 13 ++++++------- - yubico/yubikey_usb_hid.py | 2 +- - 4 files changed, 29 insertions(+), 26 deletions(-) - -diff --git a/yubico/yubikey_config.py b/yubico/yubikey_config.py -index 4f9ae29..24f0ba0 100644 ---- a/yubico/yubikey_config.py -+++ b/yubico/yubikey_config.py -@@ -27,6 +27,10 @@ - from yubikey_config_util import YubiKeyConfigBits, YubiKeyConfigFlag, YubiKeyExtendedFlag, YubiKeyTicketFlag - import yubikey - -+# these used to be defined here; import them for backwards compatibility -+from yubikey_defs import SLOT_CONFIG, SLOT_CONFIG2, SLOT_UPDATE1, SLOT_UPDATE2, SLOT_SWAP, command2str -+ -+ - TicketFlags = [ - YubiKeyTicketFlag('TAB_FIRST', 0x01, min_ykver=(1, 0), doc='Send TAB before first part'), - YubiKeyTicketFlag('APPEND_TAB1', 0x02, min_ykver=(1, 0), doc='Send TAB after first part'), -@@ -79,24 +83,6 @@ - YubiKeyExtendedFlag('DORMANT', 0x40, min_ykver=(2, 3), doc='Dormant configuration (can be woken up and flag removed = requires update flag)'), - ] - --SLOT_CONFIG = 0x01 # First (default / V1) configuration --SLOT_CONFIG2 = 0x03 # Second (V2) configuration --SLOT_UPDATE1 = 0x04 # Update slot 1 --SLOT_UPDATE2 = 0x05 # Update slot 2 --SLOT_SWAP = 0x06 # Swap slot 1 and 2 -- --def command2str(num): -- """ Turn command number into name """ -- known = {0x01: "SLOT_CONFIG", -- 0x03: "SLOT_CONFIG2", -- 0x04: "SLOT_UPDATE1", -- 0x05: "SLOT_UPDATE2", -- 0x06: "SLOT_SWAP", -- } -- if num in known: -- return known[num] -- return "0x%02x" % (num) -- - class YubiKeyConfigError(yubico_exception.YubicoError): - """ - Exception raised for YubiKey configuration errors. -diff --git a/yubico/yubikey_defs.py b/yubico/yubikey_defs.py -index 843b8d9..bd4f7c4 100644 ---- a/yubico/yubikey_defs.py -+++ b/yubico/yubikey_defs.py -@@ -31,3 +31,21 @@ - OTP_CHALRESP_SIZE = 16 # Number of bytes returned for an Yubico-OTP challenge (not from ykdef.h) - - UID_SIZE = 6 # Size of secret ID field -+ -+SLOT_CONFIG = 0x01 # First (default / V1) configuration -+SLOT_CONFIG2 = 0x03 # Second (V2) configuration -+SLOT_UPDATE1 = 0x04 # Update slot 1 -+SLOT_UPDATE2 = 0x05 # Update slot 2 -+SLOT_SWAP = 0x06 # Swap slot 1 and 2 -+ -+def command2str(num): -+ """ Turn command number into name """ -+ known = {0x01: "SLOT_CONFIG", -+ 0x03: "SLOT_CONFIG2", -+ 0x04: "SLOT_UPDATE1", -+ 0x05: "SLOT_UPDATE2", -+ 0x06: "SLOT_SWAP", -+ } -+ if num in known: -+ return known[num] -+ return "0x%02x" % (num) -diff --git a/yubico/yubikey_frame.py b/yubico/yubikey_frame.py -index c34b4ec..63df89d 100644 ---- a/yubico/yubikey_frame.py -+++ b/yubico/yubikey_frame.py -@@ -16,7 +16,6 @@ - import yubico_util - import yubikey_defs - import yubico_exception --import yubikey_config - from yubico_version import __version__ - - class YubiKeyFrame: -@@ -93,13 +92,13 @@ def _debug_string(self, debug, data): - """ - if not debug: - return data -- if self.command in [yubikey_config.SLOT_CONFIG, -- yubikey_config.SLOT_CONFIG2, -- yubikey_config.SLOT_UPDATE1, -- yubikey_config.SLOT_UPDATE2, -- yubikey_config.SLOT_SWAP, -+ if self.command in [yubikey_defs.SLOT_CONFIG, -+ yubikey_defs.SLOT_CONFIG2, -+ yubikey_defs.SLOT_UPDATE1, -+ yubikey_defs.SLOT_UPDATE2, -+ yubikey_defs.SLOT_SWAP, - ]: -- # annotate according to config_st (see yubikey_config.to_string()) -+ # annotate according to config_st (see yubikey_defs.to_string()) - if ord(data[-1]) == 0x80: - return (data, "FFFFFFF") - if ord(data[-1]) == 0x81: -diff --git a/yubico/yubikey_usb_hid.py b/yubico/yubikey_usb_hid.py -index 716ddaf..1fd4baa 100644 ---- a/yubico/yubikey_usb_hid.py -+++ b/yubico/yubikey_usb_hid.py -@@ -280,7 +280,7 @@ def _write_config(self, cfg, slot): - old_pgm_seq = self._status.pgm_seq - frame = cfg.to_frame(slot=slot) - self._debug("Writing %s frame :\n%s\n" % \ -- (yubikey_config.command2str(frame.command), cfg)) -+ (yubikey_defs.command2str(frame.command), cfg)) - self._write(frame) - self._waitfor_clear(yubikey_defs.SLOT_WRITE_FLAG) - # make sure we have a fresh pgm_seq value - -From 3fe8f804faae595e32e880abe349cc6e6d0c26bf Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 1 Jul 2015 15:19:06 +0200 -Subject: [PATCH 3/6] Breaking circular imports: Move base classes to - yubico_base.py - -This breaks the yubikey <-> yubikey_usb_hid circular import ---- - yubico/yubikey.py | 180 +-------------------------------------------- - yubico/yubikey_base.py | 182 ++++++++++++++++++++++++++++++++++++++++++++++ - yubico/yubikey_config.py | 32 ++++---- - yubico/yubikey_usb_hid.py | 20 ++--- - 4 files changed, 209 insertions(+), 205 deletions(-) - create mode 100644 yubico/yubikey_base.py - -diff --git a/yubico/yubikey.py b/yubico/yubikey.py -index c576e80..d23af88 100644 ---- a/yubico/yubikey.py -+++ b/yubico/yubikey.py -@@ -32,185 +32,7 @@ - ] - - from yubico_version import __version__ --import yubico_exception -- --class YubiKeyError(yubico_exception.YubicoError): -- """ -- Exception raised concerning YubiKey operations. -- -- Attributes: -- reason -- explanation of the error -- """ -- def __init__(self, reason='no details'): -- yubico_exception.YubicoError.__init__(self, reason) -- --class YubiKeyTimeout(YubiKeyError): -- """ -- Exception raised when a YubiKey operation timed out. -- -- Attributes: -- reason -- explanation of the error -- """ -- def __init__(self, reason='no details'): -- YubiKeyError.__init__(self, reason) -- --class YubiKeyVersionError(YubiKeyError): -- """ -- Exception raised when the YubiKey is not capable of something requested. -- -- Attributes: -- reason -- explanation of the error -- """ -- def __init__(self, reason='no details'): -- YubiKeyError.__init__(self, reason) -- -- --class YubiKeyCapabilities(): -- """ -- Class expressing the functionality of a YubiKey. -- -- This base class should be the superset of all sub-classes. -- -- In this base class, we lie and say 'yes' to all capabilities. -- -- If the base class is used (such as when creating a YubiKeyConfig() -- before getting a YubiKey()), errors must be handled at runtime -- (or later, when the user is unable to use the YubiKey). -- """ -- -- model = 'Unknown' -- version = (0, 0, 0,) -- version_num = 0x0 -- default_answer = True -- -- def __init__(self, model = None, version = None, default_answer = None): -- self.model = model -- if default_answer is not None: -- self.default_answer = default_answer -- if version is not None: -- self.version = version -- (major, minor, build,) = version -- # convert 2.1.3 to 0x00020103 -- self.version_num = (major << 24) | (minor << 16) | build -- return None -- -- def __repr__(self): -- return '<%s instance at %s: Device %s %s (default: %s)>' % ( -- self.__class__.__name__, -- hex(id(self)), -- self.model, -- self.version, -- self.default_answer, -- ) -- -- def have_yubico_OTP(self): -- return self.default_answer -- -- def have_OATH(self, mode): -- return self.default_answer -- -- def have_challenge_response(self, mode): -- return self.default_answer -- -- def have_serial_number(self): -- return self.default_answer -- -- def have_ticket_flag(self, flag): -- return self.default_answer -- -- def have_config_flag(self, flag): -- return self.default_answer -- -- def have_extended_flag(self, flag): -- return self.default_answer -- -- def have_extended_scan_code_mode(self): -- return self.default_answer -- -- def have_shifted_1_mode(self): -- return self.default_answer -- -- def have_nfc_ndef(self): -- return self.default_answer -- -- def have_configuration_slot(self): -- return self.default_answer -- --class YubiKey(): -- """ -- Base class for accessing YubiKeys -- """ -- -- debug = None -- capabilities = None -- -- def __init__(self, debug, capabilities = None): -- self.debug = debug -- if capabilities is None: -- self.capabilities = YubiKeyCapabilities(default_answer = False) -- else: -- self.capabilities = capabilities -- return None -- -- def version(self): -- """ Get the connected YubiKey's version as a string. """ -- pass -- -- def serial(self, may_block=True): -- """ -- Get the connected YubiKey's serial number. -- -- Note that since version 2.?.? this requires the YubiKey to be -- configured with the extended flag SERIAL_API_VISIBLE. -- -- If the YubiKey is configured with SERIAL_BTN_VISIBLE set to True, -- it will start blinking and require a button press before revealing -- the serial number, with a 15 seconds timeout. Set `may_block' -- to False to abort if this is the case. -- """ -- pass -- -- def challenge(self, challenge, mode='HMAC', slot=1, variable=True, may_block=True): -- """ -- Get the response to a challenge from a connected YubiKey. -- -- `mode' is either 'HMAC' or 'OTP'. -- `slot' is 1 or 2. -- `variable' is only relevant for mode == HMAC. -- -- If variable is True, challenge will be padded such that the -- YubiKey will compute the HMAC as if there were no padding. -- If variable is False, challenge will always be NULL-padded -- to 64 bytes. -- -- The special case of no input will be HMACed by the YubiKey -- (in variable HMAC mode) as data = 0x00, length = 1. -- -- In mode 'OTP', the challenge should be exactly 6 bytes. The -- response will be a YubiKey "ticket" with the 6-byte challenge -- in the ticket.uid field. The rest of the "ticket" will contain -- timestamp and counter information, so two identical challenges -- will NOT result in the same responses. The response is -- decryptable using AES ECB if you have access to the AES key -- programmed into the YubiKey. -- """ -- pass -- -- def init_config(self): -- """ -- Return a YubiKey configuration object for this type of YubiKey. -- """ -- pass -- -- def write_config(self, cfg, slot): -- """ -- Configure a YubiKey using a configuration object. -- """ -- pass -- --# Since YubiKeyUSBHID is a subclass of YubiKey (defined here above), --# the import must be after the declaration of YubiKey. We also carefully --# import only what we need to not get a circular import of modules. -+from yubikey_base import YubiKeyError, YubiKeyTimeout, YubiKeyVersionError, YubiKeyCapabilities, YubiKey - from yubikey_usb_hid import YubiKeyUSBHID, YubiKeyUSBHIDError - from yubikey_neo_usb_hid import YubiKeyNEO_USBHID, YubiKeyNEO_USBHIDError - -diff --git a/yubico/yubikey_base.py b/yubico/yubikey_base.py -new file mode 100644 -index 0000000..ef53e2e ---- /dev/null -+++ b/yubico/yubikey_base.py -@@ -0,0 +1,182 @@ -+""" -+module for Yubikey base classes -+""" -+# Copyright (c) 2010, 2011, 2012 Yubico AB -+# See the file COPYING for licence statement. -+ -+from yubico_version import __version__ -+import yubico_exception -+ -+class YubiKeyError(yubico_exception.YubicoError): -+ """ -+ Exception raised concerning YubiKey operations. -+ -+ Attributes: -+ reason -- explanation of the error -+ """ -+ def __init__(self, reason='no details'): -+ yubico_exception.YubicoError.__init__(self, reason) -+ -+class YubiKeyTimeout(YubiKeyError): -+ """ -+ Exception raised when a YubiKey operation timed out. -+ -+ Attributes: -+ reason -- explanation of the error -+ """ -+ def __init__(self, reason='no details'): -+ YubiKeyError.__init__(self, reason) -+ -+class YubiKeyVersionError(YubiKeyError): -+ """ -+ Exception raised when the YubiKey is not capable of something requested. -+ -+ Attributes: -+ reason -- explanation of the error -+ """ -+ def __init__(self, reason='no details'): -+ YubiKeyError.__init__(self, reason) -+ -+ -+class YubiKeyCapabilities(): -+ """ -+ Class expressing the functionality of a YubiKey. -+ -+ This base class should be the superset of all sub-classes. -+ -+ In this base class, we lie and say 'yes' to all capabilities. -+ -+ If the base class is used (such as when creating a YubiKeyConfig() -+ before getting a YubiKey()), errors must be handled at runtime -+ (or later, when the user is unable to use the YubiKey). -+ """ -+ -+ model = 'Unknown' -+ version = (0, 0, 0,) -+ version_num = 0x0 -+ default_answer = True -+ -+ def __init__(self, model = None, version = None, default_answer = None): -+ self.model = model -+ if default_answer is not None: -+ self.default_answer = default_answer -+ if version is not None: -+ self.version = version -+ (major, minor, build,) = version -+ # convert 2.1.3 to 0x00020103 -+ self.version_num = (major << 24) | (minor << 16) | build -+ return None -+ -+ def __repr__(self): -+ return '<%s instance at %s: Device %s %s (default: %s)>' % ( -+ self.__class__.__name__, -+ hex(id(self)), -+ self.model, -+ self.version, -+ self.default_answer, -+ ) -+ -+ def have_yubico_OTP(self): -+ return self.default_answer -+ -+ def have_OATH(self, mode): -+ return self.default_answer -+ -+ def have_challenge_response(self, mode): -+ return self.default_answer -+ -+ def have_serial_number(self): -+ return self.default_answer -+ -+ def have_ticket_flag(self, flag): -+ return self.default_answer -+ -+ def have_config_flag(self, flag): -+ return self.default_answer -+ -+ def have_extended_flag(self, flag): -+ return self.default_answer -+ -+ def have_extended_scan_code_mode(self): -+ return self.default_answer -+ -+ def have_shifted_1_mode(self): -+ return self.default_answer -+ -+ def have_nfc_ndef(self): -+ return self.default_answer -+ -+ def have_configuration_slot(self): -+ return self.default_answer -+ -+class YubiKey(): -+ """ -+ Base class for accessing YubiKeys -+ """ -+ -+ debug = None -+ capabilities = None -+ -+ def __init__(self, debug, capabilities = None): -+ self.debug = debug -+ if capabilities is None: -+ self.capabilities = YubiKeyCapabilities(default_answer = False) -+ else: -+ self.capabilities = capabilities -+ return None -+ -+ def version(self): -+ """ Get the connected YubiKey's version as a string. """ -+ pass -+ -+ def serial(self, may_block=True): -+ """ -+ Get the connected YubiKey's serial number. -+ -+ Note that since version 2.?.? this requires the YubiKey to be -+ configured with the extended flag SERIAL_API_VISIBLE. -+ -+ If the YubiKey is configured with SERIAL_BTN_VISIBLE set to True, -+ it will start blinking and require a button press before revealing -+ the serial number, with a 15 seconds timeout. Set `may_block' -+ to False to abort if this is the case. -+ """ -+ pass -+ -+ def challenge(self, challenge, mode='HMAC', slot=1, variable=True, may_block=True): -+ """ -+ Get the response to a challenge from a connected YubiKey. -+ -+ `mode' is either 'HMAC' or 'OTP'. -+ `slot' is 1 or 2. -+ `variable' is only relevant for mode == HMAC. -+ -+ If variable is True, challenge will be padded such that the -+ YubiKey will compute the HMAC as if there were no padding. -+ If variable is False, challenge will always be NULL-padded -+ to 64 bytes. -+ -+ The special case of no input will be HMACed by the YubiKey -+ (in variable HMAC mode) as data = 0x00, length = 1. -+ -+ In mode 'OTP', the challenge should be exactly 6 bytes. The -+ response will be a YubiKey "ticket" with the 6-byte challenge -+ in the ticket.uid field. The rest of the "ticket" will contain -+ timestamp and counter information, so two identical challenges -+ will NOT result in the same responses. The response is -+ decryptable using AES ECB if you have access to the AES key -+ programmed into the YubiKey. -+ """ -+ pass -+ -+ def init_config(self): -+ """ -+ Return a YubiKey configuration object for this type of YubiKey. -+ """ -+ pass -+ -+ def write_config(self, cfg, slot): -+ """ -+ Configure a YubiKey using a configuration object. -+ """ -+ pass -diff --git a/yubico/yubikey_config.py b/yubico/yubikey_config.py -index 24f0ba0..a3e9146 100644 ---- a/yubico/yubikey_config.py -+++ b/yubico/yubikey_config.py -@@ -25,7 +25,7 @@ - import yubico_exception - import yubikey_config_util - from yubikey_config_util import YubiKeyConfigBits, YubiKeyConfigFlag, YubiKeyExtendedFlag, YubiKeyTicketFlag --import yubikey -+import yubikey_base - - # these used to be defined here; import them for backwards compatibility - from yubikey_defs import SLOT_CONFIG, SLOT_CONFIG2, SLOT_UPDATE1, SLOT_UPDATE2, SLOT_SWAP, command2str -@@ -110,7 +110,7 @@ def __init__(self, ykver=None, capabilities=None, update=False, swap=False): - slot 1 be slot 2 and vice versa. Set swap=True for this. - """ - if capabilities is None: -- self.capabilities = yubikey.YubiKeyCapabilities(default_answer = True) -+ self.capabilities = yubikey_base.YubiKeyCapabilities(default_answer = True) - else: - self.capabilities = capabilities - -@@ -270,8 +270,8 @@ def mode_yubikey_otp(self, private_uid, aes_key): - Set the YubiKey up for standard OTP validation. - """ - if not self.capabilities.have_yubico_OTP(): -- raise yubikey.YubiKeyVersionError('Yubico OTP not available in %s version %d.%d' \ -- % (self.capabilities.model, self.ykver[0], self.ykver[1])) -+ raise yubikey_base.YubiKeyVersionError('Yubico OTP not available in %s version %d.%d' \ -+ % (self.capabilities.model, self.ykver[0], self.ykver[1])) - if private_uid.startswith('h:'): - private_uid = binascii.unhexlify(private_uid[2:]) - if len(private_uid) != yubikey_defs.UID_SIZE: -@@ -288,8 +288,8 @@ def mode_oath_hotp(self, secret, digits=6, factor_seed=None, omp=0x0, tt=0x0, mu - Requires YubiKey 2.1. - """ - if not self.capabilities.have_OATH('HOTP'): -- raise yubikey.YubiKeyVersionError('OATH HOTP not available in %s version %d.%d' \ -- % (self.capabilities.model, self.ykver[0], self.ykver[1])) -+ raise yubikey_base.YubiKeyVersionError('OATH HOTP not available in %s version %d.%d' \ -+ % (self.capabilities.model, self.ykver[0], self.ykver[1])) - if digits != 6 and digits != 8: - raise yubico_exception.InputError('OATH-HOTP digits must be 6 or 8') - -@@ -320,9 +320,9 @@ def mode_challenge_response(self, secret, type='HMAC', variable=True, require_bu - if not type.upper() in ['HMAC', 'OTP']: - raise yubico_exception.InputError('Invalid \'type\' (%s)' % type) - if not self.capabilities.have_challenge_response(type.upper()): -- raise yubikey.YubiKeyVersionError('%s Challenge-Response not available in %s version %d.%d' \ -- % (type.upper(), self.capabilities.model, \ -- self.ykver[0], self.ykver[1])) -+ raise yubikey_base.YubiKeyVersionError('%s Challenge-Response not available in %s version %d.%d' \ -+ % (type.upper(), self.capabilities.model, \ -+ self.ykver[0], self.ykver[1])) - self._change_mode('CHAL_RESP', major=2, minor=2) - if type.upper() == 'HMAC': - self.config_flag('CHAL_HMAC', True) -@@ -344,8 +344,8 @@ def ticket_flag(self, which, new=None): - flag = _get_flag(which, TicketFlags) - if flag: - if not self.capabilities.have_ticket_flag(flag): -- raise yubikey.YubiKeyVersionError('Ticket flag %s requires %s, and this is %s %d.%d' -- % (which, flag.req_string(self.capabilities.model), \ -+ raise yubikey_base.YubiKeyVersionError('Ticket flag %s requires %s, and this is %s %d.%d' -+ % (which, flag.req_string(self.capabilities.model), \ - self.capabilities.model, self.ykver[0], self.ykver[1])) - req_major, req_minor = flag.req_version() - self._require_version(major=req_major, minor=req_minor) -@@ -367,8 +367,8 @@ def config_flag(self, which, new=None): - flag = _get_flag(which, ConfigFlags) - if flag: - if not self.capabilities.have_config_flag(flag): -- raise yubikey.YubiKeyVersionError('Config flag %s requires %s, and this is %s %d.%d' -- % (which, flag.req_string(self.capabilities.model), \ -+ raise yubikey_base.YubiKeyVersionError('Config flag %s requires %s, and this is %s %d.%d' -+ % (which, flag.req_string(self.capabilities.model), \ - self.capabilities.model, self.ykver[0], self.ykver[1])) - req_major, req_minor = flag.req_version() - self._require_version(major=req_major, minor=req_minor) -@@ -390,8 +390,8 @@ def extended_flag(self, which, new=None): - flag = _get_flag(which, ExtendedFlags) - if flag: - if not self.capabilities.have_extended_flag(flag): -- raise yubikey.YubiKeyVersionError('Extended flag %s requires %s, and this is %s %d.%d' -- % (which, flag.req_string(self.capabilities.model), \ -+ raise yubikey_base.YubiKeyVersionError('Extended flag %s requires %s, and this is %s %d.%d' -+ % (which, flag.req_string(self.capabilities.model), \ - self.capabilities.model, self.ykver[0], self.ykver[1])) - req_major, req_minor = flag.req_version() - self._require_version(major=req_major, minor=req_minor) -@@ -472,7 +472,7 @@ def _require_version(self, major, minor=0): - """ Update the minimum version of YubiKey this configuration can be applied to. """ - new_ver = (major, minor) - if self.ykver and new_ver > self.ykver: -- raise yubikey.YubiKeyVersionError('Configuration requires YubiKey %d.%d, and this is %d.%d' -+ raise yubikey_base.YubiKeyVersionError('Configuration requires YubiKey %d.%d, and this is %d.%d' - % (major, minor, self.ykver[0], self.ykver[1])) - if new_ver > self.yk_req_version: - self.yk_req_version = new_ver -diff --git a/yubico/yubikey_usb_hid.py b/yubico/yubikey_usb_hid.py -index 1fd4baa..6af248b 100644 ---- a/yubico/yubikey_usb_hid.py -+++ b/yubico/yubikey_usb_hid.py -@@ -21,8 +21,8 @@ - import yubikey_frame - import yubikey_config - import yubikey_defs --import yubikey --from yubikey import YubiKey -+import yubikey_base -+from yubikey_base import YubiKey - import struct - import time - import sys -@@ -85,7 +85,7 @@ - class YubiKeyUSBHIDError(yubico_exception.YubicoError): - """ Exception raised for errors with the USB HID communication. """ - --class YubiKeyUSBHIDCapabilities(yubikey.YubiKeyCapabilities): -+class YubiKeyUSBHIDCapabilities(yubikey_base.YubiKeyCapabilities): - """ - Capture the capabilities of the various versions of YubiKeys. - -@@ -93,9 +93,9 @@ class YubiKeyUSBHIDCapabilities(yubikey.YubiKeyCapabilities): - in one or more versions, leaving the other ones at False through default_answer. - """ - def __init__(self, model, version, default_answer): -- yubikey.YubiKeyCapabilities.__init__(self, model = model, \ -- version = version, \ -- default_answer = default_answer) -+ yubikey_base.YubiKeyCapabilities.__init__(self, model = model, \ -+ version = version, \ -+ default_answer = default_answer) - - def have_yubico_OTP(self): - """ Yubico OTP support has always been available in the standard YubiKey. """ -@@ -203,13 +203,13 @@ def version(self): - def serial(self, may_block=True): - """ Get the YubiKey serial number (requires YubiKey 2.2). """ - if not self.capabilities.have_serial_number(): -- raise yubikey.YubiKeyVersionError("Serial number unsupported in YubiKey %s" % self.version() ) -+ raise yubikey_base.YubiKeyVersionError("Serial number unsupported in YubiKey %s" % self.version() ) - return self._read_serial(may_block) - - def challenge_response(self, challenge, mode='HMAC', slot=1, variable=True, may_block=True): - """ Issue a challenge to the YubiKey and return the response (requires YubiKey 2.2). """ - if not self.capabilities.have_challenge_response(mode): -- raise yubikey.YubiKeyVersionError("%s challenge-response unsupported in YubiKey %s" % (mode, self.version()) ) -+ raise yubikey_base.YubiKeyVersionError("%s challenge-response unsupported in YubiKey %s" % (mode, self.version()) ) - return self._challenge_response(challenge, mode, slot, variable, may_block) - - def init_config(self, **kw): -@@ -222,7 +222,7 @@ def write_config(self, cfg, slot=1): - """ Write a configuration to the YubiKey. """ - cfg_req_ver = cfg.version_required() - if cfg_req_ver > self.version_num(): -- raise yubikey.YubiKeyVersionError('Configuration requires YubiKey version %i.%i (this is %s)' % \ -+ raise yubikey_base.YubiKeyVersionError('Configuration requires YubiKey version %i.%i (this is %s)' % \ - (cfg_req_ver[0], cfg_req_ver[1], self.version())) - if not self.capabilities.have_configuration_slot(slot): - raise YubiKeyUSBHIDError("Can't write configuration to slot %i" % (slot)) -@@ -436,7 +436,7 @@ def _waitfor(self, mode, mask, may_block, timeout=2): - reason = 'Timed out waiting for YubiKey to clear status 0x%x' % mask - else: - reason = 'Timed out waiting for YubiKey to set status 0x%x' % mask -- raise yubikey.YubiKeyTimeout(reason) -+ raise yubikey_base.YubiKeyTimeout(reason) - time.sleep(sleep) - sleep = min(sleep + sleep, 0.5) - else: - -From 1f2e611c491a168ff5632b3365c399b0e059d367 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 1 Jul 2015 14:18:34 +0200 -Subject: [PATCH 4/6] Use Python 3-compatible syntax - -- Use parentheses with print - (python-yubico only ever gives one argument to print) -- Use 'as' syntax when catching expressions (PEP; Python 2.6+) -- Use explicit relative imports (PEP 328; Python 2.4+) -- Use range instead of xrange - (this is in a debugging tool, the memory overhead is negligible, - and the entire result is iterated over) ---- - test/test_yubikey_config.py | 32 ++++++++++++++++---------------- - test/test_yubikey_frame.py | 2 +- - test/test_yubikey_usb_hid.py | 8 ++++---- - yubico/__init__.py | 6 +++--- - yubico/yubico_exception.py | 2 +- - yubico/yubico_util.py | 8 ++++---- - yubico/yubikey.py | 8 ++++---- - yubico/yubikey_base.py | 4 ++-- - yubico/yubikey_config.py | 18 +++++++++--------- - yubico/yubikey_defs.py | 2 +- - yubico/yubikey_frame.py | 8 ++++---- - yubico/yubikey_neo_usb_hid.py | 8 ++++---- - yubico/yubikey_usb_hid.py | 20 ++++++++++---------- - 13 files changed, 63 insertions(+), 63 deletions(-) - -diff --git a/test/test_yubikey_config.py b/test/test_yubikey_config.py -index 29b8649..5fc694c 100644 ---- a/test/test_yubikey_config.py -+++ b/test/test_yubikey_config.py -@@ -41,8 +41,8 @@ def test_static_ticket(self): - - data = Config.to_frame(slot=1).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -@@ -75,8 +75,8 @@ def test_static_ticket_with_access_code(self): - - data = Config.to_frame(slot=1).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -@@ -113,8 +113,8 @@ def test_fixed_and_oath_hotp(self): - - data = Config.to_frame(slot=2).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -@@ -138,8 +138,8 @@ def test_challenge_response_hmac_nist(self): - - data = Config.to_frame(slot=2).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -@@ -186,8 +186,8 @@ def test_oath_hotp_like_windows(self): - - data = Config.to_frame(slot=2).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -@@ -211,8 +211,8 @@ def test_oath_hotp_like_windows2(self): - - data = Config.to_frame(slot=2).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -@@ -236,8 +236,8 @@ def test_oath_hotp_like_windows_factory_seed(self): - - data = Config.to_frame(slot=2).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -@@ -260,8 +260,8 @@ def test_fixed_length_hmac_like_windows(self): - - data = Config.to_frame(slot=2).to_feature_reports() - -- print "EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -+ yubico.yubico_util.hexdump(''.join(data)))) - - self.assertEqual(data, expected) - -diff --git a/test/test_yubikey_frame.py b/test/test_yubikey_frame.py -index f6cbb6e..5437922 100644 ---- a/test/test_yubikey_frame.py -+++ b/test/test_yubikey_frame.py -@@ -50,7 +50,7 @@ def test_repr(self): - """ Test string representation of object """ - # to achieve 100% test coverage ;) - frame = YubiKeyFrame(command=0x4d) -- print "Frame is represented as %s" % frame -+ print("Frame is represented as %s" % frame) - re_match = re.search("YubiKeyFrame instance at .*: 77.$", str(frame)) - self.assertNotEqual(re_match, None) - -diff --git a/test/test_yubikey_usb_hid.py b/test/test_yubikey_usb_hid.py -index 356b461..f801a33 100644 ---- a/test/test_yubikey_usb_hid.py -+++ b/test/test_yubikey_usb_hid.py -@@ -18,10 +18,10 @@ def setUp(self): - """ Test connecting to the YubiKey """ - if self.YK is None: - try: -- print "open key" -+ print("open key") - self.YK = YubiKeyUSBHID() - return -- except YubiKeyUSBHIDError, err: -+ except YubiKeyUSBHIDError as err: - self.fail("No YubiKey connected (?) : %s" % str(err)) - - def tearDown(self): -@@ -33,7 +33,7 @@ def test_status(self): - """ Test the simplest form of communication : a status read request """ - status = self.YK.status() - version = self.YK.version() -- print "Version returned: %s" % version -+ print("Version returned: %s" % version) - re_match = re.match("\d+\.\d+\.\d+$", version) - self.assertNotEqual(re_match, None) - -@@ -49,7 +49,7 @@ def test_challenge_response(self): - def test_serial(self): - """ Test serial number retrieval (requires YubiKey 2) """ - serial = self.YK.serial() -- print "Serial returned : %s" % serial -+ print("Serial returned : %s" % serial) - self.assertEqual(type(serial), type(1)) - - if __name__ == '__main__': -diff --git a/yubico/__init__.py b/yubico/__init__.py -index 738897e..d81c1b1 100644 ---- a/yubico/__init__.py -+++ b/yubico/__init__.py -@@ -20,7 +20,7 @@ - # Copyright (c) 2010, 2011, 2012 Yubico AB - # See the file COPYING for licence statement. - --from yubico_version import __version__ -+from .yubico_version import __version__ - - __all__ = [ - # classes -@@ -40,5 +40,5 @@ - ] - - # to not have to import yubico.yubikey --from yubikey import YubiKey --from yubikey import find_key as find_yubikey -+from .yubikey import YubiKey -+from .yubikey import find_key as find_yubikey -diff --git a/yubico/yubico_exception.py b/yubico/yubico_exception.py -index 3adba6c..e2fd393 100644 ---- a/yubico/yubico_exception.py -+++ b/yubico/yubico_exception.py -@@ -22,7 +22,7 @@ class for exceptions used in the other Yubico modules - 'YubiKeyTimeout', - ] - --from yubico_version import __version__ -+from .yubico_version import __version__ - - class YubicoError(Exception): - """ -diff --git a/yubico/yubico_util.py b/yubico/yubico_util.py -index 8e13f32..5af3956 100644 ---- a/yubico/yubico_util.py -+++ b/yubico/yubico_util.py -@@ -15,9 +15,9 @@ - # classes - ] - --from yubico_version import __version__ --import yubikey_defs --import yubico_exception -+from .yubico_version import __version__ -+from . import yubikey_defs -+from . import yubico_exception - import string - - _CRC_OK_RESIDUAL = 0xf0b8 -@@ -101,7 +101,7 @@ def hexdump(src, length=8, colorize=False): - - def group(data, num): - """ Split data into chunks of num chars each """ -- return [data[i:i+num] for i in xrange(0, len(data), num)] -+ return [data[i:i+num] for i in range(0, len(data), num)] - - def modhex_decode(data): - """ Convert a modhex string to ordinary hex. """ -diff --git a/yubico/yubikey.py b/yubico/yubikey.py -index d23af88..f71d56f 100644 ---- a/yubico/yubikey.py -+++ b/yubico/yubikey.py -@@ -31,10 +31,10 @@ - 'YubiKeyTimeout', - ] - --from yubico_version import __version__ --from yubikey_base import YubiKeyError, YubiKeyTimeout, YubiKeyVersionError, YubiKeyCapabilities, YubiKey --from yubikey_usb_hid import YubiKeyUSBHID, YubiKeyUSBHIDError --from yubikey_neo_usb_hid import YubiKeyNEO_USBHID, YubiKeyNEO_USBHIDError -+from .yubico_version import __version__ -+from .yubikey_base import YubiKeyError, YubiKeyTimeout, YubiKeyVersionError, YubiKeyCapabilities, YubiKey -+from .yubikey_usb_hid import YubiKeyUSBHID, YubiKeyUSBHIDError -+from .yubikey_neo_usb_hid import YubiKeyNEO_USBHID, YubiKeyNEO_USBHIDError - - def find_key(debug=False, skip=0): - """ -diff --git a/yubico/yubikey_base.py b/yubico/yubikey_base.py -index ef53e2e..9378082 100644 ---- a/yubico/yubikey_base.py -+++ b/yubico/yubikey_base.py -@@ -4,8 +4,8 @@ - # Copyright (c) 2010, 2011, 2012 Yubico AB - # See the file COPYING for licence statement. - --from yubico_version import __version__ --import yubico_exception -+from .yubico_version import __version__ -+from . import yubico_exception - - class YubiKeyError(yubico_exception.YubicoError): - """ -diff --git a/yubico/yubikey_config.py b/yubico/yubikey_config.py -index a3e9146..3a02114 100644 ---- a/yubico/yubikey_config.py -+++ b/yubico/yubikey_config.py -@@ -15,20 +15,20 @@ - 'YubiKeyConfig', - ] - --from yubico_version import __version__ -+from .yubico_version import __version__ - - import struct - import binascii --import yubico_util --import yubikey_defs --import yubikey_frame --import yubico_exception --import yubikey_config_util --from yubikey_config_util import YubiKeyConfigBits, YubiKeyConfigFlag, YubiKeyExtendedFlag, YubiKeyTicketFlag --import yubikey_base -+from . import yubico_util -+from . import yubikey_defs -+from . import yubikey_frame -+from . import yubico_exception -+from . import yubikey_config_util -+from .yubikey_config_util import YubiKeyConfigBits, YubiKeyConfigFlag, YubiKeyExtendedFlag, YubiKeyTicketFlag -+from . import yubikey_base - - # these used to be defined here; import them for backwards compatibility --from yubikey_defs import SLOT_CONFIG, SLOT_CONFIG2, SLOT_UPDATE1, SLOT_UPDATE2, SLOT_SWAP, command2str -+from .yubikey_defs import SLOT_CONFIG, SLOT_CONFIG2, SLOT_UPDATE1, SLOT_UPDATE2, SLOT_SWAP, command2str - - - TicketFlags = [ -diff --git a/yubico/yubikey_defs.py b/yubico/yubikey_defs.py -index bd4f7c4..777df30 100644 ---- a/yubico/yubikey_defs.py -+++ b/yubico/yubikey_defs.py -@@ -18,7 +18,7 @@ - # classes - ] - --from yubico_version import __version__ -+from .yubico_version import __version__ - - # Yubikey Low level interface #2.3 - RESP_TIMEOUT_WAIT_MASK = 0x1f # Mask to get timeout value -diff --git a/yubico/yubikey_frame.py b/yubico/yubikey_frame.py -index 63df89d..80919c9 100644 ---- a/yubico/yubikey_frame.py -+++ b/yubico/yubikey_frame.py -@@ -13,10 +13,10 @@ - - import struct - --import yubico_util --import yubikey_defs --import yubico_exception --from yubico_version import __version__ -+from . import yubico_util -+from . import yubikey_defs -+from . import yubico_exception -+from .yubico_version import __version__ - - class YubiKeyFrame: - """ -diff --git a/yubico/yubikey_neo_usb_hid.py b/yubico/yubikey_neo_usb_hid.py -index 7711779..0543b8e 100644 ---- a/yubico/yubikey_neo_usb_hid.py -+++ b/yubico/yubikey_neo_usb_hid.py -@@ -16,10 +16,10 @@ - - import struct - --from yubico_version import __version__ --import yubikey_usb_hid --import yubikey_frame --import yubico_exception -+from .yubico_version import __version__ -+from . import yubikey_usb_hid -+from . import yubikey_frame -+from . import yubico_exception - - # commands from ykdef.h - _SLOT_NDEF = 0x08 # Write YubiKey NEO NDEF -diff --git a/yubico/yubikey_usb_hid.py b/yubico/yubikey_usb_hid.py -index 6af248b..3cf47a4 100644 ---- a/yubico/yubikey_usb_hid.py -+++ b/yubico/yubikey_usb_hid.py -@@ -14,15 +14,15 @@ - 'YubiKeyUSBHIDStatus', - ] - --from yubico_version import __version__ -- --import yubico_util --import yubico_exception --import yubikey_frame --import yubikey_config --import yubikey_defs --import yubikey_base --from yubikey_base import YubiKey -+from .yubico_version import __version__ -+ -+from . import yubico_util -+from . import yubico_exception -+from . import yubikey_frame -+from . import yubikey_config -+from . import yubikey_defs -+from . import yubikey_base -+from .yubikey_base import YubiKey - import struct - import time - import sys -@@ -455,7 +455,7 @@ def _open(self, skip=0): - try: - self._usb_handle = usb_device.open() - self._usb_handle.detachKernelDriver(0) -- except Exception, error: -+ except Exception as error: - if 'could not detach kernel driver from interface' in str(error): - self._debug('The in-kernel-HID driver has already been detached\n') - else: - -From ebb015bf0b32a6d3c3a9e86580c90b13545506b6 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 1 Jul 2015 17:38:05 +0200 -Subject: [PATCH 5/6] Distinguish text strings and bytestrings for Python 3 - compatibility - -All (potentially binary) data is bytestrings; text (including -e.g. hexdumps and exception messages) is text strings. - -Note that in Python 2, there's no difference between text (str, '...') -and bytestrings (bytes, b'...'). ---- - test/test_yubico.py | 8 +- - test/test_yubikey_config.py | 190 +++++++++++++++++++++--------------------- - test/test_yubikey_frame.py | 20 ++--- - test/test_yubikey_usb_hid.py | 4 +- - yubico/yubico_util.py | 70 +++++++++++----- - yubico/yubikey_config.py | 37 ++++---- - yubico/yubikey_frame.py | 16 ++-- - yubico/yubikey_neo_usb_hid.py | 13 +-- - yubico/yubikey_usb_hid.py | 16 ++-- - 9 files changed, 205 insertions(+), 169 deletions(-) - -diff --git a/test/test_yubico.py b/test/test_yubico.py -index f045d31..cd87f42 100644 ---- a/test/test_yubico.py -+++ b/test/test_yubico.py -@@ -14,7 +14,7 @@ class TestCRC(unittest.TestCase): - - def test_first(self): - """ Test CRC16 trivial case """ -- buffer = '\x01\x02\x03\x04' -+ buffer = b'\x01\x02\x03\x04' - crc = crc16(buffer) - self.assertEqual(crc, 0xc66e) - return buffer,crc -@@ -31,19 +31,19 @@ def test_second(self): - - def test_hexdump(self): - """ Test hexdump function, normal use """ -- bytes = '\x01\x02\x03\x04\x05\x06\x07\x08' -+ bytes = b'\x01\x02\x03\x04\x05\x06\x07\x08' - self.assertEqual(yubico_util.hexdump(bytes, length=4), \ - '0000 01 02 03 04\n0004 05 06 07 08\n') - - def test_hexdump(self): - """ Test hexdump function, with colors """ -- bytes = '\x01\x02\x03\x04\x05\x06\x07\x08' -+ bytes = b'\x01\x02\x03\x04\x05\x06\x07\x08' - self.assertEqual(yubico_util.hexdump(bytes, length=4, colorize=True), \ - '0000 \x1b[0m01 02 03\x1b[0m 04\n0004 \x1b[0m05 06 07\x1b[0m 08\n') - - def test_modhex_decode(self): - """ Test modhex decoding """ -- self.assertEqual("0123456789abcdef", yubico_util.modhex_decode("cbdefghijklnrtuv")) -+ self.assertEqual(b"0123456789abcdef", yubico_util.modhex_decode(b"cbdefghijklnrtuv")) - - if __name__ == '__main__': - unittest.main() -diff --git a/test/test_yubikey_config.py b/test/test_yubikey_config.py -index 5fc694c..50067d7 100644 ---- a/test/test_yubikey_config.py -+++ b/test/test_yubikey_config.py -@@ -25,24 +25,24 @@ def test_static_ticket(self): - #ticket_flags: APPEND_CR - #config_flags: STATIC_TICKET - -- expected = ['\x00\x00\x00\x00\x00\x00\x00\x80', -- '\x00\xe2\xbe\xe9\xa3\x65\x68\x83', -- '\xa0\x0d\x02\x6a\x02\xf8\x5e\x84', -- '\x61\xe6\xfb\x00\x00\x00\x00\x85', -- '\x00\x00\x00\x00\x20\x20\x00\x86', -- '\x00\x5a\x93\x00\x00\x00\x00\x87', -- '\x00\x01\x95\x56\x00\x00\x00\x89' -+ expected = [b'\x00\x00\x00\x00\x00\x00\x00\x80', -+ b'\x00\xe2\xbe\xe9\xa3\x65\x68\x83', -+ b'\xa0\x0d\x02\x6a\x02\xf8\x5e\x84', -+ b'\x61\xe6\xfb\x00\x00\x00\x00\x85', -+ b'\x00\x00\x00\x00\x20\x20\x00\x86', -+ b'\x00\x5a\x93\x00\x00\x00\x00\x87', -+ b'\x00\x01\x95\x56\x00\x00\x00\x89' - ] - - Config = self.Config -- Config.aes_key('h:e2bee9a36568a00d026a02f85e61e6fb') -+ Config.aes_key(b'h:e2bee9a36568a00d026a02f85e61e6fb') - Config.ticket_flag('APPEND_CR', True) - Config.config_flag('STATIC_TICKET', True) - - data = Config.to_frame(slot=1).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - -@@ -57,26 +57,26 @@ def test_static_ticket_with_access_code(self): - #ticket_flags: APPEND_CR - #config_flags: STATIC_TICKET - -- expected = ['\x00\x00\x00\x00\x00\x00\x00\x80', -- '\x00\xe2\xbe\xe9\xa3\x65\x68\x83', -- '\xa0\x0d\x02\x6a\x02\xf8\x5e\x84', -- '\x61\xe6\xfb\x01\x02\x03\x04\x85', -- '\x05\x06\x00\x00\x20\x20\x00\x86', -- '\x00\x0d\x39\x01\x02\x03\x04\x87', -- '\x05\x06\x00\x00\x00\x00\x00\x88', -- '\x00\x01\xc2\xfc\x00\x00\x00\x89', -+ expected = [b'\x00\x00\x00\x00\x00\x00\x00\x80', -+ b'\x00\xe2\xbe\xe9\xa3\x65\x68\x83', -+ b'\xa0\x0d\x02\x6a\x02\xf8\x5e\x84', -+ b'\x61\xe6\xfb\x01\x02\x03\x04\x85', -+ b'\x05\x06\x00\x00\x20\x20\x00\x86', -+ b'\x00\x0d\x39\x01\x02\x03\x04\x87', -+ b'\x05\x06\x00\x00\x00\x00\x00\x88', -+ b'\x00\x01\xc2\xfc\x00\x00\x00\x89', - ] - - Config = self.Config -- Config.aes_key('h:e2bee9a36568a00d026a02f85e61e6fb') -+ Config.aes_key(b'h:e2bee9a36568a00d026a02f85e61e6fb') - Config.ticket_flag('APPEND_CR', True) - Config.config_flag('STATIC_TICKET', True) -- Config.unlock_key('h:010203040506') -+ Config.unlock_key(b'h:010203040506') - - data = Config.to_frame(slot=1).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - -@@ -90,56 +90,56 @@ def test_fixed_and_oath_hotp(self): - #ticket_flags: APPEND_CR|OATH_HOTP - #config_flags: OATH_FIXED_MODHEX1|OATH_FIXED_MODHEX2|STATIC_TICKET - -- expected = ['\x4d\x4d\x4d\x4d\x00\x00\x00\x80', -- '\x00\x52\x3d\x7c\xe7\xe7\xb6\x83', -- '\xee\x85\x35\x17\xa3\xe3\xcc\x84', -- '\x19\x85\xc7\x00\x00\x00\x00\x85', -- '\x00\x00\x04\x00\x60\x70\x00\x86', -- '\x00\x72\xad\xaa\xbb\xcc\xdd\x87', -- '\xee\xff\x00\x00\x00\x00\x00\x88', -- '\x00\x03\xfe\xc4\x00\x00\x00\x89', -+ expected = [b'\x4d\x4d\x4d\x4d\x00\x00\x00\x80', -+ b'\x00\x52\x3d\x7c\xe7\xe7\xb6\x83', -+ b'\xee\x85\x35\x17\xa3\xe3\xcc\x84', -+ b'\x19\x85\xc7\x00\x00\x00\x00\x85', -+ b'\x00\x00\x04\x00\x60\x70\x00\x86', -+ b'\x00\x72\xad\xaa\xbb\xcc\xdd\x87', -+ b'\xee\xff\x00\x00\x00\x00\x00\x88', -+ b'\x00\x03\xfe\xc4\x00\x00\x00\x89', - ] - - Config = self.Config -- Config.aes_key('h:523d7ce7e7b6ee853517a3e3cc1985c7') -- Config.fixed_string('m:ftftftft') -+ Config.aes_key(b'h:523d7ce7e7b6ee853517a3e3cc1985c7') -+ Config.fixed_string(b'm:ftftftft') - Config.ticket_flag('APPEND_CR', True) - Config.ticket_flag('OATH_HOTP', True) - Config.config_flag('OATH_FIXED_MODHEX1', True) - Config.config_flag('OATH_FIXED_MODHEX2', True) - Config.config_flag('STATIC_TICKET', True) -- Config.unlock_key('h:aabbccddeeff') -- Config.access_key('h:000000000000') -+ Config.unlock_key(b'h:aabbccddeeff') -+ Config.access_key(b'h:000000000000') - - data = Config.to_frame(slot=2).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - - def test_challenge_response_hmac_nist(self): - """ Test HMAC challenge response with NIST test vector """ - -- expected = ['\x00\x00\x00\x00\x00\x00\x00\x80', -- '\x00\x00\x40\x41\x42\x43\x00\x82', -- '\x00\x30\x31\x32\x33\x34\x35\x83', -- '\x36\x37\x38\x39\x3a\x3b\x3c\x84', -- '\x3d\x3e\x3f\x00\x00\x00\x00\x85', -- '\x00\x00\x00\x04\x40\x26\x00\x86', -- '\x00\x98\x41\x00\x00\x00\x00\x87', -- '\x00\x03\x95\x56\x00\x00\x00\x89', -+ expected = [b'\x00\x00\x00\x00\x00\x00\x00\x80', -+ b'\x00\x00\x40\x41\x42\x43\x00\x82', -+ b'\x00\x30\x31\x32\x33\x34\x35\x83', -+ b'\x36\x37\x38\x39\x3a\x3b\x3c\x84', -+ b'\x3d\x3e\x3f\x00\x00\x00\x00\x85', -+ b'\x00\x00\x00\x04\x40\x26\x00\x86', -+ b'\x00\x98\x41\x00\x00\x00\x00\x87', -+ b'\x00\x03\x95\x56\x00\x00\x00\x89', - ] - - Config = self.Config -- secret = 'h:303132333435363738393a3b3c3d3e3f40414243' -+ secret = b'h:303132333435363738393a3b3c3d3e3f40414243' - Config.mode_challenge_response(secret, type='HMAC', variable=True) - Config.extended_flag('SERIAL_API_VISIBLE', True) - - data = Config.to_frame(slot=2).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - -@@ -170,98 +170,98 @@ def test_default_flags(self): - def test_oath_hotp_like_windows(self): - """ Test plain OATH-HOTP with NIST test vector """ - -- expected = ['\x00\x00\x00\x00\x00\x00\x00\x80', -- '\x00\x00\x40\x41\x42\x43\x00\x82', -- '\x00\x30\x31\x32\x33\x34\x35\x83', -- '\x36\x37\x38\x39\x3a\x3b\x3c\x84', -- '\x3d\x3e\x3f\x00\x00\x00\x00\x85', -- '\x00\x00\x00\x00\x40\x00\x00\x86', -- '\x00\x6a\xb9\x00\x00\x00\x00\x87', -- '\x00\x03\x95\x56\x00\x00\x00\x89', -+ expected = [b'\x00\x00\x00\x00\x00\x00\x00\x80', -+ b'\x00\x00\x40\x41\x42\x43\x00\x82', -+ b'\x00\x30\x31\x32\x33\x34\x35\x83', -+ b'\x36\x37\x38\x39\x3a\x3b\x3c\x84', -+ b'\x3d\x3e\x3f\x00\x00\x00\x00\x85', -+ b'\x00\x00\x00\x00\x40\x00\x00\x86', -+ b'\x00\x6a\xb9\x00\x00\x00\x00\x87', -+ b'\x00\x03\x95\x56\x00\x00\x00\x89', - ] - - Config = self.Config -- secret = 'h:303132333435363738393a3b3c3d3e3f40414243' -+ secret = b'h:303132333435363738393a3b3c3d3e3f40414243' - Config.mode_oath_hotp(secret) - - data = Config.to_frame(slot=2).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - - def test_oath_hotp_like_windows2(self): - """ Test OATH-HOTP with NIST test vector and token identifier """ - -- expected = ['\x01\x02\x03\x04\x05\x06\x00\x80', -- '\x00\x00\x40\x41\x42\x43\x00\x82', -- '\x00\x30\x31\x32\x33\x34\x35\x83', -- '\x36\x37\x38\x39\x3a\x3b\x3c\x84', -- '\x3d\x3e\x3f\x00\x00\x00\x00\x85', -- '\x00\x00\x06\x00\x40\x42\x00\x86', -- '\x00\x0e\xec\x00\x00\x00\x00\x87', -- '\x00\x03\x95\x56\x00\x00\x00\x89', -+ expected = [b'\x01\x02\x03\x04\x05\x06\x00\x80', -+ b'\x00\x00\x40\x41\x42\x43\x00\x82', -+ b'\x00\x30\x31\x32\x33\x34\x35\x83', -+ b'\x36\x37\x38\x39\x3a\x3b\x3c\x84', -+ b'\x3d\x3e\x3f\x00\x00\x00\x00\x85', -+ b'\x00\x00\x06\x00\x40\x42\x00\x86', -+ b'\x00\x0e\xec\x00\x00\x00\x00\x87', -+ b'\x00\x03\x95\x56\x00\x00\x00\x89', - ] - - Config = self.Config -- secret = 'h:303132333435363738393a3b3c3d3e3f40414243' -- Config.mode_oath_hotp(secret, digits=8, factor_seed='', omp=0x01, tt=0x02, mui='\x03\x04\x05\x06') -+ secret = b'h:303132333435363738393a3b3c3d3e3f40414243' -+ Config.mode_oath_hotp(secret, digits=8, factor_seed='', omp=0x01, tt=0x02, mui=b'\x03\x04\x05\x06') - Config.config_flag('OATH_FIXED_MODHEX2', True) - - data = Config.to_frame(slot=2).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - - def test_oath_hotp_like_windows_factory_seed(self): - """ Test OATH-HOTP factor_seed """ - -- expected = ['\x01\x02\x03\x04\x05\x06\x00\x80', -- '\x00\x00\x40\x41\x42\x43\x01\x82', -- '\x21\x30\x31\x32\x33\x34\x35\x83', -- '\x36\x37\x38\x39\x3a\x3b\x3c\x84', -- '\x3d\x3e\x3f\x00\x00\x00\x00\x85', -- '\x00\x00\x06\x00\x40\x42\x00\x86', -- '\x00\x03\xea\x00\x00\x00\x00\x87', -- '\x00\x03\x95\x56\x00\x00\x00\x89', -+ expected = [b'\x01\x02\x03\x04\x05\x06\x00\x80', -+ b'\x00\x00\x40\x41\x42\x43\x01\x82', -+ b'\x21\x30\x31\x32\x33\x34\x35\x83', -+ b'\x36\x37\x38\x39\x3a\x3b\x3c\x84', -+ b'\x3d\x3e\x3f\x00\x00\x00\x00\x85', -+ b'\x00\x00\x06\x00\x40\x42\x00\x86', -+ b'\x00\x03\xea\x00\x00\x00\x00\x87', -+ b'\x00\x03\x95\x56\x00\x00\x00\x89', - ] - - Config = self.Config -- secret = 'h:303132333435363738393a3b3c3d3e3f40414243' -- Config.mode_oath_hotp(secret, digits=8, factor_seed=0x2101, omp=0x01, tt=0x02, mui='\x03\x04\x05\x06') -+ secret = b'h:303132333435363738393a3b3c3d3e3f40414243' -+ Config.mode_oath_hotp(secret, digits=8, factor_seed=0x2101, omp=0x01, tt=0x02, mui=b'\x03\x04\x05\x06') - Config.config_flag('OATH_FIXED_MODHEX2', True) - - data = Config.to_frame(slot=2).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - - def test_fixed_length_hmac_like_windows(self): - """ Test fixed length HMAC SHA1 """ - -- expected = ['\x00\x00\x00\x00\x00\x00\x00\x80', -- '\x00\x00\x40\x41\x42\x43\x00\x82', -- '\x00\x30\x31\x32\x33\x34\x35\x83', -- '\x36\x37\x38\x39\x3a\x3b\x3c\x84', -- '\x3d\x3e\x3f\x00\x00\x00\x00\x85', -- '\x00\x00\x00\x00\x40\x22\x00\x86', -- '\x00\xe9\x0f\x00\x00\x00\x00\x87', -- '\x00\x03\x95\x56\x00\x00\x00\x89', -+ expected = [b'\x00\x00\x00\x00\x00\x00\x00\x80', -+ b'\x00\x00\x40\x41\x42\x43\x00\x82', -+ b'\x00\x30\x31\x32\x33\x34\x35\x83', -+ b'\x36\x37\x38\x39\x3a\x3b\x3c\x84', -+ b'\x3d\x3e\x3f\x00\x00\x00\x00\x85', -+ b'\x00\x00\x00\x00\x40\x22\x00\x86', -+ b'\x00\xe9\x0f\x00\x00\x00\x00\x87', -+ b'\x00\x03\x95\x56\x00\x00\x00\x89', - ] - - Config = self.Config -- secret = 'h:303132333435363738393a3b3c3d3e3f40414243' -+ secret = b'h:303132333435363738393a3b3c3d3e3f40414243' - Config.mode_challenge_response(secret, type='HMAC', variable=False) - - data = Config.to_frame(slot=2).to_feature_reports() - -- print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(''.join(expected)), -- yubico.yubico_util.hexdump(''.join(data)))) -+ print("EXPECT:\n%s\nGOT:\n%s\n" %( yubico.yubico_util.hexdump(b''.join(expected)), -+ yubico.yubico_util.hexdump(b''.join(data)))) - - self.assertEqual(data, expected) - -@@ -292,14 +292,14 @@ def test_version_required_4(self): - capa = yubico.yubikey_usb_hid.YubiKeyUSBHIDCapabilities( \ - model = 'YubiKey', version = version, default_answer = False) - Config = YubiKeyConfigUSBHID(ykver = version, capabilities = capa) -- secret = 'h:303132333435363738393a3b3c3d3e3f40414243' -+ secret = b'h:303132333435363738393a3b3c3d3e3f40414243' - self.assertRaises(yubico.yubikey.YubiKeyVersionError, Config.mode_challenge_response, secret) - - def test_version_required_5(self): - """ Test YubiKey 2.2 with v2.2 mode """ - - Config = self.Config -- secret = 'h:303132333435363738393a3b3c3d3e3f' -+ secret = b'h:303132333435363738393a3b3c3d3e3f' - Config.mode_challenge_response(secret, type='OTP') - self.assertEqual('CHAL_RESP', Config._mode) - -diff --git a/test/test_yubikey_frame.py b/test/test_yubikey_frame.py -index 5437922..e1308c4 100644 ---- a/test/test_yubikey_frame.py -+++ b/test/test_yubikey_frame.py -@@ -17,7 +17,7 @@ def test_get_ykframe(self): - self.assertEqual(len(buffer), 70, "yubikey command buffer should always be 70 bytes") - - # check that empty payload works (64 * '\x00') -- all_zeros = '\x00' * 64 -+ all_zeros = b'\x00' * 64 - - self.assertTrue(buffer.startswith(all_zeros)) - -@@ -26,25 +26,25 @@ def test_get_ykframe_feature_reports(self): - """ Test normal use """ - res = YubiKeyFrame(command=0x32).to_feature_reports() - -- self.assertEqual(res, ['\x00\x00\x00\x00\x00\x00\x00\x80', -- '\x00\x32\x6b\x5b\x00\x00\x00\x89' -+ self.assertEqual(res, [b'\x00\x00\x00\x00\x00\x00\x00\x80', -+ b'\x00\x32\x6b\x5b\x00\x00\x00\x89' - ]) - - - def test_get_ykframe_feature_reports2(self): - """ Test one serie of non-zero bytes in the middle of the payload """ -- payload = '\x00' * 38 -- payload += '\x01\x02\x03' -- payload += '\x00' * 23 -+ payload = b'\x00' * 38 -+ payload += b'\x01\x02\x03' -+ payload += b'\x00' * 23 - res = YubiKeyFrame(command=0x32, payload=payload).to_feature_reports() - -- self.assertEqual(res, ['\x00\x00\x00\x00\x00\x00\x00\x80', -- '\x00\x00\x00\x01\x02\x03\x00\x85', -- '\x002\x01s\x00\x00\x00\x89']) -+ self.assertEqual(res, [b'\x00\x00\x00\x00\x00\x00\x00\x80', -+ b'\x00\x00\x00\x01\x02\x03\x00\x85', -+ b'\x002\x01s\x00\x00\x00\x89']) - - def test_bad_payload(self): - """ Test that we get an exception for four bytes payload """ -- self.assertRaises(yubico_exception.InputError, YubiKeyFrame, command=0x32, payload='test') -+ self.assertRaises(yubico_exception.InputError, YubiKeyFrame, command=0x32, payload=b'test') - - def test_repr(self): - """ Test string representation of object """ -diff --git a/test/test_yubikey_usb_hid.py b/test/test_yubikey_usb_hid.py -index f801a33..c7e105c 100644 ---- a/test/test_yubikey_usb_hid.py -+++ b/test/test_yubikey_usb_hid.py -@@ -41,9 +41,9 @@ def test_status(self): - def test_challenge_response(self): - """ Test challenge-response, assumes a NIST PUB 198 A.2 20 bytes test vector in Slot 2 (variable input) """ - -- secret = struct.pack('64s', 'Sample #2') -+ secret = struct.pack('64s', b'Sample #2') - response = self.YK.challenge_response(secret, mode='HMAC', slot=2) -- self.assertEqual(response, '\x09\x22\xd3\x40\x5f\xaa\x3d\x19\x4f\x82\xa4\x58\x30\x73\x7d\x5c\xc6\xc7\x5d\x24') -+ self.assertEqual(response, b'\x09\x22\xd3\x40\x5f\xaa\x3d\x19\x4f\x82\xa4\x58\x30\x73\x7d\x5c\xc6\xc7\x5d\x24') - - #@unittest.skipIf(self.YK is None, "No USB HID YubiKey found") - def test_serial(self): -diff --git a/yubico/yubico_util.py b/yubico/yubico_util.py -index 5af3956..38056e6 100644 ---- a/yubico/yubico_util.py -+++ b/yubico/yubico_util.py -@@ -15,20 +15,37 @@ - # classes - ] - -+import sys -+import string -+ - from .yubico_version import __version__ - from . import yubikey_defs - from . import yubico_exception --import string - - _CRC_OK_RESIDUAL = 0xf0b8 - -+def ord_byte(byte): -+ """Convert a byte to its integer value""" -+ if sys.version_info < (3, 0): -+ return ord(byte) -+ else: -+ # In Python 3, single bytes are represented as integers -+ return int(byte) -+ -+def chr_byte(number): -+ """Convert an integer value to a length-1 bytestring""" -+ if sys.version_info < (3, 0): -+ return chr(number) -+ else: -+ return bytes([number]) -+ - def crc16(data): - """ -- Calculate an ISO13239 CRC checksum of the input buffer. -+ Calculate an ISO13239 CRC checksum of the input buffer (bytestring). - """ - m_crc = 0xffff - for this in data: -- m_crc ^= ord(this) -+ m_crc ^= ord_byte(this) - for _ in range(8): - j = m_crc & 1 - m_crc >>= 1 -@@ -39,6 +56,8 @@ def crc16(data): - def validate_crc16(data): - """ - Validate that the CRC of the contents of buffer is the residual OK value. -+ -+ The input is a bytestring. - """ - return crc16(data) == _CRC_OK_RESIDUAL - -@@ -74,27 +93,30 @@ def disable(self): - self.enabled = False - - def hexdump(src, length=8, colorize=False): -- """ Produce a string hexdump of src, for debug output.""" -+ """ Produce a string hexdump of src, for debug output. -+ -+ Input: bytestring; output: text string -+ """ - if not src: - return str(src) -- if type(src) is not str: -- raise yubico_exception.InputError('Hexdump \'src\' must be string (got %s)' % type(src)) -+ if type(src) is not bytes: -+ raise yubico_exception.InputError('Hexdump \'src\' must be bytestring (got %s)' % type(src)) - offset = 0 - result = '' - for this in group(src, length): - if colorize: -- last, this = this[-1:], this[:-1] -+ last, this = this[-1], this[:-1] - colors = DumpColors() - color = colors.get('RESET') -- if ord(last) & yubikey_defs.RESP_PENDING_FLAG: -+ if ord_byte(last) & yubikey_defs.RESP_PENDING_FLAG: - # write to key - color = colors.get('BLUE') -- elif ord(last) & yubikey_defs.SLOT_WRITE_FLAG: -+ elif ord_byte(last) & yubikey_defs.SLOT_WRITE_FLAG: - color = colors.get('GREEN') -- hex_s = color + ' '.join(["%02x" % ord(x) for x in this]) + colors.get('RESET') -- hex_s += " %02x" % ord(last) -+ hex_s = color + ' '.join(["%02x" % ord_byte(x) for x in this]) + colors.get('RESET') -+ hex_s += " %02x" % ord_byte(last) - else: -- hex_s = ' '.join(["%02x" % ord(x) for x in this]) -+ hex_s = ' '.join(["%02x" % ord_byte(x) for x in this]) - result += "%04X %s\n" % (offset, hex_s) - offset += length - return result -@@ -104,17 +126,25 @@ def group(data, num): - return [data[i:i+num] for i in range(0, len(data), num)] - - def modhex_decode(data): -- """ Convert a modhex string to ordinary hex. """ -- t_map = string.maketrans("cbdefghijklnrtuv", "0123456789abcdef") -+ """ Convert a modhex bytestring to ordinary hex. """ -+ try: -+ maketrans = string.maketrans -+ except AttributeError: -+ # Python 3 -+ maketrans = bytes.maketrans -+ t_map = maketrans(b"cbdefghijklnrtuv", b"0123456789abcdef") - return data.translate(t_map) - - def hotp_truncate(hmac_result, length=6): -- """ Perform the HOTP Algorithm truncating. """ -+ """ Perform the HOTP Algorithm truncating. -+ -+ Input is a bytestring. -+ """ - if len(hmac_result) != 20: - raise yubico_exception.YubicoError("HMAC-SHA-1 not 20 bytes long") -- offset = ord(hmac_result[19]) & 0xf -- bin_code = (ord(hmac_result[offset]) & 0x7f) << 24 \ -- | (ord(hmac_result[offset+1]) & 0xff) << 16 \ -- | (ord(hmac_result[offset+2]) & 0xff) << 8 \ -- | (ord(hmac_result[offset+3]) & 0xff) -+ offset = ord_byte(hmac_result[19]) & 0xf -+ bin_code = (ord_byte(hmac_result[offset]) & 0x7f) << 24 \ -+ | (ord_byte(hmac_result[offset+1]) & 0xff) << 16 \ -+ | (ord_byte(hmac_result[offset+2]) & 0xff) << 8 \ -+ | (ord_byte(hmac_result[offset+3]) & 0xff) - return bin_code % (10 ** length) -diff --git a/yubico/yubikey_config.py b/yubico/yubikey_config.py -index 3a02114..430ec7a 100644 ---- a/yubico/yubikey_config.py -+++ b/yubico/yubikey_config.py -@@ -17,6 +17,7 @@ - - from .yubico_version import __version__ - -+import sys - import struct - import binascii - from . import yubico_util -@@ -118,16 +119,16 @@ def __init__(self, ykver=None, capabilities=None, update=False, swap=False): - self.yk_req_version = (0, 0) - self.ykver = ykver - -- self.fixed = '' -- self.uid = '' -- self.key = '' -- self.access_code = '' -+ self.fixed = b'' -+ self.uid = b'' -+ self.key = b'' -+ self.access_code = b'' - - self.ticket_flags = YubiKeyConfigBits(0x0) - self.config_flags = YubiKeyConfigBits(0x0) - self.extended_flags = YubiKeyConfigBits(0x0) - -- self.unlock_code = '' -+ self.unlock_code = b'' - self._mode = '' - if update or swap: - self._require_version(major=2, minor=3) -@@ -233,10 +234,10 @@ def unlock_key(self, data): - """ - Access code to allow re-programming of your YubiKey. - -- Supply data as either a raw string, or a hexlified string prefixed by 'h:'. -+ Supply data as either a raw bytestring, or a hexlified bytestring prefixed by 'h:'. - The result, after any hex decoding, must be 6 bytes. - """ -- if data.startswith('h:'): -+ if data.startswith(b'h:'): - new = binascii.unhexlify(data[2:]) - else: - new = data -@@ -256,7 +257,7 @@ def access_key(self, data): - Supply data as either a raw string, or a hexlified string prefixed by 'h:'. - The result, after any hex decoding, must be 6 bytes. - """ -- if data.startswith('h:'): -+ if data.startswith(b'h:'): - new = binascii.unhexlify(data[2:]) - else: - new = data -@@ -272,7 +273,7 @@ def mode_yubikey_otp(self, private_uid, aes_key): - if not self.capabilities.have_yubico_OTP(): - raise yubikey_base.YubiKeyVersionError('Yubico OTP not available in %s version %d.%d' \ - % (self.capabilities.model, self.ykver[0], self.ykver[1])) -- if private_uid.startswith('h:'): -+ if private_uid.startswith(b'h:'): - private_uid = binascii.unhexlify(private_uid[2:]) - if len(private_uid) != yubikey_defs.UID_SIZE: - raise yubico_exception.InputError('Private UID must be %i bytes' % (yubikey_defs.UID_SIZE)) -@@ -299,7 +300,7 @@ def mode_oath_hotp(self, secret, digits=6, factor_seed=None, omp=0x0, tt=0x0, mu - self.config_flag('OATH_HOTP8', True) - if omp or tt or mui: - decoded_mui = self._decode_input_string(mui) -- fixed = chr(omp) + chr(tt) + decoded_mui -+ fixed = yubico_util.chr_byte(omp) + yubico_util.chr_byte(tt) + decoded_mui - self.fixed_string(fixed) - if factor_seed: - self.uid = self.uid + struct.pack('= (3, 0) and isinstance(data, str): -+ data = data.encode('ascii') -+ if data.startswith(b'm:'): -+ data = b'h:' + yubico_util.modhex_decode(data[2:]) -+ if data.startswith(b'h:'): - return(binascii.unhexlify(data[2:])) - else: - return(data) -@@ -503,10 +506,10 @@ def _set_20_bytes_key(self, data): - """ - Set a 20 bytes key. This is used in CHAL_HMAC and OATH_HOTP mode. - -- Supply data as either a raw string, or a hexlified string prefixed by 'h:'. -+ Supply data as either a raw bytestring, or a hexlified bytestring prefixed by 'h:'. - The result, after any hex decoding, must be 20 bytes. - """ -- if data.startswith('h:'): -+ if data.startswith(b'h:'): - new = binascii.unhexlify(data[2:]) - else: - new = data -diff --git a/yubico/yubikey_frame.py b/yubico/yubikey_frame.py -index 80919c9..c43c6a1 100644 ---- a/yubico/yubikey_frame.py -+++ b/yubico/yubikey_frame.py -@@ -28,11 +28,13 @@ class YubiKeyFrame: - flags. - """ - -- def __init__(self, command, payload=''): -- if payload is '': -- payload = '\x00' * 64 -+ def __init__(self, command, payload=b''): -+ if not payload: -+ payload = b'\x00' * 64 - if len(payload) != 64: - raise yubico_exception.InputError('payload must be empty or 64 bytes') -+ if not isinstance(payload, bytes): -+ raise yubico_exception.InputError('payload must be a bytestring') - self.payload = payload - self.command = command - self.crc = yubico_util.crc16(payload) -@@ -59,7 +61,7 @@ def to_string(self): - # unsigned short crc; - # unsigned char filler[3]; - # } YKFRAME; -- filler = '' -+ filler = b'' - return struct.pack('<64sBH3s', - self.payload, self.command, self.crc, filler) - -@@ -77,11 +79,11 @@ def to_feature_reports(self, debug=False): - this, rest = rest[:7], rest[7:] - if seq > 0 and rest: - # never skip first or last serie -- if this != '\x00\x00\x00\x00\x00\x00\x00': -- this += chr(yubikey_defs.SLOT_WRITE_FLAG + seq) -+ if this != b'\x00\x00\x00\x00\x00\x00\x00': -+ this += yubico_util.chr_byte(yubikey_defs.SLOT_WRITE_FLAG + seq) - out.append(self._debug_string(debug, this)) - else: -- this += chr(yubikey_defs.SLOT_WRITE_FLAG + seq) -+ this += yubico_util.chr_byte(yubikey_defs.SLOT_WRITE_FLAG + seq) - out.append(self._debug_string(debug, this)) - seq += 1 - return out -diff --git a/yubico/yubikey_neo_usb_hid.py b/yubico/yubikey_neo_usb_hid.py -index 0543b8e..88fceba 100644 ---- a/yubico/yubikey_neo_usb_hid.py -+++ b/yubico/yubikey_neo_usb_hid.py -@@ -20,6 +20,7 @@ - from . import yubikey_usb_hid - from . import yubikey_frame - from . import yubico_exception -+from . import yubico_util - - # commands from ykdef.h - _SLOT_NDEF = 0x08 # Write YubiKey NEO NDEF -@@ -127,11 +128,11 @@ class YubiKeyNEO_NDEF(): - - ndef_type = _NDEF_URI_TYPE - ndef_str = None -- access_code = chr(0x0) * _ACC_CODE_SIZE -+ access_code = yubico_util.chr_byte(0x0) * _ACC_CODE_SIZE - # For _NDEF_URI_TYPE - ndef_uri_rt = 0x0 # No prepending - # For _NDEF_TEXT_TYPE -- ndef_text_lang = 'en' -+ ndef_text_lang = b'en' - ndef_text_enc = 'UTF-8' - - def __init__(self, data, access_code = None): -@@ -199,7 +200,7 @@ def to_frame(self, slot=_SLOT_NDEF): - Return the current configuration as a YubiKeyFrame object. - """ - data = self.to_string() -- payload = data.ljust(64, chr(0x0)) -+ payload = data.ljust(64, b'\0') - return yubikey_frame.YubiKeyFrame(command = slot, payload = payload) - - def _encode_ndef_uri_type(self, data): -@@ -211,11 +212,11 @@ def _encode_ndef_uri_type(self, data): - """ - t = 0x0 - for (code, prefix) in uri_identifiers: -- if data[:len(prefix)].lower() == prefix: -+ if data[:len(prefix)].decode('latin-1').lower() == prefix: - t = code - data = data[len(prefix):] - break -- data = chr(t) + data -+ data = yubico_util.chr_byte(t) + data - return data - - def _encode_ndef_text_params(self, data): -@@ -226,4 +227,4 @@ def _encode_ndef_text_params(self, data): - status = len(self.ndef_text_lang) - if self.ndef_text_enc == 'UTF16': - status = status & 0b10000000 -- return chr(status) + self.ndef_text_lang + data -+ return yubico_util.chr_byte(status) + self.ndef_text_lang + data -diff --git a/yubico/yubikey_usb_hid.py b/yubico/yubikey_usb_hid.py -index 3cf47a4..3a90701 100644 ---- a/yubico/yubikey_usb_hid.py -+++ b/yubico/yubikey_usb_hid.py -@@ -248,16 +248,16 @@ def _challenge_response(self, challenge, mode, slot, variable, may_block): - raise yubico_exception.InputError('Mode HMAC challenge too big (%i/%i)' \ - % (yubikey_defs.SHA1_MAX_BLOCK_SIZE, len(challenge))) - if len(challenge) < yubikey_defs.SHA1_MAX_BLOCK_SIZE: -- pad_with = chr(0x0) -- if variable and challenge[-1] == pad_with: -- pad_with = chr(0xff) -+ pad_with = b'\0' -+ if variable and challenge[-1:] == pad_with: -+ pad_with = b'\xff' - challenge = challenge.ljust(yubikey_defs.SHA1_MAX_BLOCK_SIZE, pad_with) - response_len = yubikey_defs.SHA1_DIGEST_SIZE - elif mode == 'OTP': - if len(challenge) != yubikey_defs.UID_SIZE: - raise yubico_exception.InputError('Mode OTP challenge must be %i bytes (got %i)' \ - % (yubikey_defs.UID_SIZE, len(challenge))) -- challenge = challenge.ljust(yubikey_defs.SHA1_MAX_BLOCK_SIZE, chr(0x0)) -+ challenge = challenge.ljust(yubikey_defs.SHA1_MAX_BLOCK_SIZE, b'\0') - response_len = 16 - else: - raise yubico_exception.InputError('Invalid mode supplied (%s, valid values are HMAC and OTP)' \ -@@ -297,7 +297,7 @@ def _read_response(self, may_block=False): - # continue reading while response pending is set - while True: - this = self._read() -- flags = ord(this[7]) -+ flags = yubico_util.ord_byte(this[7]) - if flags & yubikey_defs.RESP_PENDING_FLAG: - seq = flags & 0b00011111 - if res and (seq == 0): -@@ -321,7 +321,7 @@ def _read(self): - self._debug("Failed reading %i bytes (got %i) from USB HID YubiKey.\n" - % (_FEATURE_RPT_SIZE, recv)) - raise YubiKeyUSBHIDError('Failed reading from USB HID YubiKey') -- data = ''.join(chr(c) for c in recv) -+ data = b''.join(yubico_util.chr_byte(c) for c in recv) - self._debug("READ : %s" % (yubico_util.hexdump(data, colorize=True))) - return data - -@@ -344,7 +344,7 @@ def _write_reset(self): - """ - Reset read mode by issuing a dummy write. - """ -- data = '\x00\x00\x00\x00\x00\x00\x00\x8f' -+ data = b'\x00\x00\x00\x00\x00\x00\x00\x8f' - self._raw_write(data) - self._waitfor_clear(yubikey_defs.SLOT_WRITE_FLAG) - return True -@@ -401,7 +401,7 @@ def _waitfor(self, mode, mask, may_block, timeout=2): - resp_timeout = False # YubiKey hasn't indicated RESP_TIMEOUT (yet) - while not finished: - this = self._read() -- flags = ord(this[7]) -+ flags = yubico_util.ord_byte(this[7]) - - if flags & yubikey_defs.RESP_TIMEOUT_WAIT_FLAG: - if not resp_timeout: - -From adde4903eb9efa34b9b5fbd2bf988f934333fd11 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Wed, 1 Jul 2015 20:02:38 +0200 -Subject: [PATCH 6/6] Unshadow a hexdump test - -The test_hexdump method was defined twice, the second overwriting -the first. Use a unique name to have them both run. ---- - test/test_yubico.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/test/test_yubico.py b/test/test_yubico.py -index cd87f42..de2e2a5 100644 ---- a/test/test_yubico.py -+++ b/test/test_yubico.py -@@ -35,7 +35,7 @@ def test_hexdump(self): - self.assertEqual(yubico_util.hexdump(bytes, length=4), \ - '0000 01 02 03 04\n0004 05 06 07 08\n') - -- def test_hexdump(self): -+ def test_hexdump2(self): - """ Test hexdump function, with colors """ - bytes = b'\x01\x02\x03\x04\x05\x06\x07\x08' - self.assertEqual(yubico_util.hexdump(bytes, length=4, colorize=True), \ diff --git a/python-yubico-python3_util_examples.patch b/python-yubico-python3_util_examples.patch deleted file mode 100644 index 8deb620..0000000 --- a/python-yubico-python3_util_examples.patch +++ /dev/null @@ -1,547 +0,0 @@ -From 9039356ba6a08c21ac6b25200dc58e3d14ab1367 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Fri, 3 Jul 2015 14:10:55 +0200 -Subject: [PATCH] Add Python3 compatibility to util and examples - -- Use print as a function -- Use 'as' syntax when catching exceptions -- Use six.moves.input instead of raw_input -- Split text & bytes -- Use binascii.hexlify instead of encode('hex') - -Also, add iv argument to AES.new. It is required in newer -versions of PyCrypto. ---- - examples/configure_neo_ndef | 16 +++--- - examples/configure_nist_test_key | 13 ++--- - examples/nist_challenge_response | 25 +++++---- - examples/rolling_challenge_response | 105 +++++++++++++++++++----------------- - examples/update_cfg_remove_cr | 22 ++++---- - examples/yubikey-inventory | 4 +- - util/yubikey-totp | 18 +++---- - yubico/yubikey_frame.py | 18 +++---- - yubico/yubikey_neo_usb_hid.py | 2 +- - 9 files changed, 119 insertions(+), 104 deletions(-) - -diff --git a/examples/configure_neo_ndef b/examples/configure_neo_ndef -index 81bd927..44fc87d 100755 ---- a/examples/configure_neo_ndef -+++ b/examples/configure_neo_ndef -@@ -5,7 +5,8 @@ Set up a YubiKey NEO NDEF - - import sys - import struct --import urllib -+ -+import six - - import yubico - import yubico.yubikey_neo_usb_hid -@@ -16,18 +17,21 @@ if len(sys.argv) != 2: - - url = sys.argv[1] - -+if sys.version_info >= (3, 0): -+ url = url.encode('utf-8') -+ - try: - YK = yubico.yubikey_neo_usb_hid.YubiKeyNEO_USBHID(debug=True) -- print "Version : %s " % YK.version() -+ print("Version : %s " % YK.version()) - - ndef = yubico.yubikey_neo_usb_hid.YubiKeyNEO_NDEF(data = url) - -- user_input = raw_input('Write configuration to YubiKey? [y/N] : ') -+ user_input = six.moves.input('Write configuration to YubiKey? [y/N] : ') - if user_input in ('y', 'ye', 'yes'): - YK.write_ndef(ndef) -- print "\nSuccess!" -+ print("\nSuccess!") - else: -- print "\nAborted" -+ print("\nAborted") - except yubico.yubico_exception.YubicoError as inst: -- print "ERROR: %s" % inst.reason -+ print("ERROR: %s" % inst.reason) - sys.exit(1) -diff --git a/examples/configure_nist_test_key b/examples/configure_nist_test_key -index 8bb80b6..ae0dd22 100755 ---- a/examples/configure_nist_test_key -+++ b/examples/configure_nist_test_key -@@ -7,24 +7,25 @@ Set up a YubiKey with a NIST PUB 198 A.2 - import sys - import struct - import yubico -+import six - - slot=2 - - try: - YK = yubico.find_yubikey(debug=True) -- print "Version : %s " % YK.version() -+ print("Version : %s " % YK.version()) - - Cfg = YK.init_config() -- key='h:303132333435363738393a3b3c3d3e3f40414243' -+ key = b'h:303132333435363738393a3b3c3d3e3f40414243' - Cfg.mode_challenge_response(key, type='HMAC', variable=True) - Cfg.extended_flag('SERIAL_API_VISIBLE', True) - -- user_input = raw_input('Write configuration to slot %i of YubiKey? [y/N] : ' % slot ) -+ user_input = six.moves.input('Write configuration to slot %i of YubiKey? [y/N] : ' % slot ) - if user_input in ('y', 'ye', 'yes'): - YK.write_config(Cfg, slot=slot) -- print "\nSuccess!" -+ print("\nSuccess!") - else: -- print "\nAborted" -+ print("\nAborted") - except yubico.yubico_exception.YubicoError as inst: -- print "ERROR: %s" % inst.reason -+ print("ERROR: %s" % inst.reason) - sys.exit(1) -diff --git a/examples/nist_challenge_response b/examples/nist_challenge_response -index 0c42ea2..f5ea188 100755 ---- a/examples/nist_challenge_response -+++ b/examples/nist_challenge_response -@@ -8,8 +8,8 @@ import sys - import yubico - - expected = \ -- '\x09\x22\xd3\x40\x5f\xaa\x3d\x19\x4f\x82' + \ -- '\xa4\x58\x30\x73\x7d\x5c\xc6\xc7\x5d\x24' -+ b'\x09\x22\xd3\x40\x5f\xaa\x3d\x19\x4f\x82' + \ -+ b'\xa4\x58\x30\x73\x7d\x5c\xc6\xc7\x5d\x24' - - # turn on YubiKey debug if -v is given as an argument - debug = False -@@ -19,25 +19,28 @@ if len(sys.argv) > 1: - # Look for and initialize the YubiKey - try: - YK = yubico.find_yubikey(debug=debug) -- print "Version : %s " % YK.version() -- print "Serial : %i" % YK.serial() -- print "" -+ print("Version : %s " % YK.version()) -+ print("Serial : %i" % YK.serial()) -+ print("") - - # Do challenge-response -- secret = 'Sample #2'.ljust(64, chr(0x0)) -- print "Sending challenge : %s\n" % repr(secret) -+ secret = b'Sample #2'.ljust(64, b'\0') -+ print("Sending challenge : %s\n" % repr(secret)) - - response = YK.challenge_response(secret, slot=2) - except yubico.yubico_exception.YubicoError as inst: -- print "ERROR: %s" % inst.reason -+ print("ERROR: %s" % inst.reason) - sys.exit(1) - --print "Response :\n%s\n" % yubico.yubico_util.hexdump(response) -+print("Response :\n%s\n" % yubico.yubico_util.hexdump(response)) -+ -+# Workaround for http://bugs.python.org/issue24596 -+del YK - - # Check if the response matched the expected one - if response == expected: -- print "OK! Response matches the NIST PUB 198 A.2 expected response." -+ print("OK! Response matches the NIST PUB 198 A.2 expected response.") - sys.exit(0) - else: -- print "ERROR! Response does NOT match the NIST PUB 198 A.2 expected response." -+ print("ERROR! Response does NOT match the NIST PUB 198 A.2 expected response.") - sys.exit(1) -diff --git a/examples/rolling_challenge_response b/examples/rolling_challenge_response -index c383f00..c371392 100755 ---- a/examples/rolling_challenge_response -+++ b/examples/rolling_challenge_response -@@ -22,8 +22,10 @@ import json - import hmac - import argparse - import hashlib -+import binascii - - import yubico -+import six - - from Crypto.Cipher import AES - -@@ -70,10 +72,10 @@ def parse_args(): - - def init_demo(args): - """ Initializes the demo by asking a few questions and creating a new stat file. """ -- hmac_key = raw_input("Enter HMAC-SHA1 key as 40 chars of hex (or press enter for random key) : ") -+ hmac_key = six.moves.input("Enter HMAC-SHA1 key as 40 chars of hex (or press enter for random key) : ") - if hmac_key: - try: -- hmac_key = hmac_key.decode('hex') -+ hmac_key = binascii.unhexlify(hmac_key) - except: - sys.stderr.write("Could not decode HMAC-SHA1 key. Please enter 40 hex-chars.\n") - sys.exit(1) -@@ -83,12 +85,12 @@ def init_demo(args): - sys.stderr.write("Decoded HMAC-SHA1 key is %i bytes, expected 20.\n" %( len(hmac_key))) - sys.exit(1) - -- print "To program a YubiKey >= 2.2 for challenge-response with this key, use :" -- print "" -- print " $ ykpersonalize -%i -ochal-resp -ochal-hmac -ohmac-lt64 -a %s" % (args.slot, hmac_key.encode('hex')) -- print "" -+ print("To program a YubiKey >= 2.2 for challenge-response with this key, use :") -+ print("") -+ print(" $ ykpersonalize -%i -ochal-resp -ochal-hmac -ohmac-lt64 -a %s" % (args.slot, binascii.hexlify(hmac_key).decode('ascii'))) -+ print("") - -- passphrase = raw_input("Enter the secret passphrase to protect with the rolling challenges : ") -+ passphrase = six.moves.input("Enter the secret passphrase to protect with the rolling challenges : ") - - secret_dict = {"count": 0, - "passphrase": passphrase, -@@ -99,81 +101,84 @@ def do_challenge(args): - """ Send a challenge to the YubiKey and use the result to decrypt the state file. """ - outer_j = load_state_file(args) - challenge = outer_j["challenge"] -- print "Challenge : %s" % (challenge) -- response = get_yubikey_response(args, outer_j["challenge"].decode('hex')) -+ print("Challenge : %s" % (challenge)) -+ response = get_yubikey_response(args, binascii.unhexlify(outer_j["challenge"])) - if args.debug or args.verbose: -- print "\nGot %i bytes response %s\n" % (len(response), response.encode('hex')) -+ print("\nGot %i bytes response %s\n" % (len(response), binascii.hexlify(response))) - else: -- print "Response : %s" % (response.encode('hex')) -+ print("Response : %s" % binascii.hexlify(response)) - inner_j = decrypt_with_response(args, outer_j["inner"], response) - if args.verbose or args.debug: -- print "\nDecrypted 'inner' :\n%s\n" % (inner_j) -+ print("\nDecrypted 'inner' :\n%s\n" % (inner_j)) - - secret_dict = {} - try: -- secret_dict = json.loads(inner_j) -+ secret_dict = json.loads(inner_j.decode('ascii')) - except ValueError: - sys.stderr.write("\nCould not parse decoded data as JSON, you probably did not produce the right response.\n") - sys.exit(1) - - secret_dict["count"] += 1 - -- print "\nThe passphrase protected using rolling challenges is :\n" -- print "\t%s\n\nAccessed %i times.\n" % (secret_dict["passphrase"], secret_dict["count"]) -- roll_next_challenge(args, secret_dict["hmac_key"].decode('hex'), secret_dict) -+ print("\nThe passphrase protected using rolling challenges is :\n") -+ print("\t%s\n\nAccessed %i times.\n" % (secret_dict["passphrase"], secret_dict["count"])) -+ roll_next_challenge(args, binascii.unhexlify(secret_dict["hmac_key"]), secret_dict) - - def get_yubikey_response(args, challenge): - """ - Do challenge-response with the YubiKey if one is found. Otherwise prompt user to fake a response. """ - try: - YK = yubico.find_yubikey(debug = args.debug) -- response = YK.challenge_response(challenge.ljust(64, chr(0x0)), slot = args.slot) -+ response = YK.challenge_response(challenge.ljust(64, b'\0'), slot = args.slot) - return response - except yubico.yubico_exception.YubicoError as e: -- print "YubiKey challenge-response failed (%s)" % e.reason -- print "" -- response = raw_input("Assuming you do not have a YubiKey. Enter repsonse manually (hex encoded) : ") -- return response -+ print("YubiKey challenge-response failed (%s)" % e.reason) -+ print("") -+ response = six.moves.input("Assuming you do not have a YubiKey. Enter repsonse manually (hex encoded) : ") -+ return binascii.unhexlify(response) - - def roll_next_challenge(args, hmac_key, inner_dict): - """ - When we have the HMAC-SHA1 key in clear, generate a random challenge and compute the - expected response for that challenge. -+ -+ hmac_key is a 20-byte bytestring - """ -- if len(hmac_key) != 20: -- hmac_key = hmac_key.decode('hex') -+ if len(hmac_key) != 20 or not isinstance(hmac_key, bytes): -+ hmac_key = binascii.unhexlify(hmac_key) - - challenge = os.urandom(args.challenge_length) - response = get_response(hmac_key, challenge) - -- print "Generated challenge : %s" % (challenge.encode('hex')) -- print "Expected response : %s (sssh, don't tell anyone)" % (response) -- print "" -+ print("Generated challenge : %s" % binascii.hexlify(challenge).decode('ascii')) -+ print("Expected response : %s (sssh, don't tell anyone)" % binascii.hexlify(response).decode('ascii')) -+ print("") - if args.debug or args.verbose or args.init: -- print "To manually verify that your YubiKey produces this response, use :" -- print "" -- print " $ ykchalresp -%i -x %s" % (args.slot, challenge.encode('hex')) -- print "" -+ print("To manually verify that your YubiKey produces this response, use :") -+ print("") -+ print(" $ ykchalresp -%i -x %s" % (args.slot, binascii.hexlify(challenge).decode('ascii'))) -+ print("") - -- inner_dict["hmac_key"] = hmac_key.encode('hex') -+ inner_dict["hmac_key"] = binascii.hexlify(hmac_key).decode('ascii') - inner_j = json.dumps(inner_dict, indent = 4) - if args.verbose or args.debug: -- print "Inner JSON :\n%s\n" % (inner_j) -+ print("Inner JSON :\n%s\n" % (inner_j)) - inner_ciphertext = encrypt_with_response(args, inner_j, response) -- outer_dict = {"challenge": challenge.encode('hex'), -- "inner": inner_ciphertext, -+ outer_dict = {"challenge": binascii.hexlify(challenge).decode('ascii'), -+ "inner": inner_ciphertext.decode('ascii'), - } - outer_j = json.dumps(outer_dict, indent = 4) - if args.verbose or args.debug: -- print "\nOuter JSON :\n%s\n" % (outer_j) -+ print("\nOuter JSON :\n%s\n" % (outer_j)) - -- print "Saving 'outer' JSON to file '%s'" % (args.filename) -+ print("Saving 'outer' JSON to file '%s'" % (args.filename)) - write_state_file(args, outer_j) - - def get_response(hmac_key, challenge): -- """ Compute the expected response for `challenge'. """ -+ """ Compute the expected response for `challenge', as hexadecimal string """ -+ print(binascii.hexlify(hmac_key), binascii.hexlify(challenge), hashlib.sha1) - h = hmac.new(hmac_key, challenge, hashlib.sha1) -- return h.hexdigest() -+ return h.digest() - - def encrypt_with_response(args, data, key): - """ -@@ -191,14 +196,14 @@ def encrypt_with_response(args, data, key): - data += ' ' * (16 - pad) - - # need to pad key as well -- aes_key = key.decode('hex') -- aes_key += chr(0x0) * (32 - len(aes_key)) -+ aes_key = key -+ aes_key += b'\0' * (32 - len(aes_key)) - if args.debug: -- print ("AES-CBC encrypting 'inner' with key (%i bytes) : %s" % (len(aes_key), aes_key.encode('hex'))) -+ print(("AES-CBC encrypting 'inner' with key (%i bytes) : %s" % (len(aes_key), binascii.hexlify(aes_key)))) - -- obj = AES.new(aes_key, AES.MODE_CBC) -+ obj = AES.new(aes_key, AES.MODE_CBC, b'\0' * 16) - ciphertext = obj.encrypt(data) -- return ciphertext.encode('hex') -+ return binascii.hexlify(ciphertext) - - def decrypt_with_response(args, data, key): - """ -@@ -206,17 +211,17 @@ def decrypt_with_response(args, data, key): - """ - aes_key = key - try: -- aes_key = key.decode('hex') -- except TypeError: -+ aes_key = binascii.unhexlify(key) -+ except (TypeError, binascii.Error): - # was not hex encoded - pass - # need to pad key -- aes_key += chr(0x0) * (32 - len(aes_key)) -+ aes_key += b'\0' * (32 - len(aes_key)) - if args.debug: -- print ("AES-CBC decrypting 'inner' using key (%i bytes) : %s" % (len(aes_key), aes_key.encode('hex'))) -+ print(("AES-CBC decrypting 'inner' using key (%i bytes) : %s" % (len(aes_key), binascii.hexlify(aes_key)))) - -- obj = AES.new(aes_key, AES.MODE_CBC) -- plaintext = obj.decrypt(data.decode('hex')) -+ obj = AES.new(aes_key, AES.MODE_CBC, b'\0' * 16) -+ plaintext = obj.decrypt(binascii.unhexlify(data)) - return plaintext - - def write_state_file(args, data): -@@ -236,7 +241,7 @@ def main(): - else: - do_challenge(args) - -- print "\nDone\n" -+ print("\nDone\n") - - if __name__ == '__main__': - main() -diff --git a/examples/update_cfg_remove_cr b/examples/update_cfg_remove_cr -index bc27849..78012b3 100755 ---- a/examples/update_cfg_remove_cr -+++ b/examples/update_cfg_remove_cr -@@ -6,39 +6,41 @@ Set up a YubiKey for standard OTP with CR, then remove it. - import sys - import struct - import yubico -+import six -+import binascii - - slot=2 - - try: - YK = yubico.find_yubikey(debug=True) -- print "Version : %s " % YK.version() -- print "Status : %s " % YK.status() -+ print("Version : %s " % YK.version()) -+ print("Status : %s " % YK.status()) - - Cfg = YK.init_config() - Cfg.extended_flag('ALLOW_UPDATE', True) - Cfg.ticket_flag('APPEND_CR', True) - Cfg.extended_flag('SERIAL_API_VISIBLE', True) -- Cfg.uid = '010203040506'.decode('hex') -+ Cfg.uid = binascii.unhexlify('010203040506') - Cfg.fixed_string("m:ftccftbbftdd") - Cfg.aes_key('h:' + 32 * 'a') - -- user_input = raw_input('Write configuration to slot %i of YubiKey? [y/N] : ' % slot ) -+ user_input = six.moves.input('Write configuration to slot %i of YubiKey? [y/N] : ' % slot ) - if user_input in ('y', 'ye', 'yes'): - YK.write_config(Cfg, slot=slot) -- print "\nSuccess!" -- print "Status : %s " % YK.status() -+ print("\nSuccess!") -+ print("Status : %s " % YK.status()) - else: -- print "\nAborted" -+ print("\nAborted") - sys.exit(0) - -- raw_input("Press enter to update...") -+ six.moves.input("Press enter to update...") - - Cfg = YK.init_config(update=True) - Cfg.ticket_flag('APPEND_CR', False) - - print ("Updating..."); - YK.write_config(Cfg, slot=slot) -- print "\nSuccess!" -+ print("\nSuccess!") - except yubico.yubico_exception.YubicoError as inst: -- print "ERROR: %s" % inst.reason -+ print("ERROR: %s" % inst.reason) - sys.exit(1) -diff --git a/examples/yubikey-inventory b/examples/yubikey-inventory -index 0b34a22..e36414d 100755 ---- a/examples/yubikey-inventory -+++ b/examples/yubikey-inventory -@@ -29,9 +29,9 @@ if len(sys.argv) > 1: - keys = get_all_yubikeys(debug) - - if not keys: -- print "No YubiKey found." -+ print("No YubiKey found.") - else: - n = 1 - for this in keys: -- print "YubiKey #%02i : %s %s" % (n, this.description, this.status()) -+ print("YubiKey #%02i : %s %s" % (n, this.description, this.status())) - n += 1 -diff --git a/util/yubikey-totp b/util/yubikey-totp -index f02ad07..9ace901 100755 ---- a/util/yubikey-totp -+++ b/util/yubikey-totp -@@ -38,6 +38,7 @@ import time - import struct - import yubico - import argparse -+import binascii - - default_slot=2 - default_time=int(time.time()) -@@ -97,18 +98,17 @@ def make_totp(args): - """ - YK = yubico.find_yubikey(debug=args.debug) - if args.debug or args.verbose: -- print "Version : %s " % YK.version() -+ print("Version : %s " % YK.version()) - if args.debug: -- print "Serial : %i" % YK.serial() -- print "" -+ print("Serial : %i" % YK.serial()) -+ print("") - # Do challenge-response - secret = struct.pack("> Q", args.time / args.step).ljust(64, chr(0x0)) - if args.debug: -- print "Sending challenge : %s\n" % (secret.encode('hex')) -+ print("Sending challenge : %s\n" % (binascii.hexlify(secret))) - response = YK.challenge_response(secret, slot=args.slot) - # format with appropriate number of leading zeros -- fmt = "%." + str(args.digits) + "i" -- totp_str = fmt % (yubico.yubico_util.hotp_truncate(response, length=args.digits)) -+ totp_str = '%.*i' % (args.digits, yubico.yubico_util.hotp_truncate(response, length=args.digits)) - return totp_str - - def main(): -@@ -118,14 +118,14 @@ def main(): - otp = None - try: - otp = make_totp(args) -- except yubico.yubico_exception.YubicoError, e: -- print "ERROR: %s" % (e.reason) -+ except yubico.yubico_exception.YubicoError as e: -+ print("ERROR: %s" % (e.reason)) - return 1 - - if not otp: - return 1 - -- print otp -+ print(otp) - return 0 - - if __name__ == '__main__': -diff --git a/yubico/yubikey_frame.py b/yubico/yubikey_frame.py -index c43c6a1..f095d20 100644 ---- a/yubico/yubikey_frame.py -+++ b/yubico/yubikey_frame.py -@@ -101,24 +101,24 @@ def _debug_string(self, debug, data): - yubikey_defs.SLOT_SWAP, - ]: - # annotate according to config_st (see yubikey_defs.to_string()) -- if ord(data[-1]) == 0x80: -+ if yubico_util.ord_byte(data[-1]) == 0x80: - return (data, "FFFFFFF") -- if ord(data[-1]) == 0x81: -+ if yubico_util.ord_byte(data[-1]) == 0x81: - return (data, "FFFFFFF") -- if ord(data[-1]) == 0x82: -+ if yubico_util.ord_byte(data[-1]) == 0x82: - return (data, "FFUUUUU") -- if ord(data[-1]) == 0x83: -+ if yubico_util.ord_byte(data[-1]) == 0x83: - return (data, "UKKKKKK") -- if ord(data[-1]) == 0x84: -+ if yubico_util.ord_byte(data[-1]) == 0x84: - return (data, "KKKKKKK") -- if ord(data[-1]) == 0x85: -+ if yubico_util.ord_byte(data[-1]) == 0x85: - return (data, "KKKAAAA") -- if ord(data[-1]) == 0x86: -+ if yubico_util.ord_byte(data[-1]) == 0x86: - return (data, "AAlETCr") -- if ord(data[-1]) == 0x87: -+ if yubico_util.ord_byte(data[-1]) == 0x87: - return (data, "rCR") - # after payload -- if ord(data[-1]) == 0x89: -+ if yubico_util.ord_byte(data[-1]) == 0x89: - return (data, " Scr") - else: - return (data, '') -diff --git a/yubico/yubikey_neo_usb_hid.py b/yubico/yubikey_neo_usb_hid.py -index 88fceba..7030c59 100644 ---- a/yubico/yubikey_neo_usb_hid.py -+++ b/yubico/yubikey_neo_usb_hid.py -@@ -188,7 +188,7 @@ def to_string(self): - first = struct.pack(fmt, - len(data), - self.ndef_type, -- data.ljust(_NDEF_DATA_SIZE, chr(0x0)), -+ data.ljust(_NDEF_DATA_SIZE, b'\0'), - self.access_code, - ) - #crc = 0xffff - yubico_util.crc16(first) diff --git a/python-yubico.spec b/python-yubico.spec index 4c3de56..0f878a8 100644 --- a/python-yubico.spec +++ b/python-yubico.spec @@ -2,14 +2,13 @@ %global srcname yubico Name: python-%{srcname} -Version: 1.3.2 -Release: 18%{?dist} +Version: 1.3.3 +Release: 1%{?dist} Summary: Pure-python library for interacting with Yubikeys License: BSD URL: https://github.com/Yubico/%{name} Source0: https://github.com/Yubico/%{name}/archive/%{name}-%{version}.tar.gz -Patch0: python-yubico-py3.patch BuildArch: noarch @@ -53,6 +52,10 @@ nosetests-%{python3_version} -e test_challenge_response -e test_serial -e test_s %changelog +* Thu Mar 05 2020 Mohan Boddu - 1.3.3-1 +- Update to 1.3.3 +- Removing py3 patches + * Thu Jan 30 2020 Fedora Release Engineering - 1.3.2-18 - Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild diff --git a/sources b/sources index 0a94ca1..cf82fb9 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -3012d95a043b1da93486e0b555b95234 python-yubico-1.3.2.tar.gz +SHA512 (python-yubico-1.3.3.tar.gz) = f8f0d7156da98c5f8c2f7e4f7285bef349b3e7291e5e268a728823a8cdf1628b8586bc0cc1591f5587c6573ac5cb2c79bb07cb179968da4d1d9bb8ff5e164fe6