From c34104548c189fa858adfd22443023f4bd11bbd6 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 10 Jun 2016 15:19:33 +0200 Subject: [PATCH 01/76] Port to Python 3.5 using 2to3 tool --- src/mifareauth.py | 6 +++--- src/nfc.py | 30 +++++++++++++++--------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/mifareauth.py b/src/mifareauth.py index 750424f..7cb1ead 100644 --- a/src/mifareauth.py +++ b/src/mifareauth.py @@ -74,7 +74,7 @@ def run(self): time.sleep(5) except (KeyboardInterrupt, SystemExit): loop = False - except IOError, e: + except IOError as e: self.log("Exception: " + str(e)) loop = True # not str(e).startswith("NFC Error whilst polling") # except Exception, e: @@ -218,13 +218,13 @@ def auth_and_write(self, block, uid, data, key = "\xff\xff\xff\xff\xff\xff"): def read_card(self, uid): """Takes a uid, reads the card and return data for use in writing the card""" key = "\xff\xff\xff\xff\xff\xff" - print "Reading card", uid.encode("hex") + print("Reading card", uid.encode("hex")) self._card_uid = self.select_card() self._authenticate(0x00, uid, key) block = 0 for block in range(64): data = self.auth_and_read(block, uid, key) - print block, data.encode("hex"), "".join([ x if x in string.printable else "." for x in data]) + print(block, data.encode("hex"), "".join([ x if x in string.printable else "." for x in data])) def write_card(self, uid, data): """Accepts data of the recently read card with UID uid, and writes any changes necessary to it""" diff --git a/src/nfc.py b/src/nfc.py index e1d5e22..496c3fb 100644 --- a/src/nfc.py +++ b/src/nfc.py @@ -48,7 +48,7 @@ def from_param(cls, x): class UserString: def __init__(self, seq): - if isinstance(seq, basestring): + if isinstance(seq, str): self.data = seq elif isinstance(seq, UserString): self.data = seq.data[:] @@ -57,7 +57,7 @@ def __init__(self, seq): def __str__(self): return str(self.data) def __repr__(self): return repr(self.data) def __int__(self): return int(self.data) - def __long__(self): return long(self.data) + def __long__(self): return int(self.data) def __float__(self): return float(self.data) def __complex__(self): return complex(self.data) def __hash__(self): return hash(self.data) @@ -79,12 +79,12 @@ def __getslice__(self, start, end): def __add__(self, other): if isinstance(other, UserString): return self.__class__(self.data + other.data) - elif isinstance(other, basestring): + elif isinstance(other, str): return self.__class__(self.data + other) else: return self.__class__(self.data + str(other)) def __radd__(self, other): - if isinstance(other, basestring): + if isinstance(other, str): return self.__class__(other + self.data) else: return self.__class__(str(other) + self.data) @@ -98,7 +98,7 @@ def __mod__(self, args): def capitalize(self): return self.__class__(self.data.capitalize()) def center(self, width, *args): return self.__class__(self.data.center(width, *args)) - def count(self, sub, start = 0, end = sys.maxint): + def count(self, sub, start = 0, end = sys.maxsize): return self.data.count(sub, start, end) def decode(self, encoding = None, errors = None): # XXX improve this? if encoding: @@ -116,13 +116,13 @@ def encode(self, encoding = None, errors = None): # XXX improve this? return self.__class__(self.data.encode(encoding)) else: return self.__class__(self.data.encode()) - def endswith(self, suffix, start = 0, end = sys.maxint): + def endswith(self, suffix, start = 0, end = sys.maxsize): return self.data.endswith(suffix, start, end) def expandtabs(self, tabsize = 8): return self.__class__(self.data.expandtabs(tabsize)) - def find(self, sub, start = 0, end = sys.maxint): + def find(self, sub, start = 0, end = sys.maxsize): return self.data.find(sub, start, end) - def index(self, sub, start = 0, end = sys.maxint): + def index(self, sub, start = 0, end = sys.maxsize): return self.data.index(sub, start, end) def isalpha(self): return self.data.isalpha() def isalnum(self): return self.data.isalnum() @@ -142,9 +142,9 @@ def partition(self, sep): return self.data.partition(sep) def replace(self, old, new, maxsplit = -1): return self.__class__(self.data.replace(old, new, maxsplit)) - def rfind(self, sub, start = 0, end = sys.maxint): + def rfind(self, sub, start = 0, end = sys.maxsize): return self.data.rfind(sub, start, end) - def rindex(self, sub, start = 0, end = sys.maxint): + def rindex(self, sub, start = 0, end = sys.maxsize): return self.data.rindex(sub, start, end) def rjust(self, width, *args): return self.__class__(self.data.rjust(width, *args)) @@ -156,7 +156,7 @@ def split(self, sep = None, maxsplit = -1): def rsplit(self, sep = None, maxsplit = -1): return self.data.rsplit(sep, maxsplit) def splitlines(self, keepends = 0): return self.data.splitlines(keepends) - def startswith(self, prefix, start = 0, end = sys.maxint): + def startswith(self, prefix, start = 0, end = sys.maxsize): return self.data.startswith(prefix, start, end) def strip(self, chars = None): return self.__class__(self.data.strip(chars)) def swapcase(self): return self.__class__(self.data.swapcase()) @@ -199,7 +199,7 @@ def __setslice__(self, start, end, sub): start = max(start, 0); end = max(end, 0) if isinstance(sub, UserString): self.data = self.data[:start] + sub.data + self.data[end:] - elif isinstance(sub, basestring): + elif isinstance(sub, str): self.data = self.data[:start] + sub + self.data[end:] else: self.data = self.data[:start] + str(sub) + self.data[end:] @@ -211,7 +211,7 @@ def immutable(self): def __iadd__(self, other): if isinstance(other, UserString): self.data += other.data - elif isinstance(other, basestring): + elif isinstance(other, str): self.data += other else: self.data += str(other) @@ -226,7 +226,7 @@ class String(MutableString, Union): ('data', c_char_p)] def __init__(self, obj = ""): - if isinstance(obj, (str, unicode, UserString)): + if isinstance(obj, (str, UserString)): self.data = str(obj) else: self.raw = obj @@ -377,7 +377,7 @@ def load(self, path): return ctypes.CDLL(path, ctypes.RTLD_GLOBAL) else: return ctypes.cdll.LoadLibrary(path) - except OSError, e: + except OSError as e: raise ImportError(e) def getpaths(self, libname): From dd0b55027447313c1e2990a6f92f97520026d3b2 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 10 Jun 2016 15:24:21 +0200 Subject: [PATCH 02/76] AutoPEP8 all code --- src/mifareauth.py | 33 ++-- src/nfc.py | 479 ++++++++++++++++++++++++++++++++-------------- 2 files changed, 354 insertions(+), 158 deletions(-) diff --git a/src/mifareauth.py b/src/mifareauth.py index 7cb1ead..2e2ce99 100644 --- a/src/mifareauth.py +++ b/src/mifareauth.py @@ -15,7 +15,8 @@ # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301, USA. import time import logging @@ -23,11 +24,14 @@ import string import nfc + def hex_dump(string): """Dumps data as hexstrings""" return ' '.join(["%0.2X" % ord(x) for x in string]) -### NFC device setup +# NFC device setup + + class NFCReader(object): MC_AUTH_A = 0x60 MC_AUTH_B = 0x61 @@ -60,7 +64,8 @@ def run(self): try: self._clean_card() conn_strings = (nfc.nfc_connstring * 10)() - devices_found = nfc.nfc_list_devices(self.__context, conn_strings, 10) + devices_found = nfc.nfc_list_devices( + self.__context, conn_strings, 10) if devices_found >= 1: self.__device = nfc.nfc_open(self.__context, conn_strings[0]) try: @@ -108,8 +113,8 @@ def _poll_loop(self): if nt.nti.nai.szUidLen == 4: uid = "".join([chr(nt.nti.nai.abtUid[i]) for i in range(4)]) if uid: - if not ((self._card_uid and self._card_present and uid == self._card_uid) and \ - time.mktime(time.gmtime()) <= self._card_last_seen + self.card_timeout): + if not ((self._card_uid and self._card_present and uid == self._card_uid) and + time.mktime(time.gmtime()) <= self._card_last_seen + self.card_timeout): self._setup_device() self.read_card(uid) self._card_uid = uid @@ -128,8 +133,10 @@ def select_card(self): Returns the UID of the card selected """ nt = nfc.nfc_target() - _ = nfc.nfc_initiator_select_passive_target(self.__device, self.__modulations[0], None, 0, ctypes.byref(nt)) - uid = "".join([chr(nt.nti.nai.abtUid[i]) for i in range(nt.nti.nai.szUidLen)]) + _ = nfc.nfc_initiator_select_passive_target( + self.__device, self.__modulations[0], None, 0, ctypes.byref(nt)) + uid = "".join([chr(nt.nti.nai.abtUid[i]) + for i in range(nt.nti.nai.szUidLen)]) return uid def _setup_device(self): @@ -168,7 +175,8 @@ def __write_block(self, block, data): if nfc.nfc_device_set_property_bool(self.__device, nfc.NP_EASY_FRAMING, True) < 0: raise Exception("Error setting Easy Framing property") if len(data) > 16: - raise ValueError("Data value to be written cannot be more than 16 characters.") + raise ValueError( + "Data value to be written cannot be more than 16 characters.") abttx = (ctypes.c_uint8 * 18)() abttx[0] = self.MC_WRITE abttx[1] = block @@ -178,7 +186,7 @@ def __write_block(self, block, data): return nfc.nfc_initiator_transceive_bytes(self.__device, ctypes.pointer(abttx), len(abttx), ctypes.pointer(abtrx), len(abtrx), 0) - def _authenticate(self, block, uid, key = "\xff\xff\xff\xff\xff\xff", use_b_key = False): + def _authenticate(self, block, uid, key="\xff\xff\xff\xff\xff\xff", use_b_key=False): """Authenticates to a particular block using a specified key""" if nfc.nfc_device_set_property_bool(self.__device, nfc.NP_EASY_FRAMING, True) < 0: raise Exception("Error setting Easy Framing property") @@ -193,7 +201,7 @@ def _authenticate(self, block, uid, key = "\xff\xff\xff\xff\xff\xff", use_b_key return nfc.nfc_initiator_transceive_bytes(self.__device, ctypes.pointer(abttx), len(abttx), ctypes.pointer(abtrx), len(abtrx), 0) - def auth_and_read(self, block, uid, key = "\xff\xff\xff\xff\xff\xff"): + def auth_and_read(self, block, uid, key="\xff\xff\xff\xff\xff\xff"): """Authenticates and then reads a block Returns '' if the authentication failed @@ -205,7 +213,7 @@ def auth_and_read(self, block, uid, key = "\xff\xff\xff\xff\xff\xff"): return self._read_block(block) return '' - def auth_and_write(self, block, uid, data, key = "\xff\xff\xff\xff\xff\xff"): + def auth_and_write(self, block, uid, data, key="\xff\xff\xff\xff\xff\xff"): """Authenticates and then writes a block """ @@ -224,7 +232,8 @@ def read_card(self, uid): block = 0 for block in range(64): data = self.auth_and_read(block, uid, key) - print(block, data.encode("hex"), "".join([ x if x in string.printable else "." for x in data])) + print(block, data.encode("hex"), "".join( + [x if x in string.printable else "." for x in data])) def write_card(self, uid, data): """Accepts data of the recently read card with UID uid, and writes any changes necessary to it""" diff --git a/src/nfc.py b/src/nfc.py index 496c3fb..df8b319 100644 --- a/src/nfc.py +++ b/src/nfc.py @@ -10,7 +10,9 @@ # Begin preamble -import ctypes, os, sys +import ctypes +import os +import sys from ctypes import cast, c_int, c_int16, c_int32, c_uint8, c_uint32, c_int64, c_char, c_char_p, c_size_t, c_void_p, sizeof, Structure, Union, CFUNCTYPE _int_types = (c_int16, c_int32) @@ -25,12 +27,14 @@ del t del _int_types + class c_void(Structure): # c_void_p is a buggy return type, converting to int, so # POINTER(None) == c_void_p is actually written as # POINTER(c_void), so it can be treated as a real pointer. _fields_ = [('dummy', c_int)] + def POINTER(obj): p = ctypes.POINTER(obj) @@ -46,7 +50,9 @@ def from_param(cls, x): return p + class UserString: + def __init__(self, seq): if isinstance(seq, str): self.data = seq @@ -54,12 +60,19 @@ def __init__(self, seq): self.data = seq.data[:] else: self.data = str(seq) + def __str__(self): return str(self.data) + def __repr__(self): return repr(self.data) + def __int__(self): return int(self.data) + def __long__(self): return int(self.data) + def __float__(self): return float(self.data) + def __complex__(self): return complex(self.data) + def __hash__(self): return hash(self.data) def __cmp__(self, string): @@ -67,13 +80,17 @@ def __cmp__(self, string): return cmp(self.data, string.data) else: return cmp(self.data, string) + def __contains__(self, char): return char in self.data def __len__(self): return len(self.data) + def __getitem__(self, index): return self.__class__(self.data[index]) + def __getslice__(self, start, end): - start = max(start, 0); end = max(end, 0) + start = max(start, 0) + end = max(end, 0) return self.__class__(self.data[start:end]) def __add__(self, other): @@ -83,24 +100,30 @@ def __add__(self, other): return self.__class__(self.data + other) else: return self.__class__(self.data + str(other)) + def __radd__(self, other): if isinstance(other, str): return self.__class__(other + self.data) else: return self.__class__(str(other) + self.data) + def __mul__(self, n): return self.__class__(self.data * n) __rmul__ = __mul__ + def __mod__(self, args): return self.__class__(self.data % args) # the following methods are defined in alphabetical order: def capitalize(self): return self.__class__(self.data.capitalize()) + def center(self, width, *args): return self.__class__(self.data.center(width, *args)) - def count(self, sub, start = 0, end = sys.maxsize): + + def count(self, sub, start=0, end=sys.maxsize): return self.data.count(sub, start, end) - def decode(self, encoding = None, errors = None): # XXX improve this? + + def decode(self, encoding=None, errors=None): # XXX improve this? if encoding: if errors: return self.__class__(self.data.decode(encoding, errors)) @@ -108,7 +131,8 @@ def decode(self, encoding = None, errors = None): # XXX improve this? return self.__class__(self.data.decode(encoding)) else: return self.__class__(self.data.decode()) - def encode(self, encoding = None, errors = None): # XXX improve this? + + def encode(self, encoding=None, errors=None): # XXX improve this? if encoding: if errors: return self.__class__(self.data.encode(encoding, errors)) @@ -116,57 +140,97 @@ def encode(self, encoding = None, errors = None): # XXX improve this? return self.__class__(self.data.encode(encoding)) else: return self.__class__(self.data.encode()) - def endswith(self, suffix, start = 0, end = sys.maxsize): + + def endswith(self, suffix, start=0, end=sys.maxsize): return self.data.endswith(suffix, start, end) - def expandtabs(self, tabsize = 8): + + def expandtabs(self, tabsize=8): return self.__class__(self.data.expandtabs(tabsize)) - def find(self, sub, start = 0, end = sys.maxsize): + + def find(self, sub, start=0, end=sys.maxsize): return self.data.find(sub, start, end) - def index(self, sub, start = 0, end = sys.maxsize): + + def index(self, sub, start=0, end=sys.maxsize): return self.data.index(sub, start, end) + def isalpha(self): return self.data.isalpha() + def isalnum(self): return self.data.isalnum() - def isdecimal(self): return self.data.isdecimal() #pylint: disable-msg=E1103 + + def isdecimal( + self): return self.data.isdecimal() # pylint: disable-msg=E1103 + def isdigit(self): return self.data.isdigit() + def islower(self): return self.data.islower() - def isnumeric(self): return self.data.isnumeric() #pylint: disable-msg=E1103 + + def isnumeric( + self): return self.data.isnumeric() # pylint: disable-msg=E1103 + def isspace(self): return self.data.isspace() + def istitle(self): return self.data.istitle() + def isupper(self): return self.data.isupper() + def join(self, seq): return self.data.join(seq) + def ljust(self, width, *args): return self.__class__(self.data.ljust(width, *args)) + def lower(self): return self.__class__(self.data.lower()) - def lstrip(self, chars = None): return self.__class__(self.data.lstrip(chars)) + + def lstrip(self, chars=None): return self.__class__( + self.data.lstrip(chars)) + def partition(self, sep): return self.data.partition(sep) - def replace(self, old, new, maxsplit = -1): + + def replace(self, old, new, maxsplit=-1): return self.__class__(self.data.replace(old, new, maxsplit)) - def rfind(self, sub, start = 0, end = sys.maxsize): + + def rfind(self, sub, start=0, end=sys.maxsize): return self.data.rfind(sub, start, end) - def rindex(self, sub, start = 0, end = sys.maxsize): + + def rindex(self, sub, start=0, end=sys.maxsize): return self.data.rindex(sub, start, end) + def rjust(self, width, *args): return self.__class__(self.data.rjust(width, *args)) + def rpartition(self, sep): return self.data.rpartition(sep) - def rstrip(self, chars = None): return self.__class__(self.data.rstrip(chars)) - def split(self, sep = None, maxsplit = -1): + + def rstrip(self, chars=None): return self.__class__( + self.data.rstrip(chars)) + + def split(self, sep=None, maxsplit=-1): return self.data.split(sep, maxsplit) - def rsplit(self, sep = None, maxsplit = -1): + + def rsplit(self, sep=None, maxsplit=-1): return self.data.rsplit(sep, maxsplit) - def splitlines(self, keepends = 0): return self.data.splitlines(keepends) - def startswith(self, prefix, start = 0, end = sys.maxsize): + + def splitlines(self, keepends=0): return self.data.splitlines(keepends) + + def startswith(self, prefix, start=0, end=sys.maxsize): return self.data.startswith(prefix, start, end) - def strip(self, chars = None): return self.__class__(self.data.strip(chars)) + + def strip(self, chars=None): return self.__class__(self.data.strip(chars)) + def swapcase(self): return self.__class__(self.data.swapcase()) + def title(self): return self.__class__(self.data.title()) + def translate(self, *args): return self.__class__(self.data.translate(*args)) + def upper(self): return self.__class__(self.data.upper()) + def zfill(self, width): return self.__class__(self.data.zfill(width)) + class MutableString(UserString): + """mutable string objects Python strings are immutable objects. This has the advantage, that @@ -181,33 +245,45 @@ class MutableString(UserString): errors that would be very hard to track down. A faster and better solution is to rewrite your program using lists.""" - def __init__(self, string = ""): + + def __init__(self, string=""): self.data = string + def __hash__(self): raise TypeError("unhashable type (it is mutable)") + def __setitem__(self, index, sub): if index < 0: index += len(self.data) - if index < 0 or index >= len(self.data): raise IndexError + if index < 0 or index >= len(self.data): + raise IndexError self.data = self.data[:index] + sub + self.data[index + 1:] + def __delitem__(self, index): if index < 0: index += len(self.data) - if index < 0 or index >= len(self.data): raise IndexError + if index < 0 or index >= len(self.data): + raise IndexError self.data = self.data[:index] + self.data[index + 1:] + def __setslice__(self, start, end, sub): - start = max(start, 0); end = max(end, 0) + start = max(start, 0) + end = max(end, 0) if isinstance(sub, UserString): self.data = self.data[:start] + sub.data + self.data[end:] elif isinstance(sub, str): self.data = self.data[:start] + sub + self.data[end:] else: self.data = self.data[:start] + str(sub) + self.data[end:] + def __delslice__(self, start, end): - start = max(start, 0); end = max(end, 0) + start = max(start, 0) + end = max(end, 0) self.data = self.data[:start] + self.data[end:] + def immutable(self): return UserString(self.data) + def __iadd__(self, other): if isinstance(other, UserString): self.data += other.data @@ -216,16 +292,18 @@ def __iadd__(self, other): else: self.data += str(other) return self + def __imul__(self, n): self.data *= n return self + class String(MutableString, Union): _fields_ = [('raw', POINTER(c_char)), ('data', c_char_p)] - def __init__(self, obj = ""): + def __init__(self, obj=""): if isinstance(obj, (str, UserString)): self.data = str(obj) else: @@ -264,7 +342,8 @@ def from_param(cls, obj): return String.from_param(obj._as_parameter_) from_param = classmethod(from_param) -def ReturnString(obj, func = None, arguments = None): + +def ReturnString(obj, func=None, arguments=None): return String.from_param(obj) # As of ctypes 1.0, ctypes does not support custom error-checking @@ -274,23 +353,30 @@ def ReturnString(obj, func = None, arguments = None): # # Non-primitive return values wrapped with UNCHECKED won't be # typechecked, and will be converted to c_void_p. + + def UNCHECKED(type): if (hasattr(type, "_type_") and isinstance(type._type_, str) - and type._type_ != "P"): + and type._type_ != "P"): return type else: return c_void_p # ctypes doesn't have direct support for variadic functions, so we have to write # our own wrapper class + + class _variadic_function(object): + def __init__(self, func, restype, argtypes): self.func = func self.func.restype = restype self.argtypes = argtypes + def _as_parameter_(self): # So we can pass this variadic function as a function pointer return self.func + def __call__(self, *args): fixed_args = [] i = 0 @@ -341,18 +427,24 @@ def __call__(self, *args): # POSSIBILITY OF SUCH DAMAGE. # ---------------------------------------------------------------------------- -import os.path, re, sys, glob +import os.path +import re +import sys +import glob import platform import ctypes import ctypes.util + def _environ_path(name): if name in os.environ: return os.environ[name].split(":") else: return [] + class LibraryLoader(object): + def __init__(self): self.other_dirs = [] @@ -390,16 +482,18 @@ def getpaths(self, libname): yield path path = ctypes.util.find_library(libname) - if path: yield path + if path: + yield path def getplatformpaths(self, libname): return [] # Darwin (Mac OS X) + class DarwinLibraryLoader(LibraryLoader): name_formats = ["lib%s.dylib", "lib%s.so", "lib%s.bundle", "%s.dylib", - "%s.so", "%s.bundle", "%s"] + "%s.so", "%s.bundle", "%s"] def getplatformpaths(self, libname): if os.path.pathsep in libname: @@ -422,7 +516,8 @@ def getdirs(self, libname): within a bundle (OS X .app). ''' - dyld_fallback_library_path = _environ_path("DYLD_FALLBACK_LIBRARY_PATH") + dyld_fallback_library_path = _environ_path( + "DYLD_FALLBACK_LIBRARY_PATH") if not dyld_fallback_library_path: dyld_fallback_library_path = [os.path.expanduser('~/lib'), '/usr/local/lib', '/usr/lib'] @@ -439,7 +534,7 @@ def getdirs(self, libname): dirs.append(".") dirs.append(os.path.dirname(__file__)) - if hasattr(sys, 'frozen') and sys.frozen == 'macosx_app': #pylint: disable-msg=E1101 + if hasattr(sys, 'frozen') and sys.frozen == 'macosx_app': # pylint: disable-msg=E1101 dirs.append(os.path.join( os.environ['RESOURCEPATH'], '..', @@ -451,6 +546,7 @@ def getdirs(self, libname): # Posix + class PosixLibraryLoader(LibraryLoader): _ld_so_cache = None @@ -464,18 +560,21 @@ def _create_ld_so_cache(self): directories = [] for name in ("LD_LIBRARY_PATH", - "SHLIB_PATH", # HPUX - "LIBPATH", # OS/2, AIX - "LIBRARY_PATH", # BE/OS - ): + "SHLIB_PATH", # HPUX + "LIBPATH", # OS/2, AIX + "LIBRARY_PATH", # BE/OS + ): if name in os.environ: directories.extend(os.environ[name].split(os.pathsep)) directories.extend(self.other_dirs) directories.append(".") directories.append(os.path.dirname(__file__)) - try: directories.extend([dir.strip() for dir in open('/etc/ld.so.conf')]) - except IOError: pass + try: + directories.extend([dir.strip() + for dir in open('/etc/ld.so.conf')]) + except IOError: + pass unix_lib_dirs_list = ['/lib', '/usr/lib', '/lib64', '/usr/lib64'] if sys.platform.startswith('linux'): @@ -484,10 +583,12 @@ def _create_ld_so_cache(self): bitage = platform.architecture()[0] if bitage.startswith('32'): # Assume Intel/AMD x86 compat - unix_lib_dirs_list += ['/lib/i386-linux-gnu', '/usr/lib/i386-linux-gnu'] + unix_lib_dirs_list += ['/lib/i386-linux-gnu', + '/usr/lib/i386-linux-gnu'] elif bitage.startswith('64'): # Assume Intel/AMD x86 compat - unix_lib_dirs_list += ['/lib/x86_64-linux-gnu', '/usr/lib/x86_64-linux-gnu'] + unix_lib_dirs_list += ['/lib/x86_64-linux-gnu', + '/usr/lib/x86_64-linux-gnu'] else: # guess... unix_lib_dirs_list += glob.glob('/lib/*linux-gnu') @@ -521,25 +622,32 @@ def getplatformpaths(self, libname): self._create_ld_so_cache() result = self._ld_so_cache.get(libname) - if result: yield result + if result: + yield result path = ctypes.util.find_library(libname) - if path: yield os.path.join("/lib", path) + if path: + yield os.path.join("/lib", path) # Windows + class _WindowsLibrary(object): + def __init__(self, path): self.cdll = ctypes.cdll.LoadLibrary(path) self.windll = ctypes.windll.LoadLibrary(path) def __getattr__(self, name): - try: return getattr(self.cdll, name) + try: + return getattr(self.cdll, name) except AttributeError: - try: return getattr(self.windll, name) + try: + return getattr(self.windll, name) except AttributeError: raise + class WindowsLibraryLoader(LibraryLoader): name_formats = ["%s.dll", "lib%s.dll", "%slib.dll"] @@ -591,6 +699,7 @@ def getplatformpaths(self, libname): loader = loaderclass.get(sys.platform, PosixLibraryLoader)() + def add_library_search_dirs(other_dirs): loader.other_dirs = other_dirs @@ -612,70 +721,86 @@ def add_library_search_dirs(other_dirs): # No modules # /usr/include/nfc/nfc-types.h: 42 + + class struct_nfc_context(Structure): _pack_ = 1 -nfc_context = struct_nfc_context # /usr/include/nfc/nfc-types.h: 42 +nfc_context = struct_nfc_context # /usr/include/nfc/nfc-types.h: 42 # /usr/include/nfc/nfc-types.h: 47 + + class struct_nfc_device(Structure): _pack_ = 1 -nfc_device = struct_nfc_device # /usr/include/nfc/nfc-types.h: 47 +nfc_device = struct_nfc_device # /usr/include/nfc/nfc-types.h: 47 # /usr/include/nfc/nfc-types.h: 52 + + class struct_nfc_driver(Structure): _pack_ = 1 -nfc_driver = struct_nfc_driver # /usr/include/nfc/nfc-types.h: 52 +nfc_driver = struct_nfc_driver # /usr/include/nfc/nfc-types.h: 52 -nfc_connstring = c_char * 1024 # /usr/include/nfc/nfc-types.h: 57 +nfc_connstring = c_char * 1024 # /usr/include/nfc/nfc-types.h: 57 -enum_anon_18 = c_int # /usr/include/nfc/nfc-types.h: 137 +enum_anon_18 = c_int # /usr/include/nfc/nfc-types.h: 137 -NP_TIMEOUT_COMMAND = 0 # /usr/include/nfc/nfc-types.h: 137 +NP_TIMEOUT_COMMAND = 0 # /usr/include/nfc/nfc-types.h: 137 -NP_TIMEOUT_ATR = (NP_TIMEOUT_COMMAND + 1) # /usr/include/nfc/nfc-types.h: 137 +NP_TIMEOUT_ATR = (NP_TIMEOUT_COMMAND + 1) # /usr/include/nfc/nfc-types.h: 137 -NP_TIMEOUT_COM = (NP_TIMEOUT_ATR + 1) # /usr/include/nfc/nfc-types.h: 137 +NP_TIMEOUT_COM = (NP_TIMEOUT_ATR + 1) # /usr/include/nfc/nfc-types.h: 137 -NP_HANDLE_CRC = (NP_TIMEOUT_COM + 1) # /usr/include/nfc/nfc-types.h: 137 +NP_HANDLE_CRC = (NP_TIMEOUT_COM + 1) # /usr/include/nfc/nfc-types.h: 137 -NP_HANDLE_PARITY = (NP_HANDLE_CRC + 1) # /usr/include/nfc/nfc-types.h: 137 +NP_HANDLE_PARITY = (NP_HANDLE_CRC + 1) # /usr/include/nfc/nfc-types.h: 137 -NP_ACTIVATE_FIELD = (NP_HANDLE_PARITY + 1) # /usr/include/nfc/nfc-types.h: 137 +NP_ACTIVATE_FIELD = (NP_HANDLE_PARITY + 1) # /usr/include/nfc/nfc-types.h: 137 -NP_ACTIVATE_CRYPTO1 = (NP_ACTIVATE_FIELD + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_ACTIVATE_CRYPTO1 = (NP_ACTIVATE_FIELD + 1) -NP_INFINITE_SELECT = (NP_ACTIVATE_CRYPTO1 + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_INFINITE_SELECT = (NP_ACTIVATE_CRYPTO1 + 1) -NP_ACCEPT_INVALID_FRAMES = (NP_INFINITE_SELECT + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_ACCEPT_INVALID_FRAMES = (NP_INFINITE_SELECT + 1) -NP_ACCEPT_MULTIPLE_FRAMES = (NP_ACCEPT_INVALID_FRAMES + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_ACCEPT_MULTIPLE_FRAMES = (NP_ACCEPT_INVALID_FRAMES + 1) -NP_AUTO_ISO14443_4 = (NP_ACCEPT_MULTIPLE_FRAMES + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_AUTO_ISO14443_4 = (NP_ACCEPT_MULTIPLE_FRAMES + 1) -NP_EASY_FRAMING = (NP_AUTO_ISO14443_4 + 1) # /usr/include/nfc/nfc-types.h: 137 +NP_EASY_FRAMING = (NP_AUTO_ISO14443_4 + 1) # /usr/include/nfc/nfc-types.h: 137 -NP_FORCE_ISO14443_A = (NP_EASY_FRAMING + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_FORCE_ISO14443_A = (NP_EASY_FRAMING + 1) -NP_FORCE_ISO14443_B = (NP_FORCE_ISO14443_A + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_FORCE_ISO14443_B = (NP_FORCE_ISO14443_A + 1) -NP_FORCE_SPEED_106 = (NP_FORCE_ISO14443_B + 1) # /usr/include/nfc/nfc-types.h: 137 +# /usr/include/nfc/nfc-types.h: 137 +NP_FORCE_SPEED_106 = (NP_FORCE_ISO14443_B + 1) -nfc_property = enum_anon_18 # /usr/include/nfc/nfc-types.h: 137 +nfc_property = enum_anon_18 # /usr/include/nfc/nfc-types.h: 137 -enum_anon_19 = c_int # /usr/include/nfc/nfc-types.h: 150 +enum_anon_19 = c_int # /usr/include/nfc/nfc-types.h: 150 -NDM_UNDEFINED = 0 # /usr/include/nfc/nfc-types.h: 150 +NDM_UNDEFINED = 0 # /usr/include/nfc/nfc-types.h: 150 -NDM_PASSIVE = (NDM_UNDEFINED + 1) # /usr/include/nfc/nfc-types.h: 150 +NDM_PASSIVE = (NDM_UNDEFINED + 1) # /usr/include/nfc/nfc-types.h: 150 -NDM_ACTIVE = (NDM_PASSIVE + 1) # /usr/include/nfc/nfc-types.h: 150 +NDM_ACTIVE = (NDM_PASSIVE + 1) # /usr/include/nfc/nfc-types.h: 150 -nfc_dep_mode = enum_anon_19 # /usr/include/nfc/nfc-types.h: 150 +nfc_dep_mode = enum_anon_19 # /usr/include/nfc/nfc-types.h: 150 # /usr/include/nfc/nfc-types.h: 174 + + class struct_anon_20(Structure): _pack_ = 1 @@ -702,9 +827,11 @@ class struct_anon_20(Structure): ('ndm', nfc_dep_mode), ] -nfc_dep_info = struct_anon_20 # /usr/include/nfc/nfc-types.h: 174 +nfc_dep_info = struct_anon_20 # /usr/include/nfc/nfc-types.h: 174 # /usr/include/nfc/nfc-types.h: 187 + + class struct_anon_21(Structure): _pack_ = 1 @@ -725,9 +852,11 @@ class struct_anon_21(Structure): ('abtAts', c_uint8 * 254), ] -nfc_iso14443a_info = struct_anon_21 # /usr/include/nfc/nfc-types.h: 187 +nfc_iso14443a_info = struct_anon_21 # /usr/include/nfc/nfc-types.h: 187 # /usr/include/nfc/nfc-types.h: 199 + + class struct_anon_22(Structure): _pack_ = 1 @@ -746,9 +875,11 @@ class struct_anon_22(Structure): ('abtSysCode', c_uint8 * 2), ] -nfc_felica_info = struct_anon_22 # /usr/include/nfc/nfc-types.h: 199 +nfc_felica_info = struct_anon_22 # /usr/include/nfc/nfc-types.h: 199 # /usr/include/nfc/nfc-types.h: 214 + + class struct_anon_23(Structure): _pack_ = 1 @@ -765,9 +896,11 @@ class struct_anon_23(Structure): ('ui8CardIdentifier', c_uint8), ] -nfc_iso14443b_info = struct_anon_23 # /usr/include/nfc/nfc-types.h: 214 +nfc_iso14443b_info = struct_anon_23 # /usr/include/nfc/nfc-types.h: 214 # /usr/include/nfc/nfc-types.h: 230 + + class struct_anon_24(Structure): _pack_ = 1 @@ -786,9 +919,11 @@ class struct_anon_24(Structure): ('abtAtr', c_uint8 * 33), ] -nfc_iso14443bi_info = struct_anon_24 # /usr/include/nfc/nfc-types.h: 230 +nfc_iso14443bi_info = struct_anon_24 # /usr/include/nfc/nfc-types.h: 230 # /usr/include/nfc/nfc-types.h: 238 + + class struct_anon_25(Structure): _pack_ = 1 @@ -799,9 +934,11 @@ class struct_anon_25(Structure): ('abtUID', c_uint8 * 8), ] -nfc_iso14443b2sr_info = struct_anon_25 # /usr/include/nfc/nfc-types.h: 238 +nfc_iso14443b2sr_info = struct_anon_25 # /usr/include/nfc/nfc-types.h: 238 # /usr/include/nfc/nfc-types.h: 248 + + class struct_anon_26(Structure): _pack_ = 1 @@ -816,9 +953,11 @@ class struct_anon_26(Structure): ('btFabCode', c_uint8), ] -nfc_iso14443b2ct_info = struct_anon_26 # /usr/include/nfc/nfc-types.h: 248 +nfc_iso14443b2ct_info = struct_anon_26 # /usr/include/nfc/nfc-types.h: 248 # /usr/include/nfc/nfc-types.h: 257 + + class struct_anon_27(Structure): _pack_ = 1 @@ -831,9 +970,11 @@ class struct_anon_27(Structure): ('btId', c_uint8 * 4), ] -nfc_jewel_info = struct_anon_27 # /usr/include/nfc/nfc-types.h: 257 +nfc_jewel_info = struct_anon_27 # /usr/include/nfc/nfc-types.h: 257 # /usr/include/nfc/nfc-types.h: 272 + + class union_anon_28(Union): _pack_ = 1 @@ -858,51 +999,53 @@ class union_anon_28(Union): ('ndi', nfc_dep_info), ] -nfc_target_info = union_anon_28 # /usr/include/nfc/nfc-types.h: 272 +nfc_target_info = union_anon_28 # /usr/include/nfc/nfc-types.h: 272 -enum_anon_29 = c_int # /usr/include/nfc/nfc-types.h: 284 +enum_anon_29 = c_int # /usr/include/nfc/nfc-types.h: 284 -NBR_UNDEFINED = 0 # /usr/include/nfc/nfc-types.h: 284 +NBR_UNDEFINED = 0 # /usr/include/nfc/nfc-types.h: 284 -NBR_106 = (NBR_UNDEFINED + 1) # /usr/include/nfc/nfc-types.h: 284 +NBR_106 = (NBR_UNDEFINED + 1) # /usr/include/nfc/nfc-types.h: 284 -NBR_212 = (NBR_106 + 1) # /usr/include/nfc/nfc-types.h: 284 +NBR_212 = (NBR_106 + 1) # /usr/include/nfc/nfc-types.h: 284 -NBR_424 = (NBR_212 + 1) # /usr/include/nfc/nfc-types.h: 284 +NBR_424 = (NBR_212 + 1) # /usr/include/nfc/nfc-types.h: 284 -NBR_847 = (NBR_424 + 1) # /usr/include/nfc/nfc-types.h: 284 +NBR_847 = (NBR_424 + 1) # /usr/include/nfc/nfc-types.h: 284 -nfc_baud_rate = enum_anon_29 # /usr/include/nfc/nfc-types.h: 284 +nfc_baud_rate = enum_anon_29 # /usr/include/nfc/nfc-types.h: 284 -enum_anon_30 = c_int # /usr/include/nfc/nfc-types.h: 299 +enum_anon_30 = c_int # /usr/include/nfc/nfc-types.h: 299 -NMT_ISO14443A = 1 # /usr/include/nfc/nfc-types.h: 299 +NMT_ISO14443A = 1 # /usr/include/nfc/nfc-types.h: 299 -NMT_JEWEL = (NMT_ISO14443A + 1) # /usr/include/nfc/nfc-types.h: 299 +NMT_JEWEL = (NMT_ISO14443A + 1) # /usr/include/nfc/nfc-types.h: 299 -NMT_ISO14443B = (NMT_JEWEL + 1) # /usr/include/nfc/nfc-types.h: 299 +NMT_ISO14443B = (NMT_JEWEL + 1) # /usr/include/nfc/nfc-types.h: 299 -NMT_ISO14443BI = (NMT_ISO14443B + 1) # /usr/include/nfc/nfc-types.h: 299 +NMT_ISO14443BI = (NMT_ISO14443B + 1) # /usr/include/nfc/nfc-types.h: 299 -NMT_ISO14443B2SR = (NMT_ISO14443BI + 1) # /usr/include/nfc/nfc-types.h: 299 +NMT_ISO14443B2SR = (NMT_ISO14443BI + 1) # /usr/include/nfc/nfc-types.h: 299 -NMT_ISO14443B2CT = (NMT_ISO14443B2SR + 1) # /usr/include/nfc/nfc-types.h: 299 +NMT_ISO14443B2CT = (NMT_ISO14443B2SR + 1) # /usr/include/nfc/nfc-types.h: 299 -NMT_FELICA = (NMT_ISO14443B2CT + 1) # /usr/include/nfc/nfc-types.h: 299 +NMT_FELICA = (NMT_ISO14443B2CT + 1) # /usr/include/nfc/nfc-types.h: 299 -NMT_DEP = (NMT_FELICA + 1) # /usr/include/nfc/nfc-types.h: 299 +NMT_DEP = (NMT_FELICA + 1) # /usr/include/nfc/nfc-types.h: 299 -nfc_modulation_type = enum_anon_30 # /usr/include/nfc/nfc-types.h: 299 +nfc_modulation_type = enum_anon_30 # /usr/include/nfc/nfc-types.h: 299 -enum_anon_31 = c_int # /usr/include/nfc/nfc-types.h: 308 +enum_anon_31 = c_int # /usr/include/nfc/nfc-types.h: 308 -N_TARGET = 0 # /usr/include/nfc/nfc-types.h: 308 +N_TARGET = 0 # /usr/include/nfc/nfc-types.h: 308 -N_INITIATOR = (N_TARGET + 1) # /usr/include/nfc/nfc-types.h: 308 +N_INITIATOR = (N_TARGET + 1) # /usr/include/nfc/nfc-types.h: 308 -nfc_mode = enum_anon_31 # /usr/include/nfc/nfc-types.h: 308 +nfc_mode = enum_anon_31 # /usr/include/nfc/nfc-types.h: 308 # /usr/include/nfc/nfc-types.h: 317 + + class struct_anon_32(Structure): _pack_ = 1 @@ -915,9 +1058,11 @@ class struct_anon_32(Structure): ('nbr', nfc_baud_rate), ] -nfc_modulation = struct_anon_32 # /usr/include/nfc/nfc-types.h: 317 +nfc_modulation = struct_anon_32 # /usr/include/nfc/nfc-types.h: 317 # /usr/include/nfc/nfc-types.h: 326 + + class struct_anon_33(Structure): _pack_ = 1 @@ -930,7 +1075,7 @@ class struct_anon_33(Structure): ('nm', nfc_modulation), ] -nfc_target = struct_anon_33 # /usr/include/nfc/nfc-types.h: 326 +nfc_target = struct_anon_33 # /usr/include/nfc/nfc-types.h: 326 # /usr/include/nfc/nfc.h: 80 if hasattr(_libs['nfc'], 'nfc_init'): @@ -971,7 +1116,8 @@ class struct_anon_33(Structure): # /usr/include/nfc/nfc.h: 88 if hasattr(_libs['nfc'], 'nfc_list_devices'): nfc_list_devices = _libs['nfc'].nfc_list_devices - nfc_list_devices.argtypes = [POINTER(nfc_context), POINTER(nfc_connstring), c_size_t] + nfc_list_devices.argtypes = [ + POINTER(nfc_context), POINTER(nfc_connstring), c_size_t] nfc_list_devices.restype = c_size_t # /usr/include/nfc/nfc.h: 89 @@ -988,38 +1134,47 @@ class struct_anon_33(Structure): # /usr/include/nfc/nfc.h: 93 if hasattr(_libs['nfc'], 'nfc_initiator_init_secure_element'): - nfc_initiator_init_secure_element = _libs['nfc'].nfc_initiator_init_secure_element + nfc_initiator_init_secure_element = _libs[ + 'nfc'].nfc_initiator_init_secure_element nfc_initiator_init_secure_element.argtypes = [POINTER(nfc_device)] nfc_initiator_init_secure_element.restype = c_int # /usr/include/nfc/nfc.h: 94 if hasattr(_libs['nfc'], 'nfc_initiator_select_passive_target'): - nfc_initiator_select_passive_target = _libs['nfc'].nfc_initiator_select_passive_target - nfc_initiator_select_passive_target.argtypes = [POINTER(nfc_device), nfc_modulation, POINTER(c_uint8), c_size_t, POINTER(nfc_target)] + nfc_initiator_select_passive_target = _libs[ + 'nfc'].nfc_initiator_select_passive_target + nfc_initiator_select_passive_target.argtypes = [POINTER( + nfc_device), nfc_modulation, POINTER(c_uint8), c_size_t, POINTER(nfc_target)] nfc_initiator_select_passive_target.restype = c_int # /usr/include/nfc/nfc.h: 95 if hasattr(_libs['nfc'], 'nfc_initiator_list_passive_targets'): - nfc_initiator_list_passive_targets = _libs['nfc'].nfc_initiator_list_passive_targets - nfc_initiator_list_passive_targets.argtypes = [POINTER(nfc_device), nfc_modulation, POINTER(nfc_target), c_size_t] + nfc_initiator_list_passive_targets = _libs[ + 'nfc'].nfc_initiator_list_passive_targets + nfc_initiator_list_passive_targets.argtypes = [ + POINTER(nfc_device), nfc_modulation, POINTER(nfc_target), c_size_t] nfc_initiator_list_passive_targets.restype = c_int # /usr/include/nfc/nfc.h: 96 if hasattr(_libs['nfc'], 'nfc_initiator_poll_target'): nfc_initiator_poll_target = _libs['nfc'].nfc_initiator_poll_target - nfc_initiator_poll_target.argtypes = [POINTER(nfc_device), POINTER(nfc_modulation), c_size_t, c_uint8, c_uint8, POINTER(nfc_target)] + nfc_initiator_poll_target.argtypes = [POINTER(nfc_device), POINTER( + nfc_modulation), c_size_t, c_uint8, c_uint8, POINTER(nfc_target)] nfc_initiator_poll_target.restype = c_int # /usr/include/nfc/nfc.h: 97 if hasattr(_libs['nfc'], 'nfc_initiator_select_dep_target'): - nfc_initiator_select_dep_target = _libs['nfc'].nfc_initiator_select_dep_target - nfc_initiator_select_dep_target.argtypes = [POINTER(nfc_device), nfc_dep_mode, nfc_baud_rate, POINTER(nfc_dep_info), POINTER(nfc_target), c_int] + nfc_initiator_select_dep_target = _libs[ + 'nfc'].nfc_initiator_select_dep_target + nfc_initiator_select_dep_target.argtypes = [POINTER( + nfc_device), nfc_dep_mode, nfc_baud_rate, POINTER(nfc_dep_info), POINTER(nfc_target), c_int] nfc_initiator_select_dep_target.restype = c_int # /usr/include/nfc/nfc.h: 98 if hasattr(_libs['nfc'], 'nfc_initiator_poll_dep_target'): nfc_initiator_poll_dep_target = _libs['nfc'].nfc_initiator_poll_dep_target - nfc_initiator_poll_dep_target.argtypes = [POINTER(nfc_device), nfc_dep_mode, nfc_baud_rate, POINTER(nfc_dep_info), POINTER(nfc_target), c_int] + nfc_initiator_poll_dep_target.argtypes = [POINTER( + nfc_device), nfc_dep_mode, nfc_baud_rate, POINTER(nfc_dep_info), POINTER(nfc_target), c_int] nfc_initiator_poll_dep_target.restype = c_int # /usr/include/nfc/nfc.h: 99 @@ -1030,62 +1185,76 @@ class struct_anon_33(Structure): # /usr/include/nfc/nfc.h: 100 if hasattr(_libs['nfc'], 'nfc_initiator_transceive_bytes'): - nfc_initiator_transceive_bytes = _libs['nfc'].nfc_initiator_transceive_bytes - nfc_initiator_transceive_bytes.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8), c_size_t, c_int] + nfc_initiator_transceive_bytes = _libs[ + 'nfc'].nfc_initiator_transceive_bytes + nfc_initiator_transceive_bytes.argtypes = [POINTER(nfc_device), POINTER( + c_uint8), c_size_t, POINTER(c_uint8), c_size_t, c_int] nfc_initiator_transceive_bytes.restype = c_int # /usr/include/nfc/nfc.h: 101 if hasattr(_libs['nfc'], 'nfc_initiator_transceive_bits'): nfc_initiator_transceive_bits = _libs['nfc'].nfc_initiator_transceive_bits - nfc_initiator_transceive_bits.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8), POINTER(c_uint8), c_size_t, POINTER(c_uint8)] + nfc_initiator_transceive_bits.argtypes = [POINTER(nfc_device), POINTER( + c_uint8), c_size_t, POINTER(c_uint8), POINTER(c_uint8), c_size_t, POINTER(c_uint8)] nfc_initiator_transceive_bits.restype = c_int # /usr/include/nfc/nfc.h: 102 if hasattr(_libs['nfc'], 'nfc_initiator_transceive_bytes_timed'): - nfc_initiator_transceive_bytes_timed = _libs['nfc'].nfc_initiator_transceive_bytes_timed - nfc_initiator_transceive_bytes_timed.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8), c_size_t, POINTER(c_uint32)] + nfc_initiator_transceive_bytes_timed = _libs[ + 'nfc'].nfc_initiator_transceive_bytes_timed + nfc_initiator_transceive_bytes_timed.argtypes = [POINTER(nfc_device), POINTER( + c_uint8), c_size_t, POINTER(c_uint8), c_size_t, POINTER(c_uint32)] nfc_initiator_transceive_bytes_timed.restype = c_int # /usr/include/nfc/nfc.h: 103 if hasattr(_libs['nfc'], 'nfc_initiator_transceive_bits_timed'): - nfc_initiator_transceive_bits_timed = _libs['nfc'].nfc_initiator_transceive_bits_timed - nfc_initiator_transceive_bits_timed.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8), POINTER(c_uint8), c_size_t, POINTER(c_uint8), POINTER(c_uint32)] + nfc_initiator_transceive_bits_timed = _libs[ + 'nfc'].nfc_initiator_transceive_bits_timed + nfc_initiator_transceive_bits_timed.argtypes = [POINTER(nfc_device), POINTER( + c_uint8), c_size_t, POINTER(c_uint8), POINTER(c_uint8), c_size_t, POINTER(c_uint8), POINTER(c_uint32)] nfc_initiator_transceive_bits_timed.restype = c_int # /usr/include/nfc/nfc.h: 104 if hasattr(_libs['nfc'], 'nfc_initiator_target_is_present'): - nfc_initiator_target_is_present = _libs['nfc'].nfc_initiator_target_is_present - nfc_initiator_target_is_present.argtypes = [POINTER(nfc_device), nfc_target] + nfc_initiator_target_is_present = _libs[ + 'nfc'].nfc_initiator_target_is_present + nfc_initiator_target_is_present.argtypes = [ + POINTER(nfc_device), nfc_target] nfc_initiator_target_is_present.restype = c_int # /usr/include/nfc/nfc.h: 107 if hasattr(_libs['nfc'], 'nfc_target_init'): nfc_target_init = _libs['nfc'].nfc_target_init - nfc_target_init.argtypes = [POINTER(nfc_device), POINTER(nfc_target), POINTER(c_uint8), c_size_t, c_int] + nfc_target_init.argtypes = [ + POINTER(nfc_device), POINTER(nfc_target), POINTER(c_uint8), c_size_t, c_int] nfc_target_init.restype = c_int # /usr/include/nfc/nfc.h: 108 if hasattr(_libs['nfc'], 'nfc_target_send_bytes'): nfc_target_send_bytes = _libs['nfc'].nfc_target_send_bytes - nfc_target_send_bytes.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, c_int] + nfc_target_send_bytes.argtypes = [ + POINTER(nfc_device), POINTER(c_uint8), c_size_t, c_int] nfc_target_send_bytes.restype = c_int # /usr/include/nfc/nfc.h: 109 if hasattr(_libs['nfc'], 'nfc_target_receive_bytes'): nfc_target_receive_bytes = _libs['nfc'].nfc_target_receive_bytes - nfc_target_receive_bytes.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, c_int] + nfc_target_receive_bytes.argtypes = [ + POINTER(nfc_device), POINTER(c_uint8), c_size_t, c_int] nfc_target_receive_bytes.restype = c_int # /usr/include/nfc/nfc.h: 110 if hasattr(_libs['nfc'], 'nfc_target_send_bits'): nfc_target_send_bits = _libs['nfc'].nfc_target_send_bits - nfc_target_send_bits.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8)] + nfc_target_send_bits.argtypes = [ + POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8)] nfc_target_send_bits.restype = c_int # /usr/include/nfc/nfc.h: 111 if hasattr(_libs['nfc'], 'nfc_target_receive_bits'): nfc_target_receive_bits = _libs['nfc'].nfc_target_receive_bits - nfc_target_receive_bits.argtypes = [POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8)] + nfc_target_receive_bits.argtypes = [ + POINTER(nfc_device), POINTER(c_uint8), c_size_t, POINTER(c_uint8)] nfc_target_receive_bits.restype = c_int # /usr/include/nfc/nfc.h: 114 @@ -1138,26 +1307,32 @@ class struct_anon_33(Structure): # /usr/include/nfc/nfc.h: 122 if hasattr(_libs['nfc'], 'nfc_device_get_supported_modulation'): - nfc_device_get_supported_modulation = _libs['nfc'].nfc_device_get_supported_modulation - nfc_device_get_supported_modulation.argtypes = [POINTER(nfc_device), nfc_mode, POINTER(POINTER(nfc_modulation_type))] + nfc_device_get_supported_modulation = _libs[ + 'nfc'].nfc_device_get_supported_modulation + nfc_device_get_supported_modulation.argtypes = [ + POINTER(nfc_device), nfc_mode, POINTER(POINTER(nfc_modulation_type))] nfc_device_get_supported_modulation.restype = c_int # /usr/include/nfc/nfc.h: 123 if hasattr(_libs['nfc'], 'nfc_device_get_supported_baud_rate'): - nfc_device_get_supported_baud_rate = _libs['nfc'].nfc_device_get_supported_baud_rate - nfc_device_get_supported_baud_rate.argtypes = [POINTER(nfc_device), nfc_modulation_type, POINTER(POINTER(nfc_baud_rate))] + nfc_device_get_supported_baud_rate = _libs[ + 'nfc'].nfc_device_get_supported_baud_rate + nfc_device_get_supported_baud_rate.argtypes = [ + POINTER(nfc_device), nfc_modulation_type, POINTER(POINTER(nfc_baud_rate))] nfc_device_get_supported_baud_rate.restype = c_int # /usr/include/nfc/nfc.h: 126 if hasattr(_libs['nfc'], 'nfc_device_set_property_int'): nfc_device_set_property_int = _libs['nfc'].nfc_device_set_property_int - nfc_device_set_property_int.argtypes = [POINTER(nfc_device), nfc_property, c_int] + nfc_device_set_property_int.argtypes = [ + POINTER(nfc_device), nfc_property, c_int] nfc_device_set_property_int.restype = c_int # /usr/include/nfc/nfc.h: 127 if hasattr(_libs['nfc'], 'nfc_device_set_property_bool'): nfc_device_set_property_bool = _libs['nfc'].nfc_device_set_property_bool - nfc_device_set_property_bool.argtypes = [POINTER(nfc_device), nfc_property, c_uint8] + nfc_device_set_property_bool.argtypes = [ + POINTER(nfc_device), nfc_property, c_uint8] nfc_device_set_property_bool.restype = c_int # /usr/include/nfc/nfc.h: 130 @@ -1174,8 +1349,10 @@ class struct_anon_33(Structure): # /usr/include/nfc/nfc.h: 132 if hasattr(_libs['nfc'], 'iso14443a_locate_historical_bytes'): - iso14443a_locate_historical_bytes = _libs['nfc'].iso14443a_locate_historical_bytes - iso14443a_locate_historical_bytes.argtypes = [POINTER(c_uint8), c_size_t, POINTER(c_size_t)] + iso14443a_locate_historical_bytes = _libs[ + 'nfc'].iso14443a_locate_historical_bytes + iso14443a_locate_historical_bytes.argtypes = [ + POINTER(c_uint8), c_size_t, POINTER(c_size_t)] iso14443a_locate_historical_bytes.restype = POINTER(c_uint8) # /usr/include/nfc/nfc.h: 134 @@ -1196,8 +1373,10 @@ class struct_anon_33(Structure): # /usr/include/nfc/nfc.h: 136 if hasattr(_libs['nfc'], 'nfc_device_get_information_about'): - nfc_device_get_information_about = _libs['nfc'].nfc_device_get_information_about - nfc_device_get_information_about.argtypes = [POINTER(nfc_device), POINTER(POINTER(c_char))] + nfc_device_get_information_about = _libs[ + 'nfc'].nfc_device_get_information_about + nfc_device_get_information_about.argtypes = [ + POINTER(nfc_device), POINTER(POINTER(c_char))] nfc_device_get_information_about.restype = c_int # /usr/include/nfc/nfc.h: 139 @@ -1227,10 +1406,14 @@ class struct_anon_33(Structure): str_nfc_target.restype = c_int # /usr/include/nfc/nfc-emulation.h: 43 + + class struct_nfc_emulator(Structure): _pack_ = 1 # /usr/include/nfc/nfc-emulation.h: 53 + + class struct_nfc_emulation_state_machine(Structure): _pack_ = 1 @@ -1250,14 +1433,16 @@ class struct_nfc_emulation_state_machine(Structure): 'data', ] struct_nfc_emulation_state_machine._fields_ = [ - ('io', CFUNCTYPE(UNCHECKED(c_int), POINTER(struct_nfc_emulator), POINTER(c_uint8), c_size_t, POINTER(c_uint8), c_size_t)), + ('io', CFUNCTYPE(UNCHECKED(c_int), POINTER(struct_nfc_emulator), + POINTER(c_uint8), c_size_t, POINTER(c_uint8), c_size_t)), ('data', POINTER(None)), ] # /usr/include/nfc/nfc-emulation.h: 58 if hasattr(_libs['nfc'], 'nfc_emulate_target'): nfc_emulate_target = _libs['nfc'].nfc_emulate_target - nfc_emulate_target.argtypes = [POINTER(nfc_device), POINTER(struct_nfc_emulator), c_int] + nfc_emulate_target.argtypes = [ + POINTER(nfc_device), POINTER(struct_nfc_emulator), c_int] nfc_emulate_target.restype = c_int # /usr/include/nfc/nfc-types.h: 36 @@ -1267,6 +1452,8 @@ class struct_nfc_emulation_state_machine(Structure): pass # /usr/include/nfc/nfc.h: 62 + + def __has_attribute(x): return 0 @@ -1354,15 +1541,15 @@ def __has_attribute(x): except: pass -nfc_context = struct_nfc_context # /usr/include/nfc/nfc-types.h: 42 +nfc_context = struct_nfc_context # /usr/include/nfc/nfc-types.h: 42 -nfc_device = struct_nfc_device # /usr/include/nfc/nfc-types.h: 47 +nfc_device = struct_nfc_device # /usr/include/nfc/nfc-types.h: 47 -nfc_driver = struct_nfc_driver # /usr/include/nfc/nfc-types.h: 52 +nfc_driver = struct_nfc_driver # /usr/include/nfc/nfc-types.h: 52 -nfc_emulator = struct_nfc_emulator # /usr/include/nfc/nfc-emulation.h: 43 +nfc_emulator = struct_nfc_emulator # /usr/include/nfc/nfc-emulation.h: 43 -nfc_emulation_state_machine = struct_nfc_emulation_state_machine # /usr/include/nfc/nfc-emulation.h: 53 +# /usr/include/nfc/nfc-emulation.h: 53 +nfc_emulation_state_machine = struct_nfc_emulation_state_machine # No inserted files - From d9435eb3d2f64d1d762adc6f6b422d2e25de211b Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 10 Jun 2016 17:26:58 +0200 Subject: [PATCH 03/76] Add debug and tryouts for NXP NTag 216. The NTag 216 has a different memoty capacity and thus different array sizes are needed for read/write. --- src/mifareauth.py | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/src/mifareauth.py b/src/mifareauth.py index 2e2ce99..c663d24 100644 --- a/src/mifareauth.py +++ b/src/mifareauth.py @@ -58,6 +58,10 @@ def __init__(self, logger): def run(self): """Starts the looping thread""" + import ipdb; ipdb.set_trace() + # break 119 + # break 240 + # break 208 self.__context = ctypes.pointer(nfc.nfc_context()) nfc.nfc_init(ctypes.byref(self.__context)) loop = True @@ -109,9 +113,13 @@ def _poll_loop(self): if res < 0: raise IOError("NFC Error whilst polling") elif res >= 1: + print("_poll_loop: res = {}. nt.nti.nai.szUidLen = {}".format(res, nt.nti.nai.szUidLen)) uid = None - if nt.nti.nai.szUidLen == 4: - uid = "".join([chr(nt.nti.nai.abtUid[i]) for i in range(4)]) + uidLen = 7 + if nt.nti.nai.szUidLen == uidLen: + # uid = "".join([chr(nt.nti.nai.abtUid[i]) for i in range(uidLen)]) + uid = bytearray([nt.nti.nai.abtUid[i] for i in range(uidLen)]) + print("_poll_loop: uid = {}".format(uid)) if uid: if not ((self._card_uid and self._card_present and uid == self._card_uid) and time.mktime(time.gmtime()) <= self._card_last_seen + self.card_timeout): @@ -135,8 +143,7 @@ def select_card(self): nt = nfc.nfc_target() _ = nfc.nfc_initiator_select_passive_target( self.__device, self.__modulations[0], None, 0, ctypes.byref(nt)) - uid = "".join([chr(nt.nti.nai.abtUid[i]) - for i in range(nt.nti.nai.szUidLen)]) + uid = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)]) return uid def _setup_device(self): @@ -194,12 +201,13 @@ def _authenticate(self, block, uid, key="\xff\xff\xff\xff\xff\xff", use_b_key=Fa abttx[0] = self.MC_AUTH_A if not use_b_key else self.MC_AUTH_B abttx[1] = block for i in range(6): - abttx[i + 2] = ord(key[i]) + abttx[i + 2] = key[i] for i in range(4): - abttx[i + 8] = ord(uid[i]) + abttx[i + 8] = uid[i] abtrx = (ctypes.c_uint8 * 250)() - return nfc.nfc_initiator_transceive_bytes(self.__device, ctypes.pointer(abttx), len(abttx), + transceived = nfc.nfc_initiator_transceive_bytes(self.__device, ctypes.pointer(abttx), len(abttx), ctypes.pointer(abtrx), len(abtrx), 0) + return transceived def auth_and_read(self, block, uid, key="\xff\xff\xff\xff\xff\xff"): """Authenticates and then reads a block @@ -207,7 +215,7 @@ def auth_and_read(self, block, uid, key="\xff\xff\xff\xff\xff\xff"): Returns '' if the authentication failed """ # Reselect the card so that we can reauthenticate - self.select_card() + # self.select_card() res = self._authenticate(block, uid, key) if res >= 0: return self._read_block(block) @@ -225,15 +233,19 @@ def auth_and_write(self, block, uid, data, key="\xff\xff\xff\xff\xff\xff"): def read_card(self, uid): """Takes a uid, reads the card and return data for use in writing the card""" - key = "\xff\xff\xff\xff\xff\xff" - print("Reading card", uid.encode("hex")) + key = bytearray([0xff] * 6) + # print("Reading card", uid.encode("hex")) self._card_uid = self.select_card() self._authenticate(0x00, uid, key) block = 0 + + all_data = [] for block in range(64): data = self.auth_and_read(block, uid, key) - print(block, data.encode("hex"), "".join( - [x if x in string.printable else "." for x in data])) + # print(block, data.encode("hex"), "".join( + # [x if x in string.printable else "." for x in data])) + all_data += [data] + print("read_card: '{}'".format(''.join(all_data))) def write_card(self, uid, data): """Accepts data of the recently read card with UID uid, and writes any changes necessary to it""" From 95a2f27fb08e5ede0b9a95c9c902ed3348b1d1bf Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 20 Jun 2016 16:37:53 +0200 Subject: [PATCH 04/76] Read NTag in simplest possible script with $ python3 -m src.ntag_read --- src/__init__.py | 0 src/ntag_read.py | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/__init__.py create mode 100755 src/ntag_read.py diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ntag_read.py b/src/ntag_read.py new file mode 100755 index 0000000..801bc4f --- /dev/null +++ b/src/ntag_read.py @@ -0,0 +1,36 @@ +#! /usr/bin/env python3 + +from . import nfc +import ctypes +import binascii + +context = ctypes.pointer(nfc.nfc_context()) +nfc.nfc_init(ctypes.byref(context)) + +conn_strings = (nfc.nfc_connstring * 10)() +devices_found = nfc.nfc_list_devices(context, conn_strings, 10) + +if not devices_found: + print("No devices found") + exit(-1) + +device = nfc.nfc_open(context, conn_strings[0]) + +init = nfc.nfc_initiator_init(device) + +nt = nfc.nfc_target() + +mods = [(nfc.NMT_ISO14443A, nfc.NBR_106)] +modulations = (nfc.nfc_modulation * len(mods))() +for i in range(len(mods)): + modulations[i].nmt = mods[i][0] + modulations[i].nbr = mods[i][1] + +res = nfc.nfc_initiator_poll_target(device, modulations, len(modulations), 10, 2, ctypes.byref(nt)) + +if res < 0: + raise IOError("NFC Error whilst polling") + +uidLen = 7 +uid = bytearray([nt.nti.nai.abtUid[i] for i in range(uidLen)]) +print("uid = {}".format(binascii.hexlify(uid))) \ No newline at end of file From 4ab8017f43fc68628a919e201669d815858f4130 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 20 Jun 2016 16:38:25 +0200 Subject: [PATCH 05/76] Print UID as hex in mifareauth --- src/mifareauth.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mifareauth.py b/src/mifareauth.py index c663d24..26de5f6 100644 --- a/src/mifareauth.py +++ b/src/mifareauth.py @@ -23,6 +23,7 @@ import ctypes import string import nfc +import binascii def hex_dump(string): @@ -58,7 +59,7 @@ def __init__(self, logger): def run(self): """Starts the looping thread""" - import ipdb; ipdb.set_trace() + # import ipdb; ipdb.set_trace() # break 119 # break 240 # break 208 @@ -119,7 +120,7 @@ def _poll_loop(self): if nt.nti.nai.szUidLen == uidLen: # uid = "".join([chr(nt.nti.nai.abtUid[i]) for i in range(uidLen)]) uid = bytearray([nt.nti.nai.abtUid[i] for i in range(uidLen)]) - print("_poll_loop: uid = {}".format(uid)) + print("_poll_loop: uid = {}".format(binascii.hexlify(uid))) if uid: if not ((self._card_uid and self._card_present and uid == self._card_uid) and time.mktime(time.gmtime()) <= self._card_last_seen + self.card_timeout): From 6cd5d0e44a7602c8316c539d1b618c289d5f2c11 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 20 Jun 2016 17:07:30 +0200 Subject: [PATCH 06/76] Reading data from NTag213 sort-of works. First read actually reads only sensible data, later reads only the end part makes sense --- src/ntag_read.py | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index 801bc4f..426a094 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -4,6 +4,12 @@ import ctypes import binascii +MC_AUTH_A = 0x60 +MC_AUTH_B = 0x61 +MC_READ = 0x30 +MC_WRITE = 0xA0 +card_timeout = 10 + context = ctypes.pointer(nfc.nfc_context()) nfc.nfc_init(ctypes.byref(context)) @@ -33,4 +39,39 @@ uidLen = 7 uid = bytearray([nt.nti.nai.abtUid[i] for i in range(uidLen)]) -print("uid = {}".format(binascii.hexlify(uid))) \ No newline at end of file +print("uid = {}".format(binascii.hexlify(uid))) + +# setup device +if nfc.nfc_device_set_property_bool(device, nfc.NP_ACTIVATE_CRYPTO1, True) < 0: + raise Exception("Error setting Crypto1 enabled") +if nfc.nfc_device_set_property_bool(device, nfc.NP_INFINITE_SELECT, False) < 0: + raise Exception("Error setting Single Select option") +if nfc.nfc_device_set_property_bool(device, nfc.NP_AUTO_ISO14443_4, False) < 0: + raise Exception("Error setting No Auto ISO14443-A jiggery pokery") +if nfc.nfc_device_set_property_bool(device, nfc.NP_HANDLE_PARITY, True) < 0: + raise Exception("Error setting Easy Framing property") + +# Select card, but waits for tag the be removed and placed again +# nt = nfc.nfc_target() +# _ = nfc.nfc_initiator_select_passive_target(device, modulations[0], None, 0, ctypes.byref(nt)) +# uid = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)]) +# print("uid = {}".format(binascii.hexlify(uid))) + +# _read_block +if nfc.nfc_device_set_property_bool(device, nfc.NP_EASY_FRAMING, True) < 0: + raise Exception("Error setting Easy Framing property") + +for block in range(45): # 45 pages in NTAG213 + abttx = (ctypes.c_uint8 * 2)() # command length + abttx[0] = MC_READ + abttx[1] = block + abtrx = (ctypes.c_uint8 * 16)() # 16 is the minimum + res = nfc.nfc_initiator_transceive_bytes(device, + ctypes.pointer(abttx), len(abttx), + ctypes.pointer(abtrx), len(abtrx), + 0) + if res < 0: + raise IOError("Error reading data") + #print("".join([chr(abtrx[i]) for i in range(res)])) + + print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) \ No newline at end of file From 8daa38ad4b353da0d0ec582e1252ee5a5defb609 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 20 Jun 2016 17:10:57 +0200 Subject: [PATCH 07/76] Nicely closing and exiting --- src/ntag_read.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index 426a094..d675f2f 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -74,4 +74,8 @@ raise IOError("Error reading data") #print("".join([chr(abtrx[i]) for i in range(res)])) - print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) \ No newline at end of file + print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) + +nfc.nfc_close(device) + +nfc.nfc_exit(context) \ No newline at end of file From bc9c9791ff61b7719cd69592dc16c169f1fe67bd Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 09:05:00 +0200 Subject: [PATCH 08/76] Split read into own function to try alternative implementations --- src/ntag_read.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index d675f2f..c50443a 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -61,20 +61,26 @@ if nfc.nfc_device_set_property_bool(device, nfc.NP_EASY_FRAMING, True) < 0: raise Exception("Error setting Easy Framing property") -for block in range(45): # 45 pages in NTAG213 - abttx = (ctypes.c_uint8 * 2)() # command length - abttx[0] = MC_READ - abttx[1] = block - abtrx = (ctypes.c_uint8 * 16)() # 16 is the minimum - res = nfc.nfc_initiator_transceive_bytes(device, - ctypes.pointer(abttx), len(abttx), - ctypes.pointer(abtrx), len(abtrx), - 0) - if res < 0: - raise IOError("Error reading data") - #print("".join([chr(abtrx[i]) for i in range(res)])) - - print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) +def read_simple(pages): + for block in range(pages): # 45 pages in NTAG213 + abttx = (ctypes.c_uint8 * 2)() # command length + abttx[0] = MC_READ + abttx[1] = block + abtrx = (ctypes.c_uint8 * 16)() # 16 is the minimum + res = nfc.nfc_initiator_transceive_bytes(device, + ctypes.pointer(abttx), len(abttx), + ctypes.pointer(abtrx), len(abtrx), + 0) + if res < 0: + raise IOError("Error reading data") + #print("".join([chr(abtrx[i]) for i in range(res)])) + + print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) + +def read_like_mfultralight(pages): + pass + +read_simple(45) nfc.nfc_close(device) From 4edca595b6742e21dabe5cef8b82b93b04ae8dd1 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 10:34:40 +0200 Subject: [PATCH 09/76] Understanding more and more of this, wrapped nfc.nfc_initiator_transceive_bytes in more pythonic tranceive_bytes --- src/ntag_read.py | 156 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 138 insertions(+), 18 deletions(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index c50443a..cb1fedb 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -8,6 +8,10 @@ MC_AUTH_B = 0x61 MC_READ = 0x30 MC_WRITE = 0xA0 +MC_TRANSFER = 0xB0 +MC_DECREMENT = 0xC0 +MC_INCREMENT = 0xC1 +MC_STORE = 0xC2 card_timeout = 10 context = ctypes.pointer(nfc.nfc_context()) @@ -57,28 +61,144 @@ # uid = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)]) # print("uid = {}".format(binascii.hexlify(uid))) +def set_easy_framing(enable=True): + if nfc.nfc_device_set_property_bool(device, nfc.NP_EASY_FRAMING, enable) < 0: + raise Exception("Error setting Easy Framing property") + # _read_block -if nfc.nfc_device_set_property_bool(device, nfc.NP_EASY_FRAMING, True) < 0: - raise Exception("Error setting Easy Framing property") +set_easy_framing(True) + +# def nfc_initiator_mifare_cmd(pnd, mc, ui8Block, pmp=None): +# """ +# /** +# * @brief Execute a MIFARE Classic Command +# * @return Returns true if action was successfully performed; otherwise returns false. +# * @param pmp Some commands need additional information. This information should be supplied in the mifare_param union. +# * +# * The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number. +# * @note There are three different types of information (Authenticate, Data and Value). +# * +# * First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID. +# * They are both used to initialize the internal cipher-state of the PN53X chip. +# * After a successful authentication it will be possible to execute other commands (e.g. Read/Write). +# * The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process. +# */ +# :param pnd: nfc_device +# :param mc: mifare_command +# :param ui8Block: block to execute command on (page) +# :param pmp: mifare_param +# :return: +# """ +# abtRx = bytearray(265) +# szParamLen = 0 +# abtCmd = bytearray(265) +# abtCmd[0] = mc # The MIFARE Classic command +# abtCmd[1] = ui8Block # The block address (1K=0x00..0x39, 4K=0x00..0xff) +# +# +# if mc == MC_READ: # or MC_STORE +# szParamLen = 0 +# elif mc == MC_AUTH_A or mc == MC_AUTH_B: +# szParamLen = 10 #sizeof(struct mifare_param_auth) +# elif mc == MC_WRITE: +# szParamLen = 16 #sizeof(struct mifare_param_data) +# elif mc in [MC_DECREMENT, MC_INCREMENT, MC_TRANSFER]: +# szParamLen = 4 #sizeof(struct mifare_param_value) +# else: +# return False +# +# abtCmd[1:1+szParamLen] = pmp[szParamLen] +# +# set_easy_framing(True) +# +# res = nfc.nfc_initiator_transceive_bytes(pnd, +# abtCmd, 2+szParamLen, +# ctypes.pointer(abtRx), len(abtRx)) +# if res < 0: +# raise IOError("Error reading data") +# +# if mc == MC_READ: +# if res == 16: +# return abtRx[:16] +# else: +# print("Could not read, res={}".format(res)) +# return [] +# return [] + +# def read_like_mfultralight(pages): +# +# pagestep = 4 +# failure = False +# uiBlocks = pages +# read_pages = 0 +# print("Reading {} pages |".format(uiBlocks + 1), end='') +# +# for page in range(uiBlocks, step=pagestep): #(page = 0 page <= uiBlocks page += 4) +# print("page: %d\n", page) +# +# # Try to read out the data block +# data = nfc_initiator_mifare_cmd(device, MC_READ, page) +# +# # if (nfc_initiator_mifare_cmd(pnd, MC_READ, page, & mp)) { +# # memcpy(mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16) +# # } else { +# # bFailure = true +# # break +# # } +# +# for i in range(pagestep): +# print("{}".format({True:'.', False:'x'}[failure]), end='') +# read_pages += 1 +# print("|") +# print("Done, %d of %d pages read.\n", read_pages, uiBlocks + 1) +# +# +# return success + + def read_simple(pages): for block in range(pages): # 45 pages in NTAG213 - abttx = (ctypes.c_uint8 * 2)() # command length - abttx[0] = MC_READ - abttx[1] = block - abtrx = (ctypes.c_uint8 * 16)() # 16 is the minimum - res = nfc.nfc_initiator_transceive_bytes(device, - ctypes.pointer(abttx), len(abttx), - ctypes.pointer(abtrx), len(abtrx), - 0) - if res < 0: - raise IOError("Error reading data") - #print("".join([chr(abtrx[i]) for i in range(res)])) - - print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) - -def read_like_mfultralight(pages): - pass + # abttx = (ctypes.c_uint8 * 2)() # command length + # abttx[0] = MC_READ + # abttx[1] = block + # abtrx = (ctypes.c_uint8 * 16)() # 16 is the minimum + # res = nfc.nfc_initiator_transceive_bytes(device, + # ctypes.pointer(abttx), len(abttx), + # ctypes.pointer(abtrx), len(abtrx), + # 0) + # if res < 0: + # raise IOError("Error reading data") + # #print("".join([chr(abtrx[i]) for i in range(res)])) + # + # print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) + data = tranceive_bytes(device, [MC_READ, block], 16) + print("{:3}: {}".format(block, binascii.hexlify(data))) + +def tranceive_bytes(device, transmission, receive_length): + """ + Send the bytes in the send + :param device: The device *via* which to transmit the bytes + :param transmission: Data or command to send: + :type transmission bytes + :param receive_length: how many bytes to receive? + :type receive_length int + :return: + """ + abttx = (ctypes.c_uint8 * len(transmission))() # command length + for index, byte in enumerate(transmission): + abttx[index] = byte + + abtrx = (ctypes.c_uint8 * receive_length)() # 16 is the minimum + res = nfc.nfc_initiator_transceive_bytes(device, + ctypes.pointer(abttx), len(abttx), + ctypes.pointer(abtrx), len(abtrx), + 0) + if res < 0: + raise IOError("Error reading data") + + data = bytes(abtrx[:res]) + return data read_simple(45) From d2ffa98fde852daf5fe5bbb5093009b802a45f27 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 10:35:13 +0200 Subject: [PATCH 10/76] Removed Mifare classic code that was already outcommented --- src/ntag_read.py | 89 ------------------------------------------------ 1 file changed, 89 deletions(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index cb1fedb..d8dfd98 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -68,95 +68,6 @@ def set_easy_framing(enable=True): # _read_block set_easy_framing(True) -# def nfc_initiator_mifare_cmd(pnd, mc, ui8Block, pmp=None): -# """ -# /** -# * @brief Execute a MIFARE Classic Command -# * @return Returns true if action was successfully performed; otherwise returns false. -# * @param pmp Some commands need additional information. This information should be supplied in the mifare_param union. -# * -# * The specified MIFARE command will be executed on the tag. There are different commands possible, they all require the destination block number. -# * @note There are three different types of information (Authenticate, Data and Value). -# * -# * First an authentication must take place using Key A or B. It requires a 48 bit Key (6 bytes) and the UID. -# * They are both used to initialize the internal cipher-state of the PN53X chip. -# * After a successful authentication it will be possible to execute other commands (e.g. Read/Write). -# * The MIFARE Classic Specification (http://www.nxp.com/acrobat/other/identification/M001053_MF1ICS50_rev5_3.pdf) explains more about this process. -# */ -# :param pnd: nfc_device -# :param mc: mifare_command -# :param ui8Block: block to execute command on (page) -# :param pmp: mifare_param -# :return: -# """ -# abtRx = bytearray(265) -# szParamLen = 0 -# abtCmd = bytearray(265) -# abtCmd[0] = mc # The MIFARE Classic command -# abtCmd[1] = ui8Block # The block address (1K=0x00..0x39, 4K=0x00..0xff) -# -# -# if mc == MC_READ: # or MC_STORE -# szParamLen = 0 -# elif mc == MC_AUTH_A or mc == MC_AUTH_B: -# szParamLen = 10 #sizeof(struct mifare_param_auth) -# elif mc == MC_WRITE: -# szParamLen = 16 #sizeof(struct mifare_param_data) -# elif mc in [MC_DECREMENT, MC_INCREMENT, MC_TRANSFER]: -# szParamLen = 4 #sizeof(struct mifare_param_value) -# else: -# return False -# -# abtCmd[1:1+szParamLen] = pmp[szParamLen] -# -# set_easy_framing(True) -# -# res = nfc.nfc_initiator_transceive_bytes(pnd, -# abtCmd, 2+szParamLen, -# ctypes.pointer(abtRx), len(abtRx)) -# if res < 0: -# raise IOError("Error reading data") -# -# if mc == MC_READ: -# if res == 16: -# return abtRx[:16] -# else: -# print("Could not read, res={}".format(res)) -# return [] -# return [] - -# def read_like_mfultralight(pages): -# -# pagestep = 4 -# failure = False -# uiBlocks = pages -# read_pages = 0 -# print("Reading {} pages |".format(uiBlocks + 1), end='') -# -# for page in range(uiBlocks, step=pagestep): #(page = 0 page <= uiBlocks page += 4) -# print("page: %d\n", page) -# -# # Try to read out the data block -# data = nfc_initiator_mifare_cmd(device, MC_READ, page) -# -# # if (nfc_initiator_mifare_cmd(pnd, MC_READ, page, & mp)) { -# # memcpy(mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16) -# # } else { -# # bFailure = true -# # break -# # } -# -# for i in range(pagestep): -# print("{}".format({True:'.', False:'x'}[failure]), end='') -# read_pages += 1 -# print("|") -# print("Done, %d of %d pages read.\n", read_pages, uiBlocks + 1) -# -# -# return success - - - def read_simple(pages): for block in range(pages): # 45 pages in NTAG213 # abttx = (ctypes.c_uint8 * 2)() # command length From 1d86edd2db35ef2bb57b39c1da7b23a83e0871d7 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 10:41:10 +0200 Subject: [PATCH 11/76] Remove code moved to separate function --- src/ntag_read.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index d8dfd98..7bcb069 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -70,20 +70,7 @@ def set_easy_framing(enable=True): def read_simple(pages): for block in range(pages): # 45 pages in NTAG213 - # abttx = (ctypes.c_uint8 * 2)() # command length - # abttx[0] = MC_READ - # abttx[1] = block - # abtrx = (ctypes.c_uint8 * 16)() # 16 is the minimum - # res = nfc.nfc_initiator_transceive_bytes(device, - # ctypes.pointer(abttx), len(abttx), - # ctypes.pointer(abtrx), len(abtrx), - # 0) - # if res < 0: - # raise IOError("Error reading data") - # #print("".join([chr(abtrx[i]) for i in range(res)])) - # - # print("{:3}: {}".format(block, binascii.hexlify(bytes(abtrx[:res])))) - data = tranceive_bytes(device, [MC_READ, block], 16) + data = tranceive_bytes(device, bytes([MC_READ, block]), 16) print("{:3}: {}".format(block, binascii.hexlify(data))) def tranceive_bytes(device, transmission, receive_length): From 0d93b2c7c041c8e4284050853e6910e4543e2c5b Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 11:03:58 +0200 Subject: [PATCH 12/76] Add fucntions to read a single page of 4 bytes while the minimal read length is 16 bytes --- src/ntag_read.py | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index 7bcb069..25543fd 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -68,11 +68,6 @@ def set_easy_framing(enable=True): # _read_block set_easy_framing(True) -def read_simple(pages): - for block in range(pages): # 45 pages in NTAG213 - data = tranceive_bytes(device, bytes([MC_READ, block]), 16) - print("{:3}: {}".format(block, binascii.hexlify(data))) - def tranceive_bytes(device, transmission, receive_length): """ Send the bytes in the send @@ -98,8 +93,24 @@ def tranceive_bytes(device, transmission, receive_length): data = bytes(abtrx[:res]) return data +def read_page(device, page): + recv_data = tranceive_bytes(device, bytes([MC_READ, page]), 16) + data = recv_data[:4] # Only the first 4 bytes as a page is 4 bytes + return data + +def read_simple(pages): + for page in range(pages): # 45 pages in NTAG213 + data = read_page(device, page) + print("{:3}: {}".format(page, binascii.hexlify(data))) + read_simple(45) +def read_print(device, page, length=4): + data = tranceive_bytes(device, bytes([MC_READ, page]), 16) + if length: + data = data[:length] # Only the first $length bytes + print("{:3}: {}".format(page, binascii.hexlify(data))) + nfc.nfc_close(device) nfc.nfc_exit(context) \ No newline at end of file From d630d06e04b926119a8fdcc5b6ee28c2638b3eca Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 11:16:47 +0200 Subject: [PATCH 13/76] Can also write pages now --- src/ntag_read.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/ntag_read.py b/src/ntag_read.py index 25543fd..13941bb 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -111,6 +111,39 @@ def read_print(device, page, length=4): data = data[:length] # Only the first $length bytes print("{:3}: {}".format(page, binascii.hexlify(data))) + +def write_block(device, block, data): + """Writes a block of data to an NTag + Raises an exception on error + """ + set_easy_framing(True) + + if len(data) > 16: + raise ValueError( "Data value to be written cannot be more than 16 bytes.") + + abttx = bytearray(18) # 18 is 1 byte for command, 1 byte for block/page address, 16 for actual data + abttx[0] = MC_WRITE + abttx[1] = block + for index, byte in enumerate(data): + # abttx[i + 2] = ord((data + "\x00" * (16 - len(data)))[i]) + abttx[index + 2] = byte + # abtrx = (ctypes.c_uint8 * 250)() + # return nfc.nfc_initiator_transceive_bytes(self.__device, ctypes.pointer(abttx), len(abttx), + # ctypes.pointer(abtrx), len(abtrx), 0) + + recv = tranceive_bytes(device, bytes(abttx), 250) + return recv + +def write_page(device, page, data): + if len(data) > 4: + raise ValueError( "Data value to be written cannot be more than 4 bytes.") + return write_block(device, page, data) + +print("write: ", write_page(device, 5, bytes([0xff,0xff,0xff,0xff]))) + +read_simple(45) + + nfc.nfc_close(device) nfc.nfc_exit(context) \ No newline at end of file From ec8b171f9c3cf20adb3fe5fee4a9be62ae62f8cd Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 11:49:39 +0200 Subject: [PATCH 14/76] Writing the full user memory of an NTag 213. Some bytes seem to be locked though --- src/ntag_read.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index 13941bb..caaad35 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -4,6 +4,10 @@ import ctypes import binascii +ntag_213 = {"user_memory_start":4, "user_memory_end":39} # 4 is the first page of the user memory, 39 is the last +ntag_215 = {"user_memory_start":4, "user_memory_end":129} # 4 is the first page of the user memory, 39 is the last +ntag_216 = {"user_memory_start":4, "user_memory_end":225} # 4 is the first page of the user memory, 39 is the last + MC_AUTH_A = 0x60 MC_AUTH_B = 0x61 MC_READ = 0x30 @@ -101,15 +105,15 @@ def read_page(device, page): def read_simple(pages): for page in range(pages): # 45 pages in NTAG213 data = read_page(device, page) - print("{:3}: {}".format(page, binascii.hexlify(data))) + print("Read page {:3}: {}".format(page, binascii.hexlify(data))) -read_simple(45) +# read_simple(45) def read_print(device, page, length=4): data = tranceive_bytes(device, bytes([MC_READ, page]), 16) if length: data = data[:length] # Only the first $length bytes - print("{:3}: {}".format(page, binascii.hexlify(data))) + print("Read page {:3}: {}".format(page, binascii.hexlify(data))) def write_block(device, block, data): @@ -134,15 +138,31 @@ def write_block(device, block, data): recv = tranceive_bytes(device, bytes(abttx), 250) return recv -def write_page(device, page, data): +def write_page(device, page, data, debug=False): + if debug: + print("Write page {:3}: {}".format(page, binascii.hexlify(data))) if len(data) > 4: raise ValueError( "Data value to be written cannot be more than 4 bytes.") return write_block(device, page, data) -print("write: ", write_page(device, 5, bytes([0xff,0xff,0xff,0xff]))) +# write_page(device, 4, bytes([0xff,0xff,0xff,0xff])) +# write_page(device, 5, bytes([0xff,0xff,0xff,0xff])) +# write_page(device, 6, bytes([0xff,0xff,0xff,0xff])) -read_simple(45) +def write_user_memory(device, data, tagtype): + start = tagtype['user_memory_start'] + end = tagtype['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + + page_contents = [data[i:i+4] for i in range(0, len(data), 4)] + print("Writing {} pages".format(len(page_contents))) + for page, content in zip(range(start, end), page_contents): + write_page(device, page, content, debug=True) +write_user_memory(device, bytes([0x00] * 4 * 100), ntag_213) + +print("-" * 10) + +read_simple(45) nfc.nfc_close(device) From 9bbedaade89220178a029a1fc76d208932e57540 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 21 Jun 2016 12:57:37 +0200 Subject: [PATCH 15/76] Disabled UID ASCII Mirroring on NTag213. Also not prettyprinting hex data for easy compy/paste. Added function to read only the user data --- src/ntag_read.py | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index caaad35..2dbaa78 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -63,7 +63,7 @@ # nt = nfc.nfc_target() # _ = nfc.nfc_initiator_select_passive_target(device, modulations[0], None, 0, ctypes.byref(nt)) # uid = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)]) -# print("uid = {}".format(binascii.hexlify(uid))) +# print("uid = {}".format(uid)) def set_easy_framing(enable=True): if nfc.nfc_device_set_property_bool(device, nfc.NP_EASY_FRAMING, enable) < 0: @@ -103,9 +103,14 @@ def read_page(device, page): return data def read_simple(pages): + accumulated = [] + for page in range(pages): # 45 pages in NTAG213 data = read_page(device, page) - print("Read page {:3}: {}".format(page, binascii.hexlify(data))) + print("Read page {:3}: {}".format(page, data)) + accumulated += list(data) + + return bytes(accumulated) # read_simple(45) @@ -113,8 +118,7 @@ def read_print(device, page, length=4): data = tranceive_bytes(device, bytes([MC_READ, page]), 16) if length: data = data[:length] # Only the first $length bytes - print("Read page {:3}: {}".format(page, binascii.hexlify(data))) - + print("Read page {:3}: {}".format(page, data)) def write_block(device, block, data): """Writes a block of data to an NTag @@ -140,7 +144,7 @@ def write_block(device, block, data): def write_page(device, page, data, debug=False): if debug: - print("Write page {:3}: {}".format(page, binascii.hexlify(data))) + print("Write page {:3}: {}".format(page, data)) if len(data) > 4: raise ValueError( "Data value to be written cannot be more than 4 bytes.") return write_block(device, page, data) @@ -158,11 +162,23 @@ def write_user_memory(device, data, tagtype): for page, content in zip(range(start, end), page_contents): write_page(device, page, content, debug=True) -write_user_memory(device, bytes([0x00] * 4 * 100), ntag_213) +def read_user_memory(device, tagtype): + start = tagtype['user_memory_start'] + end = tagtype['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + + user_memory = [] + for page in range(start, end): + user_memory += list(read_page(device, page)) + + return bytes(user_memory) + + +write_page(device, 41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring +# write_user_memory(device, bytes([0x00] * 4 * 100), ntag_213) print("-" * 10) -read_simple(45) +print(read_user_memory(device, ntag_213)) nfc.nfc_close(device) From 6e802576acf33b3ad22a69851b7cb10a8bf499fc Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 13:23:25 +0200 Subject: [PATCH 16/76] Disable UID ascii mirror EM-546 --- src/ntag_read.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ntag_read.py b/src/ntag_read.py index 2dbaa78..ce9ede0 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -173,7 +173,7 @@ def read_user_memory(device, tagtype): return bytes(user_memory) -write_page(device, 41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring +write_page(device, 41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring # write_user_memory(device, bytes([0x00] * 4 * 100), ntag_213) print("-" * 10) From bf8c8595a9332f4b675bf458e5f0a511bd7d5f21 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 13:33:23 +0200 Subject: [PATCH 17/76] Move setup.py to root of repository --- setup.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 setup.py diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..db5633f --- /dev/null +++ b/setup.py @@ -0,0 +1,33 @@ +"""PyNFC distutils installer file""" + +# Pynfc is a python wrapper for the libnfc library +# Copyright (C) 2009 Mike Auty +# PyCrypto1 is based on public domain optimized code by I.C.Weiner +# See (http://cryptolib.com/ciphers/crypto1/crypto1.c) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from distutils.core import setup, Extension + +setup( + name = "pynfc", + version = "1.7.0_alpha1", + description = "Python bindings for libnfc", + author = "Mike Auty", + data_files = [('examples', ['mifareauth.py'])], + license = "GPL-2", + py_modules = ['pynfc', 'pycrypto1', 'py14443a'] +) + From f07796c75e5f5e63476b56667b6f48c3065fe34d Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 14:00:31 +0200 Subject: [PATCH 18/76] Rename module to pynfc --- setup.py | 2 +- src/ntag_read.py | 2 +- src/{nfc.py => pynfc.py} | 0 src/setup.py | 33 --------------------------------- 4 files changed, 2 insertions(+), 35 deletions(-) rename src/{nfc.py => pynfc.py} (100%) delete mode 100644 src/setup.py diff --git a/setup.py b/setup.py index db5633f..67d09a2 100644 --- a/setup.py +++ b/setup.py @@ -28,6 +28,6 @@ author = "Mike Auty", data_files = [('examples', ['mifareauth.py'])], license = "GPL-2", - py_modules = ['pynfc', 'pycrypto1', 'py14443a'] + py_modules = ['src.pynfc'] ) diff --git a/src/ntag_read.py b/src/ntag_read.py index ce9ede0..5f9daa2 100755 --- a/src/ntag_read.py +++ b/src/ntag_read.py @@ -1,6 +1,6 @@ #! /usr/bin/env python3 -from . import nfc +from . import pynfc as nfc import ctypes import binascii diff --git a/src/nfc.py b/src/pynfc.py similarity index 100% rename from src/nfc.py rename to src/pynfc.py diff --git a/src/setup.py b/src/setup.py deleted file mode 100644 index db5633f..0000000 --- a/src/setup.py +++ /dev/null @@ -1,33 +0,0 @@ -"""PyNFC distutils installer file""" - -# Pynfc is a python wrapper for the libnfc library -# Copyright (C) 2009 Mike Auty -# PyCrypto1 is based on public domain optimized code by I.C.Weiner -# See (http://cryptolib.com/ciphers/crypto1/crypto1.c) -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -from distutils.core import setup, Extension - -setup( - name = "pynfc", - version = "1.7.0_alpha1", - description = "Python bindings for libnfc", - author = "Mike Auty", - data_files = [('examples', ['mifareauth.py'])], - license = "GPL-2", - py_modules = ['pynfc', 'pycrypto1', 'py14443a'] -) - From c217151ac41a5cbd60f299eab77d9dedd6bc1a09 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 14:07:14 +0200 Subject: [PATCH 19/76] Set correct datafiles in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 67d09a2..8f9edac 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,7 @@ version = "1.7.0_alpha1", description = "Python bindings for libnfc", author = "Mike Auty", - data_files = [('examples', ['mifareauth.py'])], + data_files = [('examples', ['src/mifareauth.py', 'src/ntag_read.py'])], license = "GPL-2", py_modules = ['src.pynfc'] ) From 24e2cc217e7fe4140f3a4039aad01744c8ac8fd5 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 14:30:59 +0200 Subject: [PATCH 20/76] Rename src folder to pynfc for easy installation: sudo python(3) setup.py install --- {src => pynfc}/__init__.py | 0 {src => pynfc}/mifareauth.py | 0 {src => pynfc}/ntag_read.py | 0 {src => pynfc}/pynfc.py | 0 setup.py | 4 ++-- 5 files changed, 2 insertions(+), 2 deletions(-) rename {src => pynfc}/__init__.py (100%) rename {src => pynfc}/mifareauth.py (100%) rename {src => pynfc}/ntag_read.py (100%) rename {src => pynfc}/pynfc.py (100%) diff --git a/src/__init__.py b/pynfc/__init__.py similarity index 100% rename from src/__init__.py rename to pynfc/__init__.py diff --git a/src/mifareauth.py b/pynfc/mifareauth.py similarity index 100% rename from src/mifareauth.py rename to pynfc/mifareauth.py diff --git a/src/ntag_read.py b/pynfc/ntag_read.py similarity index 100% rename from src/ntag_read.py rename to pynfc/ntag_read.py diff --git a/src/pynfc.py b/pynfc/pynfc.py similarity index 100% rename from src/pynfc.py rename to pynfc/pynfc.py diff --git a/setup.py b/setup.py index 8f9edac..9f5026d 100644 --- a/setup.py +++ b/setup.py @@ -26,8 +26,8 @@ version = "1.7.0_alpha1", description = "Python bindings for libnfc", author = "Mike Auty", - data_files = [('examples', ['src/mifareauth.py', 'src/ntag_read.py'])], + data_files = [('examples', ['pynfc/mifareauth.py', 'pynfc/ntag_read.py'])], license = "GPL-2", - py_modules = ['src.pynfc'] + packages=['pynfc'], ) From 416927f26b377fadf256999d8e2df313ff4ce1be Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 15:06:32 +0200 Subject: [PATCH 21/76] Convert ntag_read example to OO-style instead of procedural. Allows for easier reuse outside of library --- pynfc/ntag_read.py | 329 +++++++++++++++++++++++---------------------- 1 file changed, 166 insertions(+), 163 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 5f9daa2..fd9f803 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -3,183 +3,186 @@ from . import pynfc as nfc import ctypes import binascii - -ntag_213 = {"user_memory_start":4, "user_memory_end":39} # 4 is the first page of the user memory, 39 is the last -ntag_215 = {"user_memory_start":4, "user_memory_end":129} # 4 is the first page of the user memory, 39 is the last -ntag_216 = {"user_memory_start":4, "user_memory_end":225} # 4 is the first page of the user memory, 39 is the last - -MC_AUTH_A = 0x60 -MC_AUTH_B = 0x61 -MC_READ = 0x30 -MC_WRITE = 0xA0 -MC_TRANSFER = 0xB0 -MC_DECREMENT = 0xC0 -MC_INCREMENT = 0xC1 -MC_STORE = 0xC2 -card_timeout = 10 - -context = ctypes.pointer(nfc.nfc_context()) -nfc.nfc_init(ctypes.byref(context)) - -conn_strings = (nfc.nfc_connstring * 10)() -devices_found = nfc.nfc_list_devices(context, conn_strings, 10) - -if not devices_found: - print("No devices found") - exit(-1) - -device = nfc.nfc_open(context, conn_strings[0]) - -init = nfc.nfc_initiator_init(device) - -nt = nfc.nfc_target() - -mods = [(nfc.NMT_ISO14443A, nfc.NBR_106)] -modulations = (nfc.nfc_modulation * len(mods))() -for i in range(len(mods)): - modulations[i].nmt = mods[i][0] - modulations[i].nbr = mods[i][1] - -res = nfc.nfc_initiator_poll_target(device, modulations, len(modulations), 10, 2, ctypes.byref(nt)) - -if res < 0: - raise IOError("NFC Error whilst polling") - -uidLen = 7 -uid = bytearray([nt.nti.nai.abtUid[i] for i in range(uidLen)]) -print("uid = {}".format(binascii.hexlify(uid))) - -# setup device -if nfc.nfc_device_set_property_bool(device, nfc.NP_ACTIVATE_CRYPTO1, True) < 0: - raise Exception("Error setting Crypto1 enabled") -if nfc.nfc_device_set_property_bool(device, nfc.NP_INFINITE_SELECT, False) < 0: - raise Exception("Error setting Single Select option") -if nfc.nfc_device_set_property_bool(device, nfc.NP_AUTO_ISO14443_4, False) < 0: - raise Exception("Error setting No Auto ISO14443-A jiggery pokery") -if nfc.nfc_device_set_property_bool(device, nfc.NP_HANDLE_PARITY, True) < 0: - raise Exception("Error setting Easy Framing property") - -# Select card, but waits for tag the be removed and placed again -# nt = nfc.nfc_target() -# _ = nfc.nfc_initiator_select_passive_target(device, modulations[0], None, 0, ctypes.byref(nt)) -# uid = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)]) -# print("uid = {}".format(uid)) - -def set_easy_framing(enable=True): - if nfc.nfc_device_set_property_bool(device, nfc.NP_EASY_FRAMING, enable) < 0: - raise Exception("Error setting Easy Framing property") - -# _read_block -set_easy_framing(True) - -def tranceive_bytes(device, transmission, receive_length): - """ - Send the bytes in the send - :param device: The device *via* which to transmit the bytes - :param transmission: Data or command to send: - :type transmission bytes - :param receive_length: how many bytes to receive? - :type receive_length int - :return: - """ - abttx = (ctypes.c_uint8 * len(transmission))() # command length - for index, byte in enumerate(transmission): - abttx[index] = byte - - abtrx = (ctypes.c_uint8 * receive_length)() # 16 is the minimum - res = nfc.nfc_initiator_transceive_bytes(device, - ctypes.pointer(abttx), len(abttx), - ctypes.pointer(abtrx), len(abtrx), - 0) - if res < 0: - raise IOError("Error reading data") - - data = bytes(abtrx[:res]) - return data - -def read_page(device, page): - recv_data = tranceive_bytes(device, bytes([MC_READ, page]), 16) - data = recv_data[:4] # Only the first 4 bytes as a page is 4 bytes - return data - -def read_simple(pages): - accumulated = [] - - for page in range(pages): # 45 pages in NTAG213 - data = read_page(device, page) +import enum + +NTAG_213 = {"user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last +NTAG_215 = {"user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last +NTAG_216 = {"user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last + +class Commands(enum.Enum): + MC_AUTH_A = 0x60 + MC_AUTH_B = 0x61 + MC_READ = 0x30 + MC_WRITE = 0xA0 + MC_TRANSFER = 0xB0 + MC_DECREMENT = 0xC0 + MC_INCREMENT = 0xC1 + MC_STORE = 0xC2 + +class NTagReader(object): + card_timeout = 10 + + def __init__(self): + self.context = ctypes.pointer(nfc.nfc_context()) + nfc.nfc_init(ctypes.byref(self.context)) + + conn_strings = (nfc.nfc_connstring * 10)() + devices_found = nfc.nfc_list_devices(self.context, conn_strings, 10) + + if not devices_found: + IOError("No devices found") + + self.device = nfc.nfc_open(self.context, conn_strings[0]) + _ = nfc.nfc_initiator_init(self.device) + + def setup_target(self): + nt = nfc.nfc_target() + + mods = [(nfc.NMT_ISO14443A, nfc.NBR_106)] + modulations = (nfc.nfc_modulation * len(mods))() + for i in range(len(mods)): + modulations[i].nmt = mods[i][0] + modulations[i].nbr = mods[i][1] + + res = nfc.nfc_initiator_poll_target(self.device, modulations, len(modulations), 10, 2, ctypes.byref(nt)) + + if res < 0: + raise IOError("NFC Error whilst polling") + + uidLen = 7 + uid = bytearray([nt.nti.nai.abtUid[i] for i in range(uidLen)]) + print("uid = {}".format(binascii.hexlify(uid))) + + # setup device + if nfc.nfc_device_set_property_bool(self.device, nfc.NP_ACTIVATE_CRYPTO1, True) < 0: + raise Exception("Error setting Crypto1 enabled") + if nfc.nfc_device_set_property_bool(self.device, nfc.NP_INFINITE_SELECT, False) < 0: + raise Exception("Error setting Single Select option") + if nfc.nfc_device_set_property_bool(self.device, nfc.NP_AUTO_ISO14443_4, False) < 0: + raise Exception("Error setting No Auto ISO14443-A jiggery pokery") + if nfc.nfc_device_set_property_bool(self.device, nfc.NP_HANDLE_PARITY, True) < 0: + raise Exception("Error setting Easy Framing property") + + # Select card, but waits for tag the be removed and placed again + # nt = nfc.nfc_target() + # _ = nfc.nfc_initiator_select_passive_target(self.device, modulations[0], None, 0, ctypes.byref(nt)) + # uid = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)]) + # print("uid = {}".format(uid)) + + def set_easy_framing(self, enable=True): + if nfc.nfc_device_set_property_bool(self.device, nfc.NP_EASY_FRAMING, enable) < 0: + raise Exception("Error setting Easy Framing property") + + def transceive_bytes(self, transmission, receive_length): + """ + Send the bytes in the send + :param device: The device *via* which to transmit the bytes + :param transmission: Data or command to send: + :type transmission bytes + :param receive_length: how many bytes to receive? + :type receive_length int + :return: + """ + + abttx = (ctypes.c_uint8 * len(transmission))() # command length + for index, byte in enumerate(transmission): + abttx[index] = byte + + abtrx = (ctypes.c_uint8 * receive_length)() # 16 is the minimum + res = nfc.nfc_initiator_transceive_bytes(self.device, + ctypes.pointer(abttx), len(abttx), + ctypes.pointer(abtrx), len(abtrx), + 0) + if res < 0: + raise IOError("Error reading data") + + data = bytes(abtrx[:res]) + return data + + def read_page(self, page): + recv_data = self.transceive_bytes(bytes([int(Commands.MC_READ.value), page]), 16) + data = recv_data[:4] # Only the first 4 bytes as a page is 4 bytes + return data + + def read_simple(self, pages): + self.set_easy_framing(True) + + accumulated = [] + + for page in range(pages): # 45 pages in NTAG213 + data = self.read_page(page) + print("Read page {:3}: {}".format(page, data)) + accumulated += list(data) + + return bytes(accumulated) + + def read_print(self, page, length=4): + data = self.transceive_bytes(bytes([int(Commands.MC_READ.value), page]), 16) + if length: + data = data[:length] # Only the first $length bytes print("Read page {:3}: {}".format(page, data)) - accumulated += list(data) - - return bytes(accumulated) - -# read_simple(45) - -def read_print(device, page, length=4): - data = tranceive_bytes(device, bytes([MC_READ, page]), 16) - if length: - data = data[:length] # Only the first $length bytes - print("Read page {:3}: {}".format(page, data)) - -def write_block(device, block, data): - """Writes a block of data to an NTag - Raises an exception on error - """ - set_easy_framing(True) - if len(data) > 16: - raise ValueError( "Data value to be written cannot be more than 16 bytes.") + def write_block(self, block, data): + """Writes a block of data to an NTag + Raises an exception on error + """ + self.set_easy_framing(True) - abttx = bytearray(18) # 18 is 1 byte for command, 1 byte for block/page address, 16 for actual data - abttx[0] = MC_WRITE - abttx[1] = block - for index, byte in enumerate(data): - # abttx[i + 2] = ord((data + "\x00" * (16 - len(data)))[i]) - abttx[index + 2] = byte - # abtrx = (ctypes.c_uint8 * 250)() - # return nfc.nfc_initiator_transceive_bytes(self.__device, ctypes.pointer(abttx), len(abttx), - # ctypes.pointer(abtrx), len(abtrx), 0) + if len(data) > 16: + raise ValueError( "Data value to be written cannot be more than 16 bytes.") - recv = tranceive_bytes(device, bytes(abttx), 250) - return recv + abttx = bytearray(18) # 18 is 1 byte for command, 1 byte for block/page address, 16 for actual data + abttx[0] = int(Commands.MC_WRITE.value) + abttx[1] = block + for index, byte in enumerate(data): + abttx[index + 2] = byte -def write_page(device, page, data, debug=False): - if debug: - print("Write page {:3}: {}".format(page, data)) - if len(data) > 4: - raise ValueError( "Data value to be written cannot be more than 4 bytes.") - return write_block(device, page, data) + recv = self.transceive_bytes(bytes(abttx), 250) + return recv -# write_page(device, 4, bytes([0xff,0xff,0xff,0xff])) -# write_page(device, 5, bytes([0xff,0xff,0xff,0xff])) -# write_page(device, 6, bytes([0xff,0xff,0xff,0xff])) + def write_page(self, page, data, debug=False): + if debug: + print("Write page {:3}: {}".format(page, data)) + if len(data) > 4: + raise ValueError( "Data value to be written cannot be more than 4 bytes.") + return self.write_block(page, data) -def write_user_memory(device, data, tagtype): - start = tagtype['user_memory_start'] - end = tagtype['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + def write_user_memory(self, data, tag_type): + start = tag_type['user_memory_start'] + end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value - page_contents = [data[i:i+4] for i in range(0, len(data), 4)] - print("Writing {} pages".format(len(page_contents))) - for page, content in zip(range(start, end), page_contents): - write_page(device, page, content, debug=True) + page_contents = [data[i:i+4] for i in range(0, len(data), 4)] + print("Writing {} pages".format(len(page_contents))) + for page, content in zip(range(start, end), page_contents): + self.write_page(page, content, debug=True) -def read_user_memory(device, tagtype): - start = tagtype['user_memory_start'] - end = tagtype['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + def read_user_memory(self, tag_type): + start = tag_type['user_memory_start'] + end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value - user_memory = [] - for page in range(start, end): - user_memory += list(read_page(device, page)) + user_memory = [] + for page in range(start, end): + user_memory += list(self.read_page(page)) - return bytes(user_memory) + return bytes(user_memory) + def close(self): + nfc.nfc_close(self.device) + nfc.nfc_exit(self.context) -write_page(device, 41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring -# write_user_memory(device, bytes([0x00] * 4 * 100), ntag_213) +if __name__ == "__main__": + reader = NTagReader() + reader.setup_target() + reader.set_easy_framing() -print("-" * 10) + reader.write_page(41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring + # write_user_memory(self.device, bytes([0x00] * 4 * 100), NTAG_213) + # write_page(self.device, 4, bytes([0xff,0xff,0xff,0xff])) + # write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) + # write_page(self.device, 6, bytes([0xff,0xff,0xff,0xff])) -print(read_user_memory(device, ntag_213)) + print("-" * 10) -nfc.nfc_close(device) + print(reader.read_user_memory(NTAG_213)) -nfc.nfc_exit(context) \ No newline at end of file + reader.close() From 098c95b03ccb98cf4fc685610e2166967c2d4e68 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 15:11:41 +0200 Subject: [PATCH 22/76] More apt names --- pynfc/ntag_read.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index fd9f803..7536c21 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -19,7 +19,7 @@ class Commands(enum.Enum): MC_INCREMENT = 0xC1 MC_STORE = 0xC2 -class NTagReader(object): +class NTagReadWrite(object): card_timeout = 10 def __init__(self): @@ -171,11 +171,11 @@ def close(self): nfc.nfc_exit(self.context) if __name__ == "__main__": - reader = NTagReader() - reader.setup_target() - reader.set_easy_framing() + read_writer= NTagReadWrite() + read_writer.setup_target() + read_writer.set_easy_framing() - reader.write_page(41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring + read_writer.write_page(41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring # write_user_memory(self.device, bytes([0x00] * 4 * 100), NTAG_213) # write_page(self.device, 4, bytes([0xff,0xff,0xff,0xff])) # write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) @@ -183,6 +183,6 @@ def close(self): print("-" * 10) - print(reader.read_user_memory(NTAG_213)) + print(read_writer.read_user_memory(NTAG_213)) - reader.close() + read_writer.close() From 5c421294b1d559afa2cfb338283218505d585dc0 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 15:46:40 +0200 Subject: [PATCH 23/76] Add docs and logging --- pynfc/ntag_read.py | 129 ++++++++++++++++++++++++++------------------- 1 file changed, 74 insertions(+), 55 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 7536c21..8f9a962 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -4,11 +4,15 @@ import ctypes import binascii import enum +import logging NTAG_213 = {"user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last NTAG_215 = {"user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last NTAG_216 = {"user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last +SET_CONNSTRING = 'You may need to $ export LIBNFC_DEFAULT_DEVICE="pn532_uart:/dev/ttyUSB0" ' \ + 'or edit /etc/nfc/libnfc.conf and set device.connstring in case of a failure' + class Commands(enum.Enum): MC_AUTH_A = 0x60 MC_AUTH_B = 0x61 @@ -20,22 +24,49 @@ class Commands(enum.Enum): MC_STORE = 0xC2 class NTagReadWrite(object): + """ + Allows to read/write to an NTag 21x device. + Tested with a Adafruit PN532 breakout board connected via serial over an FTDI cable + """ card_timeout = 10 - def __init__(self): - self.context = ctypes.pointer(nfc.nfc_context()) - nfc.nfc_init(ctypes.byref(self.context)) - - conn_strings = (nfc.nfc_connstring * 10)() - devices_found = nfc.nfc_list_devices(self.context, conn_strings, 10) - - if not devices_found: - IOError("No devices found") - - self.device = nfc.nfc_open(self.context, conn_strings[0]) - _ = nfc.nfc_initiator_init(self.device) + def __init__(self, logger=None): + """Initialize a ReadWrite object + :param logger: function to be called as logging. Can be import logging; logging.getLogger("ntag_read").info or simply the builtin print function. + Defaults to no logging""" + def nolog(log): + pass + self.log = logger if logger else nolog + + try: + self.context = ctypes.pointer(nfc.nfc_context()) + self.log("Created NFC library context") + nfc.nfc_init(ctypes.byref(self.context)) + self.log("Initializing NFC library") + + conn_strings = (nfc.nfc_connstring * 10)() + devices_found = nfc.nfc_list_devices(self.context, conn_strings, 10) + # import ipdb; ipdb.set_trace() + self.log("{} devices found".format(devices_found)) + + if not devices_found: + IOError("No devices found. "+SET_CONNSTRING) + else: + self.log("Using conn_string[0] = {} to get a device. {}".format(conn_strings[0].value, SET_CONNSTRING)) + + self.device = nfc.nfc_open(self.context, conn_strings[0]) + self.log("Opened device {}, initializing NFC initiator".format(self.device)) + _ = nfc.nfc_initiator_init(self.device) + self.log("NFC initiator initialized") + except IOError as error: + IOError(SET_CONNSTRING) def setup_target(self): + """ + Find a target if there is one and returns the target's UID + :return: UID of the found target + :rtype bytes + """ nt = nfc.nfc_target() mods = [(nfc.NMT_ISO14443A, nfc.NBR_106)] @@ -50,8 +81,7 @@ def setup_target(self): raise IOError("NFC Error whilst polling") uidLen = 7 - uid = bytearray([nt.nti.nai.abtUid[i] for i in range(uidLen)]) - print("uid = {}".format(binascii.hexlify(uid))) + uid = bytes([nt.nti.nai.abtUid[i] for i in range(uidLen)]) # setup device if nfc.nfc_device_set_property_bool(self.device, nfc.NP_ACTIVATE_CRYPTO1, True) < 0: @@ -63,11 +93,7 @@ def setup_target(self): if nfc.nfc_device_set_property_bool(self.device, nfc.NP_HANDLE_PARITY, True) < 0: raise Exception("Error setting Easy Framing property") - # Select card, but waits for tag the be removed and placed again - # nt = nfc.nfc_target() - # _ = nfc.nfc_initiator_select_passive_target(self.device, modulations[0], None, 0, ctypes.byref(nt)) - # uid = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)]) - # print("uid = {}".format(uid)) + return uid def set_easy_framing(self, enable=True): if nfc.nfc_device_set_property_bool(self.device, nfc.NP_EASY_FRAMING, enable) < 0: @@ -81,7 +107,7 @@ def transceive_bytes(self, transmission, receive_length): :type transmission bytes :param receive_length: how many bytes to receive? :type receive_length int - :return: + :return: whatever was received back. Should be nothing actually """ abttx = (ctypes.c_uint8 * len(transmission))() # command length @@ -100,27 +126,22 @@ def transceive_bytes(self, transmission, receive_length): return data def read_page(self, page): - recv_data = self.transceive_bytes(bytes([int(Commands.MC_READ.value), page]), 16) - data = recv_data[:4] # Only the first 4 bytes as a page is 4 bytes + """Read the bytes at the given page""" + received_data = self.transceive_bytes(bytes([int(Commands.MC_READ.value), page]), 16) + data = received_data[:4] # Only the first 4 bytes as a page is 4 bytes return data - def read_simple(self, pages): - self.set_easy_framing(True) - - accumulated = [] - - for page in range(pages): # 45 pages in NTAG213 - data = self.read_page(page) - print("Read page {:3}: {}".format(page, data)) - accumulated += list(data) + def read_user_memory(self, tag_type): + """Read the complete user memory, ie. the actual content of the tag. + Configuration bytes surrounding the user memory is omitted""" + start = tag_type['user_memory_start'] + end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value - return bytes(accumulated) + user_memory = [] + for page in range(start, end): + user_memory += list(self.read_page(page)) - def read_print(self, page, length=4): - data = self.transceive_bytes(bytes([int(Commands.MC_READ.value), page]), 16) - if length: - data = data[:length] # Only the first $length bytes - print("Read page {:3}: {}".format(page, data)) + return bytes(user_memory) def write_block(self, block, data): """Writes a block of data to an NTag @@ -148,6 +169,9 @@ def write_page(self, page, data, debug=False): return self.write_block(page, data) def write_user_memory(self, data, tag_type): + """Read the complete user memory, ie. the actual content of the tag. + Configuration bytes surrounding the user memory are omitted, given the correct tag type. + Otherwise, we cannot know where user memory start and ends""" start = tag_type['user_memory_start'] end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value @@ -156,32 +180,27 @@ def write_user_memory(self, data, tag_type): for page, content in zip(range(start, end), page_contents): self.write_page(page, content, debug=True) - def read_user_memory(self, tag_type): - start = tag_type['user_memory_start'] - end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value - - user_memory = [] - for page in range(start, end): - user_memory += list(self.read_page(page)) - - return bytes(user_memory) - def close(self): nfc.nfc_close(self.device) nfc.nfc_exit(self.context) if __name__ == "__main__": - read_writer= NTagReadWrite() - read_writer.setup_target() + logger = print # logging.getLogger("ntag_read").info + + read_writer= NTagReadWrite(logger) + + uid = read_writer.setup_target() + print("uid = {}".format(binascii.hexlify(uid))) + read_writer.set_easy_framing() - read_writer.write_page(41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring - # write_user_memory(self.device, bytes([0x00] * 4 * 100), NTAG_213) - # write_page(self.device, 4, bytes([0xff,0xff,0xff,0xff])) - # write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) - # write_page(self.device, 6, bytes([0xff,0xff,0xff,0xff])) + # read_writer.write_page(41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring + # read_writer.write_user_memory(self.device, bytes([0x00] * 4 * 100), NTAG_213) + # read_writer.write_page(self.device, 4, bytes([0xff,0xff,0xff,0xff])) + # read_writer.write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) + # read_writer.write_page(self.device, 6, bytes([0xff,0xff,0xff,0xff])) - print("-" * 10) + # print("-" * 10) print(read_writer.read_user_memory(NTAG_213)) From f2283d45e448cb82e9174c66bd17ea31e5abf4f5 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 22 Jun 2016 16:16:58 +0200 Subject: [PATCH 24/76] Handier importing --- pynfc/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pynfc/__init__.py b/pynfc/__init__.py index e69de29..b37383f 100644 --- a/pynfc/__init__.py +++ b/pynfc/__init__.py @@ -0,0 +1 @@ +from .ntag_read import * \ No newline at end of file From 563eed650afa2efe4fd1a1cc40e2a6ca289a4a97 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 23 Jun 2016 09:35:32 +0200 Subject: [PATCH 25/76] Make the tag types an Enum --- pynfc/ntag_read.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 8f9a962..43373ab 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -6,9 +6,10 @@ import enum import logging -NTAG_213 = {"user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last -NTAG_215 = {"user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last -NTAG_216 = {"user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last +class TagType(enum.Enum): + NTAG_213 = {"user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last + NTAG_215 = {"user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last + NTAG_216 = {"user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last SET_CONNSTRING = 'You may need to $ export LIBNFC_DEFAULT_DEVICE="pn532_uart:/dev/ttyUSB0" ' \ 'or edit /etc/nfc/libnfc.conf and set device.connstring in case of a failure' @@ -195,13 +196,13 @@ def close(self): read_writer.set_easy_framing() # read_writer.write_page(41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring - # read_writer.write_user_memory(self.device, bytes([0x00] * 4 * 100), NTAG_213) + # read_writer.write_user_memory(self.device, bytes([0x00] * 4 * 100), TagType.NTAG_213.value) # read_writer.write_page(self.device, 4, bytes([0xff,0xff,0xff,0xff])) # read_writer.write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) # read_writer.write_page(self.device, 6, bytes([0xff,0xff,0xff,0xff])) # print("-" * 10) - print(read_writer.read_user_memory(NTAG_213)) + print(read_writer.read_user_memory(tag_type=TagType.NTAG_213.value)) read_writer.close() From c21992c55bb06de5d5ed770f9a96c15ed773ebcb Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 23 Jun 2016 09:47:34 +0200 Subject: [PATCH 26/76] Pass the enum itself and not the value of the members --- pynfc/ntag_read.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 43373ab..dece99b 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -135,8 +135,8 @@ def read_page(self, page): def read_user_memory(self, tag_type): """Read the complete user memory, ie. the actual content of the tag. Configuration bytes surrounding the user memory is omitted""" - start = tag_type['user_memory_start'] - end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + start = tag_type.value['user_memory_start'] + end = tag_type.value['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value user_memory = [] for page in range(start, end): @@ -173,8 +173,8 @@ def write_user_memory(self, data, tag_type): """Read the complete user memory, ie. the actual content of the tag. Configuration bytes surrounding the user memory are omitted, given the correct tag type. Otherwise, we cannot know where user memory start and ends""" - start = tag_type['user_memory_start'] - end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + start = tag_type.value['user_memory_start'] + end = tag_type.value['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value page_contents = [data[i:i+4] for i in range(0, len(data), 4)] print("Writing {} pages".format(len(page_contents))) @@ -203,6 +203,6 @@ def close(self): # print("-" * 10) - print(read_writer.read_user_memory(tag_type=TagType.NTAG_213.value)) + print(read_writer.read_user_memory(tag_type=TagType.NTAG_213)) read_writer.close() From e24b9fbd22b97a6e9b6cfa8303a82696d0df39b3 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 23 Jun 2016 10:49:28 +0200 Subject: [PATCH 27/76] Also use self.log rather than print when writing --- pynfc/ntag_read.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index dece99b..ce2089b 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -177,7 +177,7 @@ def write_user_memory(self, data, tag_type): end = tag_type.value['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value page_contents = [data[i:i+4] for i in range(0, len(data), 4)] - print("Writing {} pages".format(len(page_contents))) + self.log("Writing {} pages".format(len(page_contents))) for page, content in zip(range(start, end), page_contents): self.write_page(page, content, debug=True) From cf7c933df5d3c98af5947055381c296fb434dc4f Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 23 Jun 2016 10:51:59 +0200 Subject: [PATCH 28/76] Write debugging is options for all user memory --- pynfc/ntag_read.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index ce2089b..ce84252 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -169,7 +169,7 @@ def write_page(self, page, data, debug=False): raise ValueError( "Data value to be written cannot be more than 4 bytes.") return self.write_block(page, data) - def write_user_memory(self, data, tag_type): + def write_user_memory(self, data, tag_type, debug=False): """Read the complete user memory, ie. the actual content of the tag. Configuration bytes surrounding the user memory are omitted, given the correct tag type. Otherwise, we cannot know where user memory start and ends""" @@ -179,7 +179,7 @@ def write_user_memory(self, data, tag_type): page_contents = [data[i:i+4] for i in range(0, len(data), 4)] self.log("Writing {} pages".format(len(page_contents))) for page, content in zip(range(start, end), page_contents): - self.write_page(page, content, debug=True) + self.write_page(page, content, debug) def close(self): nfc.nfc_close(self.device) From c01036d0cdf1ecffb8a396c4c1cba1e23db97dcc Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 24 Jun 2016 09:10:14 +0200 Subject: [PATCH 29/76] Do not silently write only a portion of the data but raise exception when tag too small for data --- pynfc/ntag_read.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index ce84252..797e357 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -175,8 +175,15 @@ def write_user_memory(self, data, tag_type, debug=False): Otherwise, we cannot know where user memory start and ends""" start = tag_type.value['user_memory_start'] end = tag_type.value['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + mem_size = (end-start) page_contents = [data[i:i+4] for i in range(0, len(data), 4)] + content_size = len(page_contents) + + if content_size > mem_size: + raise ValueError("{type} user memory ({mem_size} 4-byte pages) too small for content ({content_size} 4-byte pages)". + format(type=tag_type, mem_size=mem_size, content_size=content_size)) + self.log("Writing {} pages".format(len(page_contents))) for page, content in zip(range(start, end), page_contents): self.write_page(page, content, debug) From c6045b7e9b69694d60734d0a23d2e75a880b2c0c Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 24 Jun 2016 11:40:38 +0200 Subject: [PATCH 30/76] Listing UIDs if multiple tags are present --- pynfc/ntag_read.py | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 797e357..cd2d5e4 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -39,6 +39,12 @@ def nolog(log): pass self.log = logger if logger else nolog + mods = [(nfc.NMT_ISO14443A, nfc.NBR_106)] + self.modulations = (nfc.nfc_modulation * len(mods))() + for i in range(len(mods)): + self.modulations[i].nmt = mods[i][0] + self.modulations[i].nbr = mods[i][1] + try: self.context = ctypes.pointer(nfc.nfc_context()) self.log("Created NFC library context") @@ -62,6 +68,23 @@ def nolog(log): except IOError as error: IOError(SET_CONNSTRING) + def list_targets(self, max_targets=10): + """ + List the targets detected by the device + :param max_targets: amount of targets to maximally find + :return: list of bytes with the found UIDs + """ + targets = (nfc.nfc_target * max_targets)() + count = nfc.nfc_initiator_list_passive_targets(self.device, self.modulations[0], targets, len(targets)) + + uids = [] + for index in range(count): + uidLen = 7 + uid = bytes([targets[index].nti.nai.abtUid[i] for i in range(uidLen)]) + uids += [uid] + + return uids + def setup_target(self): """ Find a target if there is one and returns the target's UID @@ -70,13 +93,7 @@ def setup_target(self): """ nt = nfc.nfc_target() - mods = [(nfc.NMT_ISO14443A, nfc.NBR_106)] - modulations = (nfc.nfc_modulation * len(mods))() - for i in range(len(mods)): - modulations[i].nmt = mods[i][0] - modulations[i].nbr = mods[i][1] - - res = nfc.nfc_initiator_poll_target(self.device, modulations, len(modulations), 10, 2, ctypes.byref(nt)) + res = nfc.nfc_initiator_poll_target(self.device, self.modulations, len(self.modulations), 10, 2, ctypes.byref(nt)) if res < 0: raise IOError("NFC Error whilst polling") @@ -195,7 +212,13 @@ def close(self): if __name__ == "__main__": logger = print # logging.getLogger("ntag_read").info - read_writer= NTagReadWrite(logger) + read_writer = NTagReadWrite(logger) + + uids = read_writer.list_targets() + if len(uids) > 1: + print("Found {count} uids: {uids}. Please remove all but one from the device".format(count=len(uids), uids=uids)) + exit(-1) + uid = read_writer.setup_target() print("uid = {}".format(binascii.hexlify(uid))) From 20c16d450e69ac8143127eec71bafbd5f56c61c5 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 19 Jul 2016 10:48:07 +0200 Subject: [PATCH 31/76] Busy implementing password protection and authentication. Borked 1 tag so far --- pynfc/ntag_read.py | 141 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 11 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index cd2d5e4..6fe4a4b 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -15,14 +15,15 @@ class TagType(enum.Enum): 'or edit /etc/nfc/libnfc.conf and set device.connstring in case of a failure' class Commands(enum.Enum): - MC_AUTH_A = 0x60 - MC_AUTH_B = 0x61 + MC_GET_VERSION = 0x60 MC_READ = 0x30 - MC_WRITE = 0xA0 - MC_TRANSFER = 0xB0 - MC_DECREMENT = 0xC0 - MC_INCREMENT = 0xC1 - MC_STORE = 0xC2 + MC_FAST_READ = 0x3a + MC_WRITE = 0xA2 + MC_COMPATIBILITY_WRITE = 0xA0 + MC_READ_CNT = 0x39 + MC_PWD_AUTH = 0x1b + MC_READ_SIG = 0x3c + class NTagReadWrite(object): """ @@ -171,7 +172,7 @@ def write_block(self, block, data): raise ValueError( "Data value to be written cannot be more than 16 bytes.") abttx = bytearray(18) # 18 is 1 byte for command, 1 byte for block/page address, 16 for actual data - abttx[0] = int(Commands.MC_WRITE.value) + abttx[0] = int(Commands.MC_COMPATIBILITY_WRITE.value) abttx[1] = block for index, byte in enumerate(data): abttx[index + 2] = byte @@ -205,6 +206,104 @@ def write_user_memory(self, data, tag_type, debug=False): for page, content in zip(range(start, end), page_contents): self.write_page(page, content, debug) + def authenticate(self, password, acknowledge=b'\x00\x00'): + """After issuesing this command correctly, the tag goes into the Authenticated-state, + during which the protected bytes can be written + :param password the 4-byte password with which the tag is protected + :type password bytes + :param acknowledge the 2 Password ACKnowledge bytes. If these are received, the password was correct + :returns whether the password was correct or not + :rtype bool""" + self.set_easy_framing(True) + + if len(password) != 4: + raise ValueError( "Password must be 4 bytes") + + if len(acknowledge) != 2: + raise ValueError( "Password ACKnowledge must be 2 bytes") + + cmd = int(Commands.MC_PWD_AUTH.value) + + ctypes_key = (ctypes.c_uint8 * len(password))() # command length + for index, byte in enumerate(password): + ctypes_key[index] = byte + + crc = (ctypes.c_uint8 * 2)() + + nfc.iso14443a_crc(ctypes.pointer(ctypes_key), len(password), ctypes.pointer(crc)) + + abttx = bytes([cmd]) + password + bytes(crc) + + recv = self.transceive_bytes(bytes(abttx), 16) + + return recv == acknowledge + + def set_password(self, tag_type, password=b'\xff\xff\xff\xff', acknowledge=b'\x00\x00', max_attempts=None, + also_read=False, auth_from=0xFF, lock_config=False, enable_counter=False, protect_counter=False): + """ + + The AUTH0-byte (byte 3 on page 0x29/0x83/0xE3 for resp Ntag 213,215,216) defines the page address from which the password verification is required. + 0xFF effectively disables it + + The ACCESS-byte (byte 0 on page 0x2A/0x84/0xE4 for resp Ntag 213,215,216) consists of some bitfields: + - 7: PROT: 0 = write access is password protected, 1 = read and write are is password protected + - 6: CGFLCK: Write locking bit for the user configuration + - 5: RFUI (reserved for future use) + - 4: NFC_CNT_EN: NFC counter configuration + - 3: NFC_CNT_PWD_PROT: NFC counter password protection + - 2,1,0: AUTHLIM: Limitation of negative password verification attempts + + The PACK-bytes in the PACK-page have a 16-bit password acknowledge used during the password verification process + + Password protected is needed to prevent the user from accidentally writing the tag with a NFC enabled phone. + With a password, writing is still possible but needs to be deliberate. + The password must thus protect writing only, but for the whole tag so the start page in AUTH0 must be 0 + There's no need to lock the user configuration (i.e. these bytes generated here), so CGFLCK=0 + """ + cfg0_page = tag_type.value['user_memory_end'] + 2 + cfg1_page = cfg0_page + 1 + pwd_page = cfg1_page + 1 + pack_page = pwd_page + 1 + + cfg0 = bytearray(self.read_page(cfg0_page)) + # [MIRROR, rfui, MIRROR_PAGE, AUTH0], so we overwrite + cfg0[3] = auth_from + + access = 0b00000000 + + prot = 0b10000000 if also_read else 0b00000000 + access |= prot + + cfglck = 0b01000000 if lock_config else 0b00000000 + access |= cfglck + + nfc_cnt_en = 0b00010000 if enable_counter else 0b00000000 + access |= nfc_cnt_en + + nfc_cnt_pwd_prot = 0b00001000 if protect_counter else 0b00000000 + access |= nfc_cnt_pwd_prot + + if max_attempts and max_attempts > 7: + raise ValueError("Max_attempts can be set to 7 at most (0b111) ") + + authlim = max_attempts if max_attempts != None else 0b000 # 3 bit field, at the end of the byte so no shifting is needed + access |= authlim + + # ACCESS, rfui, rfui, rfui + cfg1 = [access, 0b00000000, 0b00000000, 0b00000000] + + # Password + pwd = password + + # [PACK, PACK, rfui, rfui + pack = acknowledge + bytes([0b00000000, 0b00000000]) # unused + + self.write_page(pack_page, pack) + self.write_page(pwd_page, pwd) + self.write_page(cfg1_page, cfg1) + self.write_page(cfg0_page, cfg0) + + def close(self): nfc.nfc_close(self.device) nfc.nfc_exit(self.context) @@ -219,6 +318,8 @@ def close(self): print("Found {count} uids: {uids}. Please remove all but one from the device".format(count=len(uids), uids=uids)) exit(-1) + tt = TagType.NTAG_216 + testpage = 200 # Must be available on the chosen tag type. uid = read_writer.setup_target() print("uid = {}".format(binascii.hexlify(uid))) @@ -229,10 +330,28 @@ def close(self): # read_writer.write_user_memory(self.device, bytes([0x00] * 4 * 100), TagType.NTAG_213.value) # read_writer.write_page(self.device, 4, bytes([0xff,0xff,0xff,0xff])) # read_writer.write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) - # read_writer.write_page(self.device, 6, bytes([0xff,0xff,0xff,0xff])) - # print("-" * 10) - print(read_writer.read_user_memory(tag_type=TagType.NTAG_213)) + read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # Now, this page is writable + + print(read_writer.read_user_memory(tag_type=tt)) + + password = bytes([1, 2, 3, 4]) + ack = bytes([0xaa, 0xaa]) + + import ipdb; ipdb.set_trace() + read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) + + read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore + + try: + read_writer.authenticate(password=password, acknowledge=ack) + + read_writer.write_page(testpage, bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again + except: pass + + print(read_writer.read_user_memory(tag_type=tt)) + + read_writer.set_password(tt) # Default arguments set to default state, clearing the password read_writer.close() From b963aadce182bcf92edd3282e32fd14d40bbb019 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 19 Jul 2016 14:55:56 +0200 Subject: [PATCH 32/76] Busy making authentication work. Not much progress but did some investigation --- pynfc/ntag_read.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 6fe4a4b..a5dcb85 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -207,14 +207,28 @@ def write_user_memory(self, data, tag_type, debug=False): self.write_page(page, content, debug) def authenticate(self, password, acknowledge=b'\x00\x00'): - """After issuesing this command correctly, the tag goes into the Authenticated-state, + """After issuing this command correctly, the tag goes into the Authenticated-state, during which the protected bytes can be written :param password the 4-byte password with which the tag is protected :type password bytes :param acknowledge the 2 Password ACKnowledge bytes. If these are received, the password was correct :returns whether the password was correct or not :rtype bool""" - self.set_easy_framing(True) + + # With easy framing enabled, there will be an "Application level error". + # With easy-framing disabled, 'Chip error: "Timeout" (01), returned error: "RF Transmission Error" (-20))' + # The PWD_AUTH command can have a timeout of max. 5ms. + # With the timeout in tranceive_bytes set to: + # 0ms: "Chip error: "Timeout" (01), returned error: "RF Transmission Error" (-20))", + # 1ms, "libnfc.bus.uart Timeout!" even before authenticating, its simply too short + # 5ms, "libnfc.bus.uart Timeout!" even before authenticating, its simply too short + # 10ms, "libnfc.bus.uart Timeout!" + # 100ms: "Chip error: "Timeout" (01), returned error: "RF Transmission Error" (-20))", + # Which would indicate the wait for the UART is long enough (also the default). + # But, this sets the timeout for the communication between host and PN532, not between PN532 and NTag. + # On the other hand, this 5ms is the same for reading, to there should not be a need to set a different timeout + # for PN532-to-NTag communication. + self.set_easy_framing(False) if len(password) != 4: raise ValueError( "Password must be 4 bytes") @@ -332,23 +346,21 @@ def close(self): # read_writer.write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) - read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # Now, this page is writable + # read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # Now, this page is writable print(read_writer.read_user_memory(tag_type=tt)) password = bytes([1, 2, 3, 4]) ack = bytes([0xaa, 0xaa]) - import ipdb; ipdb.set_trace() - read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) + # import ipdb; ipdb.set_trace() + # read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) - read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore + # read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore - try: - read_writer.authenticate(password=password, acknowledge=ack) + read_writer.authenticate(password=password, acknowledge=ack) - read_writer.write_page(testpage, bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again - except: pass + read_writer.write_page(testpage, bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again print(read_writer.read_user_memory(tag_type=tt)) From 9206c4eb4216f07681907d717ec660f1b3d5676e Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 20 Jul 2016 09:31:56 +0200 Subject: [PATCH 33/76] D'oh! I appended the CRC of the password, which libnfc/pynfc already does for me internally. The __main__ now works, with libnfc loglevel = 3 (debug) --- pynfc/ntag_read.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index a5dcb85..d3fff47 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -246,7 +246,7 @@ def authenticate(self, password, acknowledge=b'\x00\x00'): nfc.iso14443a_crc(ctypes.pointer(ctypes_key), len(password), ctypes.pointer(crc)) - abttx = bytes([cmd]) + password + bytes(crc) + abttx = bytes([cmd]) + password recv = self.transceive_bytes(bytes(abttx), 16) @@ -346,17 +346,16 @@ def close(self): # read_writer.write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) - # read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # Now, this page is writable + read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # Now, this page is writable print(read_writer.read_user_memory(tag_type=tt)) password = bytes([1, 2, 3, 4]) ack = bytes([0xaa, 0xaa]) - # import ipdb; ipdb.set_trace() - # read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) + read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) - # read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore + read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore read_writer.authenticate(password=password, acknowledge=ack) From 7cf17f1b8f5cfb57c8dc191174ff010f227e77db Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 20 Jul 2016 10:58:51 +0200 Subject: [PATCH 34/76] Testing password protection. Somehow, I can write to the target after setting a password but not authenticating. If I re-start the connection, I cannot read anything from the target and get a Timeout error: Chip error: "Timeout" (01), returned error: "RF Transmission Error" (-20)) --- pynfc/ntag_read.py | 129 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 105 insertions(+), 24 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index d3fff47..578db9e 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -317,8 +317,8 @@ def set_password(self, tag_type, password=b'\xff\xff\xff\xff', acknowledge=b'\x0 self.write_page(cfg1_page, cfg1) self.write_page(cfg0_page, cfg0) - def close(self): + nfc.nfc_idle(self.device) nfc.nfc_close(self.device) nfc.nfc_exit(self.context) @@ -335,34 +335,115 @@ def close(self): tt = TagType.NTAG_216 testpage = 200 # Must be available on the chosen tag type. - uid = read_writer.setup_target() - print("uid = {}".format(binascii.hexlify(uid))) - - read_writer.set_easy_framing() - - # read_writer.write_page(41, bytes([0b0000000, 0b00000000, 0b00000000, 0xFF])) # Disable ascii UID mirroring - # read_writer.write_user_memory(self.device, bytes([0x00] * 4 * 100), TagType.NTAG_213.value) - # read_writer.write_page(self.device, 4, bytes([0xff,0xff,0xff,0xff])) - # read_writer.write_page(self.device, 5, bytes([0xff,0xff,0xff,0xff])) - - - read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # Now, this page is writable - - print(read_writer.read_user_memory(tag_type=tt)) - password = bytes([1, 2, 3, 4]) ack = bytes([0xaa, 0xaa]) - read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) - - read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore - - read_writer.authenticate(password=password, acknowledge=ack) - read_writer.write_page(testpage, bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again + uid = read_writer.setup_target() + print("uid = {}".format(binascii.hexlify(uid))) - print(read_writer.read_user_memory(tag_type=tt)) + read_writer.set_easy_framing() - read_writer.set_password(tt) # Default arguments set to default state, clearing the password + # Below, we'll test and demonstrate the behavior of password protection against writing + # The tag is supposed to start with no password protection configured, as the factory default is. + # This is also how the tag should end, eventually + # + # 1: The test starts by writing to a page, which should be OK because there is not password protection. + # 2: This is verified by reading the data again + # + # 3: Then, we set a password, after which we close the connection so make sure we start over with the tag in its idle state + # + # 4: Without authenticating with this password, we try writing again. This should fail, as we are not authenticated + # 5: We verify that the write was unsuccessful: the page should still have its old content + # + # 6: We authenticate ourselves + # + # 7: And try to write again, which should be allowed since we are now authenticated + # 8: Again, this is verified + # + # 9: Lastly, we clear the password and the protection to their default states, so the test is repeatable. + + # 1 + try: + read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # With no password set, this page is writable + except OSError as e: + print("ERROR 1: Could not write test page: {err}".format(err=e)) + exit() + + # 2 + try: + current_test_content = read_writer.read_page(testpage) + if current_test_content != bytes([0xff,0xff,0xff,0xff]): + print("ERROR: The test page was not written") + except OSError as e: + print("ERROR 2: Could not read test page: {err}".format(err=e)) + exit() + + # 3 + try: + read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) + except OSError as e: + print("ERROR 3: Could not set a password") + + # Close this connection, so we definitely need to re-authenticate + # # import ipdb; ipdb.set_trace() + # read_writer.close() + # del read_writer + # + # read_writer = NTagReadWrite(logger) + # uids = read_writer.list_targets() + # read_writer.setup_target() + # read_writer.set_easy_framing() + + # 4 + try: + read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore + except OSError as e: + print("OK: Could (correctly) not write test page, because we just set a password and now this page is password locked: {err}".format(err=e)) + + # 5 + try: + current_test_content = read_writer.read_page(testpage) + if current_test_content != bytes([0xff, 0xff, 0xff, 0xff]): + print("ERROR 5: The test page was changed while password protected and not authenticated") + if current_test_content == bytes([0x00,0x00,0x00,0x00]): + print("\tThe test page was overwritten with what we wrote without authentication") + else: + print("OK: the test page could not be written after a password was required and not authenticated") + except OSError as e: + print("ERROR 5: Could not read test page: {err}".format(err=e)) + exit() + + # 6 + try: + read_writer.authenticate(password=password, acknowledge=ack) + except OSError as e: + print("ERROR 6: Could not authenticate: {err}".format(err=e)) + + # 7 + try: + read_writer.write_page(testpage, bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again + except OSError as e: + print("ERROR 7: Could not write test page: {err}".format(err=e)) + + # 8 + try: + current_test_content = read_writer.read_page(testpage) + if current_test_content != bytes([0xaa, 0xaa, 0xaa, 0xaa]): + print("ERROR 8: The test page was not written after authentication") + except OSError as e: + print("ERROR 8: Could not read test page: {err}".format(err=e)) + exit() + + # 9 + try: + read_writer.set_password(tt) # Default arguments set to default state, clearing the password + except OSError as e: + print("ERROR 9: Could not clear password") + + # import ipdb; ipdb.set_trace() read_writer.close() + del read_writer + + print("Test completed") From 4b0347b0f79438f7b81dfea26716337f5181c3e4 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 20 Jul 2016 11:24:21 +0200 Subject: [PATCH 35/76] Test that we can read after setting password --- pynfc/ntag_read.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 578db9e..0614ce7 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -353,8 +353,9 @@ def close(self): # 2: This is verified by reading the data again # # 3: Then, we set a password, after which we close the connection so make sure we start over with the tag in its idle state + # 3a: Check that we can still read # - # 4: Without authenticating with this password, we try writing again. This should fail, as we are not authenticated + # 4: Without authenticating with the password, we try writing again. This should fail, as we are not authenticated # 5: We verify that the write was unsuccessful: the page should still have its old content # # 6: We authenticate ourselves @@ -396,6 +397,15 @@ def close(self): # read_writer.setup_target() # read_writer.set_easy_framing() + # 3a + try: + current_test_content = read_writer.read_page(testpage) + if current_test_content != bytes([0xff, 0xff, 0xff, 0xff]): + print("ERROR 3b: The test page was changed after setting password but before writing") + except OSError as e: + print("ERROR 3b: Could not read test page after setting password: {err}".format(err=e)) + exit() + # 4 try: read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore From cd8c36c7ed2c4c586b8686812e456c1780668176 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 20 Jul 2016 11:43:08 +0200 Subject: [PATCH 36/76] Add confirmation messages after successfull steps as well. Also: try to clear password before starting this test --- pynfc/ntag_read.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 0614ce7..7c6a9d8 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -342,9 +342,15 @@ def close(self): uid = read_writer.setup_target() print("uid = {}".format(binascii.hexlify(uid))) + try: + read_writer.authenticate(password=password, acknowledge=ack) + read_writer.set_password(tt) + except: pass + read_writer.set_easy_framing() + # Below, we'll test and demonstrate the behavior of password protection against writing # The tag is supposed to start with no password protection configured, as the factory default is. # This is also how the tag should end, eventually @@ -368,6 +374,7 @@ def close(self): # 1 try: read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # With no password set, this page is writable + print(" OK 1: Can write page when no password set") except OSError as e: print("ERROR 1: Could not write test page: {err}".format(err=e)) exit() @@ -377,6 +384,7 @@ def close(self): current_test_content = read_writer.read_page(testpage) if current_test_content != bytes([0xff,0xff,0xff,0xff]): print("ERROR: The test page was not written") + print(" OK 2: Can read page when no password set") except OSError as e: print("ERROR 2: Could not read test page: {err}".format(err=e)) exit() @@ -384,6 +392,7 @@ def close(self): # 3 try: read_writer.set_password(tt, password=password, acknowledge=ack, auth_from=testpage) + print(" OK 3: password protection set") except OSError as e: print("ERROR 3: Could not set a password") @@ -402,6 +411,8 @@ def close(self): current_test_content = read_writer.read_page(testpage) if current_test_content != bytes([0xff, 0xff, 0xff, 0xff]): print("ERROR 3b: The test page was changed after setting password but before writing") + print(" OK 3b: Can read page after setting password") + except OSError as e: print("ERROR 3b: Could not read test page after setting password: {err}".format(err=e)) exit() @@ -410,7 +421,7 @@ def close(self): try: read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore except OSError as e: - print("OK: Could (correctly) not write test page, because we just set a password and now this page is password locked: {err}".format(err=e)) + print(" OK 4: Could (correctly) not write test page, because we just set a password and now this page is password locked: {err}".format(err=e)) # 5 try: @@ -420,7 +431,7 @@ def close(self): if current_test_content == bytes([0x00,0x00,0x00,0x00]): print("\tThe test page was overwritten with what we wrote without authentication") else: - print("OK: the test page could not be written after a password was required and not authenticated") + print(" OK 5: the test page could not be written after a password was required and not authenticated") except OSError as e: print("ERROR 5: Could not read test page: {err}".format(err=e)) exit() @@ -428,12 +439,14 @@ def close(self): # 6 try: read_writer.authenticate(password=password, acknowledge=ack) + print(" OK 6: authentication successful") except OSError as e: print("ERROR 6: Could not authenticate: {err}".format(err=e)) # 7 try: read_writer.write_page(testpage, bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again + print(" OK 7: write after authentication successful") except OSError as e: print("ERROR 7: Could not write test page: {err}".format(err=e)) @@ -442,6 +455,7 @@ def close(self): current_test_content = read_writer.read_page(testpage) if current_test_content != bytes([0xaa, 0xaa, 0xaa, 0xaa]): print("ERROR 8: The test page was not written after authentication") + print(" OK 8: read after writing with authentication successful") except OSError as e: print("ERROR 8: Could not read test page: {err}".format(err=e)) exit() @@ -449,6 +463,7 @@ def close(self): # 9 try: read_writer.set_password(tt) # Default arguments set to default state, clearing the password + print(" OK 9: password cleared") except OSError as e: print("ERROR 9: Could not clear password") From e93b558780fa8fd49b7a1dacd1f386432607f2e1 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 20 Jul 2016 11:55:04 +0200 Subject: [PATCH 37/76] It seems that after a failed write (due to password protection being set), the connection must be re-created. TODO: minimize and encapsulate the calls needed for this --- pynfc/ntag_read.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 7c6a9d8..05b4054 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -342,11 +342,6 @@ def close(self): uid = read_writer.setup_target() print("uid = {}".format(binascii.hexlify(uid))) - try: - read_writer.authenticate(password=password, acknowledge=ack) - read_writer.set_password(tt) - except: pass - read_writer.set_easy_framing() @@ -397,14 +392,14 @@ def close(self): print("ERROR 3: Could not set a password") # Close this connection, so we definitely need to re-authenticate - # # import ipdb; ipdb.set_trace() - # read_writer.close() - # del read_writer - # - # read_writer = NTagReadWrite(logger) - # uids = read_writer.list_targets() - # read_writer.setup_target() - # read_writer.set_easy_framing() + # import ipdb; ipdb.set_trace() + read_writer.close() + del read_writer + + read_writer = NTagReadWrite(logger) + uids = read_writer.list_targets() + read_writer.setup_target() + read_writer.set_easy_framing() # 3a try: @@ -434,7 +429,15 @@ def close(self): print(" OK 5: the test page could not be written after a password was required and not authenticated") except OSError as e: print("ERROR 5: Could not read test page: {err}".format(err=e)) - exit() + # exit() + + read_writer.close() + del read_writer + + read_writer = NTagReadWrite(logger) + uids = read_writer.list_targets() + read_writer.setup_target() + read_writer.set_easy_framing() # 6 try: From 2fd56e99eefda53d54b1bd73ce6725c50ade93f4 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 20 Jul 2016 13:01:02 +0200 Subject: [PATCH 38/76] Explicit method to open a connection even after it is closed. No need to delete and init a NTagReadWrite --- pynfc/ntag_read.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 05b4054..065eb29 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -46,6 +46,9 @@ def nolog(log): self.modulations[i].nmt = mods[i][0] self.modulations[i].nbr = mods[i][1] + self.open() + + def open(self): try: self.context = ctypes.pointer(nfc.nfc_context()) self.log("Created NFC library context") @@ -58,7 +61,7 @@ def nolog(log): self.log("{} devices found".format(devices_found)) if not devices_found: - IOError("No devices found. "+SET_CONNSTRING) + IOError("No devices found. " + SET_CONNSTRING) else: self.log("Using conn_string[0] = {} to get a device. {}".format(conn_strings[0].value, SET_CONNSTRING)) @@ -322,6 +325,7 @@ def close(self): nfc.nfc_close(self.device) nfc.nfc_exit(self.context) + if __name__ == "__main__": logger = print # logging.getLogger("ntag_read").info @@ -391,15 +395,12 @@ def close(self): except OSError as e: print("ERROR 3: Could not set a password") - # Close this connection, so we definitely need to re-authenticate - # import ipdb; ipdb.set_trace() + # Close and reopen this connection, so we definitely need to re-authenticate read_writer.close() - del read_writer - read_writer = NTagReadWrite(logger) - uids = read_writer.list_targets() + read_writer.open() + read_writer.setup_target() - read_writer.set_easy_framing() # 3a try: @@ -431,13 +432,12 @@ def close(self): print("ERROR 5: Could not read test page: {err}".format(err=e)) # exit() + # Close and reopen this connection, so we definitely need to re-authenticate read_writer.close() - del read_writer - read_writer = NTagReadWrite(logger) - uids = read_writer.list_targets() + read_writer.open() + read_writer.setup_target() - read_writer.set_easy_framing() # 6 try: From 4173c7a73adb311f38ed746fc8f8d22a74f9ad46 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 20 Jul 2016 13:10:55 +0200 Subject: [PATCH 39/76] Added docs for open(0 and close() --- pynfc/ntag_read.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 065eb29..40f1d54 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -49,6 +49,8 @@ def nolog(log): self.open() def open(self): + """Open a connection with an NTag. Initializes pynfc context, the device. + Call this after a close()""" try: self.context = ctypes.pointer(nfc.nfc_context()) self.log("Created NFC library context") @@ -321,6 +323,8 @@ def set_password(self, tag_type, password=b'\xff\xff\xff\xff', acknowledge=b'\x0 self.write_page(cfg0_page, cfg0) def close(self): + """Close connection to the target NTag and de-initialize the pynfc context. + After a failed read/write due to password protection, call close(), then open() and then do the authenticate() call""" nfc.nfc_idle(self.device) nfc.nfc_close(self.device) nfc.nfc_exit(self.context) From c0be0b84a0925ae83bb417b5608073b6f3a203a0 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 21 Jul 2016 08:55:32 +0200 Subject: [PATCH 40/76] Added method to enable the UID mirroring --- pynfc/ntag_read.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 40f1d54..db159c8 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -257,6 +257,43 @@ def authenticate(self, password, acknowledge=b'\x00\x00'): return recv == acknowledge + def enable_uid_mirror(self, tag_type, page, byte_in_page): + """ + An NTAG 21x has the option to mirror its UID to a place in the user memory. + This can be useful for signatures, which can then sign over something unique tied to the tag. + + The mirror configuration page consists of 4 bytes: + - CFG0: MIRROR, rfui, MIRROR_PAGE, AUTH0 + + The MIRROR-byte consists of some bitfields: + - 7,6: MIRROR_CONF: Set to 01 for UID ASCII Mirror + - 5,4: MIRROR_BYTE: The 2 bits define the byte position within the page defined by the MIRROR_PAGE byte (beginning of ASCII mirror) + - 3 : RFUI + - 2 : STRG_MOD_EN: STRG MOD_EN defines the modulation mode. 0 disables, 1 enables + - 1,0: RFUI + + The AUTH0-byte defines the page address from which the password verification is required. + This is set through the set_password-method. + + :param tag_type: Which type of tag are we dealing with? Used to figure out where the config pages are + :param page: On which page must the UID be mirrored? + :type page int + :param byte_in_page: On which byte in that page must the UID be mirrored. + :type byte_in_page int + :return: + """ + cfg0_page = tag_type.value['user_memory_end'] + 2 + cfg0_orig = self.read_page(cfg0_page) + + + mirror = 0b01000000 + mirror |= (byte_in_page) << 4 + + # MIRROR rfui MIRROR_PAGE AUTH0 + cfg0 = [mirror, 0b00000000, page, cfg0_orig[3]] + + self.write_page(cfg0_page, cfg0) + def set_password(self, tag_type, password=b'\xff\xff\xff\xff', acknowledge=b'\x00\x00', max_attempts=None, also_read=False, auth_from=0xFF, lock_config=False, enable_counter=False, protect_counter=False): """ From 61c1c1909a9673012ba3fe0d04929fefd8131488 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 25 Jul 2016 15:57:05 +0200 Subject: [PATCH 41/76] Update readme to latest work --- README | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README b/README index b8d0b8c..bf0caa0 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ Requirements ------------ libnfc >= 1.7.0 -python >= 2.6 < 3.0 +python > 3.5 (tested with 3.5) Building -------- @@ -15,10 +15,11 @@ The bindings are constructed at runtime using ctypes. Just ensure the library i Examples -------- +###Mifareauth + There is an example program included for conducting simple mifare authentication: python mifareauth.py - Example output (bulk of the raw hex excised for space): Connect to reader: True @@ -36,6 +37,14 @@ T -> R: CA 9E 73 93 This indicates that it successfully authenticated to the requested block. +### NTags +```bash +python ntag_read.py +``` + +This will test whether can do password protection and remove the password alltogether in the end. + + Documentation ------------- @@ -48,3 +57,4 @@ As much as possible all libnfc commands are mirrored in the created nfc object. Please note whilst this does implement the full range of features found in libnfc, their use in python may be difficult or tricky to use. Pynfc requires much more development and time dedicated to it, before it will be useful as a production tool. +The NTagReadWrite class offers a more Pythonic and high-level interface, geared towards NXP NTags 213, 215 and 216 but should be extendable/generalized to other tag types as well. \ No newline at end of file From b040d3b022924455d78ff39ca0171c6c4d272d18 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 18 Aug 2016 16:56:22 +0200 Subject: [PATCH 42/76] Include the page size (4 bytes) in the file, instead of hardcoding 4 everywhere --- pynfc/ntag_read.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index db159c8..32da707 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -25,6 +25,10 @@ class Commands(enum.Enum): MC_READ_SIG = 0x3c +class NTagInfo(object): + BYTES_PER_PAGE = 4 + + class NTagReadWrite(object): """ Allows to read/write to an NTag 21x device. @@ -152,7 +156,7 @@ def transceive_bytes(self, transmission, receive_length): def read_page(self, page): """Read the bytes at the given page""" received_data = self.transceive_bytes(bytes([int(Commands.MC_READ.value), page]), 16) - data = received_data[:4] # Only the first 4 bytes as a page is 4 bytes + data = received_data[:NTagInfo.BYTES_PER_PAGE] # Only the first 4 bytes as a page is 4 bytes return data def read_user_memory(self, tag_type): @@ -188,7 +192,7 @@ def write_block(self, block, data): def write_page(self, page, data, debug=False): if debug: print("Write page {:3}: {}".format(page, data)) - if len(data) > 4: + if len(data) > NTagInfo.BYTES_PER_PAGE: raise ValueError( "Data value to be written cannot be more than 4 bytes.") return self.write_block(page, data) @@ -200,7 +204,7 @@ def write_user_memory(self, data, tag_type, debug=False): end = tag_type.value['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value mem_size = (end-start) - page_contents = [data[i:i+4] for i in range(0, len(data), 4)] + page_contents = [data[i:i+NTagInfo.BYTES_PER_PAGE] for i in range(0, len(data), NTagInfo.BYTES_PER_PAGE)] content_size = len(page_contents) if content_size > mem_size: From 880e4738eae7442a3422ce7df93401ee24f54942 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 19 Aug 2016 10:54:54 +0200 Subject: [PATCH 43/76] Add method to check wheter UID mirroring is enabled --- pynfc/ntag_read.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 32da707..9d6510a 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -298,6 +298,28 @@ def enable_uid_mirror(self, tag_type, page, byte_in_page): self.write_page(cfg0_page, cfg0) + def check_uid_mirror(self, tag_type): + """Return to which page and byte_in_page the UID mirroring is configured. + If it is not enabled, return None + + :param tag_type: Which type of tag are we dealing with? Used to figure out where the config pages are + :returns tuple (mirror_page, byte_in_page) in case UID mirroring is enabled, None if not enabled.""" + cfg0_page = tag_type.value['user_memory_end'] + 2 + + config_page = self.read_page(cfg0_page) + mirror, _, mirror_page, auth0 = config_page + + mirroring_enabled = mirror & 0b01000000 > 0 + + mirror_byte_mask = 0b00110000 + byte_in_page = (mirror & mirror_byte_mask) >> 4 + + if mirroring_enabled: + return mirror_page, byte_in_page + else: + return None + + def set_password(self, tag_type, password=b'\xff\xff\xff\xff', acknowledge=b'\x00\x00', max_attempts=None, also_read=False, auth_from=0xFF, lock_config=False, enable_counter=False, protect_counter=False): """ From 216f77256a9c794d19b702b7e0f64bd5095ee299 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 19 Aug 2016 10:55:28 +0200 Subject: [PATCH 44/76] Add method to determine tag type and an exception for when it is not known --- pynfc/ntag_read.py | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 9d6510a..37daec2 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -6,11 +6,26 @@ import enum import logging +def bin(i): + return "0b{0:08b}".format(i) + class TagType(enum.Enum): NTAG_213 = {"user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last NTAG_215 = {"user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last NTAG_216 = {"user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last +capability_byte_type_map = {0x12: TagType.NTAG_213, + 0x3e: TagType.NTAG_215, + 0x6D: TagType.NTAG_216} + + +class UnknownTagTypeException(Exception): + def __init__(self, message, capability_byte): + super(UnknownTagTypeException, self).__init__(message) + + self.capability_byte = capability_byte + + SET_CONNSTRING = 'You may need to $ export LIBNFC_DEFAULT_DEVICE="pn532_uart:/dev/ttyUSB0" ' \ 'or edit /etc/nfc/libnfc.conf and set device.connstring in case of a failure' @@ -159,6 +174,36 @@ def read_page(self, page): data = received_data[:NTagInfo.BYTES_PER_PAGE] # Only the first 4 bytes as a page is 4 bytes return data + def determine_tag_type(self): + """ + According to the NTAG213/215/216 specification, the Capability Container byte 2 contains the memory size of the tag + This is written during tag production. The capability Container is on page 3 + The exact definitions are stated in table 4 of the datasheet: + + Table 4. NDEF memory size + IC | Value in byte 2 | NDEF memory size + --------+-----------------+----------------- + NTAG213 | 12h | 144 byte + NTAG215 | 3Eh | 496 byte + NTAG216 | 6Dh | 872 byte + """ + uid = self.setup_target() + + self.set_easy_framing() + + capability_container = self.read_page(3) + capability_byte = capability_container[2] + + try: + tag_type = capability_byte_type_map[capability_byte] + + return tag_type, uid + except KeyError as key_error: + raise UnknownTagTypeException("Tag has capability byte value {byte}, " + "which is unknown. Known keys are {keys}".format(byte=capability_byte, + keys=list(capability_byte_type_map.keys())), + capability_byte) + def read_user_memory(self, tag_type): """Read the complete user memory, ie. the actual content of the tag. Configuration bytes surrounding the user memory is omitted""" From b83d7fdf1b189ac8c94b309cd29f21d7b38f5451 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 23 Aug 2016 12:01:26 +0200 Subject: [PATCH 45/76] Use python logging library the proper way --- pynfc/ntag_read.py | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 37daec2..0856ff4 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -51,13 +51,10 @@ class NTagReadWrite(object): """ card_timeout = 10 - def __init__(self, logger=None): + def __init__(self, logger=logging.getLogger("ntag_read_write")): """Initialize a ReadWrite object - :param logger: function to be called as logging. Can be import logging; logging.getLogger("ntag_read").info or simply the builtin print function. - Defaults to no logging""" - def nolog(log): - pass - self.log = logger if logger else nolog + :param logger: logging.Logger""" + self.logger = logger mods = [(nfc.NMT_ISO14443A, nfc.NBR_106)] self.modulations = (nfc.nfc_modulation * len(mods))() @@ -72,24 +69,24 @@ def open(self): Call this after a close()""" try: self.context = ctypes.pointer(nfc.nfc_context()) - self.log("Created NFC library context") + self.logger.info("Created NFC library context") nfc.nfc_init(ctypes.byref(self.context)) - self.log("Initializing NFC library") + self.logger.info("Initializing NFC library") conn_strings = (nfc.nfc_connstring * 10)() devices_found = nfc.nfc_list_devices(self.context, conn_strings, 10) # import ipdb; ipdb.set_trace() - self.log("{} devices found".format(devices_found)) + self.logger.info("{} devices found".format(devices_found)) if not devices_found: IOError("No devices found. " + SET_CONNSTRING) else: - self.log("Using conn_string[0] = {} to get a device. {}".format(conn_strings[0].value, SET_CONNSTRING)) + self.logger.info("Using conn_string[0] = {} to get a device. {}".format(conn_strings[0].value, SET_CONNSTRING)) self.device = nfc.nfc_open(self.context, conn_strings[0]) - self.log("Opened device {}, initializing NFC initiator".format(self.device)) + self.logger.info("Opened device {}, initializing NFC initiator".format(self.device)) _ = nfc.nfc_initiator_init(self.device) - self.log("NFC initiator initialized") + self.logger.info("NFC initiator initialized") except IOError as error: IOError(SET_CONNSTRING) @@ -256,7 +253,7 @@ def write_user_memory(self, data, tag_type, debug=False): raise ValueError("{type} user memory ({mem_size} 4-byte pages) too small for content ({content_size} 4-byte pages)". format(type=tag_type, mem_size=mem_size, content_size=content_size)) - self.log("Writing {} pages".format(len(page_contents))) + self.logger.info("Writing {} pages".format(len(page_contents))) for page, content in zip(range(start, end), page_contents): self.write_page(page, content, debug) @@ -439,7 +436,7 @@ def close(self): if __name__ == "__main__": - logger = print # logging.getLogger("ntag_read").info + logger = logging.getLogger("ntag_read_write") read_writer = NTagReadWrite(logger) From bf71937a3d66bf6a0d6769351f0e6415832ecda6 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 23 Aug 2016 12:04:49 +0200 Subject: [PATCH 46/76] Convert TagType from enum to a class with normal members. Means is can be extended tot other tag types independently --- pynfc/ntag_read.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 0856ff4..5d92999 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -9,7 +9,7 @@ def bin(i): return "0b{0:08b}".format(i) -class TagType(enum.Enum): +class TagType(object): NTAG_213 = {"user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last NTAG_215 = {"user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last NTAG_216 = {"user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last @@ -204,8 +204,8 @@ def determine_tag_type(self): def read_user_memory(self, tag_type): """Read the complete user memory, ie. the actual content of the tag. Configuration bytes surrounding the user memory is omitted""" - start = tag_type.value['user_memory_start'] - end = tag_type.value['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + start = tag_type['user_memory_start'] + end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value user_memory = [] for page in range(start, end): @@ -242,8 +242,8 @@ def write_user_memory(self, data, tag_type, debug=False): """Read the complete user memory, ie. the actual content of the tag. Configuration bytes surrounding the user memory are omitted, given the correct tag type. Otherwise, we cannot know where user memory start and ends""" - start = tag_type.value['user_memory_start'] - end = tag_type.value['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + start = tag_type['user_memory_start'] + end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value mem_size = (end-start) page_contents = [data[i:i+NTagInfo.BYTES_PER_PAGE] for i in range(0, len(data), NTagInfo.BYTES_PER_PAGE)] @@ -328,7 +328,7 @@ def enable_uid_mirror(self, tag_type, page, byte_in_page): :type byte_in_page int :return: """ - cfg0_page = tag_type.value['user_memory_end'] + 2 + cfg0_page = tag_type['user_memory_end'] + 2 cfg0_orig = self.read_page(cfg0_page) @@ -346,7 +346,7 @@ def check_uid_mirror(self, tag_type): :param tag_type: Which type of tag are we dealing with? Used to figure out where the config pages are :returns tuple (mirror_page, byte_in_page) in case UID mirroring is enabled, None if not enabled.""" - cfg0_page = tag_type.value['user_memory_end'] + 2 + cfg0_page = tag_type['user_memory_end'] + 2 config_page = self.read_page(cfg0_page) mirror, _, mirror_page, auth0 = config_page @@ -384,7 +384,7 @@ def set_password(self, tag_type, password=b'\xff\xff\xff\xff', acknowledge=b'\x0 The password must thus protect writing only, but for the whole tag so the start page in AUTH0 must be 0 There's no need to lock the user configuration (i.e. these bytes generated here), so CGFLCK=0 """ - cfg0_page = tag_type.value['user_memory_end'] + 2 + cfg0_page = tag_type['user_memory_end'] + 2 cfg1_page = cfg0_page + 1 pwd_page = cfg1_page + 1 pack_page = pwd_page + 1 From 1edee6620473d670cc4138cb252e565d937eb0be Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 23 Aug 2016 13:02:34 +0200 Subject: [PATCH 47/76] Include tag name in TagType dictionaries --- pynfc/ntag_read.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 5d92999..8cac625 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -10,9 +10,9 @@ def bin(i): return "0b{0:08b}".format(i) class TagType(object): - NTAG_213 = {"user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last - NTAG_215 = {"user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last - NTAG_216 = {"user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last + NTAG_213 = {"name":"NTAG_213", "user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last + NTAG_215 = {"name":"NTAG_213", "user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last + NTAG_216 = {"name":"NTAG_213", "user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last capability_byte_type_map = {0x12: TagType.NTAG_213, 0x3e: TagType.NTAG_215, From 0c930106810024be8eb5509de8bf78143e3fbfa6 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 23 Aug 2016 14:36:45 +0200 Subject: [PATCH 48/76] Also make code runable under Python 2 with the future-module --- README | 6 +++--- pynfc/ntag_read.py | 1 + setup.py | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README b/README index bf0caa0..fc75e56 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ Requirements ------------ libnfc >= 1.7.0 -python > 3.5 (tested with 3.5) +python >= 2.6 < 3.0 (tested with 2.7 and 3.5) Building -------- @@ -39,10 +39,10 @@ This indicates that it successfully authenticated to the requested block. ### NTags ```bash -python ntag_read.py +python -m pynfc.ntag_read ``` -This will test whether can do password protection and remove the password alltogether in the end. +This will test whether can do password protection and remove the password all together in the end. Documentation diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 8cac625..c93e967 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -5,6 +5,7 @@ import binascii import enum import logging +from builtins import bytes def bin(i): return "0b{0:08b}".format(i) diff --git a/setup.py b/setup.py index 9f5026d..df7072c 100644 --- a/setup.py +++ b/setup.py @@ -29,5 +29,6 @@ data_files = [('examples', ['pynfc/mifareauth.py', 'pynfc/ntag_read.py'])], license = "GPL-2", packages=['pynfc'], + requires=['future'] ) From f015798965c65f919cdb6f0f481b2755190acd59 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 23 Aug 2016 14:45:17 +0200 Subject: [PATCH 49/76] Set correct Python version range --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index fc75e56..a96556a 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ Requirements ------------ libnfc >= 1.7.0 -python >= 2.6 < 3.0 (tested with 2.7 and 3.5) +python >= 2.6 < 3.5 (tested with 2.7 and 3.5) Building -------- From 838ff0d701ce58e98486d6ca4516d243fa36d06b Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 14 Sep 2016 14:41:03 +0200 Subject: [PATCH 50/76] Apply/Read TLV Prefix for NFC Forum Type 2 Tags. --- README | 2 +- pynfc/ntag_read.py | 57 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/README b/README index a96556a..0aa4a58 100644 --- a/README +++ b/README @@ -57,4 +57,4 @@ As much as possible all libnfc commands are mirrored in the created nfc object. Please note whilst this does implement the full range of features found in libnfc, their use in python may be difficult or tricky to use. Pynfc requires much more development and time dedicated to it, before it will be useful as a production tool. -The NTagReadWrite class offers a more Pythonic and high-level interface, geared towards NXP NTags 213, 215 and 216 but should be extendable/generalized to other tag types as well. \ No newline at end of file +The NTagReadWrite class offers a more Pythonic and high-level interface, geared towards NXP NTags 213, 215 and 216 but should be extendable/generalized to other tag types as well. diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index c93e967..e2d3e59 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -6,6 +6,7 @@ import enum import logging from builtins import bytes +import math def bin(i): return "0b{0:08b}".format(i) @@ -214,6 +215,27 @@ def read_user_memory(self, tag_type): return bytes(user_memory) + def read_ndef_message_bytes(self, tag_type): + first_page = self.read_page(tag_type["user_memory_start"]) + tag_field = first_page[0] + + # 0x03 indicates NDEF message. See NFC Forum spec "Type 2 Tag Operation Specification" table 2 for others + if tag_field == 0x03: + length_format = first_page[1] + if length_format == 0xFF: + length = int.from_bytes(first_page[2:4], byteorder='big') + else: + length = length_format + + user_memory = [] + start = tag_type["user_memory_start"] + 1 + end = tag_type["user_memory_start"] + 1 + math.ceil(length/4) + for page in range(start, end): + user_memory += list(self.read_page(page)) + return bytes(user_memory) + else: + raise ValueError("Tag does not contain NDEF message. Tag indicates {tag} in first byte".format(tag=tag_field)) + def write_block(self, block, data): """Writes a block of data to an NTag Raises an exception on error @@ -258,6 +280,40 @@ def write_user_memory(self, data, tag_type, debug=False): for page, content in zip(range(start, end), page_contents): self.write_page(page, content, debug) + @staticmethod + def _make_tag_length_header_for_value(data): + """Any value written to a NFC Forum Type 2 Tag (which NTag's are), + needs to be packed in a TLV structure of 3 fields, indicating Tag (type), Length, Value + - The Tag-field will indicate those bytes must be interpreted as an NDEF message. + - The Length is simply the number of message-bytes. + - The Value will be the bytes of the message, in case of an NDEF message. + + There are various Tags possible, value 0x03 indicates an NDEF message. + See Table 2 of the NFC Forum spec "Type 2 Tag Operation Specification", NFCForum-TS-Type-2-Tag_1.1 + for the other tag values. + + The lengths can be in 2 formats: one byte and three consecutive bytes. + - One byte is for length between 0x00 and 0xFE length + - Three consecutive bytes is for lengths between 0x00FF and 0xFFFE. + The first byte of the length-field is then set to 0xFF + """ + tag = 0x03 # NDEF message + + length = len(data) + if length <= 0xFE: + return bytes([tag, length]) + elif length <= 0xFFFE: + length_bytes = length.to_bytes(2, byteorder='big') + return bytes([tag, 0xFF]) + length_bytes + else: + raise ValueError("Length {len} of data cannot be encoded according to " + "NFC Forum spec 'Type 2 Tag Operation Specification'".format(len=length)) + + def write_ndef_message_bytes(self, message_bytes, *args, **kwargs): + tag_content = self._make_tag_length_header_for_value(message_bytes) + message_bytes + + self.write_user_memory(tag_content, *args, **kwargs) + def authenticate(self, password, acknowledge=b'\x00\x00'): """After issuing this command correctly, the tag goes into the Authenticated-state, during which the protected bytes can be written @@ -362,7 +418,6 @@ def check_uid_mirror(self, tag_type): else: return None - def set_password(self, tag_type, password=b'\xff\xff\xff\xff', acknowledge=b'\x00\x00', max_attempts=None, also_read=False, auth_from=0xFF, lock_config=False, enable_counter=False, protect_counter=False): """ From 3085a53706418b916bcfe538b6a64101ddee3189 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 6 Oct 2016 08:59:55 +0200 Subject: [PATCH 51/76] Correct TagType names --- pynfc/ntag_read.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index e2d3e59..7d61b78 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -13,8 +13,8 @@ def bin(i): class TagType(object): NTAG_213 = {"name":"NTAG_213", "user_memory_start": 4, "user_memory_end": 39} # 4 is the first page of the user memory, 39 is the last - NTAG_215 = {"name":"NTAG_213", "user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last - NTAG_216 = {"name":"NTAG_213", "user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last + NTAG_215 = {"name":"NTAG_215", "user_memory_start": 4, "user_memory_end": 129} # 4 is the first page of the user memory, 129 is the last + NTAG_216 = {"name":"NTAG_216", "user_memory_start": 4, "user_memory_end": 225} # 4 is the first page of the user memory, 255 is the last capability_byte_type_map = {0x12: TagType.NTAG_213, 0x3e: TagType.NTAG_215, From e477f50773b633f1d165e32ea32ed853a8b909ed Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Tue, 11 Oct 2016 13:40:31 +0200 Subject: [PATCH 52/76] Add method to count targets --- pynfc/ntag_read.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 7d61b78..220039e 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -109,6 +109,17 @@ def list_targets(self, max_targets=10): return uids + def count_targets(self): + """ + Count the amount of targets near the device + :return: number of targets near + """ + nt = nfc.nfc_target() + + count = nfc.nfc_initiator_poll_target(self.device, self.modulations, len(self.modulations), 1, 1, ctypes.byref(nt)) + + return max(count, 0) # Count goes to -90 if there are no targets somehow + def setup_target(self): """ Find a target if there is one and returns the target's UID From 891785a5676e1af7d25a4ebb797012a49e6d3cab Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 20 Oct 2016 16:49:29 +0200 Subject: [PATCH 53/76] Remove _alpha version indicator stdeb and $ python setup.py --command-packages=stdeb.command bdist_deb cannot handle the under_score --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index df7072c..373157f 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup( name = "pynfc", - version = "1.7.0_alpha1", + version = "1.7.0", description = "Python bindings for libnfc", author = "Mike Auty", data_files = [('examples', ['pynfc/mifareauth.py', 'pynfc/ntag_read.py'])], From 3d791710d206d986bed8989bbc2736a445f3d6d5 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Thu, 27 Oct 2016 13:18:58 +0200 Subject: [PATCH 54/76] Better error handling when opening the device --- pynfc/ntag_read.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index 220039e..af38d1f 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -69,28 +69,32 @@ def __init__(self, logger=logging.getLogger("ntag_read_write")): def open(self): """Open a connection with an NTag. Initializes pynfc context, the device. Call this after a close()""" + self.context = ctypes.pointer(nfc.nfc_context()) + self.logger.info("Created NFC library context") + nfc.nfc_init(ctypes.byref(self.context)) + self.logger.info("Initializing NFC library") + + conn_strings = (nfc.nfc_connstring * 10)() + devices_found = nfc.nfc_list_devices(self.context, conn_strings, 10) + # import ipdb; ipdb.set_trace() + self.logger.info("{} devices found".format(devices_found)) + + if not devices_found: + self.logger.error("No devices found") + raise IOError("No devices found. " + SET_CONNSTRING) + else: + self.logger.info("Using conn_string[0] = {} to get a device. {}".format(conn_strings[0].value, SET_CONNSTRING)) + + self.device = nfc.nfc_open(self.context, conn_strings[0]) + try: - self.context = ctypes.pointer(nfc.nfc_context()) - self.logger.info("Created NFC library context") - nfc.nfc_init(ctypes.byref(self.context)) - self.logger.info("Initializing NFC library") - - conn_strings = (nfc.nfc_connstring * 10)() - devices_found = nfc.nfc_list_devices(self.context, conn_strings, 10) - # import ipdb; ipdb.set_trace() - self.logger.info("{} devices found".format(devices_found)) - - if not devices_found: - IOError("No devices found. " + SET_CONNSTRING) - else: - self.logger.info("Using conn_string[0] = {} to get a device. {}".format(conn_strings[0].value, SET_CONNSTRING)) + _ = self.device.contents # This fails with a ValueError in case the device could not be opened - self.device = nfc.nfc_open(self.context, conn_strings[0]) self.logger.info("Opened device {}, initializing NFC initiator".format(self.device)) _ = nfc.nfc_initiator_init(self.device) self.logger.info("NFC initiator initialized") - except IOError as error: - IOError(SET_CONNSTRING) + except ValueError as error: + raise IOError("Could not open device on connstring {conn}: {err}".format(conn=conn_strings[0].value, err=error)) def list_targets(self, max_targets=10): """ From 928aa9cea4b1ccf9bcf596c3c269136df4ac812e Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 7 Nov 2016 11:54:14 +0100 Subject: [PATCH 55/76] Move passwords test to separate function --- pynfc/ntag_read.py | 75 ++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index af38d1f..b3c6e02 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -506,30 +506,7 @@ def close(self): nfc.nfc_exit(self.context) -if __name__ == "__main__": - logger = logging.getLogger("ntag_read_write") - - read_writer = NTagReadWrite(logger) - - uids = read_writer.list_targets() - if len(uids) > 1: - print("Found {count} uids: {uids}. Please remove all but one from the device".format(count=len(uids), uids=uids)) - exit(-1) - - tt = TagType.NTAG_216 - testpage = 200 # Must be available on the chosen tag type. - - password = bytes([1, 2, 3, 4]) - ack = bytes([0xaa, 0xaa]) - - - uid = read_writer.setup_target() - print("uid = {}".format(binascii.hexlify(uid))) - - read_writer.set_easy_framing() - - - +def test_passwords(): # Below, we'll test and demonstrate the behavior of password protection against writing # The tag is supposed to start with no password protection configured, as the factory default is. # This is also how the tag should end, eventually @@ -549,10 +526,9 @@ def close(self): # 8: Again, this is verified # # 9: Lastly, we clear the password and the protection to their default states, so the test is repeatable. - # 1 try: - read_writer.write_page(testpage, bytes([0xff,0xff,0xff,0xff])) # With no password set, this page is writable + read_writer.write_page(testpage, bytes([0xff, 0xff, 0xff, 0xff])) # With no password set, this page is writable print(" OK 1: Can write page when no password set") except OSError as e: print("ERROR 1: Could not write test page: {err}".format(err=e)) @@ -561,7 +537,7 @@ def close(self): # 2 try: current_test_content = read_writer.read_page(testpage) - if current_test_content != bytes([0xff,0xff,0xff,0xff]): + if current_test_content != bytes([0xff, 0xff, 0xff, 0xff]): print("ERROR: The test page was not written") print(" OK 2: Can read page when no password set") except OSError as e: @@ -577,11 +553,8 @@ def close(self): # Close and reopen this connection, so we definitely need to re-authenticate read_writer.close() - read_writer.open() - read_writer.setup_target() - # 3a try: current_test_content = read_writer.read_page(testpage) @@ -595,30 +568,29 @@ def close(self): # 4 try: - read_writer.write_page(testpage, bytes([0x00,0x00,0x00,0x00])) # After setting the password protection, the page cannot be written anymore + read_writer.write_page(testpage, bytes( + [0x00, 0x00, 0x00, 0x00])) # After setting the password protection, the page cannot be written anymore except OSError as e: - print(" OK 4: Could (correctly) not write test page, because we just set a password and now this page is password locked: {err}".format(err=e)) + print( + " OK 4: Could (correctly) not write test page, because we just set a password and now this page is password locked: {err}".format( + err=e)) # 5 try: current_test_content = read_writer.read_page(testpage) if current_test_content != bytes([0xff, 0xff, 0xff, 0xff]): print("ERROR 5: The test page was changed while password protected and not authenticated") - if current_test_content == bytes([0x00,0x00,0x00,0x00]): + if current_test_content == bytes([0x00, 0x00, 0x00, 0x00]): print("\tThe test page was overwritten with what we wrote without authentication") else: print(" OK 5: the test page could not be written after a password was required and not authenticated") except OSError as e: print("ERROR 5: Could not read test page: {err}".format(err=e)) # exit() - # Close and reopen this connection, so we definitely need to re-authenticate read_writer.close() - read_writer.open() - read_writer.setup_target() - # 6 try: read_writer.authenticate(password=password, acknowledge=ack) @@ -628,7 +600,8 @@ def close(self): # 7 try: - read_writer.write_page(testpage, bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again + read_writer.write_page(testpage, + bytes([0xaa, 0xaa, 0xaa, 0xaa])) # After authenticating ourselves, its writeable again print(" OK 7: write after authentication successful") except OSError as e: print("ERROR 7: Could not write test page: {err}".format(err=e)) @@ -653,5 +626,29 @@ def close(self): # import ipdb; ipdb.set_trace() read_writer.close() del read_writer - print("Test completed") + + +if __name__ == "__main__": + logger = logging.getLogger("ntag_read_write") + + read_writer = NTagReadWrite(logger) + + uids = read_writer.list_targets() + if len(uids) > 1: + print("Found {count} uids: {uids}. Please remove all but one from the device".format(count=len(uids), uids=uids)) + exit(-1) + + tt = TagType.NTAG_216 + testpage = 200 # Must be available on the chosen tag type. + + password = bytes([1, 2, 3, 4]) + ack = bytes([0xaa, 0xaa]) + + + uid = read_writer.setup_target() + print("uid = {}".format(binascii.hexlify(uid))) + + read_writer.set_easy_framing() + + test_passwords() From 66a457ad440145259ed92a1459138c8df8f33853 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 7 Nov 2016 15:58:49 +0100 Subject: [PATCH 56/76] Using a faster read method, but not yet the FAST_READ command This FAST_READ command keeps giving me 'application level error detected' with my PN532 uart over usb --- pynfc/ntag_read.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index b3c6e02..ac4381e 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -225,11 +225,26 @@ def read_user_memory(self, tag_type): end = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value user_memory = [] + for page in range(start, end): user_memory += list(self.read_page(page)) return bytes(user_memory) + def fast_read_user_memory(self, tag_type): + """Read the complete user memory, ie. the actual content of the tag. + Configuration bytes surrounding the user memory is omitted""" + start_page = tag_type['user_memory_start'] + end_page = tag_type['user_memory_end'] + 1 # + 1 because the Python range generator excluded the last value + + user_memory = [] + for page in range(start_page, end_page, 4): + received_data = self.transceive_bytes(bytes([int(Commands.MC_READ.value), page]), 4*NTagInfo.BYTES_PER_PAGE) + data = received_data[:] # Only the first 4 bytes as a page is 4 bytes + user_memory += data + + return bytes(user_memory[:(end_page - start_page)*NTagInfo.BYTES_PER_PAGE]) # As we take 4 page steps, the last bytes and pages are out of range (and thus 0x00) + def read_ndef_message_bytes(self, tag_type): first_page = self.read_page(tag_type["user_memory_start"]) tag_field = first_page[0] @@ -628,6 +643,25 @@ def test_passwords(): del read_writer print("Test completed") +import time, contextlib +@contextlib.contextmanager +def stopwatch(label=None): + start = time.time() + yield + end = time.time() + dt = end - start + if label: + print("{} takes ".format(label), end="") + print(dt) + + +def test_fast_read(): + um_norm = read_writer.read_user_memory(tt) + um_fast = read_writer.fast_read_user_memory(tt) + assert um_norm in um_fast + assert len(um_norm) == len(um_fast) + assert um_norm == um_fast + if __name__ == "__main__": logger = logging.getLogger("ntag_read_write") @@ -651,4 +685,6 @@ def test_passwords(): read_writer.set_easy_framing() - test_passwords() + # test_passwords() + + test_fast_read() \ No newline at end of file From f54e86a0658a37335bf812adf365e71132b7a66f Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Mon, 7 Nov 2016 16:01:28 +0100 Subject: [PATCH 57/76] Bump version to 1.7.1, to stay in line with libnfc. Extending the API would warrant a 1.8.0 but that would go out of sync with libnfc --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 373157f..ce0dcc5 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup( name = "pynfc", - version = "1.7.0", + version = "1.7.1", description = "Python bindings for libnfc", author = "Mike Auty", data_files = [('examples', ['pynfc/mifareauth.py', 'pynfc/ntag_read.py'])], From 0431906c48efd7739f19cd9ff535730ef0358866 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Wed, 30 Nov 2016 14:24:26 +0100 Subject: [PATCH 58/76] No dependencies on 'future' --- pynfc/ntag_read.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pynfc/ntag_read.py b/pynfc/ntag_read.py index ac4381e..52fd9dc 100755 --- a/pynfc/ntag_read.py +++ b/pynfc/ntag_read.py @@ -5,7 +5,7 @@ import binascii import enum import logging -from builtins import bytes +# from builtins import bytes import math def bin(i): diff --git a/setup.py b/setup.py index ce0dcc5..111483c 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,6 @@ data_files = [('examples', ['pynfc/mifareauth.py', 'pynfc/ntag_read.py'])], license = "GPL-2", packages=['pynfc'], - requires=['future'] + requires=[] ) From dd93fb8276543bee1d8b10500cf6003fae6fca17 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 10:27:18 +0100 Subject: [PATCH 59/76] Add a travis CI file --- .travis.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..99940da --- /dev/null +++ b/.travis.yml @@ -0,0 +1,15 @@ +language: python +python: + - "3.4" + - "3.5" +# command to install dependencies +install: + - python3 setup.py install + - pip install codecov + - pip install stdeb +# command to run tests +script: + - nosetests --with-coverage +after_success: + - bash <(curl -s https://codecov.io/bash) + - python3 setup.py --command-packages=stdeb.command bdist_deb From 719b4c0b63a4e835b7c86a8984b9ea6e26beda25 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 10:36:29 +0100 Subject: [PATCH 60/76] Add libnfc dependency --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 99940da..758a540 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,9 @@ python: - "3.4" - "3.5" # command to install dependencies +before_install: + - sudo apt-get -qq update + - sudo apt-get install -y libnfc* install: - python3 setup.py install - pip install codecov From 4ad596d08d058724677834dd3903301ca16d00bd Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 11:17:52 +0100 Subject: [PATCH 61/76] Listing search places for libnfc --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 758a540..7fbfbbb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ install: - pip install stdeb # command to run tests script: + - python3 -c "from pynfc import pynfc; ll = pynfc.PosixLibraryLoader(); print(list(ll.getpaths('nfc')))" # Debugging travis - nosetests --with-coverage after_success: - bash <(curl -s https://codecov.io/bash) From 07fa17c0dc26f7b1eb0a75de905c5fb325911854 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 11:28:58 +0100 Subject: [PATCH 62/76] Printing paths in the loader --- .travis.yml | 2 +- pynfc/pynfc.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7fbfbbb..613ac5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ install: - pip install stdeb # command to run tests script: - - python3 -c "from pynfc import pynfc; ll = pynfc.PosixLibraryLoader(); print(list(ll.getpaths('nfc')))" # Debugging travis + - python3 -c "from pynfc.pynfc import PosixLibraryLoader; ll = PosixLibraryLoader(); print(list(ll.getpaths('nfc')))" # Debugging travis - nosetests --with-coverage after_success: - bash <(curl -s https://codecov.io/bash) diff --git a/pynfc/pynfc.py b/pynfc/pynfc.py index df8b319..3e61c4d 100644 --- a/pynfc/pynfc.py +++ b/pynfc/pynfc.py @@ -453,6 +453,7 @@ def load_library(self, libname): paths = self.getpaths(libname) for path in paths: + print(path) if os.path.exists(path): return self.load(path) From f3a3cddf352d0ca2f8860008e583edc9e0b2ac3c Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 11:40:55 +0100 Subject: [PATCH 63/76] Debugging libnfc install --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 613ac5c..1210df3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,13 +5,15 @@ python: # command to install dependencies before_install: - sudo apt-get -qq update - - sudo apt-get install -y libnfc* + - sudo apt-get install -y libnfc5 install: - python3 setup.py install - pip install codecov - pip install stdeb # command to run tests -script: +script: + - dpkg -L libnfc5 + - ls /usr/lib/x86_64-linux-gnu | grep libnfc - python3 -c "from pynfc.pynfc import PosixLibraryLoader; ll = PosixLibraryLoader(); print(list(ll.getpaths('nfc')))" # Debugging travis - nosetests --with-coverage after_success: From b5b28ff066c6c627bf53b0407a9ffb2243b3faae Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 11:54:46 +0100 Subject: [PATCH 64/76] Debugging libnfc install --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1210df3..59e4b1a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ +dist: trusty +sudo: required language: python python: - "3.4" From 27f33eddc365cebc2d308a8a0fadf7d1b3ed5759 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 11:58:56 +0100 Subject: [PATCH 65/76] Debugging libnfc install --- .travis.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 59e4b1a..0271b47 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,10 +14,7 @@ install: - pip install stdeb # command to run tests script: - - dpkg -L libnfc5 - - ls /usr/lib/x86_64-linux-gnu | grep libnfc - - python3 -c "from pynfc.pynfc import PosixLibraryLoader; ll = PosixLibraryLoader(); print(list(ll.getpaths('nfc')))" # Debugging travis - nosetests --with-coverage + - sudo python3 setup.py --command-packages=stdeb.command bdist_deb after_success: - bash <(curl -s https://codecov.io/bash) - - python3 setup.py --command-packages=stdeb.command bdist_deb From d407eb3842e12790381f10b957d81980d58ee6ca Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:01:18 +0100 Subject: [PATCH 66/76] Debugging libnfc install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0271b47..3d2360e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,6 @@ install: # command to run tests script: - nosetests --with-coverage - - sudo python3 setup.py --command-packages=stdeb.command bdist_deb + - python3 setup.py --command-packages=stdeb.command bdist_deb after_success: - bash <(curl -s https://codecov.io/bash) From d89b3f81612dd5c2c4293c5f7a17691acad057b6 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:30:52 +0100 Subject: [PATCH 67/76] Debugging libnfc install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3d2360e..01eddf0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: # command to install dependencies before_install: - sudo apt-get -qq update - - sudo apt-get install -y libnfc5 + - sudo apt-get install -y libnfc5 debhelper install: - python3 setup.py install - pip install codecov From 0567577c716f49d3585e28d41c39ae425288e105 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:37:05 +0100 Subject: [PATCH 68/76] Debugging build. Tests pass, but the .deb creation not yet --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 01eddf0..a14a7f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: # command to install dependencies before_install: - sudo apt-get -qq update - - sudo apt-get install -y libnfc5 debhelper + - sudo apt-get install -y libnfc5 debhelper python3-dev install: - python3 setup.py install - pip install codecov @@ -15,6 +15,6 @@ install: # command to run tests script: - nosetests --with-coverage - - python3 setup.py --command-packages=stdeb.command bdist_deb after_success: - bash <(curl -s https://codecov.io/bash) + - sudo python3 setup.py --command-packages=stdeb.command bdist_deb From 12c7c02c5693b810c8015b1f7a91682ef411d5b5 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:39:21 +0100 Subject: [PATCH 69/76] Install stdeb using sudo --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a14a7f3..a526654 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: install: - python3 setup.py install - pip install codecov - - pip install stdeb + - sudo pip install stdeb # command to run tests script: - nosetests --with-coverage From f181a6bc8313dfaecb979a9bed90c8507eb459c7 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:46:25 +0100 Subject: [PATCH 70/76] Revert "Install stdeb using sudo" This reverts commit 12c7c02c5693b810c8015b1f7a91682ef411d5b5. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a526654..a14a7f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ before_install: install: - python3 setup.py install - pip install codecov - - sudo pip install stdeb + - pip install stdeb # command to run tests script: - nosetests --with-coverage From 480d377d3a82cda54c49ad029f128e5b0b447c6b Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:46:47 +0100 Subject: [PATCH 71/76] Lets try this? --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a14a7f3..1eb52a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,4 +17,4 @@ script: - nosetests --with-coverage after_success: - bash <(curl -s https://codecov.io/bash) - - sudo python3 setup.py --command-packages=stdeb.command bdist_deb + - python3 setup.py --command-packages=stdeb.command bdist_deb From 2dea0c930ef339716d345d4629a726b5c34f6458 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:52:32 +0100 Subject: [PATCH 72/76] Install python3-all, as suggested by https://travis-ci.org/LoyVanBeek/pynfc/jobs/187675355#L474 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1eb52a2..4e372bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: # command to install dependencies before_install: - sudo apt-get -qq update - - sudo apt-get install -y libnfc5 debhelper python3-dev + - sudo apt-get install -y libnfc5 debhelper python3-all install: - python3 setup.py install - pip install codecov From 5b466426519f4b2a14181805d7d98b4330943200 Mon Sep 17 00:00:00 2001 From: Loy van Beek Date: Fri, 30 Dec 2016 12:56:49 +0100 Subject: [PATCH 73/76] Install python3-setuptools? --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4e372bb..887c86e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: # command to install dependencies before_install: - sudo apt-get -qq update - - sudo apt-get install -y libnfc5 debhelper python3-all + - sudo apt-get install -y libnfc5 debhelper python3-all python3-setuptools install: - python3 setup.py install - pip install codecov From 41b669ecb09e74d02e20b0a4a3f5c618c2c21281 Mon Sep 17 00:00:00 2001 From: ppatrik Date: Mon, 13 Nov 2017 17:16:45 +0000 Subject: [PATCH 74/76] export nfc object too --- pynfc/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pynfc/__init__.py b/pynfc/__init__.py index b37383f..1886608 100644 --- a/pynfc/__init__.py +++ b/pynfc/__init__.py @@ -1 +1,2 @@ -from .ntag_read import * \ No newline at end of file +from .ntag_read import * +from .pynfc import * From 279d873e0eebd90afed9e3adc05c0425d33a4ba7 Mon Sep 17 00:00:00 2001 From: ppatrik Date: Mon, 13 Nov 2017 18:24:24 +0100 Subject: [PATCH 75/76] Update and rename README to README.md --- README => README.md | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) rename README => README.md (81%) diff --git a/README b/README.md similarity index 81% rename from README rename to README.md index 0aa4a58..c018cfa 100644 --- a/README +++ b/README.md @@ -1,21 +1,32 @@ -Pynfc - Python bindings for libnfc -================================== +# Pynfc - Python bindings for libnfc -Requirements ------------- +## Requirements libnfc >= 1.7.0 python >= 2.6 < 3.5 (tested with 2.7 and 3.5) -Building --------- +## Building The bindings are constructed at runtime using ctypes. Just ensure the library is correctly installed. -Examples --------- +## Instalation -###Mifareauth +``` +sudo apt-get install -y libnfc5 debhelper python3-all python3-setuptools +git clone git@github.com:ppatrik/pynfc.git +cd pynfc +python3 setup.py install +``` + +Now you can import pynfc in your projects + +```py +import pynfc as nfc; +``` + +## Examples + +### Mifareauth There is an example program included for conducting simple mifare authentication: @@ -45,8 +56,7 @@ python -m pynfc.ntag_read This will test whether can do password protection and remove the password all together in the end. -Documentation -------------- +## Documentation The pynfc bindings should offer an intuitive, yet pythonic way of calling the standard libnfc API. From a9391a8dd60bd219c581d983143bd75f7166a6cd Mon Sep 17 00:00:00 2001 From: ppatrik Date: Mon, 13 Nov 2017 18:25:09 +0100 Subject: [PATCH 76/76] Update README.md --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index c018cfa..a994a59 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ ## Requirements -libnfc >= 1.7.0 -python >= 2.6 < 3.5 (tested with 2.7 and 3.5) +* libnfc >= 1.7.0 +* python >= 2.6 < 3.5 (tested with 2.7 and 3.5) ## Building @@ -30,7 +30,8 @@ import pynfc as nfc; There is an example program included for conducting simple mifare authentication: -python mifareauth.py +```bash +> python mifareauth.py Example output (bulk of the raw hex excised for space): Connect to reader: True @@ -45,6 +46,7 @@ T -> R: A2 7F 33 EE TR == Next(TN, 96): True R -> T: 8F A4 FA D1 T -> R: CA 9E 73 93 +``` This indicates that it successfully authenticated to the requested block.