mirror of
https://github.com/brmlab/brmdoor_libnfc.git
synced 2025-06-07 08:04:06 +02:00
Authentication with NDEF message on Desfire containing signed UID via Ed25519
This commit is contained in:
parent
892b69f939
commit
d0121aaed9
12 changed files with 286 additions and 41 deletions
29
README.md
29
README.md
|
@ -28,10 +28,16 @@ It is much more general in use than to use it as authenthicator to open door.
|
||||||
|
|
||||||
You need just to run `make`. Additional dependencies:
|
You need just to run `make`. Additional dependencies:
|
||||||
|
|
||||||
- [libnfc](https://github.com/nfc-tools/libnfc/releases), already present in Raspbian 8 repositories
|
- [libnfc](https://github.com/nfc-tools/libnfc/releases), in Debian and Ubuntu as libnfc-dev
|
||||||
|
- [libfreefare](https://github.com/nfc-tools/libfreefare), in Debian and Ubuntu install libfreefare-bin and libfreefare-dev
|
||||||
|
- [python-axolotl-curve25519](https://github.com/tgalal/python-axolotl-curve25519), in Ubuntu and Debian install python-axolotl-curve25519
|
||||||
- [SWIG](http://www.swig.org/)
|
- [SWIG](http://www.swig.org/)
|
||||||
- [WiringPi2 pythonic binding](https://github.com/WiringPi/WiringPi2-Python) (for switching lock on Raspberry)
|
- [WiringPi2 pythonic binding](https://github.com/WiringPi/WiringPi2-Python) (for switching lock on Raspberry)
|
||||||
|
|
||||||
|
All dependencies except for wiring can be installed via:
|
||||||
|
|
||||||
|
`apt install libnfc-dev libfreefare-bin and libfreefare-dev python-axolotl-curve25519 swig3.0`
|
||||||
|
|
||||||
## Howto
|
## Howto
|
||||||
|
|
||||||
1. Create the database
|
1. Create the database
|
||||||
|
@ -44,17 +50,28 @@ You need just to run `make`. Additional dependencies:
|
||||||
|
|
||||||
3. Add some users
|
3. Add some users
|
||||||
|
|
||||||
- either authenthication by UID, e.g.:
|
- either authentication by UID, e.g.:
|
||||||
|
|
||||||
brmdoor_adduser.py -c brmdoor_nfc.config -a uid 34795FCC SomeUserName
|
./brmdoor_adduser.py -c brmdoor_nfc.config -a uid 34795FCC SomeUserName
|
||||||
|
|
||||||
- authenthication by Yubikey's HMAC-SHA1 programmed on slot 2
|
- authentication by Yubikey's HMAC-SHA1 programmed on slot 2
|
||||||
|
|
||||||
brmdoor_adduser.py -c brmdoor_nfc.config -a hmac 40795FCCAB0701 SomeUserName 000102030405060708090a0b0c0d0e0f31323334
|
./brmdoor_adduser.py -c brmdoor_nfc.config -a hmac 40795FCCAB0701 SomeUserName 000102030405060708090a0b0c0d0e0f31323334
|
||||||
|
|
||||||
- to program Yubikey slot 2 to use HMAC with given key, use:
|
- to program Yubikey slot 2 to use HMAC with given key (requires package `yubikey-personalization`), use:
|
||||||
|
|
||||||
ykpersonalize -2 -ochal-resp -ohmac-sha1 -ohmac-lt64 -oserial-api-visible
|
ykpersonalize -2 -ochal-resp -ohmac-sha1 -ohmac-lt64 -oserial-api-visible
|
||||||
|
|
||||||
|
- authentication using signed UID as NDEF message on Desfire:
|
||||||
|
|
||||||
|
./brmdoor_adduser.py -c brmdoor.config -a ndef 04631982cc2280 SomeUserName"
|
||||||
|
|
||||||
|
- you need to generate Ed25519 keypair, store the private key somewhere safe and put the public in config file
|
||||||
|
|
||||||
|
./generate_ed25519_keypair.py
|
||||||
|
|
||||||
|
- you need to program the Desfire card to have the signature
|
||||||
|
|
||||||
|
|
||||||
Finally, run the daemon:
|
Finally, run the daemon:
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,6 @@ def addUidAuth(cursor, uid_hex, nick):
|
||||||
print >> sys.stderr, "UID must be in proper hex encoding"
|
print >> sys.stderr, "UID must be in proper hex encoding"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def addHmacAuth(cursor, uid_hex, nick, key_hex):
|
def addHmacAuth(cursor, uid_hex, nick, key_hex):
|
||||||
"""
|
"""
|
||||||
Add user authenticated by Yubikey HMAC-SHA1. UID should be in hex, 4, 7
|
Add user authenticated by Yubikey HMAC-SHA1. UID should be in hex, 4, 7
|
||||||
|
@ -48,12 +47,28 @@ def addHmacAuth(cursor, uid_hex, nick, key_hex):
|
||||||
print >> sys.stderr, "UID and key must be in proper hex encoding"
|
print >> sys.stderr, "UID and key must be in proper hex encoding"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
def addNdefAuth(cursor, uid_hex, nick):
|
||||||
|
"""
|
||||||
|
Add user authenticated by NDEF message on Desfire. UID should be in hex, 4, 7 or 10 bytes long.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
uid_hex.decode("hex")
|
||||||
|
sql = """INSERT INTO authorized_desfires
|
||||||
|
(uid_hex, nick)
|
||||||
|
values (?, ?)
|
||||||
|
"""
|
||||||
|
sql_data = (uid_hex, nick)
|
||||||
|
cursor.execute(sql, sql_data)
|
||||||
|
except TypeError:
|
||||||
|
print >> sys.stderr, "UID must be in proper hex encoding"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = OptionParser()
|
parser = OptionParser()
|
||||||
parser.add_option("-c", "--config", action="store", type="string", dest="config",
|
parser.add_option("-c", "--config", action="store", type="string", dest="config",
|
||||||
help="Configuration file")
|
help="Configuration file")
|
||||||
parser.add_option("-a", "--authtype", action="store", type="string", dest="authtype",
|
parser.add_option("-a", "--authtype", action="store", type="string", dest="authtype",
|
||||||
help="Authenthication type - uid or hmac")
|
help="Authenthication type - uid, hmac or ndef")
|
||||||
(opts, args) = parser.parse_args()
|
(opts, args) = parser.parse_args()
|
||||||
|
|
||||||
if opts.config is None:
|
if opts.config is None:
|
||||||
|
@ -61,9 +76,9 @@ if __name__ == "__main__":
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if opts.authtype not in ["uid", "hmac"]:
|
if opts.authtype not in ["uid", "hmac", "ndef"]:
|
||||||
print >> sys.stderr, "You must specify authentication type via -a option!"
|
print >> sys.stderr, "You must specify authentication type via -a option!"
|
||||||
print >> sys.stderr, "Acceptable choices: uid, hmac"
|
print >> sys.stderr, "Acceptable choices: uid, hmac, ndef"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
config = BrmdoorConfig(opts.config)
|
config = BrmdoorConfig(opts.config)
|
||||||
|
@ -83,6 +98,13 @@ if __name__ == "__main__":
|
||||||
print >> sys.stderr, "brmdoor_adduser.py -c brmdoor.config -a hmac 40795FCCAB0701 SomeUserName 000102030405060708090a0b0c0d0e0f31323334"
|
print >> sys.stderr, "brmdoor_adduser.py -c brmdoor.config -a hmac 40795FCCAB0701 SomeUserName 000102030405060708090a0b0c0d0e0f31323334"
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
addHmacAuth(cursor, args[0], args[1], args[2])
|
addHmacAuth(cursor, args[0], args[1], args[2])
|
||||||
|
elif opts.authtype == "ndef":
|
||||||
|
if len(args) < 2:
|
||||||
|
print >> sys.stderr, "You must two additional arguments, hex UID and nick"
|
||||||
|
print >> sys.stderr, "Example:"
|
||||||
|
print >> sys.stderr, "brmdoor_adduser.py -c brmdoor.config -a ndef 34795FCC SomeUserName"
|
||||||
|
sys.exit(1)
|
||||||
|
addNdefAuth(cursor, args[0], args[1])
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
|
@ -4,6 +4,8 @@ import hmac
|
||||||
import hashlib
|
import hashlib
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
import axolotl_curve25519 as curve
|
||||||
|
|
||||||
from nfc_smartcard import NFCError
|
from nfc_smartcard import NFCError
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,7 +130,7 @@ class YubikeyHMACAuthenthicator(object):
|
||||||
if not rapdu.valid or rapdu.sw() != 0x9000:
|
if not rapdu.valid or rapdu.sw() != 0x9000:
|
||||||
raise NFCError("HMAC - response SW is not 0x9000")
|
raise NFCError("HMAC - response SW is not 0x9000")
|
||||||
except NFCError, e:
|
except NFCError, e:
|
||||||
logging.debug("Yubikey HMAC command failed: %s" % e.what())
|
logging.info("Yubikey HMAC command failed: %s" % e.what())
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if not self.hmacCheck(secretKey, challenge, rapdu.data()):
|
if not self.hmacCheck(secretKey, challenge, rapdu.data()):
|
||||||
|
@ -140,7 +142,62 @@ class YubikeyHMACAuthenthicator(object):
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""Closes connection to database"""
|
"""Closes connection to database"""
|
||||||
self.conn.close()
|
self.conn.close()
|
||||||
|
|
||||||
|
class DesfireEd25519Authenthicator(object):
|
||||||
|
"""
|
||||||
|
Reads NDEF message from Desfire and it must be signed binary value of UID
|
||||||
|
"""
|
||||||
|
def __init__(self, filename, nfcReader, pubKey):
|
||||||
|
"""
|
||||||
|
Connects to database by given filename and later checks UIDs
|
||||||
|
using the pubkey (given as binary string).
|
||||||
|
"""
|
||||||
|
#again autocommit mode
|
||||||
|
self.conn = sqlite3.connect(filename, isolation_level=None)
|
||||||
|
self.nfcReader = nfcReader
|
||||||
|
self.pubKey = pubKey
|
||||||
|
|
||||||
|
def signatureCheck(self, uid, signature):
|
||||||
|
"""
|
||||||
|
Returns true iff uid (as binary) is the message signed by signature (binary string)
|
||||||
|
"""
|
||||||
|
verified = curve.verifySignature(self.pubKey, uid, signature) == 0
|
||||||
|
return verified
|
||||||
|
|
||||||
|
|
||||||
|
def checkUIDSignature(self, uid_hex):
|
||||||
|
"""
|
||||||
|
Checks if UID is in database. If so, it retrieves NDEF which should be signature of the UID
|
||||||
|
@param uid_hex: uid to match in hex
|
||||||
|
@returns UidRecord instance if found, None otherwise
|
||||||
|
"""
|
||||||
|
cursor = self.conn.cursor()
|
||||||
|
sql = "SELECT nick FROM authorized_desfires WHERE UPPER(uid_hex)=?"
|
||||||
|
sql_data =(uid_hex.upper(),)
|
||||||
|
|
||||||
|
cursor.execute(sql, sql_data)
|
||||||
|
record = cursor.fetchone()
|
||||||
|
|
||||||
|
if record is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
nick = record[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
ndefSignature = self.nfcReader.readDesfireNDEF()
|
||||||
|
if self.signatureCheck(uid_hex.decode("hex"), ndefSignature):
|
||||||
|
return UidRecord(uid_hex, nick)
|
||||||
|
else:
|
||||||
|
logging.info("Signature check failed for Desfire NDEF for UID %s", uid_hex)
|
||||||
|
return None
|
||||||
|
except NFCError, e:
|
||||||
|
logging.info("Desfire read NDEF failed: %s" % e.what())
|
||||||
|
return None
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
"""Closes connection to database"""
|
||||||
|
self.conn.close()
|
||||||
|
|
||||||
#test routine
|
#test routine
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
authenticator = UidAuthenticator("test_uids_db.sqlite")
|
authenticator = UidAuthenticator("test_uids_db.sqlite")
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
# Unlocker is just dummy test class.
|
# Unlocker is just dummy test class.
|
||||||
[brmdoor]
|
[brmdoor]
|
||||||
auth_db_filename = test_uids_db.sqlite
|
auth_db_filename = test_uids_db.sqlite
|
||||||
|
#corresponding private key = 10ee85f987e7682d9acf24ab07ff0e302ee4cdd426f83a055d3a337a4f01314b
|
||||||
|
desfire_ed25519_pubkey = 4c625187d79fdee97a6af48cb8f854e7f313c8158de94e667e1509bd26617d27
|
||||||
#lock_opened_secs = 5
|
#lock_opened_secs = 5
|
||||||
#unknown_uid_timeout_secs = 5
|
#unknown_uid_timeout_secs = 5
|
||||||
log_file = -
|
log_file = -
|
||||||
|
|
|
@ -9,7 +9,7 @@ from binascii import hexlify
|
||||||
|
|
||||||
|
|
||||||
from nfc_smartcard import NFCDevice, NFCError
|
from nfc_smartcard import NFCDevice, NFCError
|
||||||
from brmdoor_authenticator import UidAuthenticator, YubikeyHMACAuthenthicator
|
from brmdoor_authenticator import UidAuthenticator, YubikeyHMACAuthenthicator, DesfireEd25519Authenthicator
|
||||||
import unlocker
|
import unlocker
|
||||||
|
|
||||||
class BrmdoorConfigError(ConfigParser.Error):
|
class BrmdoorConfigError(ConfigParser.Error):
|
||||||
|
@ -40,6 +40,7 @@ class BrmdoorConfig(object):
|
||||||
self.config.read(filename)
|
self.config.read(filename)
|
||||||
|
|
||||||
self.authDbFilename = self.config.get("brmdoor", "auth_db_filename")
|
self.authDbFilename = self.config.get("brmdoor", "auth_db_filename")
|
||||||
|
self.desfirePubkey = self.config.get("brmdoor", "desfire_ed25519_pubkey")
|
||||||
self.lockOpenedSecs = self.config.getint("brmdoor", "lock_opened_secs")
|
self.lockOpenedSecs = self.config.getint("brmdoor", "lock_opened_secs")
|
||||||
self.unknownUidTimeoutSecs = self.config.getint("brmdoor", "unknown_uid_timeout_secs")
|
self.unknownUidTimeoutSecs = self.config.getint("brmdoor", "unknown_uid_timeout_secs")
|
||||||
self.logFile = self.config.get("brmdoor", "log_file")
|
self.logFile = self.config.get("brmdoor", "log_file")
|
||||||
|
@ -65,6 +66,7 @@ class NFCScanner(object):
|
||||||
"""
|
"""
|
||||||
self.authenticator = UidAuthenticator(config.authDbFilename)
|
self.authenticator = UidAuthenticator(config.authDbFilename)
|
||||||
self.hmacAuthenticator = None
|
self.hmacAuthenticator = None
|
||||||
|
self.desfireAuthenticator = None
|
||||||
self.unknownUidTimeoutSecs = config.unknownUidTimeoutSecs
|
self.unknownUidTimeoutSecs = config.unknownUidTimeoutSecs
|
||||||
self.lockOpenedSecs = config.lockOpenedSecs
|
self.lockOpenedSecs = config.lockOpenedSecs
|
||||||
|
|
||||||
|
@ -82,6 +84,10 @@ class NFCScanner(object):
|
||||||
self.hmacAuthenticator = YubikeyHMACAuthenthicator(
|
self.hmacAuthenticator = YubikeyHMACAuthenthicator(
|
||||||
config.authDbFilename, self.nfc
|
config.authDbFilename, self.nfc
|
||||||
)
|
)
|
||||||
|
self.desfireAuthenticator = DesfireEd25519Authenthicator(
|
||||||
|
config.authDbFilename, self.nfc,
|
||||||
|
config.desfirePubkey
|
||||||
|
)
|
||||||
#self.nfc.pollNr = 0xFF #poll indefinitely
|
#self.nfc.pollNr = 0xFF #poll indefinitely
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
|
@ -124,7 +130,15 @@ class NFCScanner(object):
|
||||||
logging.info("Unlocking after HMAC for UID %s", record)
|
logging.info("Unlocking after HMAC for UID %s", record)
|
||||||
self.unlocker.unlock()
|
self.unlocker.unlock()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
#test for Desfire NDEF auth
|
||||||
|
record = self.desfireAuthenticator.checkUIDSignature(uid_hex)
|
||||||
|
|
||||||
|
if record is not None:
|
||||||
|
logging.info("Unlocking after Desfire NDEF ed25519 check for UID %s", record)
|
||||||
|
self.unlocker.unlock()
|
||||||
|
return
|
||||||
|
|
||||||
logging.info("Unknown UID %s", uid_hex)
|
logging.info("Unknown UID %s", uid_hex)
|
||||||
time.sleep(self.unknownUidTimeoutSecs)
|
time.sleep(self.unknownUidTimeoutSecs)
|
||||||
|
|
||||||
|
|
|
@ -28,5 +28,10 @@ if __name__ == "__main__":
|
||||||
key_hex TEXT,
|
key_hex TEXT,
|
||||||
nick TEXT)
|
nick TEXT)
|
||||||
""")
|
""")
|
||||||
|
cursor.execute("""CREATE TABLE authorized_desfires(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
uid_hex TEXT,
|
||||||
|
nick TEXT)
|
||||||
|
""")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
19
generate_ed25519_keypair.py
Executable file
19
generate_ed25519_keypair.py
Executable file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
"""
|
||||||
|
Used to generate keypair for signing NDEF messages for Mifare NDEF authentication
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import axolotl_curve25519 as curve
|
||||||
|
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
|
random32 = os.urandom(32)
|
||||||
|
|
||||||
|
private_key = curve.generatePrivateKey(random32)
|
||||||
|
public_key = curve.generatePublicKey(private_key)
|
||||||
|
|
||||||
|
print "private key in hex:", hexlify(private_key)
|
||||||
|
print "public key in hex :", hexlify(public_key)
|
||||||
|
|
27
sign_uid.py
Normal file
27
sign_uid.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import axolotl_curve25519 as curve
|
||||||
|
|
||||||
|
def signUid(private_key, uid):
|
||||||
|
"""
|
||||||
|
Create an Ed25519 signature for UID
|
||||||
|
:param private_key: Binary representation of Ed25519 key
|
||||||
|
:param uid: UID, decoded to binary from hex
|
||||||
|
:return: singature in binary format
|
||||||
|
"""
|
||||||
|
random64 = os.urandom(64)
|
||||||
|
signature = curve.calculateSignature(random64, private_key, uid)
|
||||||
|
return signature
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print >> sys.stderr, "Usage: sign_uid.py uid_hex ed25519_private_key_hex"
|
||||||
|
print >> sys.stderr, "Outputs binary signature, you will probably want to redirect it to a file"
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
private_key = sys.argv[3].decode("hex")
|
||||||
|
uid_bin = sys.argv[1].decode("hex")
|
||||||
|
sys.stdout.write(signUid(private_key, uid_bin))
|
66
test_nfc.py
66
test_nfc.py
|
@ -51,30 +51,48 @@ print "Available tests: %s" % ", ".join(sorted(tests.keys()))
|
||||||
print "Selected test: %s" % apdu_test
|
print "Selected test: %s" % apdu_test
|
||||||
|
|
||||||
# select apdus according to test name
|
# select apdus according to test name
|
||||||
hex_apdus = tests[apdu_test]
|
if apdu_test in tests:
|
||||||
apdus = [hex_apdu.replace(" ","").decode("hex") for hex_apdu in hex_apdus]
|
hex_apdus = tests[apdu_test]
|
||||||
|
apdus = [hex_apdu.replace(" ","").decode("hex") for hex_apdu in hex_apdus]
|
||||||
|
|
||||||
try:
|
|
||||||
nfc = NFCDevice()
|
|
||||||
uid = nfc.scanUID()
|
|
||||||
print "UID", hexlify(uid)
|
|
||||||
#nfc.close()
|
|
||||||
#nfc.open()
|
|
||||||
|
|
||||||
print "Now trying to send ISO14443-4 APDUs"
|
|
||||||
try:
|
try:
|
||||||
#nfc.selectPassiveTarget()
|
nfc = NFCDevice()
|
||||||
for apdu in apdus:
|
uid = nfc.scanUID()
|
||||||
print "Command APDU:", formatAPDU(apdu)
|
print "UID", hexlify(uid)
|
||||||
rapdu = nfc.sendAPDU(apdu)
|
#nfc.close()
|
||||||
print "Response APDU valid: %s, SW %04x, data %s" % (rapdu.valid(), rapdu.sw(), hexlify(rapdu.data()))
|
#nfc.open()
|
||||||
except NFCError, e:
|
|
||||||
print "Failed to transmit APDU:", e.what()
|
|
||||||
|
|
||||||
print "Device is opened:", nfc.opened()
|
print "Now trying to send ISO14443-4 APDUs"
|
||||||
print "Closing device"
|
try:
|
||||||
nfc.close()
|
#nfc.selectPassiveTarget()
|
||||||
print "Device is opened:", nfc.opened()
|
for apdu in apdus:
|
||||||
nfc.unload()
|
print "Command APDU:", formatAPDU(apdu)
|
||||||
except NFCError, e:
|
rapdu = nfc.sendAPDU(apdu)
|
||||||
print "Reading UID failed:", e.what()
|
print "Response APDU valid: %s, SW %04x, data %s" % (rapdu.valid(), rapdu.sw(), hexlify(rapdu.data()))
|
||||||
|
except NFCError, e:
|
||||||
|
print "Failed to transmit APDU:", e.what()
|
||||||
|
|
||||||
|
print "Device is opened:", nfc.opened()
|
||||||
|
print "Closing device"
|
||||||
|
nfc.close()
|
||||||
|
print "Device is opened:", nfc.opened()
|
||||||
|
nfc.unload()
|
||||||
|
except NFCError, e:
|
||||||
|
print "Reading UID failed:", e.what()
|
||||||
|
elif apdu_test == "desfire-ndef4":
|
||||||
|
try:
|
||||||
|
nfc = NFCDevice()
|
||||||
|
uid = nfc.scanUID()
|
||||||
|
print "UID", hexlify(uid)
|
||||||
|
#nfc.close()
|
||||||
|
#nfc.open()
|
||||||
|
|
||||||
|
ndef = nfc.readDesfireNDEF()
|
||||||
|
print ndef
|
||||||
|
print "Device is opened:", nfc.opened()
|
||||||
|
print "Closing device"
|
||||||
|
nfc.close()
|
||||||
|
print "Device is opened:", nfc.opened()
|
||||||
|
nfc.unload()
|
||||||
|
except NFCError, e:
|
||||||
|
print "Reading UID failed:", e.what()
|
||||||
|
|
Binary file not shown.
|
@ -1,5 +1,4 @@
|
||||||
import time
|
import time
|
||||||
import wiringpi2 as wiringpi
|
|
||||||
|
|
||||||
class Unlocker(object):
|
class Unlocker(object):
|
||||||
"""Abstract class/interface for Unlocker object.
|
"""Abstract class/interface for Unlocker object.
|
||||||
|
@ -35,14 +34,16 @@ class UnlockerWiringPi(Unlocker):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, config):
|
def __init__(self, config):
|
||||||
|
import wiringpi2 as wiringpi
|
||||||
Unlocker.__init__(self, config)
|
Unlocker.__init__(self, config)
|
||||||
wiringpi.wiringPiSetupGpio() # pin numbers follow P1 GPIO header
|
wiringpi.wiringPiSetupGpio() # pin numbers follow P1 GPIO header
|
||||||
self.lockPin = self.config.getint("UnlockerWiringPi", "lock_pin")
|
self.lockPin = self.config.getint("UnlockerWiringPi", "lock_pin")
|
||||||
wiringpi.pinMode(self.lockPin, 1) #output
|
wiringpi.pinMode(self.lockPin, 1) #output
|
||||||
|
|
||||||
def unlock(self):
|
def unlock(self):
|
||||||
"""Unlocks lock at configured pin by pulling it high.
|
"""Unlocks lock at configured pin by pulling it high.
|
||||||
"""
|
"""
|
||||||
|
import wiringpi2 as wiringpi
|
||||||
wiringpi.digitalWrite(self.lockPin, 1)
|
wiringpi.digitalWrite(self.lockPin, 1)
|
||||||
time.sleep(self.lockOpenedSecs)
|
time.sleep(self.lockOpenedSecs)
|
||||||
wiringpi.digitalWrite(self.lockPin, 0)
|
wiringpi.digitalWrite(self.lockPin, 0)
|
||||||
|
@ -52,5 +53,6 @@ class UnlockerWiringPi(Unlocker):
|
||||||
Lock the lock back. Meant to be used when program is shut down
|
Lock the lock back. Meant to be used when program is shut down
|
||||||
so that lock is not left disengaged.
|
so that lock is not left disengaged.
|
||||||
"""
|
"""
|
||||||
|
import wiringpi2 as wiringpi
|
||||||
wiringpi.digitalWrite(self.lockPin, 0)
|
wiringpi.digitalWrite(self.lockPin, 0)
|
||||||
|
|
||||||
|
|
62
write_signed_ndef_on_desfire.py
Executable file
62
write_signed_ndef_on_desfire.py
Executable file
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
from binascii import hexlify
|
||||||
|
|
||||||
|
from nfc_smartcard import NFCDevice, NFCError
|
||||||
|
from sign_uid import signUid
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
print "Usage: write_signed_ndef_on_desfire.py private_key_in_hex"
|
||||||
|
sys.exit(3)
|
||||||
|
|
||||||
|
tempFile = None
|
||||||
|
tempFname = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
print "Opening NFC reader"
|
||||||
|
nfc = NFCDevice()
|
||||||
|
nfc.pollNr = 0xFF #poll indefinitely
|
||||||
|
print "Waiting for Desfire card to appear in the reader"
|
||||||
|
uid_hex = hexlify(nfc.scanUID())
|
||||||
|
key = sys.argv[1].decode("hex")
|
||||||
|
|
||||||
|
print("Got UID %s", uid_hex)
|
||||||
|
signature = signUid(key, uid_hex.decode("hex"))
|
||||||
|
(tempFile, tempFname) = tempfile.mkstemp(dir="/tmp")
|
||||||
|
with tempFile:
|
||||||
|
tempFile.write(signature)
|
||||||
|
except NFCError, e:
|
||||||
|
#this exception happens also when scanUID times out
|
||||||
|
print("Failed to wait for Desfire card: %s" % e)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception, e:
|
||||||
|
print("Something went wrong when writing the signature to file:", e)
|
||||||
|
sys.exit(2)
|
||||||
|
finally:
|
||||||
|
nfc.close()
|
||||||
|
nfc.unload()
|
||||||
|
if tempFname:
|
||||||
|
os.unlink(tempFname)
|
||||||
|
|
||||||
|
# We'll just call the command line tools so that we don't need to copy&paste the NDEF writing code to nfc_smartcard.cpp
|
||||||
|
print "Formatting card"
|
||||||
|
res = os.system("mifare-desfire-format -y")
|
||||||
|
if res != 0:
|
||||||
|
print "Formatting failed"
|
||||||
|
sys.exit(4)
|
||||||
|
print "Creating NDEF file/application"
|
||||||
|
res = os.system("mifare-desfire-create-ndef -y")
|
||||||
|
if res != 0:
|
||||||
|
print "Creating NDEF failed"
|
||||||
|
sys.exit(4)
|
||||||
|
print "Writing NDEF with signature onto Desfire"
|
||||||
|
res = os.system("mifare-desfire-create-ndef -y -i '%'" % tempFname)
|
||||||
|
if res != 0:
|
||||||
|
print "Writing NDEF failed"
|
||||||
|
sys.exit(4)
|
||||||
|
|
||||||
|
print "All done"
|
Loading…
Add table
Add a link
Reference in a new issue