Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
c341045
Port to Python 3.5 using 2to3 tool
Jun 10, 2016
dd0b550
AutoPEP8 all code
Jun 10, 2016
d9435eb
Add debug and tryouts for NXP NTag 216.
Jun 10, 2016
95a2f27
Read NTag in simplest possible script with $ python3 -m src.ntag_read
Jun 20, 2016
4ab8017
Print UID as hex in mifareauth
Jun 20, 2016
6cd5d0e
Reading data from NTag213 sort-of works. First read actually reads on…
Jun 20, 2016
8daa38a
Nicely closing and exiting
Jun 20, 2016
bc9c979
Split read into own function to try alternative implementations
Jun 21, 2016
4edca59
Understanding more and more of this, wrapped nfc.nfc_initiator_transc…
Jun 21, 2016
d2ffa98
Removed Mifare classic code that was already outcommented
Jun 21, 2016
1d86edd
Remove code moved to separate function
Jun 21, 2016
0d93b2c
Add fucntions to read a single page of 4 bytes while the minimal read…
Jun 21, 2016
d630d06
Can also write pages now
Jun 21, 2016
ec8b171
Writing the full user memory of an NTag 213. Some bytes seem to be lo…
Jun 21, 2016
9bbedaa
Disabled UID ASCII Mirroring on NTag213. Also not prettyprinting hex …
Jun 21, 2016
6e80257
Disable UID ascii mirror
Jun 22, 2016
bf8c859
Move setup.py to root of repository
Jun 22, 2016
f07796c
Rename module to pynfc
Jun 22, 2016
c217151
Set correct datafiles in setup.py
Jun 22, 2016
24e2cc2
Rename src folder to pynfc for easy installation: sudo python(3) setu…
Jun 22, 2016
416927f
Convert ntag_read example to OO-style instead of procedural.
Jun 22, 2016
098c95b
More apt names
Jun 22, 2016
5c42129
Add docs and logging
Jun 22, 2016
f2283d4
Handier importing
Jun 22, 2016
563eed6
Make the tag types an Enum
Jun 23, 2016
c21992c
Pass the enum itself and not the value of the members
Jun 23, 2016
e24b9fb
Also use self.log rather than print when writing
Jun 23, 2016
cf7c933
Write debugging is options for all user memory
Jun 23, 2016
c01036d
Do not silently write only a portion of the data but raise exception …
Jun 24, 2016
c6045b7
Listing UIDs if multiple tags are present
Jun 24, 2016
20c16d4
Busy implementing password protection and authentication. Borked 1 ta…
Jul 19, 2016
b963aad
Busy making authentication work. Not much progress but did some inves…
Jul 19, 2016
9206c4e
D'oh! I appended the CRC of the password, which libnfc/pynfc already …
Jul 20, 2016
7cf17f1
Testing password protection. Somehow, I can write to the target after…
Jul 20, 2016
4b0347b
Test that we can read after setting password
Jul 20, 2016
cd8c36c
Add confirmation messages after successfull steps as well. Also: try …
Jul 20, 2016
e93b558
It seems that after a failed write (due to password protection being …
Jul 20, 2016
2fd56e9
Explicit method to open a connection even after it is closed. No need…
Jul 20, 2016
4173c7a
Added docs for open(0 and close()
Jul 20, 2016
c0be0b8
Added method to enable the UID mirroring
Jul 21, 2016
61c1c19
Update readme to latest work
Jul 25, 2016
b040d3b
Include the page size (4 bytes) in the file, instead of hardcoding 4 …
Aug 18, 2016
880e473
Add method to check wheter UID mirroring is enabled
Aug 19, 2016
216f772
Add method to determine tag type and an exception for when it is not …
Aug 19, 2016
b83d7fd
Use python logging library the proper way
Aug 23, 2016
bf71937
Convert TagType from enum to a class with normal members. Means is ca…
Aug 23, 2016
1edee66
Include tag name in TagType dictionaries
Aug 23, 2016
0c93010
Also make code runable under Python 2 with the future-module
Aug 23, 2016
f015798
Set correct Python version range
Aug 23, 2016
838ff0d
Apply/Read TLV Prefix for NFC Forum Type 2 Tags.
Sep 14, 2016
3085a53
Correct TagType names
Oct 6, 2016
e477f50
Add method to count targets
Oct 11, 2016
891785a
Remove _alpha version indicator
Oct 20, 2016
3d79171
Better error handling when opening the device
Oct 27, 2016
928aa9c
Move passwords test to separate function
Nov 7, 2016
66a457a
Using a faster read method, but not yet the FAST_READ command
Nov 7, 2016
f54e86a
Bump version to 1.7.1, to stay in line with libnfc.
Nov 7, 2016
35d813e
Merge pull request #1 from LoyVanBeek/feature/fast_read
LoyVanBeek Nov 7, 2016
0431906
No dependencies on 'future'
Nov 30, 2016
dd93fb8
Add a travis CI file
Dec 30, 2016
719b4c0
Add libnfc dependency
Dec 30, 2016
4ad596d
Listing search places for libnfc
Dec 30, 2016
07fa17c
Printing paths in the loader
Dec 30, 2016
f3a3cdd
Debugging libnfc install
Dec 30, 2016
b5b28ff
Debugging libnfc install
Dec 30, 2016
27f33ed
Debugging libnfc install
Dec 30, 2016
d407eb3
Debugging libnfc install
Dec 30, 2016
d89b3f8
Debugging libnfc install
Dec 30, 2016
0567577
Debugging build. Tests pass, but the .deb creation not yet
Dec 30, 2016
12c7c02
Install stdeb using sudo
Dec 30, 2016
f181a6b
Revert "Install stdeb using sudo"
Dec 30, 2016
480d377
Lets try this?
Dec 30, 2016
2dea0c9
Install python3-all, as suggested by https://travis-ci.org/LoyVanBeek…
Dec 30, 2016
5b46642
Install python3-setuptools?
Dec 30, 2016
41b669e
export nfc object too
ppatrik Nov 13, 2017
87e4b39
Merge pull request #1 from ppatrik/feature/debug_travis
ppatrik Nov 13, 2017
279d873
Update and rename README to README.md
ppatrik Nov 13, 2017
a9391a8
Update README.md
ppatrik Nov 13, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
dist: trusty
sudo: required
language: python
python:
- "3.4"
- "3.5"
# command to install dependencies
before_install:
- sudo apt-get -qq update
- sudo apt-get install -y libnfc5 debhelper python3-all python3-setuptools
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
50 changes: 36 additions & 14 deletions README → README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
Pynfc - Python bindings for libnfc
==================================
# Pynfc - Python bindings for libnfc

Requirements
------------
## Requirements

libnfc >= 1.7.0
python >= 2.6 < 3.0
* 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

There is an example program included for conducting simple mifare authentication:
```
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;
```

python mifareauth.py
## Examples

### Mifareauth

There is an example program included for conducting simple mifare authentication:

```bash
> python mifareauth.py
Example output (bulk of the raw hex excised for space):

Connect to reader: True
Expand All @@ -33,11 +46,19 @@ 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.

Documentation
-------------
### NTags
```bash
python -m pynfc.ntag_read
```

This will test whether can do password protection and remove the password all together in the end.


## Documentation

The pynfc bindings should offer an intuitive, yet pythonic way of calling the standard libnfc API.

Expand All @@ -48,3 +69,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.
2 changes: 2 additions & 0 deletions pynfc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .ntag_read import *
from .pynfc import *
64 changes: 43 additions & 21 deletions src/mifareauth.py → pynfc/mifareauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,24 @@
#
# 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
import ctypes
import string
import nfc
import binascii


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
Expand All @@ -54,13 +59,18 @@ 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
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:
Expand All @@ -74,7 +84,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:
Expand Down Expand Up @@ -104,12 +114,16 @@ 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(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):
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
Expand All @@ -128,8 +142,9 @@ 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 = bytearray([nt.nti.nai.abtUid[i] for i in range(nt.nti.nai.szUidLen)])
return uid

def _setup_device(self):
Expand Down Expand Up @@ -168,7 +183,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
Expand All @@ -178,34 +194,35 @@ 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")
abttx = (ctypes.c_uint8 * 12)()
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"):
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
"""
# 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)
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

"""
Expand All @@ -217,14 +234,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"""
Expand Down
Loading