├── .gitignore ├── CHANGES ├── ChAP.py ├── INSTALL ├── Makefile ├── README.TXT ├── RFIDIOt-android.patch ├── RFIDIOt.py.orig ├── RFIDIOtconfig.opts ├── bruteforce.py ├── cardselect.py ├── copytag.py ├── delete-smartcafe.gpsh ├── demotag.py ├── eeprom.py ├── fdxbnum.py ├── formatmifare1kvalue.py ├── froschtest.py ├── hidprox.py ├── hitag2brute.py ├── hitag2reset.py ├── isotype.py ├── java ├── Makefile ├── jcop_delete_atr_hist.gpsh ├── jcop_set_atr_hist.cap ├── jcop_set_atr_hist.gpsh ├── smartcafe_delete_atr_hist.gpsh ├── smartcafe_set_atr_hist.gpsh └── src │ └── jcop_set_atr_hist │ ├── ATRGlobal.java │ └── JCOPSetATRHist.java ├── jcop_mifare_access.cap ├── jcop_mifare_access.gpsh ├── jcopmifare.py ├── jcopsetatrhist.py ├── jcoptool.py ├── lfxtype.py ├── loginall.py ├── ls_nfc_client-3.apk ├── ls_nfc_client-readme.txt ├── mifare.pdf ├── mifarekeys.py ├── mrpkey.py ├── multiselect.py ├── nfcid.py ├── pn532emulate.py ├── pn532mitm.py ├── q5reset.py ├── readlfx.py ├── readmifare1k.py ├── readmifaresimple.py ├── readmifareultra.py ├── readtag.py ├── rfidiot-cli.py ├── rfidiot ├── RFIDIOt.py ├── __init__.py ├── iso3166.py ├── pn532.py ├── pyandroid.py ├── pynfc.py └── rfidiotglobals.py ├── script.txt ├── send_apdu.py ├── setup.py ├── sod.py ├── test.txt ├── testacg.sh ├── testfrosch-serial.sh ├── testfrosch.sh ├── testlahf.sh ├── transit.py ├── unique.py ├── upload2cosmo.gpsh ├── upload2jcop.gpsh ├── upload2nokia.gpsh ├── upload2smartcafe.gpsh ├── writelfx.py └── writemifare1k.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | build/ 3 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | v0.1: 2006-04-28 2 | First release. 3 | 4 | v0.1a: 2006-05-16 5 | Add 'Value' commands: 6 | readvalueblock 7 | writevalueblock 8 | MIFAREvb (set variables from value block) 9 | 10 | v0.1b: 2006-05-29 11 | Make readblock non MIFARE specific 12 | Add readMIFAREblock command 13 | Add reset() call to all test programs (to switch off constant read) 14 | Add readlfx program to support ACG LFX reader 15 | 16 | v0.1c: 2006-05-30 17 | Add LFXTags hash (125 kHz tag types) 18 | Add lfxtype.py (command line tag identifier) 19 | 20 | v0.d: 2006-06-01 21 | Add access control block user data byte to MIFARE structure 22 | Add LFX tag type detection to cardselect.py 23 | 24 | v0.e: 2006-09-29 25 | Add ICAO 9303 structures for Machine Readable Passports 26 | New test program: mrpkey.py for ICAO 9303 27 | Move reader config to RFIDIOtconfig.py 28 | Add EM4x05 ID decode 29 | 30 | v0.f: 2006-10-24 31 | Emergency release - 0.e lost in webserver disk crash 32 | Contains work in progress!!! 33 | Rename EM4x05 decode to more generic FDX-B 34 | Add EM4x02 'Unique' ID decode/encode 35 | Add passport file reads and image display 36 | 37 | v0.g: 2006-10-27 38 | Tidy up! 39 | Update all version numbers 40 | 41 | v.0.h: 42 | Add Hitag2 reading (readlfx) 43 | Add fdx-b cloning to Q5 / Hitag2 (fdxbnum) 44 | Add q5unfuck (does what it say on the tin!) 45 | mrpkey - display all data in GUI 46 | fdxbnum - add ability to write raw 16 digit HEX (to clone non-compliant tags) 47 | 48 | v0.i: 2006-12-10 49 | Fix login error for sector 0 50 | 51 | v0.j: 52 | Fix iso_7816_fail to allow non-passports to fail properly 53 | Add support for Frosch Hitag reader/writer 54 | Start to rationalise routines to always return True or False 55 | fdxbnum - add Frosch support for Hitag2 56 | fdxbnum - wait for blank tag in WRITE mode 57 | 58 | v0.k: 59 | was release j - forgot to update version number! 60 | 61 | v0.m: 62 | add facility to set Q5 native ID in 'q5reset.py' 63 | fix 'EM4x02' ID mode in 'unique.py' (was reversed) 64 | allow forcing of tag type in 'readlfx.py' 65 | add 'readtag.py' - read data blocks with no login 66 | add 'copytag.py' - copy data blocks to matching blank 67 | add 'isotype.py' - determine HF tag types 68 | add CHECK for Machine Readable Document in 'mrpkey.py' 69 | fix bruteforce for non complete document numbers in 'mrpkey.py' 70 | fix bruteforce length of field in 'mrpkey.py' 71 | add offsets for usa & netherlands to 'mrpkey.py' 72 | add global overrides for line/speed etc. in RFIDIOtconfig.py [AL & Philippe Biondi] 73 | 74 | v0.n: 75 | add CLONE mode to 'unique.py' 76 | make 'mrpkey.py' more intelligent about reading passport contents: 77 | read all data groups 78 | extract image from CBEFF block in EF.DG2 79 | extract public key certificate from EF.SOD (requires openssl installation) 80 | add asn.1 field length encoding rules 81 | add 'sod.py' tool for brute force finding of certificates in EF_SOD.BIN (requires openssl installation) 82 | 83 | v0.p 84 | add PCSC support (http://pcsclite.alioth.debian.org/ and http://pyscard.sourceforge.net/) [hints/tips/inspiration Henryk Plötz] 85 | fix cardselect.py and multiselect.py to check for presence of card 86 | fix 'waitfor/do nothing' in RFIDIOt.py [Philippe Biondi] 87 | cleaner check digit calc in mrpkey.py [Philippe Biondi] 88 | change -r to -R (reader type) to allow -r to be used for PCSC compatibility 89 | add speed/framesize reporting to mrpkey.py 90 | increase MAX read chunk size to 118 in mrpkey.py (needs fixing to go up to device supported size ISO_FRAMESIZE) 91 | fix bit allignment issue in FDXBID encoding/decoding [Matsche] 92 | add global uid variable 93 | add locked block reporting to readmifare 94 | add readmifaresimple.py 95 | 96 | v0.q 97 | fix asn1 field length calculation in mrpkey.py 98 | add human readable config block for Q5 in readlfx.py 99 | add Manchester encoding to RFIDIOt.py and unique.py 100 | add serial port opening and baud rate checking for ACG / Frosch in RFIDIOt.py 101 | add Q5 emulation detection in lfxtype.py 102 | 103 | v0.r 104 | add SCM Microsystems reader support 105 | add -d (debug) option 106 | switch to T=1 protocol for PC/SC 107 | add auto-detect of PC/SC reader types 108 | fix minor reporting issues in readmifaresimple.py 109 | fix setting of tag type 'ALL' on ACG readers (different for LF or HF) 110 | added a bunch of PCSC ATR card types 111 | add reading of previously stored files to mrpkey.py 112 | fix CBEFF processing in mrpkey.py 113 | fix bruteforcing of first character in mrpkey.py [Petter Bjorklund] 114 | add ID Card processing to mrpkey.py [vonJeek ] 115 | 116 | v0.s 117 | fix -L issue in RFIDIOtconfig (readernum must be 0) 118 | add human readable dump to readmifaresimple.py (ReadablePrint() in RFIDIOt) 119 | fix logic in tag selection in unique.py (would not use hitag2) 120 | add hitag2 login (password mode) to RFIDIOt.py 121 | add hitag2bruteforce program hitag2brute.py 122 | start migrating definitions into smaller files to aid sharing with other apps (e.g. iso3166.py) 123 | add Windows distribution [Zac Franken] 124 | 125 | v0.t - October 2008 126 | add WRITE function to mrpkey.py for vonJeek JCOP emulator (http://freeworld.thc.org/thc-epassport/) 127 | add Makefile and vonJeek.gpsh for installing vonJeek epassport.cap to JCOP 128 | add VONJEEK declarations for vonJeek emulator to RFIDIOt.py 129 | set mrpkey file types to binary for windows compatibility [Jeroen van Beek / vonJeek ] 130 | use windows compatible command execution for external commands in mrpkey [Jeroen van Beek / vonJeek ] 131 | add WRITE function to mrpkey.py for JMRTD JCOP emulator (http://jmrtd.org/) 132 | allow mrpkey to skip objects (e.g. fingerprint (EF.DG3) protected by active authentication) 133 | add mifarekeys.py - calculate 3DES MifarePWD for Access to Mifare memory/functions on Dual Interface JCOP cards 134 | as per Philips Application Note AN02105, http://www.nxp.com/acrobat_download/other/identification/067512.pdf 135 | add some country codes to iso3166.py [Jeroen van Beek / vonJeek ] 136 | add -g 'No GUI' option to RFIDIOtconfig.py 137 | 138 | v0.u - November 2008 139 | add testlahf.sh script for testing LAHF units 140 | fix -R reader type override in RFIDIOtconfig.py 141 | add RFIDIOtconfig.py checking for global overrides in one of the following locations (in search order): 142 | 143 | $(RFIDIOtconfig_opts) 144 | ./RFIDIOtconfig.opts 145 | /etc/RFIDIOtconfig.opts 146 | 147 | options should be specified on the first line as if typed on the command line, e.g. 148 | 149 | -s 9600 -l /dev/ttyUSB0 150 | 151 | command line options will take precedence over this file. 152 | 153 | add -n (No Init) command to RFIDIOtconfig.py - allow modules to run without hardware 154 | add display of checksum-corrected MRZ to mrpkey.py 155 | add jcop_mifare_access.cap - mifare access applet for JCOP 156 | add jcop_mifare_access.gpsh and target in Makefile for installation of jcop_mifare_access.cap 157 | add jcopmifare.py test program for JCOP mifare emulation 158 | add display of biometric features on FACE in mrpkey.py 159 | 160 | v0.v - January 2009 161 | fix ATS position & length in RFIDIOT.py 162 | add jcopsetatrhist.py - sets ATR Historical Bytes (ATS) on JCOP cards 163 | add jcop_set_atr_hist.cap - java applet for setting ATR/ATS 164 | add JAVA source for jcop_set_atr_hist.cap 165 | move iso_7816 routines into RFIDIOt (from mrpkey.py) 166 | fix exit status of all test programs and RFIDIOt (should be True on error) 167 | 168 | v0.w 169 | fix ACG reset/info sequence in RFIDIOt.py 170 | fix facial image display bug in mrpkey.py where conversion is required [Andreas Schmidt] 171 | fix RANDOM_UID setting in jcop_mifare_access.cap/jcopmifare.py (you will need a secret key from NXP) 172 | add jcoptool.py - JCOP toolkit (work in progress) 173 | mrpkey.py changes: 174 | fix binary mode when reading files under Windows (for WRITE to card) 175 | fix computation of composite checksum digit 176 | support reading non-BAC passports 177 | specify a dummy MRZ or simply the keyword 'PLAIN' for Plain Access if there is no Basic Access Control 178 | support writing non-BAC passports (only for vonJeek cards) 179 | new commands SETBAC and UNSETBAC to toggle the BAC mode on vonJeek cards 180 | extract & display signature image stored in DG7, if any 181 | fix bug in Jpeg 2000 handling & add Jpeg 2000 support for DG7 182 | better error handling if PCSC daemon is down or no reader is found 183 | support clone mode by specifying PLAIN/MRZ and WRITE: first read then write 184 | support shortened MRZ (as in mrp0wn) 185 | strip AA & EAC by default when writing, set STRIP_INDEX=False to disable stripping 186 | change Makefile to match vonJeek gpshell files (upload2jcop.gpsh & upload2nokia.gpsh) 187 | 188 | v0.x 189 | add support for ACS readers and Alcatel-Lucent Tikitag/Touchatag [props to pytey for http://hackerati.com/post/57314994/rfid-on-the-cheap-hacking-tikitag] 190 | rationalise PCSC subtypes 191 | add hidprox.py for reading HID ProxCards (only tested with OmniKey 5325) 192 | add pn532.py - definitions for nxp pn532 chip 193 | add pn532emulate.py - run nxp pn532 in emulator mode 194 | add pn532mitm.py - relay traffic between reader and emulator, and log APDU and responses 195 | 196 | v0.y 197 | fix support for ACS PCSC-2 devices (e.g. ACR 122U) 198 | add writelfx.py - test write LF devices 199 | fix 3DES key setting for ID cards in mrpkey.py 200 | allow missing files to be skipped if running in files mode in mrpkey.py 201 | 202 | v0.z 203 | add xorcheck.py - search for valid final byte of rolling LRC [input from Henryk Plötz] 204 | add transit.py - program Q5 with FDI Matalec 'TRANSIT 500' or 'TRANSIT 999' standard UID [input from Proxmark Community] 205 | 206 | v1.0a 207 | make mrpkey.py slightly easier to add new document types to 208 | add COPY and RESET functions to readmifaresimple.py 209 | add automatic keytype and default key checking to readmifaresimple.py 210 | fix MIFARE KeyA and KeyB handling on all supported readers 211 | add readmifareultra.py - read Mifare UltraLight tags [Keith Howell] 212 | add support for libnfc devices [Nick von Dadelszen] (work in progress) 213 | 214 | v1.0b 215 | allow global overrides to be specified in ENV variable, e.g. 216 | export RFIDIOtconfig="-s 9600 -l /dev/ttyUSB1 -R RFIDIOt.rfidiot.READER_ACG" 217 | use latest pynfc.py (ver 0.2) for libnfc devices 218 | add device listing to libnfc support (-N) 219 | add more keys to readmifaresimple.py [nethemba] 220 | strip leading character from ACG LFX UID 221 | add cosmo card (alternative to jcop) upload files for gpshell 222 | fix init for pn532mitm.py 223 | make sure all programs exit with status (also removes annoying PCSC error on close) 224 | wait for passport in mrpkey.py [Adam Urban] 225 | add lifecycle data to jcoptool.py 226 | 227 | v1.0c 228 | fix reading unknown block size in readblock() 229 | detect more ACS readers [Keith Howell] 230 | 231 | v1.0d 232 | port pynfc to new libNFC API (1.6.0-rc1) 233 | add libnfc mifare command support (TODO: error handling) 234 | *** note that early ACS devices such as ACR122-V1/TikiTag/TouchaTag are not currently 235 | working with native libNFC (V2 seem to work fine). This is a libNFC issue. 236 | However, ACR122-V1/TikiTag/TouchaTag devices can be used if libNFC is compiled with 237 | acr122_pcsc driver support, and then used in conjunction with pcscd, in chich case 238 | they should work as READER_LIBNFC and/or READER_PCSC types. 239 | Android support [Nick von Dadelszen] 240 | 241 | v1.0e 242 | move to a package style implementation 243 | 244 | v1.0h 245 | detect ACS reader type more reliably 246 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | to install: 2 | 3 | sudo python ./setup.py install 4 | 5 | this will create a python library called 'rfidiot'. 6 | 7 | *** important: 8 | 9 | as some scripts have moved from the execution path and into the library, you 10 | should ensure that no old copies are left lying around. in particular, the 11 | following files should only exist in your python DIST directory 12 | (e.g. /usr/local/lib/python2.7/dist-packages/rfidiot), and not in /usr/local/bin: 13 | 14 | iso3166.py 15 | iso3166.pyc 16 | pn532.py 17 | pn532.pyc 18 | pyandroid.py 19 | pyandroid.pyc 20 | pynfc.py 21 | pynfc.pyc 22 | rfidiotglobals.py 23 | rfidiotglobals.pyc 24 | RFIDIOt.py 25 | RFIDIOt.pyc 26 | 27 | for a brief moment setup was configured to create e.g. /usr/local/lib/python2.7/dist-packages/RFIDIOt 28 | which was an error, so you can safely remove /usr/local/lib/python2.7/dist-packages/RFIDIOt* or 29 | your equivelant. 30 | 31 | *** note - if you are upgrading from a version that didn't use an install script, 32 | and you've written your own clients, you'll need to make the following changes: 33 | 34 | replace all instances of 'RFIDIOTconfig' with 'rfidiot' 35 | 36 | e.g. 37 | 38 | import RFIDIOtconfig 39 | 40 | becomes 41 | 42 | import rfidiot 43 | 44 | and 45 | 46 | args= RFIDIOtconfig.args 47 | 48 | becomes 49 | 50 | args= rfidiot.args 51 | 52 | etc. 53 | 54 | everything else should behave the same as before. please inform me if you hit any snags! 55 | 56 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for uploading vonJeek epassport emulator and Mifare acccess applet 2 | # http://freeworld.thc.org/thc-epassport/ 3 | # 4 | # gpshell can be found here: 5 | # http://sourceforge.net/project/showfiles.php?group_id=143343&package_id=159897 6 | # 7 | # blank JCOP cards can be got here: 8 | # (note vonJeek applet requires 72K card) 9 | # http://www.rfidiot.org/ 10 | # 11 | # This makefile by Adam Laurie, 2008 12 | 13 | # GPShell... 14 | GPSHELL= "gpshell" 15 | GPSHELL_VONJEEK_SCRIPT="upload2jcop.gpsh" 16 | GPSHELL_VONJEEK_NOKIA_SCRIPT="upload2nokia.gpsh" 17 | GPSHELL_MIFARE_SCRIPT="jcop_mifare_access.gpsh" 18 | GPSHELL_ATR_SCRIPT="jcop_set_atr_hist.gpsh" 19 | GPSHELL_ATR_UNINSTALL_SCRIPT="jcop_delete_atr_hist.gpsh" 20 | GPSHELL_NOKIA_MIFARE_SCRIPT="nokia_jcop_mifare_access.gpsh" 21 | 22 | # install passport applet 23 | install-passport: 24 | # first clean the script of nasty windows s 25 | tr -d '\r' < $(GPSHELL_VONJEEK_SCRIPT) > /tmp/$(GPSHELL_VONJEEK_SCRIPT) 26 | $(GPSHELL) /tmp/$(GPSHELL_VONJEEK_SCRIPT) 27 | 28 | # install passport applet to Nokia 29 | # phone must have been unlocked with the unlock midlet: 30 | # Nokia NFC Unlock Service MIDlet - http://www.forum.nokia.com 31 | install-passport-nokia: 32 | tr -d '\r' < $(GPSHELL_VONJEEK_NOKIA_SCRIPT) > /tmp/$(GPSHELL_VONJEEK_NOKIA_SCRIPT) 33 | $(GPSHELL) /tmp/$(GPSHELL_VONJEEK_NOKIA_SCRIPT) 34 | 35 | # install mifare access applet 36 | install-mifare: 37 | $(GPSHELL) $(GPSHELL_MIFARE_SCRIPT) 38 | 39 | # install ATR History applet 40 | install-atr: 41 | cd java && $(GPSHELL) $(GPSHELL_ATR_SCRIPT) 42 | 43 | # delete ATR History applet 44 | uninstall-atr: 45 | cd java && $(GPSHELL) $(GPSHELL_ATR_UNINSTALL_SCRIPT) 46 | -------------------------------------------------------------------------------- /README.TXT: -------------------------------------------------------------------------------- 1 | /* RFIDIOt.py - RFID IO tools for python 2 | * 3 | * Adam Laurie 4 | * http://rfidiot.org/ 5 | * 6 | * This code is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This code is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | */ 16 | 17 | Copyright (c) 2006-2011 Adam Laurie 18 | 19 | q: What is RFIDIOt? 20 | a: A collection of tools and libraries for exploring RFID technology, written 21 | in python. 22 | 23 | q: Why RFIDIOt? 24 | a: I like silly puns. Also, I'm coming at this from an idiot's point of view: 25 | I know nothing about RFID tags, and even less about python. As such, I felt a 26 | complete idiot when I started. :) 27 | 28 | q: How can I contribute? 29 | a: Send me patches, info, new tools, coffee, money, drugs and/or a Miles Davis song :) 30 | 31 | q: What hardware is supported? 32 | a: So far this works with the ACG serial readers. I use the CF Card model, 33 | but it should also work with the USB version by changing the serial port to 34 | /dev/ttyUSB0. You can find more details here: 35 | 36 | http://www.acg.de 37 | 38 | q: So what exactly is here? 39 | a: Please see http://www.rfidiot.org/documentation.html 40 | -------------------------------------------------------------------------------- /RFIDIOt-android.patch: -------------------------------------------------------------------------------- 1 | --- RFIDIOt.py 2011-10-30 10:05:00.770555688 +1300 2 | +++ RFIDIOt-android.py 2011-10-30 10:04:37.674551272 +1300 3 | @@ -40,7 +40,8 @@ 4 | from operator import * 5 | import pynfc 6 | import signal 7 | - 8 | +import socket 9 | +import pyandroid 10 | 11 | try: 12 | import smartcard, smartcard.CardRequest 13 | @@ -153,6 +154,10 @@ 14 | elif self.readertype == self.READER_LIBNFC: 15 | self.nfc = pynfc.NFC() 16 | self.readername = self.nfc.LIBNFC_READER 17 | + #Andoid reader 18 | + elif self.readertype == self.READER_ANDROID: 19 | + self.android = pyandroid.Android() 20 | + self.readername = "Android" 21 | elif self.readertype == self.READER_NONE: 22 | self.readername = 'none' 23 | else: 24 | @@ -204,6 +209,7 @@ 25 | READER_ACS= 0x07 26 | READER_LIBNFC = 0x08 27 | READER_NONE = 0x09 28 | + READER_ANDROID = 0x10 29 | # TAG related globals 30 | errorcode= '' 31 | binary= '' 32 | @@ -765,6 +771,8 @@ 33 | os._exit(True) 34 | if self.readertype == self.READER_LIBNFC: 35 | print 'LibNFC', self.readername 36 | + if self.readertype == self.READER_ANDROID: 37 | + print 'Android Reader' 38 | print 39 | # 40 | # reader functions 41 | @@ -799,6 +807,9 @@ 42 | if self.readertype == self.READER_LIBNFC: 43 | self.nfc.powerOff() 44 | self.nfc.powerOn() 45 | + if self.readertype == self.READER_ANDROID: 46 | + self.android.reset() 47 | + 48 | def version(self): 49 | if self.readertype == self.READER_ACG: 50 | self.ser.write('v') 51 | @@ -819,6 +830,8 @@ 52 | else: 53 | print self.FROSCH_Errors[self.errorcode] 54 | os._exit(True) 55 | + if self.readertype == self.READER_ANDROID: 56 | + print 'Android version: ', self.android.VERSION 57 | def id(self): 58 | return self.readEEPROM(0)[:2] + self.readEEPROM(1)[:2] + self.readEEPROM(2)[:2] + self.readEEPROM(3)[:2] 59 | def station(self): 60 | @@ -986,6 +999,23 @@ 61 | return False 62 | except ValueError: 63 | self.errorcode = 'Error reading card using LIBNFC' + e 64 | + 65 | + if self.readertype == self.READER_ANDROID: 66 | + try: 67 | + if DEBUG: 68 | + print 'Reading card using Android' 69 | + uid = self.android.select() 70 | + if uid: 71 | + self.uid = uid 72 | + if DEBUG: 73 | + print '\tUID: ' + self.uid 74 | + return True 75 | + else: 76 | + if DEBUG: 77 | + print 'Error selecting card' 78 | + return False 79 | + except ValueError: 80 | + self.errorcode = 'Error reading card using Android' + e 81 | return False 82 | def h2publicselect(self): 83 | "select Hitag2 from Public Mode A/B/C" 84 | @@ -1007,7 +1037,7 @@ 85 | return False 86 | return True 87 | def hsselect(self,speed): 88 | - if self.readertype == self.READER_PCSC or self.readertype == self.READER_LIBNFC: 89 | + if self.readertype == self.READER_PCSC or self.readertype == self.READER_LIBNFC or self.READER_ANDROID: 90 | # low level takes care of this, so normal select only 91 | if self.select(): 92 | #fixme - find true speed/framesize 93 | @@ -1361,7 +1391,14 @@ 94 | if self.errorcode == self.ISO_OK: 95 | return True 96 | return False 97 | - dlength= 5 98 | + if self.readertype == self.READER_ANDROID: 99 | + result = self.android.sendAPDU(cla+self.ISOAPDU[ins]+p1+p2+lc+data+le) 100 | + self.data = result[0:-4] 101 | + self.errorcode = result[len(result)-4:len(result)] 102 | + if self.errorcode == self.ISO_OK: 103 | + return True 104 | + return False 105 | + dlength= 5 106 | command= pcb+cla+self.ISOAPDU[ins]+p1+p2+lc+data+le 107 | dlength += len(data) / 2 108 | dlength += len(lc) / 2 109 | -------------------------------------------------------------------------------- /RFIDIOtconfig.opts: -------------------------------------------------------------------------------- 1 | #-s 9600 -l /dev/ttyUSB1 2 | # uncomment the above line to enable global overrides 3 | # options should be all on the first line, as if added on the command line 4 | # this file will be looked for in the following places: 5 | # $(RFIDIOtconfig_opts) - note that this environment variable should be set to the full path and filename 6 | # ./RFIDIOtconfig.opts 7 | # /etc/RFIDIOtconfig.opts 8 | -------------------------------------------------------------------------------- /bruteforce.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # bruteforce.py - try random numbers to login to sector 0 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import random 26 | import sys 27 | import os 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(True) 34 | 35 | args= rfidiot.args 36 | help= rfidiot.help 37 | 38 | card.info('bruteforce v0.1i') 39 | card.select() 40 | print 'Card ID: ' + card.uid 41 | 42 | finished = 0 43 | tries = 0 44 | print ' Tries: %s\r' % tries, 45 | sys.stdout.flush() 46 | 47 | while not finished: 48 | 49 | tries += 1 50 | if tries % 10 == 0: 51 | print ' Tries: %s\r' % tries, 52 | sys.stdout.flush() 53 | 54 | if len(args) == 1: 55 | key= args[0] 56 | if len(key) != 12: 57 | print ' Static Key must be 12 HEX characters!' 58 | os._exit(True) 59 | print 'Trying static key: ' + key 60 | else: 61 | key = '%012x' % random.getrandbits(48) 62 | 63 | for type in ['AA', 'BB']: 64 | card.select() 65 | if card.login(0,type,key): 66 | print '\nlogin succeeded after %d tries!' % tries 67 | print 'key: ' + type + ' ' + key 68 | finished = 1 69 | break 70 | elif card.errorcode != 'X' and card.errorcode != '6982' and card.errorcode != '6200': 71 | print '\nerror!' 72 | print 'key: ' + type + ' ' + key 73 | print 'error code: ' + card.errorcode 74 | finished = 1 75 | break 76 | if finished: 77 | break 78 | os._exit(False) 79 | -------------------------------------------------------------------------------- /cardselect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # cardselect.py - select card and display ID 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | import rfidiot 26 | import sys 27 | import os 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(True) 34 | 35 | args= rfidiot.args 36 | 37 | card.info('cardselect v0.1m') 38 | # force card type if specified 39 | if len(args) == 1: 40 | card.settagtype(args[0]) 41 | else: 42 | card.settagtype(card.ALL) 43 | 44 | if card.select(): 45 | print ' Card ID: ' + card.uid 46 | if card.readertype == card.READER_PCSC: 47 | print ' ATR: ' + card.pcsc_atr 48 | else: 49 | if card.errorcode: 50 | print ' '+card.ISO7816ErrorCodes[card.errorcode] 51 | else: 52 | print ' No card present' 53 | os._exit(True) 54 | os._exit(False) 55 | -------------------------------------------------------------------------------- /copytag.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # copytag.py - read all sectors from a standard tag and write them back 4 | # to a blank 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | import rfidiot 26 | import sys 27 | import os 28 | import string 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | print "Couldn't open reader!" 34 | os._exit(True) 35 | 36 | card.info('copytag v0.1d') 37 | card.select() 38 | print '\nID: ' + card.uid 39 | print ' Reading:' 40 | 41 | buffer= [] 42 | 43 | card.select() 44 | for x in range(98): 45 | if card.readblock(x): 46 | print ' Block %02x: %s\r' % (x , card.data), 47 | sys.stdout.flush() 48 | buffer.append(card.data) 49 | else: 50 | if x == 0: 51 | print 'Read error: ', card.ISO7816ErrorCodes[card.errorcode] 52 | break 53 | 54 | if x > 0: 55 | print '\nRead %d blocks' % x 56 | raw_input('Remove source tag and hit to continue...') 57 | targettype= card.tagtype 58 | while 42: 59 | card.waitfortag('Waiting for blank tag...') 60 | print 'ID: ' + card.uid 61 | if card.tagtype != targettype: 62 | raw_input('Invalid tag type! Hit to continue...') 63 | continue 64 | if not card.readblock(0): 65 | raw_input('Tag not readable! Hit to continue...') 66 | continue 67 | if len(card.data) != len(buffer[0]): 68 | print 'Wrong blocksize! (%d / %d)' % (len(buffer[0]),len(card.data)), 69 | raw_input(' Hit to continue...') 70 | continue 71 | if string.upper(raw_input('*** Warning! Data will be overwritten! Continue (y/n)?')) == 'Y': 72 | break 73 | else: 74 | os._exit(False) 75 | print ' Writing:' 76 | for n in range(x): 77 | print ' Block %02x: %s\r' % (n , buffer[n]), 78 | sys.stdout.flush() 79 | if not card.writeblock(n, buffer[n]): 80 | print '\nWrite failed!' 81 | print '\n Verifying:' 82 | for n in range(x): 83 | print ' Block %02x: %s' % (n , buffer[n]), 84 | if not card.readblock(n) or card.data != buffer[n]: 85 | print '\nVerify failed!' 86 | os._exit(True) 87 | print ' OK\r', 88 | sys.stdout.flush() 89 | print 90 | os._exit(False) 91 | else: 92 | print 'No data!' 93 | os._exit(True) 94 | -------------------------------------------------------------------------------- /delete-smartcafe.gpsh: -------------------------------------------------------------------------------- 1 | // script to install epassport.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | establish_context 4 | // edit the following line to match your PCSC reader 5 | //card_connect -readerNumber 2 6 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 7 | card_connect 8 | select -AID A000000003000000 9 | open_sc -scp 2 -scpimpl 0x15 -security 1 -keyind 0 -keyver 0 -keyDerivation emvcps11 -key 404142434445464748494A4B4C4D4E4F 10 | delete -AID A00000024710 11 | card_disconnect 12 | release_context 13 | -------------------------------------------------------------------------------- /demotag.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # demotag.py - test IAIK TUG DemoTag` 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | import rfidiot 24 | import sys 25 | import os 26 | 27 | try: 28 | card= rfidiot.card 29 | except: 30 | print "Couldn't open reader!" 31 | os._exit(False) 32 | 33 | args= rfidiot.args 34 | 35 | print 'Setting ID to: ' + args[0] 36 | print card.demotag(card.DT_SET_UID,card.ToBinary(args[0])) 37 | -------------------------------------------------------------------------------- /eeprom.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # eeprom.py - display reader's eeprom settings 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | 28 | try: 29 | card= rfidiot.card 30 | except: 31 | print "Couldn't open reader!" 32 | os._exit(True) 33 | 34 | card.info('eeprom v0.1e') 35 | print 'Station:\t' + card.station() 36 | print 'Protocol:\t' + card.PCON() 37 | print 'Protocol2:\t' + card.PCON2() 38 | print 'Protocol3:\t' + card.PCON3() 39 | 40 | address= 0 41 | while address < 0xf0: 42 | print 'address %02x:\t%s' % (address,card.readEEPROM(address)) 43 | address += 1 44 | -------------------------------------------------------------------------------- /fdxbnum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # fdxbnum.py - generate / decode FDX-B EM4x05 compliant IDs 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | import string 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | os._exit(True) 33 | 34 | args= rfidiot.args 35 | help= rfidiot.help 36 | 37 | card.info('fdxbnum v0.1f') 38 | 39 | precoded= False 40 | 41 | if not help and (len(args) == 1 or len(args) == 2): 42 | print "Decode: " 43 | if len(args[0]) == 16: 44 | card.FDXBIDPrint(args[0]) 45 | else: 46 | card.FDXBIDPrint(args[0][1:]) 47 | if len(args) == 2: 48 | if args[1] == 'WRITE': 49 | precoded= True 50 | else: 51 | print 'Unrecognised option: ' + args[1] 52 | os._exit(True) 53 | else: 54 | os._exit(False) 55 | 56 | if not help and (len(args) >= 3 or precoded): 57 | if precoded: 58 | id= args[0] 59 | else: 60 | print "Encode: ", 61 | id= card.FDXBIDEncode(args[0],args[1],args[2]) 62 | print id 63 | out= card.FDXBID128Bit(id) 64 | if (len(args) == 4 and args[3] == 'WRITE') or precoded: 65 | while True: 66 | # Q5 must be forced into Q5 mode to be sure of detection so try that first 67 | if card.readertype == card.READER_ACG: 68 | card.settagtype(card.Q5) 69 | card.select() 70 | if card.readertype == card.READER_ACG: 71 | if not card.tagtype == card.Q5: 72 | card.settagtype(card.ALL) 73 | card.waitfortag('Waiting for blank tag...') 74 | print ' Tag ID: ' + card.data 75 | if card.tagtype == card.Q5 or card.tagtype == card.HITAG2: 76 | x= string.upper(raw_input(' *** Warning! This will overwrite TAG! Proceed (y/n)? ')) 77 | if x == 'N': 78 | os._exit(False) 79 | if x == 'Y': 80 | break 81 | else: 82 | x= raw_input(' Incompatible TAG! Hit to retry...') 83 | writetag= True 84 | print 85 | else: 86 | writetag= False 87 | # now turn it all back to 4 byte hex blocks for writing 88 | outbin= '' 89 | outhex= ['','','','',''] 90 | # control block for Q5: 91 | # carrier 32 (2 * 15 + 2) 92 | # rf/? (don't care) - set to 00 93 | # data inverted 94 | # biphase 95 | # maxblock 4 96 | print ' Q5 Control Block: ', 97 | q5control= '6000F0E8' 98 | print q5control 99 | for x in range(0,len(out),8): 100 | outbin += chr(int(out[x:x + 8],2)) 101 | for x in range(0,len(outbin),4): 102 | print ' Q5 Data Block %02d:' % (x / 4 + 1), 103 | outhex[x / 4 + 1]= card.ToHex(outbin[x:x+4]) 104 | print outhex[x / 4 + 1] 105 | # control block for Hitag2 106 | # Public Mode B 107 | # default password 108 | print 109 | print ' Hitag2 Control Block: ', 110 | h2control= card.HITAG2_PUBLIC_B + card.HITAG2_TRANSPORT_TAG 111 | print h2control 112 | for x in range(1,5,1): 113 | print ' Hitag2 Data Block %02d:' % (x + 3), 114 | print outhex[x] 115 | if writetag == True: 116 | print 117 | print ' Writing to tag type: ' + card.LFXTags[card.tagtype] 118 | if card.tagtype == card.Q5: 119 | outhex[0]= q5control 120 | offset= 0 121 | if card.tagtype == card.HITAG2: 122 | outhex[0]= h2control 123 | offset= 3 124 | if card.readertype == card.READER_ACG: 125 | card.login('','',card.HITAG2_TRANSPORT_RWD) 126 | for x in range(4 + offset,-1 + offset,-1): 127 | print " Writing block %02x:" % x, 128 | if not card.writeblock(x,outhex[x - offset]): 129 | # we expect a Q5 to fail after writing the control block as it re-reads 130 | # it before trying to verify the write and switches mode so is now no longer in Q5 mode 131 | if x == offset: 132 | print ' Control: ' + outhex[x - offset] 133 | print 134 | print ' Done!' 135 | # now check for FDX-B ID 136 | card.settagtype(card.EM4x05) 137 | card.select() 138 | print ' Card ID: ' + card.data 139 | else: 140 | print 'Write failed!' 141 | if card.readertype == card.READER_FROSCH: 142 | print card.FROSCH_Errors[card.errorcode] 143 | os._exit(True) 144 | else: 145 | # hitag2 don't change mode until the next time they're selected so write 146 | # confirmation of control block should be ok 147 | if x == offset: 148 | print ' Control: ' + outhex[x - offset] 149 | print 150 | print ' Done!' 151 | # now check for FDX-B ID 152 | card.reset() 153 | card.settagtype(card.EM4x05) 154 | card.select() 155 | print ' Card ID: ' + card.data 156 | else: 157 | print outhex[x - offset] 158 | if card.readertype == card.READER_ACG: 159 | card.settagtype(card.ALL) 160 | os._exit(False) 161 | print sys.argv[0] + ' - generate / decode FDX-B EM4x05 compliant IDs' 162 | print 'Usage: ' + sys.argv[0] + ' [OPTIONS] [WRITE] | [WRITE]' 163 | print 164 | print '\tIf a single 16 HEX digit ID is provided, it will be decoded according to the FDX-B standard.' 165 | print '\tAlternatively, specifying a 4 HEX digit Application ID, 3 or 4 digit decimal country code' 166 | print '\t(normally based on ISO-3166 country codes or ICAR.ORG manufacturer codes, range 0 - 4095)' 167 | print '\tand a decimal National ID Number will generate a 16 HEX digit ID.' 168 | print '\tNote: Application ID 8000 is \'Animal\', and 0000 is non-Animal.' 169 | print '\tMaximum value for country code is 999 according to the standard, but 4 digits will work.' 170 | print '\tMaximum value for National ID is 274877906943.' 171 | print 172 | print '\tIf the WRITE option is specified, a Q5 or Hitag2 will be programmed to emulate FDX-B.' 173 | print 174 | os._exit(True) 175 | -------------------------------------------------------------------------------- /formatmifare1kvalue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # formatmifare1kvalue.py - format value blocks on a mifare standard tag 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import string 27 | import os 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(True) 34 | 35 | card.info('formatmifare1k v0.1c') 36 | card.select() 37 | print 'Card ID: ' + card.data 38 | while True: 39 | x= string.upper(raw_input('\n*** Warning! This will overwrite all data blocks! Proceed (y/n)? ')) 40 | if x == 'N': 41 | os._exit(False) 42 | if x == 'Y': 43 | break 44 | 45 | sector = 1 46 | while sector < 0x10: 47 | for type in ['AA', 'BB', 'FF']: 48 | card.select() 49 | print ' sector %02x: Keytype: %s' % (sector, type), 50 | if card.login(sector,type,''): 51 | for block in range(3): 52 | print '\n block %02x: ' % ((sector * 4) + block), 53 | data= '00000000' 54 | print 'Value: ' + data, 55 | if card.writevalueblock((sector * 4) + block,data): 56 | print ' OK' 57 | elif card.errorcode: 58 | print 'error code: ' + card.errorcode 59 | elif type == 'FF': 60 | print 'login failed' 61 | print '\r', 62 | sys.stdout.flush() 63 | sector += 1 64 | print 65 | print 66 | -------------------------------------------------------------------------------- /froschtest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # froschtest.py - test frosch HTRM112 reader` 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | import rfidiot 24 | import sys 25 | import os 26 | 27 | try: 28 | card= rfidiot.card 29 | except: 30 | print "Couldn't open reader!" 31 | os._exit(True) 32 | 33 | card.info('froschtest v0.1d') 34 | print 35 | print 'Trying Hitag1: ', 36 | if card.frosch(card.FR_HT1_Get_Snr,''): 37 | print card.data[:len(card.data) -2] 38 | if not card.select(): 39 | print 'Select failed: ', 40 | print card.FROSCH_Errors[card.errorcode] 41 | else: 42 | for x in range(0,8): 43 | if card.readblock(x): 44 | print '\tBlock %02d: %s' % (x,card.data) 45 | else: 46 | print '\tBlock %0d read failed: ' % x, 47 | print card.FROSCH_Errors[card.errorcode] 48 | else: 49 | print card.FROSCH_Errors[card.errorcode] 50 | 51 | print 'Trying Hitag2: ', 52 | if card.frosch(card.FR_HT2_Get_Snr_PWD,'') or card.frosch(card.FR_HT2_Get_Snr_CRYPTO,''): 53 | print card.data[:len(card.data) -2] 54 | if not card.select(): 55 | print 'Select failed: ', 56 | print card.FROSCH_Errors[card.errorcode] 57 | else: 58 | for x in range(0,8): 59 | if card.readblock(x): 60 | print '\tBlock %02d: %s' % (x,card.data) 61 | else: 62 | print '\tBlock %0d read failed' % x, 63 | print card.FROSCH_Errors[card.errorcode] 64 | else: 65 | print card.FROSCH_Errors[card.errorcode] 66 | 67 | print 'Trying Hitag2 Public A (Unique / Miro): ', 68 | if card.frosch(card.FR_HT2_Read_Miro,''): 69 | print card.data 70 | else: 71 | print card.FROSCH_Errors[card.errorcode] 72 | 73 | print 'Trying Hitag2 Public B (FDX-B): ', 74 | if card.frosch(card.FR_HT2_Read_PublicB,''): 75 | print 'Raw: ' + card.data, 76 | print 'ID: ' + card.FDXBID128BitDecode(card.ToBinaryString(card.ToBinary(card.data))) 77 | card.FDXBIDPrint(card.FDXBID128BitDecode(card.ToBinaryString(card.ToBinary(card.data)))) 78 | else: 79 | print card.FROSCH_Errors[card.errorcode] 80 | os._exit(False) 81 | -------------------------------------------------------------------------------- /hidprox.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # hidprox.py - show HID Prox card type and site/id code 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2009, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | import sys 26 | import os 27 | import string 28 | import rfidiot 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | print "Couldn't open reader!" 34 | os._exit(True) 35 | 36 | card.info('hidprox v0.1f') 37 | 38 | if not card.readersubtype == card.READER_OMNIKEY: 39 | print 'Reader type not supported!', card.ReaderSubType, card.READER_OMNIKEY 40 | os._exit(True) 41 | 42 | try: 43 | card.select() 44 | prox= card.pcsc_atr[:6] 45 | type= card.HID_PROX_TYPES[prox] 46 | print ' Card type:', type 47 | except: 48 | if not card.pcsc_atr: 49 | print 'No card detected!' 50 | else: 51 | print 'Unrecognised card type! ATR:', card.pcsc_atr 52 | os._exit(True) 53 | 54 | # H10301 - 26 bit (FAC + CN) 55 | if prox == card.HID_PROX_H10301: 56 | fc= card.pcsc_atr[7:10] 57 | cn= card.pcsc_atr[11:16] 58 | octal= '%o' % int(card.pcsc_atr[7:16]) 59 | 60 | # H10301 - 26 bit (FAC + CN) (ATR in HEX) 61 | if prox == card.HID_PROX_H10301_H: 62 | binary= card.ToBinaryString(card.pcsc_atr[6:].decode('hex')) 63 | # strip leading zeros and parity 64 | binary= binary[7:] 65 | binary= binary[:-1] 66 | fc= int(binary[:8],2) 67 | cn= int(binary[8:],2) 68 | octal= '%o' % int(card.pcsc_atr[6:],16) 69 | 70 | # H10302 - 37 bit (CN) 71 | if prox == card.HID_PROX_H10302: 72 | fc= 'n/a' 73 | cn= card.pcsc_atr[6:18] 74 | octal= '%o' % int(card.pcsc_atr[6:18]) 75 | 76 | # H10302 - 37 bit (CN) (ATR in HEX) 77 | if prox == card.HID_PROX_H10302_H: 78 | fc= 'n/a' 79 | binary= card.ToBinaryString(card.pcsc_atr[6:].decode('hex')) 80 | # strip leading zeros and parity 81 | binary= binary[8:] 82 | binary= binary[:-1] 83 | cn= int(binary,2) 84 | octal= '%o' % int(card.pcsc_atr[6:],16) 85 | 86 | # H10304 - 37 bit (FAC + CN) 87 | if prox == card.HID_PROX_H10304: 88 | fc= card.pcsc_atr[7:12] 89 | cn= card.pcsc_atr[12:18] 90 | octal= '%o' % int(card.pcsc_atr[7:18]) 91 | 92 | # H10320 - 32 bit clock/data card 93 | if prox == card.HID_PROX_H10320: 94 | fc= 'n/a' 95 | cn= card.pcsc_atr[6:14] 96 | octal= '%o' % int(card.pcsc_atr[6:14]) 97 | 98 | # Corp 1000 - 35 bit (CIC + CN) 99 | if prox == card.HID_PROX_CORP1K: 100 | fc= card.pcsc_atr[6:10] 101 | cn= card.pcsc_atr[10:18] 102 | octal= '%o' % int(card.pcsc_atr[6:18]) 103 | 104 | print 105 | print ' Facility Code:', fc 106 | print ' Card Number:', cn 107 | print ' Octal:', octal 108 | print 109 | os._exit(False) 110 | -------------------------------------------------------------------------------- /hitag2brute.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # hitag2brute.py - Brute Force hitag2 password 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2008, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | import rfidiot 26 | import sys 27 | import os 28 | import time 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | print "Couldn't open reader!" 34 | os._exit(True) 35 | 36 | args= rfidiot.args 37 | 38 | card.info('hitag2brute v0.1c') 39 | 40 | pwd= 0x00 41 | 42 | # start at specified PWD 43 | if len(args) == 1: 44 | pwd= int(args[0],16) 45 | 46 | card.settagtype(card.ALL) 47 | 48 | if card.select(): 49 | print 'Bruteforcing tag:', card.uid 50 | else: 51 | print 'No tag found!' 52 | os._exit(True) 53 | 54 | while 42: 55 | PWD= '%08X' % pwd 56 | if card.h2login(PWD): 57 | print 'Password is %s' % PWD 58 | os._exit(False) 59 | else: 60 | if not pwd % 16: 61 | print PWD + ' \r', 62 | if not card.select(): 63 | print 'No tag found! Last try: %s\r' % PWD, 64 | else: 65 | pwd= pwd + 1 66 | sys.stdout.flush() 67 | if pwd == 0xffffffff: 68 | os._exit(True) 69 | os._exit(False) 70 | -------------------------------------------------------------------------------- /hitag2reset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # hitag2reset.py - hitag2 tags need love too... 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | import string 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(True) 34 | 35 | args= rfidiot.args 36 | help= rfidiot.help 37 | 38 | card.info('hitag2reset v0.1e') 39 | 40 | # standard config block 41 | #CFB='06' + card.HITAG2_TRANSPORT_TAG 42 | CFB=card.HITAG2_PASSWORD + card.HITAG2_TRANSPORT_TAG 43 | BLK1= card.HITAG2_TRANSPORT_RWD 44 | 45 | if len(args) == 0 or len(args) > 2 or help: 46 | print sys.argv[0] + ' - return a Hitag2 tag to life' 47 | print 'Usage: ' + sys.argv[0] + ' [ ]' 48 | print 49 | print 'If the optional PASSWD fields are specified, the password will be set,' 50 | print 'otherwise factory password \'%s\' will be used' % card.HITAG2_TRANSPORT_RWD 51 | os._exit(True) 52 | 53 | if args[0] == 'CONTROL': 54 | while True: 55 | print 56 | # if card.frosch(card.FR_HT2_Read_PublicB): 57 | # print ' Card ID: ' + card.data 58 | x= string.upper(raw_input(' *** Warning! This will overwrite TAG! Place card and proceed (y/n)? ')) 59 | if x == 'N': 60 | os._exit(False) 61 | if x == 'Y': 62 | break 63 | print 'Writing...' 64 | logins= 0 65 | if (card.h2publicselect()): 66 | print 'Hitag2 ID: ' + card.data 67 | else: 68 | print 'No TAG, or incompatible hardware!' 69 | os._exit(True) 70 | if not card.writeblock(3,CFB): 71 | print card.FROSCH_Errors[card.errorcode] 72 | print 'Block 3 write failed!' 73 | os._exit(True) 74 | else: 75 | # set new passord if specified 76 | if len(args) > 1: 77 | BLK1= args[1] 78 | #if not card.writeblock(1,B1) or not card.writeblock(2,B2): 79 | if not card.writeblock(1,BLK1): 80 | print 'Block 1 write failed!' 81 | print card.FROSCH_Errors[card.errorcode] 82 | os._exit(True) 83 | card.settagtype(card.ALL) 84 | print 'Done!' 85 | if card.select(): 86 | print ' Card ID: ' + card.uid 87 | os._exit(False) 88 | -------------------------------------------------------------------------------- /isotype.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # isotype.py - determine ISO tag type 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | import sys 26 | import os 27 | import string 28 | import rfidiot 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | print "Couldn't open reader!" 34 | os._exit(True) 35 | 36 | 37 | card.info('isotype v0.1n') 38 | 39 | typed= 0 40 | if card.readertype == card.READER_ACG: 41 | for command, cardtype in card.ISOTags.iteritems(): 42 | if not card.settagtype(command): 43 | print 'Could not test for card type: ' + cardtype 44 | continue 45 | if card.select(): 46 | print ' ID: ' + card.uid 47 | print " Tag is " + cardtype 48 | typed= True 49 | if command == card.ISO15693: 50 | print ' Manufacturer:', 51 | try: 52 | print card.ISO7816Manufacturer[card.uid[2:4]] 53 | except: 54 | print 'Unknown (%s)' % card.uid[2:4] 55 | 56 | for command, cardtype in card.ISOTagsA.iteritems(): 57 | if not card.settagtype(command): 58 | print 'Could not reset reader to ' + cardtype + '!' 59 | os._exit(True) 60 | if card.readertype == card.READER_PCSC: 61 | if card.select(): 62 | print ' ID: ' + card.uid 63 | print " Tag is " + card.tagtype 64 | if string.find(card.tagtype,"ISO 15693") >= 0: 65 | print ' Manufacturer:', 66 | try: 67 | print card.ISO7816Manufacturer[card.uid[2:4]] 68 | except: 69 | print 'Unknown (%s)' % card.uid[2:4] 70 | typed= True 71 | print 72 | print 73 | if not card.readersubtype == card.READER_ACS: 74 | card.PCSCPrintATR(card.pcsc_atr) 75 | else: 76 | print card.ISO7816ErrorCodes[card.errorcode] 77 | os._exit(True) 78 | if card.readertype == card.READER_LIBNFC: 79 | if card.select('A'): 80 | print ' ID: ' + card.uid 81 | if card.atr: 82 | print ' ATS: ' + card.atr 83 | print " Tag is ISO 14443A" 84 | typed= True 85 | if card.select('B'): 86 | print ' PUPI: ' + card.pupi 87 | print ' APP: ' + card.appdata 88 | print ' PROTO: ' + card.protocol 89 | print ' CID: ' + card.cid 90 | print " Tag is ISO 14443B" 91 | typed= True 92 | if card.select('ICLASS'): 93 | print ' ID: ' + card.uid 94 | print " Tag is ICLASS" 95 | typed= True 96 | if card.select('JEWEL'): 97 | print 'SENSRES: ' + card.btsensres 98 | print ' ID: ' + card.btid 99 | print " Tag is JEWEL" 100 | typed= True 101 | if not typed: 102 | print "Could not determine type" 103 | os._exit(True) 104 | 105 | os._exit(False) 106 | -------------------------------------------------------------------------------- /java/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile for JAVA applet jcop_set_atr_hist 3 | # 4 | # Adam Laurie, 2009 5 | # http://rfidiot.org 6 | # 7 | # See inline comments for instructions on how to set up your environment 8 | # 9 | 10 | APPLET_PACKAGE=jcop_set_atr_hist 11 | APPLET_CLASS=JCOPSetATRHist 12 | PACKAGE_AID=0xDC:0x44:0x20:0x06:0x06 13 | APPLET_AID=0xDC:0x44:0x20:0x06:0x06:0x07 14 | APPLET_AID_LENGTH=6 15 | 16 | #JAVA_HOME=/usr/local/java/jdk 17 | JAVA=$(JAVA_HOME)/bin/java 18 | JAVAC=$(JAVA_HOME)/bin/javac 19 | JAVADOC=$(JAVA_HOME)/bin/javadoc 20 | 21 | # Java Card Kit must be version 2.2.1 for gpshell 22 | # and can be downloaded here: 23 | # 24 | # http://java.sun.com/javacard/downloads/index.jsp 25 | # 26 | # download 'Java Card 2.2.1 Development Kit' and set the following variable (JCZIP) 27 | # to the zipfile name, then run 'make jckit' 28 | # 29 | JCZIP=java_card_kit-2_2_1-linux-dom.zip 30 | JCPATH=/usr/local/java/java_card_kit-2_2_1 31 | 32 | # 33 | # Global Platform API can be found here: 34 | # 35 | # http://www.globalplatform.org/specificationscard.asp 36 | # 37 | # download 'Java Card Export File for Card Specification v2.1' from the 38 | # 'Archived Card Documentation' section. Make sure you choose v2.1 and NOT v2.1.1, 39 | # and set the following variable (GPZIP) to the zipfile name, then run 'make gpapi' 40 | # (GPZIP and GPDIR were correct at time of release, so should not need changing) 41 | # 42 | GPZIP=Java_Export_v2_1_or_v2_1_1_API.zip 43 | GPDIR=GP_exportA00000015100 44 | #GPDIR=$(shell echo $(GPZIP) | cut -f1 -d'.') 45 | GPLIB=./gp21.jar 46 | GPEXPORTPATH=./gp21 47 | 48 | JCAPI=$(JCPATH)/lib/api.jar 49 | JCCONV=$(JCPATH)/lib/converter.jar 50 | JCVERIFIER=$(JCPATH)/lib/offcardverifier.jar 51 | EXPORTPATH=$(JCPATH)/api_export_files 52 | 53 | # 54 | # GPShell can be got here: 55 | # 56 | # http://sourceforge.net/project/showfiles.php?group_id=143343&package_id=159897 57 | # 58 | GPSHELL= "gpshell" 59 | GPSHELL_SCRIPT="jcop_set_atr_hist.gpsh" 60 | GPSHELL_UNINSTALL_SCRIPT="jcop_delete_atr_hist.gpsh" 61 | 62 | all: jcop_set_atr_hist.cap 63 | 64 | classes: build 65 | $(JAVAC)\ 66 | -g\ 67 | -classpath $(JCAPI):$(GPLIB):.\ 68 | -d build\ 69 | -sourcepath ./src \ 70 | -source 1.2 \ 71 | -target 1.2 \ 72 | src/jcop_set_atr_hist/JCOPSetATRHist.java 73 | 74 | jcop_set_atr_hist.cap: classes 75 | $(JAVA)\ 76 | -classpath $(JCCONV):$(JCVERIFIER)\ 77 | com.sun.javacard.converter.Converter\ 78 | -classdir build\ 79 | -exportpath $(EXPORTPATH):$(GPEXPORTPATH):.\ 80 | -applet $(APPLET_AID) $(APPLET_CLASS)\ 81 | -d build\ 82 | -out CAP\ 83 | -v\ 84 | -debug \ 85 | $(APPLET_PACKAGE) $(PACKAGE_AID) 1.0 86 | cp build/jcop_set_atr_hist/javacard/jcop_set_atr_hist.cap . 87 | 88 | build: 89 | @if ! test -e gp21.jar ; then echo "You need to set up your Global Platform environment! Read Makefile comments for help." ; exit 1 ; fi 90 | @if ! test -e $(JCCONV); then echo "You need to set up your Java Card Kit! Read Makefile comments for help."; exit 1; fi 91 | mkdir -p build 92 | 93 | install: 94 | $(GPSHELL) $(GPSHELL_SCRIPT) 95 | 96 | uninstall: 97 | $(GPSHELL) $(GPSHELL_UNINSTALL_SCRIPT) 98 | 99 | clean: 100 | rm -f jcop_set_atr_hist.cap 101 | rm -rf build 102 | 103 | gpapi: 104 | @if ! test -e $(GPZIP) ; then echo "Can't find Global Platform API zipfile! Read Makefile comments for help." ; exit 1 ; fi 105 | @unzip -x $(GPZIP) 106 | cd $(GPDIR) && jar cvf ../gp21.jar * 107 | mv $(GPDIR) gp21 108 | 109 | jckit: 110 | @if ! test -e $(JCZIP) ; then echo "Can't find Java Card Kit zipfile! Read Makefile comments for help." ; exit 1 ; fi 111 | @unzip -x $(JCZIP) 112 | -------------------------------------------------------------------------------- /java/jcop_delete_atr_hist.gpsh: -------------------------------------------------------------------------------- 1 | // script to install applet.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | //enable_trace 4 | establish_context 5 | // edit the following line to match your PCSC reader 6 | //card_connect -reader "OMNIKEY CardMan 5x21 00 01" 7 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 8 | //card_connect -reader "OMNIKEY CardMan 5x21 (OKCM0022602100142172731750393654) 00 00" 9 | card_connect 10 | //card_connect -reader "SDI010 USB Smart Card Reader (21120652200170) 00 01" 11 | select -AID A000000003000000 12 | open_sc -security 3 -mac_key 404142434445464748494A4B4C4D4E4F -enc_key 404142434445464748494A4B4C4D4E4F -kek_key 404142434445464748494A4B4C4D4E4F // Open secure channel 13 | delete -AID DC44200606 14 | get_status -element 10 15 | card_disconnect 16 | release_context 17 | -------------------------------------------------------------------------------- /java/jcop_set_atr_hist.cap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamLaurie/RFIDIOt/88f2ef9f8e02d0b1e4a03fcd5aa52e3c6ab0dc73/java/jcop_set_atr_hist.cap -------------------------------------------------------------------------------- /java/jcop_set_atr_hist.gpsh: -------------------------------------------------------------------------------- 1 | // script to install applet.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | //enable_trace 4 | establish_context 5 | // edit the following line to match your PCSC reader 6 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 7 | //card_connect -reader "OMNIKEY CardMan 5x21 (OKCM0022602100142172731750393654) 00 00" 8 | card_connect 9 | //card_connect -reader "OMNIKEY CardMan 5x21 00 01" 10 | //card_connect -reader "SDI010 USB Smart Card Reader (21120652200170) 00 01" 11 | select -AID A000000003000000 12 | open_sc -security 3 -mac_key 404142434445464748494A4B4C4D4E4F -enc_key 404142434445464748494A4B4C4D4E4F -kek_key 404142434445464748494A4B4C4D4E4F // Open secure channel 13 | delete -AID DC44200606 14 | install -file jcop_set_atr_hist.cap -priv 4 15 | get_status -element 10 16 | card_disconnect 17 | release_context 18 | -------------------------------------------------------------------------------- /java/smartcafe_delete_atr_hist.gpsh: -------------------------------------------------------------------------------- 1 | // script to install applet.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | //enable_trace 4 | establish_context 5 | card_connect 6 | select -AID A000000003000000 7 | open_sc -scp 2 -scpimpl 0x15 -security 1 -keyind 0 -keyver 0 -keyDerivation emvcps11 -key 404142434445464748494A4B4C4D4E4F 8 | delete -AID DC44200606 9 | card_disconnect 10 | release_context 11 | -------------------------------------------------------------------------------- /java/smartcafe_set_atr_hist.gpsh: -------------------------------------------------------------------------------- 1 | // script to install applet.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | //enable_trace 4 | establish_context 5 | card_connect 6 | select -AID A000000003000000 7 | open_sc -scp 2 -scpimpl 0x15 -security 1 -keyind 0 -keyver 0 -keyDerivation emvcps11 -key 404142434445464748494A4B4C4D4E4F 8 | delete -AID DC44200606 9 | install -file jcop_set_atr_hist.cap -priv 4 10 | card_disconnect 11 | release_context 12 | -------------------------------------------------------------------------------- /java/src/jcop_set_atr_hist/ATRGlobal.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Adam Laurie 3 | * http://rfidiot.org/ 4 | * 5 | * This code is copyright (c) Adam Laurie, 2009, All rights reserved. 6 | * For non-commercial use only, the following terms apply - for all other 7 | * uses, please contact the author: 8 | * 9 | * This code is free software; you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation; either version 2 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * This code is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | */ 19 | 20 | 21 | 22 | package jcop_set_atr_hist; 23 | 24 | /* 15 byte buffer for ATR Historical Bytes (ATS) must be a global */ 25 | 26 | public class ATRGlobal { 27 | public static byte[] ATR_HIST= {(byte) 0x00,(byte) 0x00,(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 28 | (byte) 0x00,(byte) 0x00,(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, 29 | (byte) 0x00,(byte) 0x00,(byte) 0x00}; 30 | } 31 | -------------------------------------------------------------------------------- /java/src/jcop_set_atr_hist/JCOPSetATRHist.java: -------------------------------------------------------------------------------- 1 | /** 2 | * JCOPSetATRHist.java - set ATR History bytes on JCOP cards 3 | * 4 | * Must be installed as "default selectable" (priv mode 0x04). 5 | * 6 | * Adam Laurie 7 | * http://rfidiot.org/ 8 | * 9 | * This code is copyright (c) Adam Laurie, 2009, All rights reserved. 10 | * For non-commercial use only, the following terms apply - for all other 11 | * uses, please contact the author: 12 | * 13 | * This code is free software; you can redistribute it and/or modify 14 | * it under the terms of the GNU General Public License as published by 15 | * the Free Software Foundation; either version 2 of the License, or 16 | * (at your option) any later version. 17 | * 18 | * This code is distributed in the hope that it will be useful, 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | * GNU General Public License for more details. 22 | */ 23 | 24 | 25 | package jcop_set_atr_hist; 26 | 27 | import javacard.framework.APDU; 28 | import javacard.framework.ISO7816; 29 | import javacard.framework.Applet; 30 | import javacard.framework.ISOException; 31 | import javacard.framework.Util; 32 | import org.globalplatform.GPSystem; 33 | 34 | public class JCOPSetATRHist extends Applet 35 | { 36 | public static void install(byte[] bArray, short bOffset, byte bLength) 37 | { 38 | new jcop_set_atr_hist.JCOPSetATRHist().register(bArray, (short) (bOffset + 1), 39 | bArray[bOffset]); 40 | } 41 | 42 | public void process(APDU apdu) 43 | { 44 | byte[] buffer = apdu.getBuffer(); 45 | byte ins = buffer[ISO7816.OFFSET_INS]; 46 | 47 | if (selectingApplet()) 48 | { 49 | return; 50 | } 51 | 52 | byte len = buffer[ISO7816.OFFSET_CDATA]; 53 | // Max ATS is 15 bytes 54 | if (len > (byte) 15) 55 | ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); 56 | 57 | Util.arrayCopy(buffer,(short) (ISO7816.OFFSET_CDATA + 1),ATRGlobal.ATR_HIST,(short) 0x00,len); 58 | switch (ins) 59 | { 60 | case (byte) 0xAB: 61 | if( ! org.globalplatform.GPSystem.setATRHistBytes(ATRGlobal.ATR_HIST,(short) 0x00, len )) 62 | ISOException.throwIt(ISO7816.SW_UNKNOWN); 63 | return; 64 | default: 65 | ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /jcop_mifare_access.cap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamLaurie/RFIDIOt/88f2ef9f8e02d0b1e4a03fcd5aa52e3c6ab0dc73/jcop_mifare_access.cap -------------------------------------------------------------------------------- /jcop_mifare_access.gpsh: -------------------------------------------------------------------------------- 1 | // script to install jcop_mifare_access.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | //enable_trace 4 | establish_context 5 | // edit the following line to match your PCSC reader 6 | //card_connect -reader "OMNIKEY CardMan 5x21 00 01" 7 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 8 | //card_connect -reader "PCSC OMNIKEY CardMan 5x21 (OKCM0071403091502571040243996509) 00 01" 9 | //card_connect -reader "SDI010 USB Smart Card Reader (21120652200170) 00 01" 10 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 11 | card_connect 12 | //card_connect -readerNumber 3 13 | select -AID A000000003000000 14 | open_sc -security 3 -mac_key 404142434445464748494A4B4C4D4E4F -enc_key 404142434445464748494A4B4C4D4E4F -kek_key 404142434445464748494A4B4C4D4E4F // Open secure channel 15 | delete -AID A00000024710 16 | delete -AID DC44200606 17 | install -file jcop_mifare_access.cap -priv 4 18 | get_status -element 10 19 | card_disconnect 20 | release_context 21 | -------------------------------------------------------------------------------- /jcopmifare.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # jcopmifare.py - test program for mifare emulation on JCOP 5 | # 6 | # This program can be used to test READ/WRITE functionality of the built-in 7 | # mifare emulation on mifare enabled JCOP cards. 8 | # The mifare access applet jcop_mifare_access.cap must be loaded onto the card first. 9 | # 10 | # Adam Laurie 11 | # http://rfidiot.org/ 12 | # 13 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 14 | # For non-commercial use only, the following terms apply - for all other 15 | # uses, please contact the author: 16 | # 17 | # This code is free software; you can redistribute it and/or modify 18 | # it under the terms of the GNU General Public License as published by 19 | # the Free Software Foundation; either version 2 of the License, or 20 | # (at your option) any later version. 21 | # 22 | # This code is distributed in the hope that it will be useful, 23 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | # GNU General Public License for more details. 26 | # 27 | # history 28 | # 15/11/08 - ver 0.1a - first cut, seems to work. :) 29 | # 13/01/09 - ver 0.1b - add RANDOM UID mode 30 | 31 | import rfidiot 32 | import sys 33 | import os 34 | 35 | try: 36 | card= rfidiot.card 37 | except: 38 | print "Couldn't open reader!" 39 | os._exit(True) 40 | 41 | args= rfidiot.args 42 | Help= rfidiot.help 43 | 44 | # fixed values required by JCOP applet 45 | CLA= '00' 46 | INS= 'MIFARE_ACCESS' 47 | P1= '03' 48 | WRITE= '01' 49 | READ= '02' 50 | RANDOM= '03' 51 | MIFARE_AID= 'DC4420060606' 52 | 53 | card.info('jcopmifare v0.1e') 54 | 55 | if Help or len(args) < 2: 56 | print '\nUsage:\n\n\t%s [OPTIONS] [SECTOR] [HEX DATA]' % sys.argv[0] 57 | print 58 | print '\tMIFARE_PWD should be the HEX 8 BYTE MifarePWD produced by mifarekeys.py, or the' 59 | print '\tRANDOM_UID secret key.' 60 | print 61 | print '\tSECTOR number must be specified for READ and WRITE operations. Note that not all' 62 | print '\tsectors are WRITEable.' 63 | print 64 | print '\tRANDOM will set card into RANDOM_UID mode. All future selects will return a random' 65 | print '\tUID instead of the one stored in sector 0. This behaviour cannot be reversed.' 66 | print 67 | print '\tHEX DATA must be 16 BYTES worth of HEX for WRITE operations.' 68 | print 69 | print '\t(default NXP transport keys are both FFFFFFFFFFFF, so MifarePWD is 0B54570745FE3AE7)' 70 | print '\t(sector 0 default is A0A1A2A3A4A5, so MifarePWD is 0FB3BBC7099ED432)' 71 | print 72 | print '\tExample:' 73 | print 74 | print '\t\t./jcopmifare.py WRITE 0B54570745FE3AE7 1 12345678123456781234567812345678' 75 | print 76 | print 77 | print '\tNote that jcop_mifare_access.cap or native Mifare emulation must be active on the card.' 78 | print 79 | os._exit(True) 80 | 81 | def mifare_read(key,sector): 82 | cla= CLA 83 | ins= INS 84 | p1= P1 85 | p2= READ 86 | data= key + '%02X' % int(sector) 87 | lc= '%02X' % (len(data) / 2) 88 | le= '10' 89 | 90 | if card.send_apdu('','','','',cla,ins,p1,p2,lc,data,le): 91 | return True, card.data 92 | return False, card.errorcode 93 | 94 | def mifare_write(key,sector,sectordata): 95 | cla= CLA 96 | ins= INS 97 | p1= P1 98 | p2= WRITE 99 | data= key + sectordata + '%02X' % int(sector) 100 | lc= '%02X' % (len(data) / 2) 101 | 102 | if card.send_apdu('','','','',cla,ins,p1,p2,lc,data,''): 103 | return True, card.data 104 | return False, card.errorcode 105 | 106 | def mifare_random(key): 107 | cla= CLA 108 | ins= INS 109 | p1= P1 110 | p2= RANDOM 111 | data= key 112 | lc= '%02X' % (len(data) / 2) 113 | 114 | if card.send_apdu('','','','',cla,ins,p1,p2,lc,data,''): 115 | return True, card.data 116 | return False, card.errorcode 117 | 118 | def select_mifare_app(): 119 | "select mifare application (AID: DC4420060606)" 120 | ins= 'SELECT_FILE' 121 | p1= '04' 122 | p2= '0C' 123 | data= MIFARE_AID 124 | lc= '%02X' % (len(data) / 2) 125 | card.send_apdu('','','','','',ins,p1,p2,lc,data,'') 126 | if card.errorcode == card.ISO_OK: 127 | return True 128 | else: 129 | return False 130 | 131 | def error_exit(message,error): 132 | print ' %s, error number: %s' % (message,error), 133 | try: 134 | print card.ISO7816ErrorCodes[error] 135 | except: 136 | print 137 | os._exit(True) 138 | 139 | if card.select(): 140 | print ' Card ID: ' + card.uid 141 | if card.readertype == card.READER_PCSC: 142 | print ' ATR: ' + card.pcsc_atr 143 | else: 144 | print ' No card present' 145 | 146 | # high speed select required for ACG 147 | if not card.hsselect('08'): 148 | print ' Could not select card for APDU processing' 149 | os._exit(True) 150 | 151 | if not select_mifare_app(): 152 | print ' Could not select mifare applet!' 153 | os._exit(True) 154 | 155 | if args[0] == 'READ': 156 | stat, data= mifare_read(args[1],args[2]) 157 | if not stat: 158 | error_exit('Read failed', data) 159 | else: 160 | print 'Data: ', data 161 | os._exit(False) 162 | 163 | if args[0] == 'WRITE': 164 | stat, data= mifare_write(args[1],args[2],args[3]) 165 | if not stat: 166 | error_exit('Write failed', data) 167 | else: 168 | print 'Write completed' 169 | os._exit(False) 170 | 171 | if args[0] == 'RANDOM': 172 | stat, data= mifare_random(args[1]) 173 | if not stat: 174 | error_exit('Random_UID mode failed', data) 175 | else: 176 | print 'Random_UID set' 177 | os._exit(False) 178 | 179 | 180 | 181 | print "Unrecognised command:", args[0] 182 | os._exit(True) 183 | -------------------------------------------------------------------------------- /jcopsetatrhist.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # jcopsetatrhist.py - set ATR History bytes on JCOP cards 5 | # 6 | # The applet jcop_set_atr_hist.cap must be loaded onto the card first, 7 | # and it must be installed as "default selectable" (priv mode 0x04). 8 | # 9 | # Adam Laurie 10 | # http://rfidiot.org/ 11 | # 12 | # This code is copyright (c) Adam Laurie, 2008, All rights reserved. 13 | # For non-commercial use only, the following terms apply - for all other 14 | # uses, please contact the author: 15 | # 16 | # This code is free software; you can redistribute it and/or modify 17 | # it under the terms of the GNU General Public License as published by 18 | # the Free Software Foundation; either version 2 of the License, or 19 | # (at your option) any later version. 20 | # 21 | # This code is distributed in the hope that it will be useful, 22 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | # GNU General Public License for more details. 25 | # 26 | 27 | import rfidiot 28 | import sys 29 | import os 30 | import string 31 | 32 | try: 33 | card= rfidiot.card 34 | except: 35 | os._exit(True) 36 | 37 | args= rfidiot.args 38 | Help= rfidiot.help 39 | 40 | # fixed values required by JCOP applet 41 | CLA= '80' 42 | P1= '00' 43 | P2= '00' 44 | JCOP_ATR_AID= 'DC4420060607' 45 | 46 | if Help or len(args) < 2: 47 | print '\nUsage:\n\n\t%s [OPTIONS] \'SET\' ' % sys.argv[0] 48 | print 49 | print '\tHEX DATA is up to 15 BYTES of ASCII HEX.' 50 | print 51 | print '\tExample:' 52 | print 53 | print '\t./jcopsetatrhist.py SET 0064041101013180009000' 54 | print 55 | os._exit(True) 56 | 57 | def jcop_set_atr_hist(bytes): 58 | cla= CLA 59 | ins= 'ATR_HIST' 60 | p1= P1 61 | p2= P2 62 | data= '%02X' % (len(bytes) / 2) + bytes 63 | lc= '%02X' % (len(data) / 2) 64 | if card.send_apdu('','','','',cla,ins,p1,p2,lc,data,''): 65 | return True, card.data 66 | return False, card.errorcode 67 | 68 | def select_atrhist_app(): 69 | "select atr_hist application (AID: DC4420060607)" 70 | ins= 'SELECT_FILE' 71 | p1= '04' 72 | p2= '0C' 73 | data= JCOP_ATR_AID 74 | lc= '%02X' % (len(data) / 2) 75 | card.send_apdu('','','','','',ins,p1,p2,lc,data,'') 76 | if card.errorcode == card.ISO_OK: 77 | return True 78 | else: 79 | return False 80 | 81 | def error_exit(message,error): 82 | print ' %s, error number: %s' % (message,error), 83 | try: 84 | print card.ISO7816ErrorCodes[error] 85 | except: 86 | print 87 | os._exit(True) 88 | 89 | card.info('jcopsetatrhist v0.1c') 90 | 91 | if card.select(): 92 | print ' Card ID: ' + card.uid 93 | if card.readertype == card.READER_PCSC: 94 | print ' ATR: ' + card.pcsc_atr 95 | else: 96 | print ' No card present' 97 | os._exit(True) 98 | 99 | # high speed select required for ACG 100 | if not card.hsselect('08'): 101 | print ' Could not select card for APDU processing' 102 | os._exit(True) 103 | 104 | if not select_atrhist_app(): 105 | print 106 | print " Can't select atrhist applet!" 107 | print ' Please load jcop_set_atr_hist.cap onto JCOP card.' 108 | print ' (Use command: gpshell java/jcop_set_atr_hist.gpsh)' 109 | print 110 | os._exit(True) 111 | 112 | if args[0] == 'SET': 113 | stat, data= jcop_set_atr_hist(args[1]) 114 | if not stat: 115 | error_exit('Set hist bytes failed', data) 116 | else: 117 | print 118 | print ' ATR History Bytes (ATS) set to', args[1] 119 | print 120 | print ' *** Remove card from reader and replace to finalise!' 121 | print 122 | print ' You can now delete jcop_set_atr_hist.cap from the JCOP card.' 123 | print ' (Use command: gpshell java/jcop_delete_atr_hist.gpsh)' 124 | print 125 | os._exit(False) 126 | else: 127 | print "Unrecognised command:", args[0] 128 | os._exit(True) 129 | -------------------------------------------------------------------------------- /jcoptool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # jcoptool.py - JCOP card toolkit 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2009, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | import string 28 | from Crypto.Cipher import DES3 29 | from Crypto.Cipher import DES 30 | from pyasn1.codec.ber import decoder 31 | 32 | try: 33 | card= rfidiot.card 34 | except: 35 | print "Couldn't open reader!" 36 | os._exit(True) 37 | 38 | args= rfidiot.args 39 | Help= rfidiot.help 40 | 41 | # fixed values required by JCOP applet 42 | CLA= '80' 43 | P1= '00' 44 | P2= '00' 45 | 46 | templates= { 47 | '66':'Card Data', 48 | '73':'Card Recognition Data', 49 | } 50 | 51 | tags= { 52 | '06':'OID', 53 | '60':'Application tag 0 - Card Management Type and Version', 54 | '63':'Application tag 3 - Card Identification Scheme', 55 | '64':'Application tag 4 - Secure Channel Protocol of the Issuer Security Domain and its implementation options', 56 | '65':'Application tag 5 - Card configuration details', 57 | '66':'Application tag 6 - Card / chip details', 58 | '67':'Application tag 7 - Issuer Security Domain\'s Trust Point certificate information', 59 | '68':'Application tag 8 - Issuer Security Domain certificate information', 60 | } 61 | 62 | registry_tags= { 63 | '4F':'AID', 64 | '9F70':'Life Cycle State', 65 | 'C5':'Privileges', 66 | 'C4':'Application\'s Executable Load File AID', 67 | 'CE':'Executable Lod File Version Number', 68 | '84':'First or only ExecutableModule AID', 69 | 'CC':'Associated Security Domain\'s AID', 70 | } 71 | 72 | card_status= { 73 | '80':'Issuer Security Domain', 74 | '40':'Applications and Supplementary Security Domains', 75 | '20':'Executable Load Files', 76 | '10':'Executable Load Files and their Executable Modules', 77 | } 78 | 79 | # life cycle state must be masked as bits 4-7 (bit numbering starting at 1) are application specific 80 | application_life_cycle_states= { 81 | '01':'LOADED', 82 | '03':'INSTALLED', 83 | '07':'SELECTABLE', 84 | '83':'LOCKED', 85 | '87':'LOCKED', 86 | } 87 | 88 | executable_life_cycle_states= { 89 | '01':'LOADED', 90 | } 91 | 92 | security_domain_life_cycle_states= { 93 | '03':'INSTALLED', 94 | '07':'SELECTABLE', 95 | '0F':'PERSONALIZED', 96 | '83':'LOCKED', 97 | '87':'LOCKED', 98 | '8B':'LOCKED', 99 | '8F':'LOCKED', 100 | } 101 | 102 | 103 | card_life_cycle_states= { 104 | '01':'OP_READY', 105 | '07':'INITIALIZED', 106 | '0F':'SECURED', 107 | '7F':'CARD_LOCKED', 108 | 'FF':'TERMINATED', 109 | } 110 | 111 | targets= { 112 | '00':'Unknown', 113 | '01':'SmartMX', 114 | '03':'sm412', 115 | } 116 | 117 | fuse_state= { 118 | '00':'Not Fused', 119 | '01':'Fused', 120 | } 121 | 122 | manufacturers= { 123 | 'PH':'Philips Semiconductors', 124 | 'NX':'NXP', 125 | } 126 | 127 | privilege_byte_1= { 128 | '80':'Security Domain', 129 | 'C0':'DAP Verification', 130 | 'A0':'Delegated Management', 131 | '10':'Card Lock', 132 | '08':'Card Terminate', 133 | '04':'Card Reset', 134 | '02':'CVM Management', 135 | 'C1':'Mandated DAP Verification', 136 | } 137 | 138 | def decode_jcop_identify(data, padding): 139 | fabkey= data[0:2] 140 | patch_id= data[2:4] 141 | target= data[4:6] 142 | mask_id= data[6:8] 143 | custom_mask= data[8:16] 144 | mask_name= data[16:28] 145 | fuse= data[28:30] 146 | rom_info= data[30:42] 147 | 148 | manufacturer= card.ToBinary(mask_name[0:4]) 149 | manufacture_year= card.ToBinary(mask_name[4:6]) 150 | manufacture_week= card.ToBinary(mask_name[6:10]) 151 | manufacture_mask= ord(card.ToBinary(mask_name[10:12])) - 64 152 | 153 | 154 | print padding + 'FABKEY ID: %s' % fabkey 155 | print padding + 'PATCH ID: %s' % patch_id 156 | print padding + 'TARGET ID: %s' % target + ' (' + targets[target] + ')' 157 | print padding + 'MASK ID: %s' % mask_id + ' (Mask %s)' % int(mask_id,16) 158 | print padding + 'CUSTOM MASK: %s' % custom_mask + ' (%s)' % card.ReadablePrint(card.ToBinary(custom_mask)) 159 | print padding + 'MASK NAME: %s' % card.ToBinary(mask_name) 160 | print padding + 'FUSE STATE: %s' % fuse + ' (' + fuse_state[fuse] + ')' 161 | print padding + 'ROM INFO: %s' % rom_info + ' (Checksum)' 162 | print padding + 'COMBO NAME: %s-m%s.%s.%s-%s' % (targets[target], mask_id, fabkey, patch_id, card.ToBinary(mask_name)) 163 | print padding + 'MANUFACTURER: %s' % manufacturers[manufacturer] 164 | print padding + 'PRODUCED: Year %s, Week %s, Build %d' % (manufacture_year, manufacture_week, manufacture_mask) 165 | 166 | def decode_jcop_lifecycle(data, padding): 167 | ic_fab= data[0:4] 168 | ic_type= data[4:8] 169 | os_id= data[8:12] 170 | os_release_date= data[12:16] 171 | os_release_level= data[16:20] 172 | ic_fab_date= data[20:24] 173 | ic_serial= data[24:32] 174 | ic_batch= data[32:36] 175 | ic_mod_fab= data[36:40] 176 | ic_mod_pack_date= data[40:44] 177 | icc_man= data[44:48] 178 | ic_embed_date= data[48:52] 179 | ic_pre_perso= data[52:56] 180 | ic_pre_perso_date= data[56:60] 181 | ic_pre_perso_equip= data[60:68] 182 | ic_perso= data[68:72] 183 | ic_perso_date= data[72:76] 184 | ic_perso_equip= data[76:84] 185 | 186 | print 187 | print padding + 'IC Fabricator %s' % ic_fab 188 | print padding + 'IC Type %s' % ic_type 189 | print padding + 'OS ID %s' % os_id 190 | print padding + 'OS Release Date %s' % os_release_date 191 | print padding + 'OS Release Level %s' % os_release_level 192 | print padding + 'IC Fabrication Date Year %s Day %s' % (ic_fab_date[0], ic_fab_date[1:4]) 193 | print padding + 'IC Serial Number %s' % ic_serial 194 | print padding + 'IC Batch Number %s' % ic_batch 195 | print padding + 'IC Module Fabricator %s' % ic_mod_fab 196 | print padding + 'IC Module Packaging Date Year %s Day %s' % (ic_mod_pack_date[0], ic_mod_pack_date[1:4]) 197 | print padding + 'ICC Manufacturer %s' % icc_man 198 | print padding + 'IC Embedding Date Year %s Day %s' % (ic_embed_date[0], ic_embed_date[1:4]) 199 | print padding + 'IC Pre-Personalizer %s' % ic_pre_perso 200 | print padding + 'IC Pre-Personalization Date %s' % ic_pre_perso_date 201 | print padding + 'IC Pre-Personalization Equipment %s' % ic_pre_perso_equip 202 | print padding + 'IC Personalizer %s' % ic_perso 203 | print padding + 'IC Personalization Date Year %s Day %s' % (ic_perso_date[0], ic_perso_date[1:4]) 204 | print padding + 'IC Personalization Equipment %s' % ic_perso_equip 205 | 206 | def decode_privileges(data): 207 | print '(', 208 | multiple= False 209 | try: 210 | for mask in privilege_byte_1.keys(): 211 | if (int(data[0:2],16) & int(mask,16)) == int(mask,16): 212 | if multiple: 213 | print '/', 214 | print privilege_byte_1[mask], 215 | multiple= True 216 | except: 217 | print ')', 218 | return 219 | print ')', 220 | 221 | # check privilege byte 0 to see if we're a security domain 222 | def check_security_domain(data): 223 | length= int(data[2:4],16) * 2 224 | i= 4 225 | while i < length + 4: 226 | for item in registry_tags.keys(): 227 | if data[i:i+len(item)] == item: 228 | itemlength= int(data[i+len(item):i+len(item)+2],16) * 2 229 | if item == card.GP_REG_PRIV: 230 | itemdata= data[i+len(item)+2:i+len(item)+2+itemlength] 231 | if (int(itemdata[0:2],16) & 0x80) == 0x80: 232 | return True 233 | i += itemlength + len(item) + 2 234 | return False 235 | 236 | def decode_gp_registry_data(data, padding, filter): 237 | if not data[0:2] == card.GP_REG_DATA: 238 | return False, '' 239 | states= application_life_cycle_states 240 | if filter == card.GP_FILTER_ISD: 241 | states= card_life_cycle_states 242 | if filter == card.GP_FILTER_ASSD: 243 | states= application_life_cycle_states 244 | if filter == card.GP_FILTER_ELF: 245 | states= executable_life_cycle_states 246 | # check if this is a security domain (not set up right, so disabled!) 247 | #if check_security_domain(data): 248 | # states= security_domain_life_cycle_states 249 | length= int(data[2:4],16) * 2 250 | i= 4 251 | while i < length + 4: 252 | decoded= False 253 | for item in registry_tags.keys(): 254 | if data[i:i+len(item)] == item: 255 | if not item == card.GP_REG_AID: 256 | print ' ', 257 | itemlength= int(data[i+len(item):i+len(item)+2],16) * 2 258 | itemdata= data[i+len(item)+2:i+len(item)+2+itemlength] 259 | print padding, registry_tags[item]+':', itemdata, 260 | if item == card.GP_REG_LCS: 261 | if filter == card.GP_FILTER_ASSD: 262 | # mask out application specific bits 263 | itemdata= '%02x' % (int(itemdata,16) & 0x87) 264 | print '( '+states[itemdata]+' )', 265 | if item == card.GP_REG_PRIV: 266 | decode_privileges(itemdata) 267 | decoded= True 268 | i += itemlength + len(item) + 2 269 | print 270 | if not decoded: 271 | return False 272 | return True 273 | 274 | card.info('jcoptool v0.1d') 275 | if Help or len(args) < 1: 276 | print '\nUsage:\n\n\t%s [OPTIONS] [ARGS] [ENC Key] [MAC Key] [KEK Key]' % sys.argv[0] 277 | print 278 | print '\tWhere COMMAND/ARGS are one of the following combinations:' 279 | print 280 | print "\tINFO\t\t\tDisplay useful info about the JCOP card and it's contents." 281 | print 282 | print '\tDES keys ENC MAC and KEK are always the final 3 arguments, and should be in HEX.' 283 | print '\tIf not specified, the default \'404142434445464748494A4B4C4D4E4F\' will be used.' 284 | print 285 | os._exit(True) 286 | 287 | command= args[0] 288 | 289 | if card.select(): 290 | print 291 | print ' Card ID: ' + card.uid 292 | if card.readertype == card.READER_PCSC: 293 | print ' ATS: %s (%s)' % (card.pcsc_ats,card.ReadablePrint(card.ToBinary(card.pcsc_ats))) 294 | else: 295 | print ' No RFID card present' 296 | print 297 | #os._exit(True) 298 | 299 | #print ' ATR: ' + card.pcsc_atr 300 | #print 301 | 302 | # high speed select required for ACG 303 | if not card.hsselect('08'): 304 | print ' Could not select RFID card for APDU processing' 305 | #os._exit(True) 306 | 307 | print 308 | print ' JCOP Identity Data:', 309 | # send pseudo file select command for JCOP IDENTIFY 310 | card.iso_7816_select_file(card.AID_JCOP_IDENTIFY,'04','00') 311 | if card.errorcode == '6A82' and len(card.data) > 0: 312 | print card.data 313 | print 314 | decode_jcop_identify(card.data,' ') 315 | else: 316 | print ' Device does not support JCOP IDENTIFY!' 317 | 318 | # card life cycle data 319 | # high speed select required for ACG 320 | if not card.hsselect('08'): 321 | print ' Could not select RFID card for APDU processing' 322 | print 323 | print ' Life Cycle data:', 324 | if not card.gp_get_data('9F7F'): 325 | print " Failed - ", card.ISO7816ErrorCodes[card.errorcode] 326 | else: 327 | print card.data 328 | if card.data[0:4] == '9F7F': 329 | decode_jcop_lifecycle(card.data[6:],' ') 330 | 331 | # select JCOP Card Manager 332 | # high speed select required for ACG 333 | if not card.hsselect('08'): 334 | print ' Could not select RFID card for APDU processing' 335 | if not card.iso_7816_select_file(card.AID_CARD_MANAGER,'04','00'): 336 | print 337 | print " Can't select Card Manager!", 338 | card.iso_7816_fail(card.errorcode) 339 | 340 | if command == 'INFO': 341 | # high speed select required for ACG 342 | if not card.hsselect('08'): 343 | print ' Could not select RFID card for APDU processing' 344 | # get Card Recognition Data 345 | if not card.gp_get_data('0066'): 346 | print 347 | print " Can't get Card Recognition Data!", 348 | card.iso_7816_fail(card.errorcode) 349 | pointer= 0 350 | item= card.data[pointer:pointer+2] 351 | if item != '66': 352 | print 'Unrecognised template:', item 353 | os._exit(True) 354 | pointer += 2 355 | item= card.data[pointer:pointer+2] 356 | length= int(item,16) 357 | 358 | print 359 | print ' Card Data length:',length 360 | pointer += 2 361 | item= card.data[pointer:pointer+2] 362 | if item != '73': 363 | print 'Unrecognised template:', item 364 | os._exit(True) 365 | pointer += 2 366 | item= card.data[pointer:pointer+2] 367 | length= int(item,16) 368 | print ' Card Recognition Data length:',length 369 | pointer += 2 370 | while pointer < len(card.data): 371 | item= card.data[pointer:pointer+2] 372 | try: 373 | print ' '+tags[item]+':', 374 | pointer += 2 375 | length= int(card.data[pointer:pointer + 2],16) 376 | pointer += 2 377 | if tags[item] == 'OID': 378 | decodedOID, dummy= decoder.decode(card.ToBinary(item+('%02x' % length)+card.data[pointer:pointer + length * 2])) 379 | print decodedOID.prettyPrint() 380 | else: 381 | if(card.data[pointer:pointer + 2]) == '06': 382 | decodedOID, dummy= decoder.decode(card.ToBinary(card.data[pointer:pointer + length * 2])) 383 | print 384 | print ' OID:', decodedOID.prettyPrint() 385 | else: 386 | print card.data[pointer:pointer + length * 2] 387 | pointer += length * 2 388 | except: 389 | print 'Unrecognised tag', item 390 | os._exit(True) 391 | # set up DES keys for encryption operations 392 | if len(args) > 1: 393 | enc_key= args[1] 394 | if len(args) > 2: 395 | mac_key= args[2] 396 | else: 397 | enc_key= card.GP_ENC_KEY 398 | mac_key= card.GP_MAC_KEY 399 | 400 | if command == 'INSTALL': 401 | if len(args) > 2: 402 | enc_key= args[2] 403 | if len(args) > 3: 404 | mac_key= args[3] 405 | else: 406 | enc_key= card.GP_ENC_KEY 407 | mac_key= card.GP_MAC_KEY 408 | 409 | if command == 'INFO' or command == 'INSTALL': 410 | # authenticate to card 411 | # initialise secure channel 412 | print 413 | print ' *** Warning' 414 | print ' *** Repeated authentication failures may permanently disable device' 415 | print 416 | x= string.upper(raw_input(' Attempt to authenticate (y/n)? ')) 417 | if not x == 'Y': 418 | os._exit(True) 419 | 420 | # high speed select required for ACG 421 | if not card.hsselect('08'): 422 | print ' Could not select RFID card for APDU processing' 423 | host_challenge= card.GetRandom(8) 424 | if not card.gp_initialize_update(host_challenge): 425 | print 'Can\'t Initialise Update!' 426 | card.iso_7816_fail(card.errorcode) 427 | card_key_diversification, card_key_info, card_sc_sequence_counter,card_challenge,card_cryptogram= card.gp_initialize_update_response_scp02(card.data) 428 | 429 | 430 | secure_channel_protocol= card_key_info[2:4] 431 | 432 | if secure_channel_protocol == card.GP_SCP02: 433 | # create ENC session key by encrypting derivation data with ENC key 434 | session_pad= '000000000000000000000000' 435 | derivation_data= '0182' + card_sc_sequence_counter + session_pad 436 | # create encryption object with ENC key 437 | e_enc= DES3.new(card.ToBinary(enc_key),DES3.MODE_CBC,card.DES_IV) 438 | enc_s_key= e_enc.encrypt(card.ToBinary(derivation_data)) 439 | # data for cryptograms 440 | card_cryptogram_source= host_challenge + card_sc_sequence_counter + card_challenge 441 | host_cryptogram_source= card_sc_sequence_counter + card_challenge + host_challenge 442 | # check card cryptogram 443 | check_cryptogram= string.upper(card.ToHex(card.DES3MAC(card.ToBinary(card_cryptogram_source), enc_s_key, ''))) 444 | if not check_cryptogram == card_cryptogram: 445 | print 'Key mismatch!' 446 | print 'Card Cryptogram: ', card_cryptogram 447 | print 'Calculated Cryptogram:', check_cryptogram 448 | os._exit(True) 449 | 450 | # cryptogram checks out, so we can use session key 451 | # create encryption object with ENC Session key 452 | s_enc= DES3.new(enc_s_key,DES3.MODE_CBC,card.DES_IV) 453 | 454 | # authenticate to card 455 | host_cryptogram= card.DES3MAC(card.ToBinary(host_cryptogram_source), enc_s_key, '') 456 | # create encryption object with MAC key 457 | e_enc= DES3.new(card.ToBinary(mac_key),DES3.MODE_CBC,card.DES_IV) 458 | # create C-MAC session key 459 | derivation_data= '0101' + card_sc_sequence_counter + session_pad 460 | cmac_s_key= e_enc.encrypt(card.ToBinary(derivation_data)) 461 | if not card.gp_external_authenticate(host_cryptogram,cmac_s_key): 462 | print 'Card Authentication failed!' 463 | card.iso_7816_fail(card.errorcode) 464 | else: 465 | print 'Unsupported Secure Channel Protocol:', secure_channel_protocol 466 | os._exit(True) 467 | 468 | 469 | print ' Authentication succeeded' 470 | # get card status (list card contents) 471 | # high speed select required for ACG 472 | #if not card.hsselect('08'): 473 | # print ' Could not select RFID card for APDU processing' 474 | print 475 | print ' Card contents:' 476 | for filter in '80','40','20','10': 477 | if not card.gp_get_status(filter,'02',''): 478 | if not card.errorcode == '6A88': 479 | print 480 | print " Can't get Card Status!", 481 | card.iso_7816_fail(card.errorcode) 482 | print 483 | print ' ', card_status[filter]+':' 484 | if card.errorcode == '6A88': 485 | print ' None!' 486 | else: 487 | if not decode_gp_registry_data(card.data,' ',filter): 488 | print ' Can\'t decode Registry!' 489 | print card.data 490 | os._exit(True) 491 | os._exit(False) 492 | -------------------------------------------------------------------------------- /lfxtype.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # lfxtype.py - select card and display tag type 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | import rfidiot 26 | import sys 27 | import os 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(True) 34 | 35 | 36 | card.info('lfxtype v0.1j') 37 | card.select() 38 | ID= card.uid 39 | if ID: 40 | print 'Card ID: ' + ID 41 | print 'Tag type: ' + card.LFXTags[card.tagtype] 42 | if card.tagtype == card.EM4x02: 43 | print ' Unique ID: ' + card.EMToUnique(ID) 44 | card.settagtype(card.Q5) 45 | card.select() 46 | if card.uid: 47 | print ' *** This is a Q5 tag in EM4x02 emulation mode ***' 48 | os._exit(False) 49 | else: 50 | print 'No TAG present!' 51 | os._exit(True) 52 | -------------------------------------------------------------------------------- /loginall.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # loginall.py - attempt to login to each sector with transport keys 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | 26 | try: 27 | card= rfidiot.card 28 | except: 29 | print "Couldn't open reader!" 30 | os._exit(True) 31 | 32 | card.info('loginall v0.1h') 33 | 34 | card.select() 35 | print '\ncard id: ' + card.uid 36 | 37 | block = 0 38 | 39 | while block < 16: 40 | for X in [ 'AA', 'BB', 'FF' ]: 41 | card.select() 42 | print '%02x %s: ' % (block, X), 43 | if card.login(block, X, ''): 44 | print "success!" 45 | elif card.errorcode: 46 | print "error: " + card.errorcode 47 | else: 48 | print "failed" 49 | block += 1 50 | os._exit(False) 51 | -------------------------------------------------------------------------------- /ls_nfc_client-3.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamLaurie/RFIDIOt/88f2ef9f8e02d0b1e4a03fcd5aa52e3c6ab0dc73/ls_nfc_client-3.apk -------------------------------------------------------------------------------- /ls_nfc_client-readme.txt: -------------------------------------------------------------------------------- 1 | /* LS_NFC_CLient - Android Network NFC Client for use with RFIDIOt 2 | * 3 | * Nick von Dadelszen 4 | * https://www.lateralsecurity.com/ 5 | * 6 | * This code is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This code is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * Copyright (c) 2011 Lateral Security 17 | */ 18 | 19 | LS_NFC_CLient is an Android application that detects an NFC card and makes a network connection to obtain commands (APDUs) to run on that card. It works by registering an intent for detection of ISODEP NFC cards, and then connecting to the server defined the application settings. This can be changed in the client UI. 20 | 21 | 22 | For the server component, you can use netcat to listen on the port and send APDUs manually. Or you can use RFIDIOt with the pyandroid patch to send commands to the card. 23 | 24 | The application has been tested on a Nexus S with the following types of cards: 25 | - Electronic passports 26 | - Paypass creditcards 27 | - OTher ISO 14443 cards 28 | 29 | You can also use RFIDIOt to make calls ro LS_NFC_Client by setting -R RFIDIOt.rfidiot.READER_ANDROID or modifying the RFIDIOtconfig.py 30 | 31 | -------------------------------------------------------------------------------- /mifare.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamLaurie/RFIDIOt/88f2ef9f8e02d0b1e4a03fcd5aa52e3c6ab0dc73/mifare.pdf -------------------------------------------------------------------------------- /mifarekeys.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # mifarekeys.py - calculate 3DES key for Mifare access on JCOP cards 5 | # as per Philips Application Note AN02105 6 | # http://www.nxp.com/acrobat_download/other/identification/067512.pdf 7 | # 8 | # Adam Laurie 9 | # http://rfidiot.org/ 10 | # 11 | # This code is copyright (c) Adam Laurie, 2008, All rights reserved. 12 | # For non-commercial use only, the following terms apply - for all other 13 | # uses, please contact the author: 14 | # 15 | # This code is free software; you can redistribute it and/or modify 16 | # it under the terms of the GNU General Public License as published by 17 | # the Free Software Foundation; either version 2 of the License, or 18 | # (at your option) any later version. 19 | # 20 | # This code is distributed in the hope that it will be useful, 21 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | # GNU General Public License for more details. 24 | # 25 | # 22/07/08 - version 1.0 - Mifare to 3DES key mapping working, but not final MifarePWD 26 | # 23/07/08 - version 1.1 - Fix 3DES ciphering FTW! 27 | # 24/07/08 - version 1.2 - Add some usage text 28 | 29 | import sys 30 | from Crypto.Cipher import DES3 31 | from Crypto.Cipher import DES 32 | 33 | def HexArray(data): 34 | # first check array is all hex digits 35 | try: 36 | int(data,16) 37 | except: 38 | return False, [] 39 | # check array is 4 hex digit pairs 40 | if len(data) != 12: 41 | return False, [] 42 | # now break into array of hex pairs 43 | out= [] 44 | for x in range(0,len(data),2): 45 | out.append(data[x:x+2]) 46 | return True, out 47 | 48 | ### main ### 49 | print('mifarekeys v0.1b') 50 | 51 | if len(sys.argv) != 3: 52 | print 53 | print "Usage:" 54 | print "\t%s " % sys.argv[0] 55 | print 56 | print "\tCreate MifarePWD for access to Mifare protected memory on Dual Interface IC" 57 | print "\t(JCOP) cards. Output is DKeyA, DKeyB and MifarePWD. DKeyA and DKeyB are used as" 58 | print "\tthe DES3 keys to generate MifarePWD with an IV of (binary) '00000000', a" 59 | print "\tChallenge of (also binary) '00000000', and a key of DKeyA+DKeyB+DKeyA." 60 | print 61 | print "\tExample:" 62 | print 63 | print "\tUsing KeyA of A0A1A2A3A4A5 and KeyB of B0B1B2B3B4B5 should give the result:" 64 | print 65 | print "\t\tDKeyA: 40424446484A7E00" 66 | print "\t\tDKeyB: 007E60626466686A" 67 | print 68 | print "\t\tMifarePWD: 8C7F46D76CE01266" 69 | print 70 | sys.exit(True) 71 | 72 | # break keyA and keyB into 2 digit hex arrays 73 | ret, keyA= HexArray(sys.argv[1]) 74 | if not ret: 75 | print "Invalid HEX string:", sys.argv[1] 76 | sys.exit(True) 77 | ret, keyB= HexArray(sys.argv[2]) 78 | if not ret: 79 | print "Invalid HEX string:", sys.argv[2] 80 | sys.exit(True) 81 | 82 | # now expand 48 bit Mifare keys to 64 bits for DES by adding 2 bytes 83 | # one is all zeros and the other is derived from the 48 Mifare key bits 84 | 85 | ### KeyA ### 86 | # first left shift 1 to create a 0 trailing bit (masked to keep it a single byte) 87 | newkeyA= '' 88 | for n in range(6): 89 | newkeyA += "%02X" % ((int(keyA[n],16) << 1) & 0xff) 90 | # now create byte 6 from bit 7 of original bytes 0-5, shifted to the correct bit position 91 | newkeyAbyte6= 0x00 92 | for n in range(6): 93 | newkeyAbyte6 |= ((int(keyA[n],16) >> n + 1) & pow(2,7 - (n + 1))) 94 | newkeyA += "%02X" % newkeyAbyte6 95 | # and finally add a 0x00 to the end 96 | newkeyA += '00' 97 | print 98 | print " DKeyA: ", newkeyA 99 | 100 | ### KeyB ### 101 | # now do keyB, which is basically the same but starting at byte 2 and prepending new bytes 102 | newkeyB= '00' 103 | # now create byte 1 from bit 7 of original bytes 0-5, shifted to the correct bit position, which is 104 | # the reverse of byte6 in KeyA 105 | newkeyBbyte1= 0x00 106 | for n in range(6): 107 | newkeyBbyte1 |= ((int(keyB[n],16) >> 7 - (n + 1)) & pow(2,n + 1)) 108 | newkeyB += "%02X" % newkeyBbyte1 109 | # left shift 1 to create a 0 trailing bit (masked to keep it a single byte) 110 | for n in range(6): 111 | newkeyB += "%02X" % ((int(keyB[n],16) << 1) & 0xff) 112 | print " DKeyB: ", newkeyB 113 | 114 | # now create triple-DES key 115 | deskeyABA= '' 116 | # build key MSB first 117 | for n in range(len(newkeyA+newkeyB+newkeyA)-2,-2,-2): 118 | deskeyABA += chr(int((newkeyA+newkeyB+newkeyA)[n:n + 2],16)) 119 | des3= DES3.new(deskeyABA,DES.MODE_CBC,'\0\0\0\0\0\0\0\0') 120 | mifarePWD= des3.encrypt('\0\0\0\0\0\0\0\0') 121 | # reverse LSB/MSB for final output 122 | mifarePWDout= '' 123 | for n in range(len(mifarePWD)-1,-1,-1): 124 | mifarePWDout += "%02X" % int(ord(mifarePWD[n])) 125 | print 126 | print " MifarePWD: ", mifarePWDout 127 | print 128 | -------------------------------------------------------------------------------- /multiselect.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # multiselect.py - continuously select card and display ID 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | import rfidiot 26 | import sys 27 | import os 28 | import time 29 | import string 30 | 31 | try: 32 | card= rfidiot.card 33 | except: 34 | os._exit(True) 35 | 36 | args= rfidiot.args 37 | 38 | card.info('multiselect v0.1n') 39 | 40 | # force card type if specified 41 | if len(args) == 1: 42 | if not card.settagtype(args[0]): 43 | print 'Could not set tag type' 44 | os._exit(True) 45 | else: 46 | card.settagtype(card.ALL) 47 | 48 | while 42: 49 | if card.select('A') or card.select('B'): 50 | print ' Tag ID: ' + card.uid, 51 | if (card.readertype == card.READER_FROSCH and card.tagtype == card.HITAG2 and card.tagmode == card.HITAG2_PASSWORD): 52 | print " Tag Type: Hitag2 (Password mode)" 53 | if (card.readertype == card.READER_FROSCH and card.tagtype == card.HITAG2 and card.tagmode == card.HITAG2_CRYPTO): 54 | print " Tag Type: Hitag2 (Crypto mode)" 55 | if (card.readertype == card.READER_ACG and string.find(card.readername,"LFX") == 0): 56 | print " Tag Type:" + card.LFXTags[card.tagtype] 57 | else: 58 | print 59 | else: 60 | print ' No card present\r', 61 | sys.stdout.flush() 62 | -------------------------------------------------------------------------------- /nfcid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # 4 | # NFC ID.py - Python code for Identifying NFC cards 5 | # version 0.1 6 | # Nick von Dadelszen (nick@lateralsecurity.com) 7 | # Lateral Security (www.lateralsecurity.com) 8 | 9 | # 10 | # This code is copyright (c) Lateral Security, 2011, All rights reserved. 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | # 25 | 26 | #import RFIDIOtconfig 27 | import sys 28 | import os 29 | import pyandroid 30 | import datetime 31 | 32 | Verbose= True 33 | Quiet= True 34 | 35 | aidlist= [ 36 | ['MASTERCARD', 'a0000000041010'], 37 | ['MASTERCARD', 'a0000000049999'], 38 | ['VISA', 'a000000003'], 39 | ['VISA Debit/Credit', 'a0000000031010'], 40 | ['VISA Credit', 'a000000003101001'], 41 | ['VISA Debit', 'a000000003101002'], 42 | ['VISA Electron', 'a0000000032010'], 43 | ['VISA V Pay', 'a0000000032020'], 44 | ['VISA Interlink', 'a0000000033010'], 45 | ['VISA Plus', 'a0000000038010'], 46 | ['VISA ATM', 'a000000003999910'], 47 | ['Maestro', 'a0000000043060'], 48 | ['Maestro UK', 'a0000000050001'], 49 | ['Maestro TEST', 'b012345678'], 50 | ['Self Service', 'a00000002401'], 51 | ['American Express', 'a000000025'], 52 | ['ExpressPay', 'a000000025010701'], 53 | ['Link', 'a0000000291010'], 54 | ['Alias AID', 'a0000000291010'], 55 | ['Cirrus', 'a0000000046000'], 56 | ['Snapper Card', 'D4100000030001'], 57 | ['Passport', 'A0000002471001'], 58 | ] 59 | 60 | 61 | n = pyandroid.Android() 62 | 63 | while(42): 64 | uid = n.select() 65 | print 'GMT Timestamp: ' + str(datetime.datetime.now()) 66 | 67 | if not Quiet: 68 | print '\nID: ' + uid 69 | print ' Data:' 70 | 71 | current = 0 72 | cc_data = False 73 | 74 | while current < len(aidlist): 75 | if Verbose: 76 | print 'Trying AID: '+ aidlist[current][0] + ':' + aidlist[current][1] 77 | apdu = '00A4040007' + aidlist[current][1] 78 | r = n.sendAPDU(apdu) 79 | #print r 80 | #print r[-4:] 81 | if not r[-4:] == '9000': 82 | apdu = apdu + '00' 83 | r = n.sendAPDU(apdu) 84 | #print r 85 | #print r[-4:] 86 | 87 | if r[-4:] == '9000': 88 | #print card.data + card.errorcode 89 | uid = uid[:-1] 90 | n.sendResults("Card found-UID: " + uid + "-Card type: " + aidlist[current][0]) 91 | break 92 | 93 | current += 1 94 | 95 | if not Quiet: 96 | print 'Ending now ...' 97 | n.deconfigure() 98 | print 99 | 100 | -------------------------------------------------------------------------------- /pn532emulate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # pn532emulate.py - switch NXP PN532 reader chip into TAG emulation mode 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2009, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | 25 | import rfidiot 26 | from rfidiot.pn532 import * 27 | import sys 28 | import os 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | os._exit(True) 34 | 35 | args= rfidiot.args 36 | help= rfidiot.help 37 | 38 | card.info('pn532emulate v0.1d') 39 | 40 | if help or len(args) < 6: 41 | print sys.argv[0] + ' - Switch NXP PN532 chip into emulation mode' 42 | print 43 | print 'Usage: ' + sys.argv[0] + ' [General Bytes] [Historical Bytes]' 44 | print 45 | print ' The NXP PN532 chip inside some readers (such as ACS/Tikitag) are capable of emulating the following tags:' 46 | print 47 | print ' ISO-14443-3' 48 | print ' ISO-14443-4' 49 | print ' Mifare' 50 | print ' FeliCa' 51 | print 52 | print ' Arguments should be specified as follows:' 53 | print 54 | print ' MODE (BitField, last 3 bits only):' 55 | print ' -----000 - Any' 56 | print ' -----001 - Passive only' 57 | print ' -----010 - DEP only' 58 | print ' -----100 - PICC only' 59 | print 60 | print ' SENS_RES:' 61 | print ' 2 Bytes, LSB first, as defined in ISO 14443-3.' 62 | print 63 | print ' NFCID1t:' 64 | print " UID Last 6 HEX digits ('08' will be prepended)." 65 | print 66 | print ' SEL_RES:' 67 | print ' 1 Byte, as defined in ISO14443-4.' 68 | print 69 | print ' NFCID2t:' 70 | print " 8 Bytes target NFC ID2. Must start with '01fe'." 71 | print 72 | print ' PAD:' 73 | print ' 8 Bytes.' 74 | print 75 | print ' SYSTEM_CODE:' 76 | print ' 2 Bytes, returned in the POL_RES frame if the 4th byte of the incoming POL_REQ' 77 | print ' command frame is 0x01.' 78 | print 79 | print ' NFCID3t:' 80 | print ' 10 Bytes, used in the ATR_RES in case of ATR_REQ received from the initiator.' 81 | print 82 | print ' General Bytes:' 83 | print ' Optional, Max 47 Bytes, to be used in the ATR_RES.' 84 | print 85 | print ' Historical Bytes:' 86 | print ' Optional, Max 48 Bytes, to be used in the ATS when in ISO/IEC 14443-4 PICC' 87 | print ' emulation mode.' 88 | print 89 | print ' Example:' 90 | print 91 | print ' ' + sys.argv[0] + ' 00 0800 dc4420 60 01fea2a3a4a5a6a7c0c1c2c3c4c5c6c7ffff aa998877665544332211 00 52464944494f7420504e353332' 92 | print 93 | print ' In ISO/IEC 14443-4 PICC emulation mode, the emulator will wait for initiator, then wait for an APDU,' 94 | print " to which it will reply '9000' and exit." 95 | print 96 | os._exit(True) 97 | 98 | if not card.readersubtype == card.READER_ACS: 99 | print ' Reader type not supported!' 100 | os._exit(True) 101 | 102 | # switch off auto-polling (for ACS v1 firmware only) (doesn't seem to help anyway!) 103 | #if not card.acs_send_apdu(card.PCSC_APDU['ACS_DISABLE_AUTO_POLL']): 104 | # print ' Could not disable auto-polling' 105 | # os._exit(True) 106 | 107 | if card.acs_send_apdu(PN532_APDU['GET_PN532_FIRMWARE']): 108 | print ' NXP PN532 Firmware:' 109 | pn532_print_firmware(card.data) 110 | 111 | if card.acs_send_apdu(PN532_APDU['GET_GENERAL_STATUS']): 112 | pn532_print_status(card.data) 113 | 114 | mode= [args[0]] 115 | sens_res= [args[1]] 116 | uid= [args[2]] 117 | sel_res= [args[3]] 118 | felica= [args[4]] 119 | nfcid= [args[5]] 120 | try: 121 | lengt= ['%02x' % (len(args[6]) / 2)] 122 | gt= [args[6]] 123 | except: 124 | lengt= ['00'] 125 | gt= [''] 126 | try: 127 | lentk= ['%02x' % (len(args[7]) / 2)] 128 | tk= [args[7]] 129 | except: 130 | lentk= ['00'] 131 | tk= [''] 132 | 133 | print ' Waiting for activation...' 134 | card.acs_send_apdu(card.PCSC_APDU['ACS_LED_RED']) 135 | status= card.acs_send_apdu(PN532_APDU['TG_INIT_AS_TARGET']+mode+sens_res+uid+sel_res+felica+nfcid+lengt+gt+lentk+tk) 136 | if not status or not card.data[:4] == 'D58D': 137 | print 'Target Init failed:', card.errorcode 138 | os._exit(True) 139 | mode= int(card.data[4:6],16) 140 | baudrate= mode & 0x70 141 | print ' Emulator activated:' 142 | print ' UID: 08%s' % uid[0] 143 | print ' Baudrate:', PN532_BAUDRATES[baudrate] 144 | print ' Mode:', 145 | if mode & 0x08: 146 | print 'ISO/IEC 14443-4 PICC' 147 | if mode & 0x04: 148 | print 'DEP' 149 | framing= mode & 0x03 150 | print ' Framing:', PN532_FRAMING[framing] 151 | print ' Initiator:', card.data[6:] 152 | print 153 | 154 | print ' Waiting for APDU...' 155 | status= card.acs_send_apdu(PN532_APDU['TG_GET_DATA']) 156 | if not status or not card.data[:4] == 'D587': 157 | print 'Target Get Data failed:', card.errorcode 158 | print 'Data:',card.data 159 | os._exit(True) 160 | errorcode= int(card.data[4:6],16) 161 | if not errorcode == 0x00: 162 | print 'Error:',PN532_ERRORS[errorcode] 163 | os._exit(True) 164 | print '<<', card.data[6:] 165 | 166 | print '>>', card.ISO_OK 167 | status= card.acs_send_apdu(PN532_APDU['TG_SET_DATA']+[card.ISO_OK]) 168 | if not status: 169 | os._exit(True) 170 | else: 171 | os._exit(False) 172 | -------------------------------------------------------------------------------- /pn532mitm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # pn532mitm.py - NXP PN532 Man-In-The_Middle - log conversations between TAG and external reader 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2009, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | from rfidiot.pn532 import * 26 | import sys 27 | import os 28 | import string 29 | import socket 30 | import time 31 | import random 32 | import operator 33 | 34 | # try to connect to remote host. if that fails, alternately listen and connect. 35 | def connect_to(host,port,type): 36 | print 'host', host, 'port', port, 'type', type 37 | peer= socket.socket(socket.AF_INET, socket.SOCK_STREAM) 38 | random.seed() 39 | first= True 40 | while 42: 41 | peer.settimeout(random.randint(1,10)) 42 | print ' Paging %s %s \r' % (host, port), 43 | sys.stdout.flush() 44 | time.sleep(1) 45 | try: 46 | if peer.connect((host,port)) == 0: 47 | print ' Connected to %s port %d ' % (host,port) 48 | send_data(peer,type) 49 | data= recv_data(peer) 50 | connection= peer 51 | break 52 | except Exception, exc: 53 | # connection refused - the other end isn't up yet 54 | if exc.errno == 111: 55 | pass 56 | else: 57 | print 'Could not open local socket: ' 58 | print exc 59 | os._exit(True) 60 | try: 61 | print ' Listening for REMOTE on port %s \r' % port, 62 | sys.stdout.flush() 63 | if first: 64 | peer.bind(('0.0.0.0',port)) 65 | peer.listen(1) 66 | first= False 67 | conn, addr= peer.accept() 68 | if conn: 69 | print ' Connected to %s port %d ' % (addr[0],addr[1]) 70 | data= recv_data(conn) 71 | send_data(conn,type) 72 | connection= conn 73 | break 74 | except socket.timeout: 75 | pass 76 | if data == type: 77 | print ' Handshake failed - both ends are set to', type 78 | time.sleep(1) 79 | connection.close() 80 | os._exit(True) 81 | print ' Remote is', data 82 | print 83 | return connection 84 | 85 | # send data with 3 digit length and 2 digit CRC 86 | def send_data(host, data): 87 | lrc= 0 88 | length= '%03x' % (len(data) + 2) 89 | for x in length + data: 90 | lrc= operator.xor(lrc,ord(x)) 91 | host.send(length) 92 | host.send(data) 93 | host.send('%02x' % lrc) 94 | 95 | # receive data of specified length and check CRC 96 | def recv_data(host): 97 | out= '' 98 | while len(out) < 3: 99 | out += host.recv(3 - len(out)) 100 | length= int(out,16) 101 | lrc= 0 102 | for x in out: 103 | lrc= operator.xor(lrc,ord(x)) 104 | out= '' 105 | while len(out) < length: 106 | out += host.recv(length - len(out)) 107 | for x in out[:-2]: 108 | lrc= operator.xor(lrc,ord(x)) 109 | if not lrc == int(out[-2:],16): 110 | print ' Remote socket CRC failed!' 111 | host.close() 112 | os._exit(True) 113 | return out[:-2] 114 | 115 | try: 116 | card= rfidiot.card 117 | except: 118 | os._exit(True) 119 | 120 | args= rfidiot.args 121 | help= rfidiot.help 122 | 123 | card.info('pn532mitm v0.1e') 124 | 125 | if help or len(args) < 1: 126 | print sys.argv[0] + ' - NXP PN532 Man-In-The-Middle' 127 | print 128 | print '\tUsage: ' + sys.argv[0] + " [LOG FILE] ['QUIET']" 129 | print 130 | print '\t Default PCSC reader will be the READER. Specify reader number to use as an EMULATOR as' 131 | print '\t the argument.' 132 | print 133 | print "\t To utilise a REMOTE device, use a string in the form 'emulator:HOST:PORT' or 'reader:HOST:PORT'." 134 | print 135 | print '\t COMMANDS and RESPONSES will be relayed between the READER and the EMULATOR, and relayed' 136 | print '\t traffic will be displayed (and logged if [LOG FILE] is specified).' 137 | print 138 | print "\t If the 'QUIET' option is specified, traffic log will not be displayed on screen." 139 | print 140 | print '\t Logging is in the format:' 141 | print 142 | print '\t << DATA... - HEX APDU received by EMULATOR and relayed to READER' 143 | print '\t >> DATA... SW1SW2 - HEX response and STATUS received by READER and relayed to EMULATOR' 144 | print 145 | print '\t Examples:' 146 | print 147 | print '\t Use device no. 2 as the READER and device no. 3 as the EMULATOR:' 148 | print 149 | print '\t ' + sys.argv[0] + ' -r 2 3' 150 | print 151 | print '\t Use device no. 2 as the EMULATOR and remote system on 192.168.1.3 port 5000 as the READER:' 152 | print 153 | print '\t ' + sys.argv[0] + ' -r 2 reader:192.168.1.3:5000' 154 | print 155 | os._exit(True) 156 | 157 | logging= False 158 | if len(args) > 1: 159 | try: 160 | logfile= open(args[1],'r') 161 | x= string.upper(raw_input(' *** Warning! File already exists! Overwrite (y/n)? ')) 162 | if not x == 'Y': 163 | os._exit(True) 164 | logfile.close() 165 | except: 166 | pass 167 | try: 168 | logfile= open(args[1],'w') 169 | logging= True 170 | except: 171 | print " Couldn't create logfile:", args[1] 172 | os._exit(True) 173 | 174 | try: 175 | if args[2] == 'QUIET': 176 | quiet= True 177 | except: 178 | quiet= False 179 | 180 | if len(args) < 1: 181 | print 'No EMULATOR or REMOTE specified' 182 | os._exit(True) 183 | 184 | # check if we are using a REMOTE system 185 | remote= '' 186 | remote_type= '' 187 | if string.find(args[0],'emulator:') == 0: 188 | remote= args[0][9:] 189 | em_remote= True 190 | remote_type= 'EMULATOR' 191 | else: 192 | em_remote= False 193 | if string.find(args[0],'reader:') == 0: 194 | remote= args[0][7:] 195 | rd_remote= True 196 | remote_type= 'READER' 197 | emulator= card 198 | else: 199 | rd_remote= False 200 | 201 | 202 | if remote: 203 | host= remote[:string.find(remote,':')] 204 | port= int(remote[string.find(remote,':') + 1:]) 205 | connection= connect_to(host, port, remote_type) 206 | else: 207 | try: 208 | readernum= int(args[0]) 209 | emulator= rfidiot.RFIDIOt.rfidiot(readernum,card.readertype,'','','','','','') 210 | print ' Emulator:', 211 | emulator.info('') 212 | if not emulator.readersubtype == card.READER_ACS: 213 | print "EMULATOR is not an ACS" 214 | os._exit(True) 215 | except: 216 | print "Couldn't initialise EMULATOR on reader", args[0] 217 | os._exit(True) 218 | 219 | # always check at least one device locally 220 | if not card.readersubtype == card.READER_ACS: 221 | print "READER is not an ACS" 222 | if remote: 223 | connection.close() 224 | os._exit(True) 225 | 226 | if card.acs_send_apdu(PN532_APDU['GET_PN532_FIRMWARE']): 227 | if remote: 228 | send_data(connection,card.data) 229 | print ' Local NXP PN532 Firmware:' 230 | else: 231 | print ' Reader NXP PN532 Firmware:' 232 | if not card.data[:4] == PN532_OK: 233 | print ' Bad data from PN532:', card.data 234 | if remote: 235 | connection.close() 236 | os._exit(True) 237 | else: 238 | pn532_print_firmware(card.data) 239 | 240 | if remote: 241 | data= recv_data(connection) 242 | print ' Remote NXP PN532 Firmware:' 243 | else: 244 | if emulator.acs_send_apdu(PN532_APDU['GET_PN532_FIRMWARE']): 245 | data= card.data 246 | emulator.acs_send_apdu(card.PCSC_APDU['ACS_LED_ORANGE']) 247 | print ' Emulator NXP PN532 Firmware:' 248 | 249 | if not data[:4] == PN532_OK: 250 | print ' Bad data from PN532:', data 251 | if remote: 252 | connection.close() 253 | os._exit(True) 254 | else: 255 | pn532_print_firmware(data) 256 | 257 | if not remote or remote_type == 'EMULATOR': 258 | card.waitfortag(' Waiting for source TAG...') 259 | full_uid= card.uid 260 | sens_res= [card.sens_res] 261 | sel_res= [card.sel_res] 262 | if remote: 263 | if remote_type == 'READER': 264 | print ' Waiting for remote TAG...' 265 | connection.settimeout(None) 266 | full_uid= recv_data(connection) 267 | sens_res= [recv_data(connection)] 268 | sel_res= [recv_data(connection)] 269 | else: 270 | send_data(connection,card.uid) 271 | send_data(connection,card.sens_res) 272 | send_data(connection,card.sel_res) 273 | 274 | mode= ['00'] 275 | print ' UID:', full_uid 276 | uid= [full_uid[2:]] 277 | print ' sens_res:', sens_res[0] 278 | print ' sel_res:', sel_res[0] 279 | print 280 | felica= ['01fea2a3a4a5a6a7c0c1c2c3c4c5c6c7ffff'] 281 | nfcid= ['aa998877665544332211'] 282 | try: 283 | lengt= ['%02x' % (len(args[6]) / 2)] 284 | gt= [args[6]] 285 | except: 286 | lengt= ['00'] 287 | gt= [''] 288 | try: 289 | lentk= ['%02x' % (len(args[7]) / 2)] 290 | tk= [args[7]] 291 | except: 292 | lentk= ['00'] 293 | tk= [''] 294 | 295 | if not remote or remote_type == 'EMULATOR': 296 | if card.acs_send_apdu(PN532_APDU['GET_GENERAL_STATUS']): 297 | data= card.data 298 | if remote: 299 | if remote_type == 'EMULATOR': 300 | send_data(connection,data) 301 | else: 302 | data= recv_data(connection) 303 | 304 | tags= pn532_print_status(data) 305 | if tags > 1: 306 | print ' Too many TAGS to EMULATE!' 307 | if remote: 308 | connection.close() 309 | os._exit(True) 310 | 311 | #emulator.acs_send_apdu(emulator.PCSC_APDU['ACS_SET_PARAMETERS']+['14']) 312 | 313 | if not remote or remote_type == 'READER': 314 | print ' Waiting for EMULATOR activation...' 315 | status= emulator.acs_send_apdu(PN532_APDU['TG_INIT_AS_TARGET']+mode+sens_res+uid+sel_res+felica+nfcid+lengt+gt+lentk+tk) 316 | if not status or not emulator.data[:4] == 'D58D': 317 | print 'Target Init failed:', emulator.errorcode, emulator.ISO7816ErrorCodes[emulator.errorcode] 318 | if remote: 319 | connection.close() 320 | os._exit(True) 321 | data= emulator.data 322 | if remote: 323 | if remote_type == 'READER': 324 | send_data(connection,data) 325 | else: 326 | print ' Waiting for remote EMULATOR activation...' 327 | connection.settimeout(None) 328 | data= recv_data(connection) 329 | 330 | mode= int(data[4:6],16) 331 | baudrate= mode & 0x70 332 | print ' Emulator activated:' 333 | print ' UID: 08%s' % uid[0] 334 | print ' Baudrate:', PN532_BAUDRATES[baudrate] 335 | print ' Mode:', 336 | if mode & 0x08: 337 | print 'ISO/IEC 14443-4 PICC' 338 | if mode & 0x04: 339 | print 'DEP' 340 | framing= mode & 0x03 341 | print ' Framing:', PN532_FRAMING[framing] 342 | initiator= data[6:] 343 | print ' Initiator:', initiator 344 | print 345 | 346 | print ' Waiting for APDU...' 347 | started= False 348 | try: 349 | while 42: 350 | # wait for emulator to receive a command 351 | if not remote or remote_type == 'READER': 352 | status= emulator.acs_send_apdu(PN532_APDU['TG_GET_DATA']) 353 | data= emulator.data 354 | #if not status or not emulator.data[:4] == 'D587': 355 | if not status: 356 | print 'Target Get Data failed:', emulator.errorcode, emulator.ISO7816ErrorCodes[emulator.errorcode] 357 | print 'Data:', emulator.data 358 | if remote: 359 | connection.close() 360 | os._exit(True) 361 | if remote: 362 | if remote_type == 'READER': 363 | send_data(connection,data) 364 | else: 365 | connection.settimeout(None) 366 | data= recv_data(connection) 367 | errorcode= int(data[4:6],16) 368 | if not errorcode == 0x00: 369 | if remote: 370 | connection.close() 371 | if errorcode == 0x29: 372 | if logging: 373 | logfile.close() 374 | print ' Session ended: EMULATOR released by Initiator' 375 | if not remote or remote_type == 'READER': 376 | emulator.acs_send_apdu(card.PCSC_APDU['ACS_LED_GREEN']) 377 | os._exit(False) 378 | print 'Error:',PN532_ERRORS[errorcode] 379 | os._exit(True) 380 | if not quiet: 381 | print '<<', data[6:] 382 | else: 383 | if not started: 384 | print ' Logging started...' 385 | started= True 386 | if logging: 387 | logfile.write('<< %s\n' % data[6:]) 388 | logfile.flush() 389 | # relay command to tag 390 | if not remote or remote_type == 'EMULATOR': 391 | status= card.acs_send_direct_apdu(data[6:]) 392 | data= card.data 393 | errorcode= card.errorcode 394 | if remote: 395 | if remote_type == 'EMULATOR': 396 | send_data(connection,data) 397 | send_data(connection,errorcode) 398 | else: 399 | data= recv_data(connection) 400 | errorcode= recv_data(connection) 401 | if not quiet: 402 | print '>>', data, errorcode 403 | if logging: 404 | logfile.write('>> %s %s\n' % (data,errorcode)) 405 | logfile.flush 406 | # relay tag's response back via emulator 407 | if not remote or remote_type == 'READER': 408 | status= emulator.acs_send_apdu(PN532_APDU['TG_SET_DATA']+[data]+[errorcode]) 409 | except: 410 | if logging: 411 | logfile.close() 412 | print ' Session ended with possible errors' 413 | if remote: 414 | connection.close() 415 | if not remote or remote_type == 'READER': 416 | emulator.acs_send_apdu(card.PCSC_APDU['ACS_LED_GREEN']) 417 | os._exit(True) 418 | -------------------------------------------------------------------------------- /q5reset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # q5reset.py - plooking too hard on your Q5? this should sort it out. 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | import string 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(True) 34 | 35 | args= rfidiot.args 36 | help= rfidiot.help 37 | 38 | card.info('q5reset v0.1g') 39 | 40 | # standard config block 41 | CFB='e601f004' 42 | B1='ff801bc2' 43 | B2='52500006' 44 | 45 | if help or len(args) == 0 or len(args) > 2: 46 | print sys.argv[0] + ' - sooth and heal a sorely mistreated Q5 tag' 47 | print 'Usage: ' + sys.argv[0] + ' [OPTIONS] [ID]' 48 | print 49 | print '\tIf the optional 8 HEX-digit ID argument is specified, the' 50 | print '\tQ5 tag will be programmed to that ID. Otherwise, only the' 51 | print '\tcontrol block will be written. If the literal \'ID\' is used' 52 | print '\tthen a default ID will be programmed.' 53 | print 54 | print '\tNote that not all Q5 chips allow programming of their ID!' 55 | print 56 | os._exit(True) 57 | 58 | if args[0] == 'CONTROL': 59 | card.settagtype(card.ALL) 60 | while True: 61 | print 62 | card.select() 63 | print ' Card ID: ' + card.uid 64 | x= string.upper(raw_input(' *** Warning! This will overwrite TAG! Place defective card and proceed (y/n)? ')) 65 | if x == 'N': 66 | os._exit(False) 67 | if x == 'Y': 68 | break 69 | print 'Writing...' 70 | card.settagtype(card.Q5) 71 | card.select() 72 | if not card.writeblock(0,CFB): 73 | print 'Write failed!' 74 | os._exit(True) 75 | else: 76 | if len(args) > 1: 77 | if not args[1] == 'ID': 78 | out= card.Unique64Bit(card.HexToQ5(args[1] + '00')) 79 | B1= '%08x' % int(out[:32],2) 80 | B2= '%08x' % int(out[32:64],2) 81 | if not card.writeblock(1,B1) or not card.writeblock(2,B2): 82 | print 'Write failed!' 83 | os._exit(True) 84 | print 'Done!' 85 | card.select() 86 | print ' Card ID: ' + card.data 87 | card.settagtype(card.ALL) 88 | os._exit(False) 89 | -------------------------------------------------------------------------------- /readlfx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # readlfx.py - read all sectors from a LFX reader 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | # usage: readlfx [KEY] 24 | # 25 | # specifiy KEY for protected tags. If not specified, TRANSPORT key will be tried. 26 | 27 | import rfidiot 28 | import sys 29 | import os 30 | 31 | try: 32 | card= rfidiot.card 33 | except: 34 | print "Couldn't open reader!" 35 | os._exit(True) 36 | 37 | args= rfidiot.args 38 | help= rfidiot.help 39 | 40 | Q5Mod= { '000':'Manchester',\ 41 | '001':'PSK 1',\ 42 | '010':'PSK 2',\ 43 | '011':'PSK 3',\ 44 | '100':'FSK 1 (a = 0)',\ 45 | '101':'FSK 2 (a = 0)',\ 46 | '110':'Biphase',\ 47 | '111':'NRZ / direct'} 48 | 49 | card.info('readlfx v0.1m') 50 | 51 | # force card type if specified 52 | if len(args) > 0: 53 | print 'Setting tag type:', args[0] 54 | card.settagtype(args[0]) 55 | else: 56 | card.settagtype(card.ALL) 57 | card.select() 58 | ID= card.uid 59 | print 'Card ID: ' + ID 60 | print 'Tag type: ' + card.LFXTags[card.tagtype] 61 | 62 | # set key if specified 63 | if len(args) > 1: 64 | key= args[1] 65 | else: 66 | key= '' 67 | 68 | # Login to Hitag2 69 | if card.tagtype == card.HITAG2 and card.readertype == card.READER_ACG: 70 | if not key: 71 | key= card.HITAG2_TRANSPORT_RWD 72 | print ' Logging in with key: ' + key 73 | if not card.login('','',key): 74 | print 'Login failed!' 75 | os._exit(True) 76 | 77 | # Interpret EM4x05 ID structure 78 | if card.tagtype == card.EM4x05: 79 | card.FDXBIDPrint(ID) 80 | 81 | # Q5 cards can emulate other cards, so check if this one responds as Q5 82 | if card.tagtype == card.EM4x02 or card.tagtype == card.Q5 or card.tagtype == card.EM4x05: 83 | print ' Checking for Q5' 84 | card.settagtype(card.Q5) 85 | card.select() 86 | Q5ID= card.uid 87 | if card.tagtype == card.Q5: 88 | print ' Q5 ID: ' + Q5ID 89 | print 90 | card.readblock(0) 91 | print ' Config Block: ', 92 | print card.ToHex(card.binary) 93 | print ' Config Binary: ', 94 | configbin= card.ToBinaryString(card.binary) 95 | print configbin 96 | print ' Reserved: ' + configbin[:12] 97 | print ' Page Select: ' + configbin[12] 98 | print ' Fast Write: ' + configbin[13] 99 | print ' Data Bit Rate n5: ' + configbin[14] 100 | print ' Data Bit Rate n4: ' + configbin[15] 101 | print ' Data Bit Rate n3: ' + configbin[16] 102 | print ' Data Bit Rate n2: ' + configbin[17] 103 | print ' Data Bit Rate n1: ' + configbin[18] 104 | print ' Data Bit Rate n0: ' + configbin[19] 105 | print ' (Field Clocks/Bit: %d)' % (2 * int(configbin[14:20],2) + 2) 106 | print ' Use AOR: ' + configbin[20] 107 | print ' Use PWD: ' + configbin[21] 108 | print ' PSK Carrier Freq: ' + configbin[22] + configbin[23] 109 | print ' Inverse data out: ' + configbin[24] 110 | print ' Modulation: ' + configbin[25] + configbin[26] + configbin[27] + " (%s)" % Q5Mod[configbin[25] + configbin[26] + configbin[27]] 111 | print ' Maxblock: ' + configbin[28] + configbin[29] + configbin[30] + " (%d)" % int (configbin[28] + configbin[29] + configbin[30],2) 112 | print ' Terminator: ' + configbin[31] 113 | print 114 | # Emulated ID is contained in 'traceability data' 115 | print ' Traceability Data 1: ', 116 | card.readblock(1) 117 | td1= card.binary 118 | # to test a hardwired number, uncomment following line (and td2 below) 119 | # td1= chr(0xff) + chr(0x98) + chr(0xa6) + chr(0x4a) 120 | print card.ToHex(td1) 121 | print ' Traceability Data 2: ', 122 | card.readblock(2) 123 | td2= card.binary 124 | # don't forget to set column parity! 125 | # td2= chr(0x98) + chr(0xf8) + chr(0xc8) + chr(0x06) 126 | print card.ToHex(td2) 127 | print ' Traceability Binary: ', 128 | tdbin= card.ToBinaryString(td1 + td2) 129 | print tdbin 130 | # traceability is broken into 4 bit chunks with even parity 131 | print 132 | print ' Header:', 133 | print tdbin[:9] 134 | print ' Parity (even)' 135 | print ' D00-D03: ' + tdbin[9:13] + ' ' + tdbin[13] 136 | print ' D10-D13: ' + tdbin[14:18] + ' ' + tdbin[18] 137 | print ' D20-D23: ' + tdbin[19:23] + ' ' + tdbin[23] 138 | print ' D30-D33: ' + tdbin[24:28] + ' ' + tdbin[28] 139 | print ' D40-D43: ' + tdbin[29:33] + ' ' + tdbin[33] 140 | print ' D50-D53: ' + tdbin[34:38] + ' ' + tdbin[38] 141 | print ' D60-D63: ' + tdbin[39:43] + ' ' + tdbin[43] 142 | print ' D70-D73: ' + tdbin[44:48] + ' ' + tdbin[48] 143 | print ' D80-D83: ' + tdbin[49:53] + ' ' + tdbin[53] 144 | print ' D90-D93: ' + tdbin[54:58] + ' ' + tdbin[58] 145 | print ' ' + tdbin[59:63] + ' ' + tdbin[63] + ' Column Parity & Stop Bit' 146 | # reconstruct data bytes 147 | d0= chr(int(tdbin[9:13] + tdbin[14:18],2)) 148 | d1= chr(int(tdbin[19:23] + tdbin[24:28],2)) 149 | d2= chr(int(tdbin[29:33] + tdbin[34:38],2)) 150 | d3= chr(int(tdbin[39:43] + tdbin[44:48],2)) 151 | d4= chr(int(tdbin[49:53] + tdbin[54:58],2)) 152 | print 153 | print ' Reconstructed data D00-D93 (UNIQUE ID): ', 154 | card.HexPrint(d0 + d1 + d2 + d3 + d4) 155 | # set ID to Q5ID so block reading works 156 | ID= Q5ID 157 | print 158 | else: 159 | print ' Native - UNIQUE ID: ' + card.EMToUnique(ID) 160 | 161 | sector = 0 162 | while sector < card.LFXTagBlocks[card.tagtype]: 163 | print ' sector %02x: ' % sector, 164 | if card.readblock(sector): 165 | print card.data 166 | else: 167 | print 'Read error: ' + card.errorcode 168 | sector += 1 169 | print 170 | 171 | # set reader back to all cards 172 | card.settagtype(card.ALL) 173 | card.select() 174 | print 175 | os._exit(False) 176 | -------------------------------------------------------------------------------- /readmifare1k.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # readmifare1k.py - read all sectors from a mifare standard tag 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | 28 | try: 29 | card= rfidiot.card 30 | except: 31 | print "Couldn't open reader!" 32 | os._exit(True) 33 | 34 | card.info('readmifare1k v0.1j') 35 | card.select() 36 | print 'Card ID: ' + card.uid 37 | 38 | blocksread= 0 39 | blockslocked= 0 40 | lockedblocks= [] 41 | 42 | for type in ['AA', 'BB', 'FF']: 43 | card.select() 44 | if card.login(0,type,''): 45 | if card.readMIFAREblock(0): 46 | card.MIFAREmfb(card.MIFAREdata) 47 | else: 48 | print 'Read error: %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 49 | os._exit(True) 50 | print "\nMIFARE data (keytype %s):" % type 51 | print "\tSerial number:\t\t%s\n\tCheck byte:\t\t%s\n\tManufacturer data:\t%s" % (card.MIFAREserialnumber, card.MIFAREcheckbyte, card.MIFAREmanufacturerdata) 52 | print 53 | 54 | sector = 1 55 | while sector < 16: 56 | locked= True 57 | for type in ['AA', 'BB', 'FF']: 58 | print ' sector %02x: Keytype: %s' % (sector,type), 59 | card.select() 60 | if card.login(sector * 4,type,''): 61 | locked= False 62 | blocksread += 1 63 | print 'Login OK. Data:' 64 | print 65 | print ' ', 66 | for block in range(4): 67 | # card.login(sector,type,'') 68 | if card.readMIFAREblock((sector * 4) + block): 69 | print card.MIFAREdata, 70 | sys.stdout.flush() 71 | else: 72 | print 'Read error: %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 73 | os._exit(True) 74 | print 75 | card.MIFAREkb(card.MIFAREdata) 76 | print " Access Block User Data Byte: " + card.MIFAREaccessconditionsuserbyte 77 | print 78 | print "\tKey A (non-readable):\t%s\n\tKey B:\t\t\t%s\n\tAccess conditions:\t%s" % (card.MIFAREkeyA, card.MIFAREkeyB, card.MIFAREaccessconditions) 79 | print "\t\tMIFAREC1:\t%s\n\t\tMIFAREC2:\t%s\n\t\tMIFAREC3:\t%s" % (hex(card.MIFAREC1)[2:], hex(card.MIFAREC2)[2:], hex(card.MIFAREC3)[2:]) 80 | print "\t\tMIFAREblock0AC: " + card.MIFAREblock0AC 81 | print "\t\t\t" + card.MIFAREACDB[card.MIFAREblock0AC] 82 | print "\t\tMIFAREblock1AC: " + card.MIFAREblock1AC 83 | print "\t\t\t" + card.MIFAREACDB[card.MIFAREblock1AC] 84 | print "\t\tMIFAREblock2AC: " + card.MIFAREblock2AC 85 | print "\t\t\t" + card.MIFAREACDB[card.MIFAREblock2AC] 86 | print "\t\tMIFAREblock3AC: " + card.MIFAREblock3AC 87 | print "\t\t\t" + card.MIFAREACKB[card.MIFAREblock3AC] 88 | print 89 | continue 90 | elif card.errorcode != '': 91 | print 'Login Error: %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 92 | elif type == 'FF': 93 | print 'Login failed' 94 | print '\r', 95 | sys.stdout.flush() 96 | if locked: 97 | blockslocked += 1 98 | lockedblocks.append(sector) 99 | sector += 1 100 | print 101 | print ' Total blocks read: %d' % blocksread 102 | print ' Total blocks locked: %d' % blockslocked 103 | if lockedblocks > 0: 104 | print ' Locked block numbers:', lockedblocks 105 | os._exit(False) 106 | -------------------------------------------------------------------------------- /readmifaresimple.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # readmifaresimple.py - read all sectors from a mifare tag 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | import sys 24 | import os 25 | import rfidiot 26 | import time 27 | import string 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(False) 34 | 35 | args= rfidiot.args 36 | help= rfidiot.help 37 | 38 | blocksread= 0 39 | blockslocked= 0 40 | lockedblocks= [] 41 | DEFAULT_KEY= 'FFFFFFFFFFFF' 42 | KEYS= ['FFFFFFFFFFFF','A0A1A2A3A4A5','B0B1B2B3B4B5','000000000000','ABCDEF012345','4D3A99C351DD','1A982C7E459A','D3F7D3F7D3F7','AABBCCDDEEFF'] 43 | KEYTYPES=['AA','BB','FF'] 44 | DEFAULT_KEYTYPE= 'AA' 45 | BLOCKS_PER_SECT= 4 46 | START_BLOCK= 0 47 | END_BLOCK= 63 48 | CloneData= [] 49 | RESET_DATA= '00000000000000000000000000000000' 50 | RESET_TRAILER= 'FFFFFFFFFFFFFF078069FFFFFFFFFFFF' 51 | 52 | if help or len(args) > 6: 53 | print sys.argv[0] + ' - read mifare tags' 54 | print 'Usage: ' + sys.argv[0] + ' [START BLOCK] [END BLOCK] [KEY] [KEYTYPE] [COPY|RESET]' 55 | print 56 | print '\tRead Mifare sector numbers [START BLOCK] to [END BLOCK], using' 57 | print '\t[KEY] to authenticate. Keys can be truncated to \'AA\' for transport' 58 | print '\tkey \'A0A1A2A3A4A5\', \'BB\' for transport key \'B0B1B2B3B4B5\' or \'FF\'' 59 | print '\tfor transport key \'FFFFFFFFFFFF\'.' 60 | print 61 | print '\tSTART BLOCK defaults to 0 and END BLOCK to 63. If not specified, KEY' 62 | print '\tdefaults to \'FFFFFFFFFFFF\', and KEYTYPE defaults to \'AA\'. All known' 63 | print '\talternative keys are tried in the event of a login failure.' 64 | print 65 | print '\tIf the option \'RESET\' is specified, the card will be programmed to' 66 | print '\tfactory defaults after reading.' 67 | print 68 | print '\tIf the option \'COPY\' is specified, a card will be programmed with' 69 | print '\twith the data blocks read (note that block 0 cannot normally be written)' 70 | print 71 | os._exit(True) 72 | 73 | card.info('readmifaresimple v0.1h') 74 | 75 | if not card.select(): 76 | card.waitfortag('waiting for Mifare TAG...') 77 | 78 | # set options 79 | 80 | reset= False 81 | copy= False 82 | 83 | try: 84 | if args[4] == 'RESET': 85 | reset= True 86 | except: 87 | pass 88 | 89 | try: 90 | if args[4] == 'COPY': 91 | copy= True 92 | except: 93 | pass 94 | 95 | if copy: 96 | try: 97 | otherkey= args[5] 98 | except: 99 | pass 100 | 101 | try: 102 | keytype= string.upper(args[3]) 103 | KEYTYPES.remove(keytype) 104 | trykeytype= [keytype] + KEYTYPES 105 | except: 106 | keytype= DEFAULT_KEYTYPE 107 | trykeytype= KEYTYPES 108 | 109 | try: 110 | key= string.upper(args[2]) 111 | trykey= [key] + KEYS 112 | except: 113 | key= DEFAULT_KEY 114 | trykey= KEYS 115 | 116 | try: 117 | endblock= int(args[1]) 118 | except: 119 | endblock= END_BLOCK 120 | 121 | try: 122 | startblock= int(args[0]) 123 | except: 124 | startblock= 0 125 | 126 | if not reset: 127 | print ' Card ID:', card.uid 128 | print 129 | print ' Reading from %02d to %02d, key %s (%s)\n' % (startblock, endblock, key, keytype) 130 | 131 | # see if key is an abbreviation 132 | # if so, only need to set keytype and login will use transport keys 133 | for d in ['AA','BB','FF']: 134 | if key == d: 135 | keytype= key 136 | key= '' 137 | 138 | if len(key) > 12: 139 | print 'Invalid key: ', key 140 | os._exit(True) 141 | 142 | block= startblock 143 | while block <= endblock and not reset: 144 | locked= True 145 | print ' Block %03i:' % block, 146 | # ACG requires a login only to the base 'sector', so block number must be divided 147 | # by BLOCKS_PER_SECT 148 | if card.readertype == card.READER_ACG: 149 | loginblock= block / BLOCKS_PER_SECT 150 | else: 151 | loginblock= block 152 | loggedin= False 153 | for y in trykey: 154 | if loggedin: 155 | break 156 | for x in trykeytype: 157 | if card.login(loginblock,x,y): 158 | loggedin= True 159 | goodkey= y 160 | goodkeytype= x 161 | break 162 | else: 163 | # clear the error 164 | card.select() 165 | 166 | if loggedin: 167 | print 'OK (%s %s) Data:' % (goodkey,goodkeytype), 168 | locked= False 169 | if card.readMIFAREblock(block): 170 | blocksread += 1 171 | print card.MIFAREdata, 172 | print card.ReadablePrint(card.ToBinary(card.MIFAREdata)) 173 | CloneData += [card.MIFAREdata] 174 | else: 175 | print 'Read error: %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 176 | else: 177 | print 'Login error: %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 178 | locked= True 179 | blockslocked += 1 180 | lockedblocks.append(block) 181 | # ACG requires re-select to clear error condition after failed login 182 | if card.readertype == card.READER_ACG: 183 | card.select() 184 | block += 1 185 | 186 | if not reset: 187 | print 188 | print ' Total blocks read: %d' % blocksread 189 | print ' Total blocks locked: %d' % blockslocked 190 | if blockslocked > 0: 191 | print ' Locked block numbers:', lockedblocks 192 | print 193 | 194 | if not reset and not copy: 195 | os._exit(False) 196 | 197 | raw_input('Place tag to be written and hit to proceed') 198 | 199 | while True: 200 | print 201 | card.select() 202 | print ' Card ID: ' + card.uid 203 | print 204 | if not reset: 205 | if keytype == 'AA': 206 | print ' KeyA will be set to', key + ', KeyB will be set to %s' % otherkey 207 | else: 208 | print ' KeyA will be set to %s,' % otherkey, 'KeyB will be set to', key 209 | else: 210 | print ' KeyA will be set to FFFFFFFFFFFF, KeyB will be set to FFFFFFFFFFFF' 211 | print 212 | x= string.upper(raw_input(' *** Warning! This will overwrite TAG! Proceed (y/n) or to select new TAG? ')) 213 | if x == 'N': 214 | os._exit(False) 215 | if x == 'Y': 216 | print 217 | break 218 | 219 | block= startblock 220 | outblock= 0 221 | while block <= endblock: 222 | # block 0 is not writeable 223 | if block == 0: 224 | block += 1 225 | outblock += 1 226 | continue 227 | print ' Block %03i: ' % block, 228 | # ACG requires a login only to the base 'sector', so block number must be divided 229 | # by BLOCKS_PER_SECT 230 | if card.readertype == card.READER_ACG: 231 | loginblock= block / BLOCKS_PER_SECT 232 | else: 233 | loginblock= block 234 | loggedin= False 235 | if not reset: 236 | # assume we're writing to a factory blank, so try default keys first 237 | trykey= KEYS + [key] 238 | trykeytype= ['AA','BB'] 239 | for y in trykey: 240 | if loggedin: 241 | break 242 | for x in trykeytype: 243 | if card.login(loginblock,x,y): 244 | loggedin= True 245 | goodkey= y 246 | goodkeytype= x 247 | break 248 | else: 249 | # clear the error 250 | card.select() 251 | 252 | if loggedin: 253 | if (block + 1) % 4: 254 | if reset: 255 | blockdata= RESET_DATA 256 | else: 257 | blockdata= CloneData[outblock] 258 | else: 259 | if reset: 260 | blockdata= RESET_TRAILER 261 | else: 262 | if keytype == 'BB': 263 | # only ACL is useful from original data 264 | blockdata= RESET_TRAILER[:12] + CloneData[outblock][12:20] + key 265 | else: 266 | # ACL plus KeyB 267 | blockdata= key + CloneData[outblock][12:20] + otherkey 268 | print 'OK (%s %s), writing: %s' % (goodkey,goodkeytype,blockdata), 269 | if card.writeblock(block,blockdata): 270 | print 'OK' 271 | else: 272 | print 'Write error: %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 273 | else: 274 | print 'Login error: %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 275 | # ACG requires re-select to clear error condition after failed login 276 | if card.readertype == card.READER_ACG: 277 | card.select() 278 | block += 1 279 | outblock += 1 280 | os._exit(False) 281 | -------------------------------------------------------------------------------- /readmifareultra.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # readmifareultra.py - read all sectors from a Ultralight tag 4 | # 5 | # Keith Howell 6 | # built on the code by: 7 | # Adam Laurie 8 | # http://rfidiot.org/ 9 | # 10 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 11 | # For non-commercial use only, the following terms apply - for all other 12 | # uses, please contact the author: 13 | # 14 | # This code is free software; you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation; either version 2 of the License, or 17 | # (at your option) any later version. 18 | # 19 | # This code is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | 25 | 26 | import rfidiot 27 | import sys 28 | import os 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | print "Couldn't open reader!" 34 | os._exit(True) 35 | 36 | help= rfidiot.help 37 | 38 | if help: 39 | print sys.argv[0] + ' - read mifare ultralight tags' 40 | print 'Usage: ' + sys.argv[0] 41 | print 42 | os._exit(True) 43 | 44 | card.info('readmifareultra v0.1b') 45 | card.waitfortag('Waiting for Mifare Ultralight...') 46 | 47 | blocks=16 48 | 49 | print '\n ID: ' + card.uid 50 | print 'Type: ' + card.tagtype 51 | 52 | card.select() 53 | # pull header block information from the tag 54 | if card.readblock(0): 55 | sn0=card.data[0:2] 56 | sn1=card.data[2:4] 57 | sn2=card.data[4:6] 58 | bcc0=card.data[6:8] 59 | else: 60 | print 'read error: %s' % card.errorcode 61 | 62 | if card.readblock(1): 63 | sn3=card.data[0:2] 64 | sn4=card.data[2:4] 65 | sn5=card.data[4:6] 66 | sn6=card.data[6:8] 67 | else: 68 | print 'read error: %s' % card.errorcode 69 | 70 | if card.readblock(2): 71 | bcc1=card.data[0:2] 72 | internal=card.data[2:4] 73 | lock0=card.data[4:6] 74 | lock1=card.data[6:8] 75 | else: 76 | print 'read error: %s' % card.errorcode 77 | 78 | if card.readblock(3): 79 | otp0=card.data[0:2] 80 | otp1=card.data[2:4] 81 | otp2=card.data[4:6] 82 | otp3=card.data[6:8] 83 | else: 84 | print 'read error: %s' % card.errorcode 85 | 86 | # convert lock bytes to binary for later use 87 | lbits0=card.ToBinaryString(card.ToBinary(lock0)) 88 | lbits1=card.ToBinaryString(card.ToBinary(lock1)) 89 | lbits=lbits1 + lbits0 90 | 91 | y=0 92 | plock='' 93 | for x in range(15,-1,-1): 94 | plock = lbits[y:y+1] + plock 95 | y += 1 96 | 97 | # show status of the OTP area on the tag 98 | print 'OTP area is', 99 | if int(plock[3:4]) == 1: 100 | print 'locked and', 101 | else: 102 | print 'unlocked and', 103 | if int(plock[0:1]) == 1: 104 | print 'cannot be changed' 105 | else: 106 | print 'can be changed' 107 | 108 | print 'If locked, blocks 4 through 9', 109 | if int(plock[1:2]) == 1: 110 | print 'cannot be unlocked' 111 | else: 112 | print 'can be unlocked' 113 | 114 | print 'If locked, blocks 0a through 0f', 115 | if int(plock[2:3]) == 1: 116 | print 'cannot be unlocked' 117 | else: 118 | print 'can be unlocked' 119 | 120 | print '\nTag Data:' 121 | # DATA0 byte starts on page/block 4 122 | for x in range(blocks): 123 | print ' Block %02x:' % x, 124 | if card.readblock(x): 125 | print card.data[:8], 126 | print card.ReadablePrint(card.ToBinary(card.data[:8])), 127 | if x > 2: 128 | if int(plock[x:x+1]) == 1: 129 | print ' locked' 130 | else: 131 | print ' unlocked' 132 | else: 133 | print ' -' 134 | else: 135 | print 'read error: %s' % card.errorcode 136 | print 137 | 138 | if x > 0: 139 | os._exit(False) 140 | else: 141 | os._exit(True) 142 | -------------------------------------------------------------------------------- /readtag.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # readtag.py - read all sectors from a standard tag 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | 28 | try: 29 | card= rfidiot.card 30 | except: 31 | print "Couldn't open reader!" 32 | os._exit(True) 33 | 34 | card.info('readtag v0.1f') 35 | card.select() 36 | print '\nID: ' + card.uid 37 | print ' Data:' 38 | 39 | card.select() 40 | for x in range(255): 41 | print ' Block %02x:' % x, 42 | if card.readblock(x): 43 | print card.data, 44 | print card.ReadablePrint(card.ToBinary(card.data)) 45 | else: 46 | print 'read error: %s, %s' % (card.errorcode, card.ISO7816ErrorCodes[card.errorcode]) 47 | 48 | print '\n Total blocks: ', 49 | print x 50 | if x > 0: 51 | os._exit(False) 52 | else: 53 | os._exit(True) 54 | -------------------------------------------------------------------------------- /rfidiot-cli.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # rfidiot-cli.py - CLI for rfidiot 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2012, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | 25 | # 26 | # This program is intended to illustrate RFIDIOt's capabilities. It is deliberately 27 | # written in a style that is easy to understand rather then one that is elegant 28 | # or efficient. Everything is done in longhand so that individual functions can 29 | # be easily understood and extracted. 30 | # 31 | # On the other hand, due to it's completely open structure, it can be a powerful 32 | # tool when commands are combined, and it's easy to create shell scripts that 33 | # perform one-off tasks that are not worth writing an entire program for. 34 | 35 | 36 | import rfidiot 37 | import sys 38 | import time 39 | 40 | args= rfidiot.args 41 | help= rfidiot.help 42 | 43 | if help or len(sys.argv) == 1: 44 | print 45 | print 'Usage: %s [OPTIONS] [ARG(s)] ... [ [ARG(s)] ... ]' % sys.argv[0] 46 | print 47 | print ' Commands:' 48 | print 49 | print ' AID Select ISO 7816 AID' 50 | print ' AIDS List well known AIDs' 51 | print ' APDU Send raw ISO 7816 APDU (use "" for empty elements)' 52 | print ' CHANGE Print message and wait for TAG to change' 53 | print ' DUMP Show data blocks' 54 | print ' FILE <"A|H"> Select ISO 7816 FILE' 55 | print ' HSS High Speed Select TAG. SPEED values are:' 56 | print ' 1 == 106 kBaud' 57 | print ' 2 == 212 kBaud' 58 | print ' 4 == 424 kBaud' 59 | print ' 8 == 848 kBaud' 60 | print ' IDENTIFY Show TAG type' 61 | print ' MF [ ... ] Mifare commands:' 62 | print ' AUTH <"A|B"> Authenticate with KEY A or B (future authentications' 63 | print ' are automated)' 64 | print ' CLONE Duplicate a Mifare TAG (KEY is KEY A of BLANK)' 65 | print ' DUMP Show data blocks' 66 | print ' KEY <"A|B"> Set Mifare KEY A or B' 67 | print ' READ Read data blocks and save as FILE' 68 | print ' WIPE Set Mifare TAG to all 00' 69 | print ' WRITE Write data blocks from FILE (note that KEY A will' 70 | print ' be inserted from previously set value and KEY B' 71 | print ' will also be inserted if set, overriding FILE value)' 72 | print ' PROMPT Print message and wait for Y/N answer (exit if N)' 73 | print ' SCRIPT Read commands from FILE (see script.txt for example)' 74 | print ' SELECT Select TAG' 75 | print ' WAIT Print message and wait for TAG' 76 | print ' WRITEHEX Write HEX data to BLOCK' 77 | print 78 | print ' Commands will be executed sequentially and must be combined as appropriate.' 79 | print ' Block numbers must be specified in HEX.' 80 | print 81 | print ' Examples:' 82 | print 83 | print ' Select TAG, set Mifare KEY A to "FFFFFFFFFFFF" and authenticate against sector 0:' 84 | print 85 | print ' rfidiot-cli.py select mf key a FFFFFFFFFFFF mf auth a 0' 86 | print 87 | print ' Write Mifare data to new TAG, changing Key A to 112233445566 (writing block 0 is allowed to fail):' 88 | print 89 | print ' rfidiot-cli.py select mf key a FFFFFFFFFFFF mf auth a 0 mf key a 112233445566 mf write 0 mifare.dat' 90 | print 91 | print ' Clone a Mifare TAG to a new blank:' 92 | print 93 | print ' rfidiot-cli.py select mf key a 112233445566 mf auth a 0 mf clone FFFFFFFFFFFF' 94 | exit(True) 95 | 96 | try: 97 | card= rfidiot.card 98 | except: 99 | print "Couldn't open reader!" 100 | exit(True) 101 | 102 | print 103 | card.info('rfidiot-cli v0.1') 104 | 105 | # globals 106 | Mifare_Key= None 107 | Mifare_KeyType= None 108 | Mifare_KeyA= None 109 | Mifare_KeyB= None 110 | 111 | # main loop 112 | args.reverse() 113 | while args: 114 | command= args.pop().upper() 115 | if command == 'AID': 116 | arg= args.pop().upper() 117 | if arg == 'ANY' or arg == 'ALL': 118 | aids= card.AIDS.keys() 119 | else: 120 | aids= [arg] 121 | while aids: 122 | aid= aids.pop() 123 | print 124 | print ' Selecting AID: %s' % aid, 125 | try: 126 | print '(%s)' % card.AIDS[aid], 127 | except: 128 | pass 129 | print 130 | print 131 | if card.iso_7816_select_file(aid,card.ISO_7816_SELECT_BY_NAME,'0C'): 132 | print ' OK' 133 | if arg == 'ANY': 134 | break 135 | else: 136 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 137 | continue 138 | if command == 'AIDS': 139 | print 140 | print ' AIDs:' 141 | print 142 | for aid in card.AIDS.iteritems(): 143 | print ' % 24s: %s' % (aid[0], aid[1]) 144 | print 145 | continue 146 | if command == 'APDU': 147 | cla= args.pop().upper() 148 | ins= args.pop().upper() 149 | p1= args.pop().upper() 150 | p2= args.pop().upper() 151 | lc= args.pop().upper() 152 | data= args.pop().upper() 153 | le= args.pop().upper() 154 | print 155 | print ' Sending APDU:', cla+ins+p1+p2+lc+data+le 156 | print 157 | if card.send_apdu('','','','',cla,ins,p1,p2,lc,data,le): 158 | print ' OK' 159 | print ' Data:', card.data 160 | else: 161 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 162 | continue 163 | if command == 'CHANGE': 164 | message= args.pop() 165 | print 166 | current= card.uid 167 | card.waitfortag(message) 168 | while card.uid == current or card.uid == '': 169 | card.waitfortag('') 170 | print 171 | continue 172 | if command == 'DUMP': 173 | start= int(args.pop(),16) 174 | end= int(args.pop(),16) 175 | print 176 | print ' Dumping data blocks %02X to %02X:' % (start, end) 177 | print 178 | sector= start 179 | while sector <= end: 180 | if card.readblock(sector): 181 | print ' %02X: %s %s' % (sector, card.data, card.ReadablePrint(card.data.decode('hex'))) 182 | else: 183 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 184 | sector += 1 185 | continue 186 | if command == 'FILE': 187 | mode= args.pop().upper() 188 | if mode == 'A': 189 | isofile= args.pop().encode('hex') 190 | elif mode == 'H': 191 | isofile= args.pop().upper() 192 | else: 193 | print 'Invalid FILE mode:', args.pop().upper() 194 | exit(True) 195 | print 196 | print ' Selecting ISO File:', isofile 197 | print 198 | if card.iso_7816_select_file(isofile,card.ISO_7816_SELECT_BY_NAME,'00'): 199 | print ' OK' 200 | else: 201 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 202 | continue 203 | if command == 'HSS': 204 | speed= '%02X' % int(args.pop()) 205 | print 206 | print ' High Speed Selecting (%s)' % card.ISO_SPEED[speed] 207 | print 208 | if card.hsselect(speed): 209 | print ' Tag ID: ' + card.uid 210 | else: 211 | if card.errorcode: 212 | print ' '+card.ISO7816ErrorCodes[card.errorcode] 213 | else: 214 | print ' No card present' 215 | continue 216 | if command == 'IDENTIFY': 217 | print 218 | print ' Identiying TAG' 219 | print 220 | if card.select(): 221 | print ' Tag ID:', card.uid, ' Tag Type:', 222 | if (card.readertype == card.READER_ACG and card.readername.find('LFX') == 0): 223 | print card.LFXTags[card.tagtype] 224 | else: 225 | print card.tagtype 226 | if card.readertype == card.READER_PCSC: 227 | if card.tagtype.find('ISO 15693') >= 0: 228 | print 229 | print ' Manufacturer:', 230 | try: 231 | print card.ISO7816Manufacturer[card.uid[2:4]] 232 | except: 233 | print 'Unknown (%s)' % card.uid[2:4] 234 | if not card.readersubtype == card.READER_ACS: 235 | print 236 | card.PCSCPrintATR(card.pcsc_atr) 237 | else: 238 | print ' No card present', 239 | continue 240 | if command == 'MF': 241 | print 242 | mfcommand= args.pop().upper() 243 | if mfcommand == 'AUTH': 244 | keytype= args.pop().upper() 245 | sector= int(args.pop(),16) 246 | print ' Authenticating to sector %02X with Mifare Key' % sector, 247 | Mifare_KeyType= keytype 248 | if keytype == 'A': 249 | Mifare_Key= Mifare_KeyA 250 | print 'A (%s)' % Mifare_Key 251 | elif keytype == 'B': 252 | Mifare_Key= Mifare_KeyB 253 | print 'B (%s)' % Mifare_Key 254 | else: 255 | print 'failed! Invalid keytype:', keytype 256 | exit(True) 257 | print 258 | if card.login(sector, Mifare_KeyType, Mifare_Key): 259 | print ' OK' 260 | else: 261 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 262 | continue 263 | if mfcommand == 'CLONE': 264 | print ' Cloning Mifare TAG', 265 | if not Mifare_KeyA: 266 | print 'failed! KEY A not set!' 267 | exit(True) 268 | if not Mifare_KeyType or not Mifare_Key: 269 | print 'failed! No authentication performed!' 270 | exit(True) 271 | print 272 | print 273 | print ' Key A will be set to:', Mifare_KeyA 274 | print 275 | blank_key= args.pop() 276 | start= 0 277 | end= 0x3F 278 | data= '' 279 | sector= start 280 | print ' Reading...' 281 | while sector <= end: 282 | if card.login(sector, Mifare_KeyType, Mifare_Key) and card.readMIFAREblock(sector): 283 | data += card.MIFAREdata.decode('hex') 284 | else: 285 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 286 | sector += 1 287 | print 288 | print ' OK' 289 | print 290 | # wait for tag to change (same UID is OK) 291 | card.waitfortag(' Replace TAG with TARGET') 292 | while card.select(): 293 | pass 294 | time.sleep(.5) 295 | while not card.select(): 296 | pass 297 | time.sleep(.5) 298 | print 299 | print 300 | print ' Writing...' 301 | sector= start 302 | p= 0 303 | while sector <= end: 304 | block= data[p:p + 16].encode('hex') 305 | if not (sector + 1) % 4: 306 | # trailing block must contain keys, so reconstruct 307 | block= Mifare_KeyA + block[12:] 308 | if not (card.login(sector, 'A', blank_key) and card.writeblock(sector, block)): 309 | if sector == 0: 310 | print ' Sector 0 write failed' 311 | card.select() 312 | else: 313 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 314 | exit(True) 315 | sector += 1 316 | p += 16 317 | print 318 | print ' OK' 319 | continue 320 | if mfcommand == 'DUMP': 321 | start= int(args.pop(),16) 322 | end= int(args.pop(),16) 323 | print ' Dumping data blocks %02X to %02X:' % (start, end), 324 | if not Mifare_KeyType or not Mifare_Key: 325 | print 'failed! No authentication performed!' 326 | exit(True) 327 | print 328 | print 329 | sector= start 330 | while sector <= end: 331 | if card.login(sector, Mifare_KeyType, Mifare_Key) and card.readMIFAREblock(sector): 332 | print ' %02X: %s %s' % (sector, card.MIFAREdata, card.ReadablePrint(card.MIFAREdata.decode('hex'))) 333 | else: 334 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 335 | sector += 1 336 | continue 337 | if mfcommand == 'KEY': 338 | print ' Setting Mifare Key', 339 | keytype= args.pop().upper() 340 | if keytype == 'A': 341 | Mifare_KeyA= args.pop().upper() 342 | print 'A:', Mifare_KeyA 343 | elif keytype == 'B': 344 | Mifare_KeyB= args.pop().upper() 345 | print 'B:', Mifare_KeyB 346 | else: 347 | print 'failed! Invalid keytype:', keytype 348 | exit(True) 349 | continue 350 | if mfcommand == 'READ': 351 | start= int(args.pop(),16) 352 | end= int(args.pop(),16) 353 | filename= args.pop() 354 | print ' Reading data blocks %02X to %02X and saving as %s:' % (start, end, filename), 355 | outfile= open(filename, "wb") 356 | if not outfile: 357 | print "failed! Couldn't open output file!" 358 | exit(True) 359 | if not Mifare_KeyType or not Mifare_Key: 360 | print 'failed! No authentication performed!' 361 | exit(True) 362 | print 363 | print 364 | sector= start 365 | while sector <= end: 366 | if card.login(sector, Mifare_KeyType, Mifare_Key) and card.readMIFAREblock(sector): 367 | outfile.write(card.MIFAREdata.decode('hex')) 368 | else: 369 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 370 | sector += 1 371 | outfile.close() 372 | print ' OK' 373 | continue 374 | if mfcommand == 'WIPE': 375 | print ' Wiping Mifare TAG', 376 | if not Mifare_KeyA: 377 | print 'failed! KEY A not set!' 378 | exit(True) 379 | if not Mifare_KeyB: 380 | print 'failed! KEY B not set!' 381 | exit(True) 382 | if not Mifare_KeyType or not Mifare_Key: 383 | print 'failed! No authentication performed!' 384 | exit(True) 385 | print 386 | print 387 | print ' Key A will be set to:', Mifare_KeyA 388 | print ' Key B will be set to:', Mifare_KeyB 389 | print 390 | start= 1 391 | end= 0x3F 392 | sector= start 393 | perms= 'FF078069' 394 | while sector <= end: 395 | if not (sector + 1) % 4: 396 | # trailing block must contain keys, so reconstruct 397 | block= Mifare_KeyA + perms + Mifare_KeyB 398 | else: 399 | block= '00' * 16 400 | if not (card.login(sector, Mifare_KeyType, Mifare_Key) and card.writeblock(sector, block)): 401 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 402 | exit(True) 403 | sector += 1 404 | print ' OK' 405 | continue 406 | if mfcommand == 'WRITE': 407 | start= int(args.pop(),16) 408 | filename= args.pop() 409 | infile= open(filename,"rb") 410 | data= infile.read() 411 | infile.close() 412 | print ' Writing data from file', filename, 413 | if len(data) % 16: 414 | print 'failed! File length is not divisible by Mifare block length (16)!' 415 | exit(True) 416 | if not Mifare_KeyA: 417 | print 'failed! KEY A not set!' 418 | exit(True) 419 | if not Mifare_KeyType or not Mifare_Key: 420 | print 'failed! No authentication performed!' 421 | exit(True) 422 | end= start + len(data) / 16 - 1 423 | print 'to blocks %02X to %02X' % (start, end) 424 | print 425 | print ' Key A will be set to:', Mifare_KeyA 426 | if Mifare_KeyB: 427 | print ' Key B will be set to:', Mifare_KeyB 428 | else: 429 | print ' Key B will be set as per file' 430 | print 431 | sector= start 432 | p= 0 433 | while sector <= end: 434 | block= data[p:p + 16].encode('hex') 435 | if not (sector + 1) % 4: 436 | # trailing block must contain keys, so reconstruct 437 | if Mifare_KeyB: 438 | block= Mifare_KeyA + block[12:20] + Mifare_KeyB 439 | else: 440 | block= Mifare_KeyA + block[12:] 441 | if not (card.login(sector, Mifare_KeyType, Mifare_Key) and card.writeblock(sector, block)): 442 | if sector == 0: 443 | print ' Sector 0 write failed' 444 | card.select() 445 | else: 446 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 447 | exit(True) 448 | sector += 1 449 | p += 16 450 | print ' OK' 451 | continue 452 | print ' Invalid MF command:', mfcommand 453 | exit(True) 454 | if command == 'PROMPT': 455 | message= args.pop() 456 | print 457 | x= raw_input(message).upper() 458 | if x == 'N': 459 | exit(False) 460 | continue 461 | if command == 'SCRIPT': 462 | filename= args.pop() 463 | infile= open(filename,"rb") 464 | print 465 | print ' Reading commands from', filename 466 | if not infile: 467 | print "failed! Can't open file!" 468 | exit(True) 469 | script= [] 470 | while 42: 471 | line= infile.readline() 472 | if line == '': 473 | break 474 | line= line.strip() 475 | if line == '': 476 | continue 477 | quoted= False 478 | for arg in line.split(' '): 479 | # skip comments 480 | if arg[0] == '#': 481 | break 482 | # quoted sections 483 | if arg[0] == '"' or arg[0] == "'": 484 | quoted= True 485 | quote= '' 486 | arg= arg[1:] 487 | if quoted: 488 | if arg[-1] == '"' or arg[-1] == "'": 489 | quote += ' ' + arg[:-1] 490 | quoted= False 491 | script.append(quote) 492 | else: 493 | quote += ' ' + arg 494 | else: 495 | script.append(arg) 496 | infile.close() 497 | script.reverse() 498 | args += script 499 | continue 500 | if command == 'SELECT': 501 | print 502 | print ' Selecting TAG' 503 | print 504 | if card.select(): 505 | print ' Tag ID: ' + card.uid 506 | if card.readertype == card.READER_PCSC: 507 | print ' ATR: ' + card.pcsc_atr 508 | else: 509 | if card.errorcode: 510 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 511 | else: 512 | print ' No card present' 513 | continue 514 | if command == 'WAIT': 515 | message= args.pop() 516 | print 517 | current= card.uid 518 | card.waitfortag(message) 519 | print 520 | continue 521 | if command == 'WRITEHEX': 522 | block= int(args.pop(),16) 523 | data= args.pop().upper() 524 | print 525 | print ' Writing data %s to block %02x' % (data, block), 526 | if not (card.writeblock(block, data)): 527 | print ' Failed: '+card.ISO7816ErrorCodes[card.errorcode] 528 | exit(True) 529 | print ' OK' 530 | continue 531 | print 532 | print 'Unrecognised command:', command 533 | exit(True) 534 | print 535 | exit(False) 536 | -------------------------------------------------------------------------------- /rfidiot/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # RFIDIOtconfig.py - shared settings for local RFIDIOt 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2006,7,8,9 All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | 24 | import rfidiotglobals 25 | 26 | import RFIDIOt 27 | import getopt 28 | import sys 29 | import os 30 | import string 31 | 32 | # help flag (-h) set? 33 | help= False 34 | 35 | # nogui flag (-g) set? 36 | nogui= False 37 | 38 | # noinit flag (-n) set? 39 | noinit= False 40 | 41 | # options specified in this file can be overridden on the command line, or in static 42 | # files as defined below, in the following order: 43 | # $(RFIDIOtconfig_opts) 44 | # ./RFIDIOtconfig.opts 45 | # /etc/RFIDIOtconfig.opts 46 | # 47 | # options can also be specified in the ENV variable $(RFIDIOtconfig) 48 | # 49 | # note that command line options will take precedence 50 | 51 | # change the following sections to match your serial port 52 | # bluetooth connections need at least 1 second timeout to establish connection 53 | 54 | # serial port (can be overridden with -l) 55 | 56 | # ignored for PCSC 57 | #line= "/dev/ttyS0" 58 | #line= "/dev/ttyS1" 59 | line= "/dev/ttyUSB0" 60 | # for Windows 61 | #line= "COM4" 62 | 63 | # reader type (can be overridden with -R) 64 | #readertype= RFIDIOt.rfidiot.READER_ACG 65 | #readertype= RFIDIOt.rfidiot.READER_FROSCH 66 | #readertype= RFIDIOt.rfidiot.READER_DEMOTAG 67 | # READER_PCSC is a meta type. Actual subtype will be auto-determined. 68 | readertype= RFIDIOt.rfidiot.READER_PCSC 69 | #readertype= RFIDIOt.rfidiot.READER_NONE 70 | #readertype= RFIDIOt.rfidiot.READER_LIBNFC 71 | #readertype= RFIDIOt.rfidiot.READER_ANDROID 72 | 73 | # PCSC reader number (can be overridden with -r) 74 | readernum= 0 75 | 76 | # serial port speed (can be overridden with -s) 77 | # ignored for PCSC 78 | speed= 9600 79 | #speed= 57600 80 | #speed= 115200 81 | #speed= 230400 82 | #speed= 460800 83 | 84 | # reader timeout (can be overriden with -t) 85 | # ignored for PCSC 86 | timeout= 1 87 | 88 | # libnfc reader number (if set to 'None' first available device will be used) 89 | # can be overridden with -f 90 | nfcreader= None 91 | 92 | def printoptions(): 93 | print '\nRFIDIOt Options:\n' 94 | print '\t-d\t\tDebug on' 95 | print '\t-f \tUse LibNFC device number (implies -R READER_LIBNFC)' 96 | print '\t-g\t\tNo GUI' 97 | print '\t-h\t\tPrint detailed help message' 98 | print '\t-n\t\tNo Init - do not initialise hardware' 99 | print '\t-N\t\tList available LibNFC devices' 100 | print '\t-r \tUse PCSC device number (implies -R READER_PCSC)' 101 | print '\t-R \tReader/writer type:' 102 | print '\t\t\t\tREADER_ACG:\tACG Serial' 103 | print '\t\t\t\tREADER_ACS:\tPC/SC Subtype ACS' 104 | print '\t\t\t\tREADER_ANDROID:\tAndroid' 105 | print '\t\t\t\tREADER_DEMOTAG:\tDemoTag' 106 | print '\t\t\t\tREADER_FROSCH:\tFrosch Hitag' 107 | print '\t\t\t\tREADER_LIBNFC:\tlibnfc' 108 | print '\t\t\t\tREADER_NONE:\tNone' 109 | print '\t\t\t\tREADER_OMNIKEY:\tPC/SC Subtype OmniKey' 110 | print '\t\t\t\tREADER_PCSC:\tPC/SC' 111 | print '\t\t\t\tREADER_SCM:\tPC/SC Subtype SCM' 112 | print '\t-l \tLine to use for reader/writer' 113 | print '\t-L\t\tList available PCSC devices' 114 | print '\t-s \tSpeed of reader/writer' 115 | print '\t-t \tTimeout for inactivity of reader/writer' 116 | print 117 | 118 | # check for global overrides in local config files, in the following order: 119 | # $(RFIDIOtconfig_opts) 120 | # ./RFIDIOtconfig.opts 121 | # /etc/RFIDIOtconfig.opts 122 | # note that command line options will take precedence 123 | extraopts= [] 124 | OptsEnv= 'RFIDIOtconfig_opts' 125 | if os.environ.has_key(OptsEnv): 126 | try: 127 | configfile= open(os.environ[OptsEnv]) 128 | extraopts= string.split(configfile.readline()) 129 | except: 130 | print "*** warning: config file set by ENV not found (%s) or empty!" % (os.environ[OptsEnv]) 131 | print "*** not checking for other option files!" 132 | else: 133 | for path in ['.','/etc']: 134 | try: 135 | configfile= open(path + '/RFIDIOtconfig.opts') 136 | extraopts= string.split(configfile.readline()) 137 | break 138 | except: 139 | pass 140 | # check for global override in environment variable 141 | OptsEnv= 'RFIDIOtconfig' 142 | if os.environ.has_key(OptsEnv): 143 | try: 144 | extraopts= string.split(os.environ[OptsEnv]) 145 | except: 146 | print "*** warning: RFIDIOtconfig found in ENV, but no options specified!" 147 | # ignore if commented out 148 | if len(extraopts) > 0: 149 | if extraopts[0][0] == '#': 150 | extraopts= [] 151 | 152 | # 'args' will be set to remaining arguments (if any) 153 | try: 154 | opts, args = getopt.getopt(extraopts + sys.argv[1:],'df:ghnNr:R:l:Ls:t:') 155 | 156 | for o, a in opts: 157 | if o == '-d': 158 | rfidiotglobals.Debug= True 159 | if o == '-f': 160 | nfcreader= int(a) 161 | readertype= RFIDIOt.rfidiot.READER_LIBNFC 162 | if o == '-g': 163 | nogui= True 164 | if o == '-h': 165 | help= True 166 | printoptions() 167 | if o == '-n': 168 | noinit= True 169 | if o == '-N': 170 | readertype= RFIDIOt.rfidiot.READER_LIBNFC 171 | card= RFIDIOt.rfidiot(readernum,readertype,line,speed,timeout,rfidiotglobals.Debug,noinit,nfcreader) 172 | card.libnfc_listreaders() 173 | os._exit(True) 174 | if o == '-r': 175 | readernum= a 176 | readertype= RFIDIOt.rfidiot.READER_PCSC 177 | if o == '-R': 178 | try: 179 | readertype= eval(a) 180 | except: 181 | readertype= eval('RFIDIOt.rfidiot.'+a) 182 | if o == '-l': 183 | line= a 184 | if o == '-L': 185 | readertype= RFIDIOt.rfidiot.READER_PCSC 186 | readernum= 0 187 | card= RFIDIOt.rfidiot(readernum,readertype,line,speed,timeout,rfidiotglobals.Debug,noinit,nfcreader) 188 | card.pcsc_listreaders() 189 | os._exit(True) 190 | if o == '-s': 191 | speed= int(a) 192 | if o == '-t': 193 | timeout= int(a) 194 | card= RFIDIOt.rfidiot(readernum,readertype,line,speed,timeout,rfidiotglobals.Debug,noinit,nfcreader) 195 | except getopt.GetoptError,e: 196 | print "RFIDIOtconfig module ERROR: %s" % e 197 | printoptions() 198 | args= [] 199 | -------------------------------------------------------------------------------- /rfidiot/pn532.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # pn532.py - NXP PN532 definitions for restricted functions 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2009, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | PN532_APDU= { 25 | 'GET_GENERAL_STATUS' : ['d4','04'], 26 | 'GET_PN532_FIRMWARE' : ['d4','02'], 27 | 'IN_ATR' : ['d4','50'], 28 | 'IN_AUTO_POLL' : ['d4','60'], 29 | 'IN_COMMUNICATE_THRU' : ['d4','42'], 30 | 'IN_DATA_EXCHANGE' : ['d4','40'], 31 | 'IN_LIST_PASSIVE_TARGET' : ['d4','4a'], 32 | 'IN_SELECT' : ['d4','54'], 33 | 'TG_GET_DATA' : ['d4','86'], 34 | 'TG_INIT_AS_TARGET' : ['d4','8c'], 35 | 'TG_SET_DATA' : ['d4','8e'], 36 | } 37 | 38 | PN532_FUNCTIONS= { 39 | 0x01 : 'ISO/IEC 14443 Type A', 40 | 0x02 : 'ISO/IEC 14443 Type B', 41 | 0x04 : 'ISO/IEC 18092', 42 | } 43 | 44 | PN532_OK= 'D503' 45 | 46 | PN532_BAUDRATES= { 47 | 0x00 : '106 kbps', 48 | 0x01 : '212 kbps', 49 | 0x02 : '424 kbps', 50 | 0x10 : '212 kbps', 51 | 0x20 : '424 kbps', 52 | } 53 | 54 | PN532_FRAMING= { 55 | 0x00 : 'Mifare', 56 | 0x01 : 'Active mode', 57 | 0x02 : 'FeliCa', 58 | } 59 | 60 | PN532_TARGETS= { 61 | '00' : 'Generic passive 106kbps (ISO/IEC1443-4A,mifare,DEP)', 62 | '10' : 'mifare card', 63 | } 64 | 65 | PN532_MODULATION= { 66 | 0x00 : 'Mifare, ISO/IEC 14443-3 Type A/B, ISO/IEC 18092 passive 106 kbps', 67 | 0x01 : 'ISO/IEC 18092 active', 68 | 0x02 : 'Innovision Jewel', 69 | 0x10 : 'FeliCa, ISO/IEC 18092 passive 212/424 kbps', 70 | } 71 | 72 | PN532_ERRORS= { 73 | 0x00 : 'No Error', 74 | 0x01 : 'Time Out', 75 | 0x02 : 'CRC Error', 76 | 0x03 : 'Parity Error', 77 | 0x04 : 'Erroneous Bit Count during Aticollision/Select (ISO 14443-3/ISO 18092 106kbps)', 78 | 0x05 : 'Mifare Framing Error', 79 | 0x06 : 'Abnormal Bit Collision during Bitwise Anticollision (106 kbps)', 80 | 0x07 : 'Communication Buffer Size Insufficient', 81 | 0x09 : 'RF Buffer Overflow (Register CIU_ERROR BufferOvfl)', 82 | 0x0a : 'Active Communication RF Timeout', 83 | 0x0b : 'RF Protocol Error', 84 | 0x0d : 'Antenna Overheat', 85 | 0x0e : 'Internal Buffer Overflow', 86 | 0x10 : 'Invalid Parameter', 87 | 0x12 : 'DEP protocol - initiator command not supported', 88 | 0x13 : 'DEP protocol - data format out of spec', 89 | 0x14 : 'Mifare authentication error', 90 | 0x23 : 'ISO/IEC 14443-3 UID check byte wrong', 91 | 0x25 : 'DEP protocol - invalid device state', 92 | 0x26 : 'Operation not allowed in this configuration', 93 | 0x27 : 'Command out of context', 94 | 0x29 : 'Target released by Initiator', 95 | 0x2a : 'ID mismatch - card has been exchanged', 96 | 0x2b : 'Activated card missing', 97 | 0x2c : 'NFCID3 mismatch', 98 | 0x2d : 'Over-current event detected', 99 | 0x2e : 'NAD missing in DEP frame', 100 | } 101 | 102 | PN532_RF= { 103 | 0x00 : 'Not present', 104 | 0x01 : 'Present', 105 | } 106 | 107 | # pn532 functions 108 | 109 | # print pn532 firmware details 110 | def pn532_print_firmware(data): 111 | if not data[:4] == PN532_OK: 112 | print ' Bad data from PN532:', data 113 | else: 114 | print ' IC:', data[4:6] 115 | print ' Rev: %d.%d' % (int(data[6:8],16),int(data[8:10])) 116 | print ' Support:', 117 | support= int(data[10:12],16) 118 | spacing= '' 119 | for n in PN532_FUNCTIONS.keys(): 120 | if support & n: 121 | print spacing + PN532_FUNCTIONS[n] 122 | spacing= ' ' 123 | print 124 | 125 | # print pn532 antenna status and return number of tags in field 126 | def pn532_print_status(data): 127 | print ' Reader PN532 Status:' 128 | print ' Last error:', PN532_ERRORS[int(data[4:6])] 129 | print ' External RF:', PN532_RF[int(data[6:8],16)] 130 | tags= int(data[8:10],16) 131 | print ' TAGS present:', tags 132 | for n in range(tags): 133 | print ' Tag number %d:' % (n + 1) 134 | print ' Logical number:', data[10 + n * 2:12 + n * 2] 135 | print ' RX Baudrate:', PN532_BAUDRATES[int(data[12 + n * 2:14 + n * 2],16)] 136 | print ' TX Baudrate:', PN532_BAUDRATES[int(data[14 + n * 2:16 + n * 2],16)] 137 | print ' Modulation:', PN532_MODULATION[int(data[16 + n * 2:18 + n * 2],16)] 138 | print ' SAM Status:', data[18 + n * 2:20 + n * 2] 139 | print 140 | return tags 141 | -------------------------------------------------------------------------------- /rfidiot/pyandroid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # 4 | # pyandroid.py - Python code for working with Android NFC reader 5 | # version 0.1 6 | # Nick von Dadelszen (nick@lateralsecurity.com) 7 | # Lateral Security (www.lateralsecurity.com) 8 | 9 | # 10 | # This code is copyright (c) Lateral Security, 2011, All rights reserved. 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | # 25 | 26 | import binascii 27 | import logging 28 | import time 29 | #import readline 30 | import socket 31 | import rfidiotglobals 32 | 33 | # listening port 34 | PORT = 4444 35 | debug = rfidiotglobals.Debug 36 | 37 | class Android(object): 38 | VERSION = "0.2" 39 | s = None 40 | c = None 41 | 42 | def __init__(self): 43 | if debug: 44 | self.initLog() 45 | if debug: 46 | self.log.debug("pyandroid starting") 47 | self.configure() 48 | 49 | def __del__(self): 50 | self.deconfigure() 51 | 52 | def deconfigure(self): 53 | if debug: 54 | self.log.debug("pyandroid: deconfiguring") 55 | if self.c is not None: 56 | self.c.send("close\n") 57 | 58 | def initLog(self, level=logging.DEBUG): 59 | # def initLog(self, level=logging.INFO): 60 | self.log = logging.getLogger("pyandroid") 61 | self.log.setLevel(level) 62 | sh = logging.StreamHandler() 63 | sh.setLevel(level) 64 | f = logging.Formatter("%(asctime)s: %(levelname)s - %(message)s") 65 | sh.setFormatter(f) 66 | self.log.addHandler(sh) 67 | 68 | def configure(self): 69 | if debug: 70 | self.log.debug("pyandroid: Setting up listening port") 71 | if self.s is not None: 72 | self.s.close() 73 | try: 74 | self.s = socket.socket() # Create a socket object 75 | self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 76 | self.s.bind(("0.0.0.0", PORT)) # Bind to the port 77 | self.s.listen(5) # Listen for connections 78 | except Exception as e: 79 | print 'pyandroid: Could not open port: %s' % PORT 80 | print e 81 | 82 | def reset(self): 83 | if debug: 84 | self.log.debug("pyandroid: Resetting connections") 85 | if self.c is not None: 86 | self.c.send("close\n") 87 | self.c.close() 88 | if self.s is not None: 89 | self.s.close() 90 | self.configure() 91 | 92 | def select(self): 93 | if debug: 94 | self.log.debug("pyandroid in select statement") 95 | print 'Waiting for connection from Android device as PCD on port: %s' % PORT 96 | self.c, addr = self.s.accept() # Establish connection with client. 97 | if debug: 98 | self.log.debug("pyandroid: Got connection from " + addr[0]) 99 | print "Got connection from ", addr 100 | # Get UID 101 | self.c.send('getUID\n') 102 | uid = self.c.recv(1024) 103 | return uid 104 | 105 | def sendAPDU(self, apdu): 106 | if debug: 107 | self.log.debug("Sending APDU: " + apdu) 108 | self.c.send(apdu + '\n') 109 | response = self.c.recv(1024) 110 | response = response[:-1] 111 | 112 | if debug: 113 | self.log.debug('APDU r =' + response) 114 | return response 115 | 116 | def sendResults(self, result): 117 | if debug: 118 | self.log.debug("Sending results: " + results) 119 | self.c.send('r:' + result + '\n') 120 | response = self.c.recv(1024) 121 | response = response[:-1] 122 | 123 | if debug: 124 | self.log.debug('Response r =' + response) 125 | return response 126 | 127 | if __name__ == "__main__": 128 | n = Android() 129 | uid = n.select() 130 | if uid: 131 | print 'UID: ' + uid 132 | print 133 | 134 | cont = True 135 | while cont: 136 | apdu = raw_input("enter the apdu to send now, send \'close\' to finish :") 137 | if apdu == 'close': 138 | cont = False 139 | else: 140 | r = n.sendAPDU(apdu) 141 | print r 142 | 143 | print 'Ending now ...' 144 | n.deconfigure() 145 | -------------------------------------------------------------------------------- /rfidiot/rfidiotglobals.py: -------------------------------------------------------------------------------- 1 | Debug=False 2 | -------------------------------------------------------------------------------- /script.txt: -------------------------------------------------------------------------------- 1 | # 2 | # example script file for rfidiot-cli 3 | # 4 | # commands can be specified one per line: 5 | select 6 | aids 7 | # or combined: 8 | select aids 9 | mf key a 112233445566 mf auth a 0 10 | # commented out: 11 | #mf write 0 mifare.dat 12 | # blank lines are ignored 13 | 14 | mf dump 0 3 15 | prompt 'Remove TAG and continue (Y/N)?' 16 | wait 'Place a TAG on reader...' identify change 'Now provide a different TAG...' identify 17 | select 18 | select # comments are allowed on end of lines 19 | 20 | -------------------------------------------------------------------------------- /send_apdu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # 4 | # send_apdu.py - Python code for Sending raw APDU commands 5 | # version 0.1 6 | # Nick von Dadelszen (nick@lateralsecurity.com) 7 | # Lateral Security (www.lateralsecurity.com) 8 | 9 | # 10 | # This code is copyright (c) Lateral Security, 2011, All rights reserved. 11 | # 12 | # This program is free software: you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation, either version 3 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program. If not, see . 24 | # 25 | 26 | import rfidiot 27 | import sys 28 | import os 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | print "Couldn't open reader!" 34 | os._exit(True) 35 | 36 | card.info('send_apdu v0.1a') 37 | card.select() 38 | print '\nID: ' + card.uid 39 | print ' Data:' 40 | 41 | cont = True 42 | while cont: 43 | apdu = raw_input("enter the apdu to send now, send \'close\' to finish :") 44 | if apdu == 'close': 45 | cont = False 46 | else: 47 | r = card.pcsc_send_apdu(apdu) 48 | print card.data + card.errorcode 49 | 50 | print 'Ending now ...' 51 | 52 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | packages= ['rfidiot'] 4 | 5 | scripts = ['cardselect.py', 'ChAP.py', 'copytag.py', 'demotag.py', 6 | 'eeprom.py', 'fdxbnum.py', 'formatmifare1kvalue.py', 'froschtest.py', 'hidprox.py', 'hitag2brute.py', 7 | 'hitag2reset.py', 'isotype.py', 'jcopmifare.py', 'jcopsetatrhist.py', 'jcoptool.py', 8 | 'lfxtype.py', 'loginall.py', 'mifarekeys.py', 'mrpkey.py', 'multiselect.py', 'pn532emulate.py', 9 | 'pn532mitm.py', 'q5reset.py', 'readlfx.py', 'readmifare1k.py', 10 | 'readmifaresimple.py', 'readmifareultra.py', 'readtag.py', 'rfidiot-cli.py', 'send_apdu.py', 'sod.py', 'transit.py', 11 | 'unique.py', 'writelfx.py', 'writemifare1k.py', 'testacg.sh', 'testlahf.sh' 12 | ] 13 | 14 | setup (name = 'rfidiot', 15 | version = '1.0', 16 | description = "RFID IO tools", 17 | author = 'Adam Laurie', 18 | author_email = 'adam@algroup.co.uk', 19 | packages= packages, 20 | scripts = scripts 21 | ) 22 | 23 | -------------------------------------------------------------------------------- /sod.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | # sod.py - try to find X509 data in EF.SOD 5 | # 6 | # Adam Laurie 7 | # http://rfidiot.org/ 8 | # 9 | # This code is copyright (c) Adam Laurie, 2007, All rights reserved. 10 | # For non-commercial use only, the following terms apply - for all other 11 | # uses, please contact the author: 12 | # 13 | # This code is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation; either version 2 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # This code is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | import commands 24 | import sys 25 | import os 26 | 27 | x= 0 28 | if len(sys.argv) > 1: 29 | sod= open(sys.argv[1],"r") 30 | else: 31 | sod= open("/tmp/EF_SOD.BIN","r") 32 | data= sod.read() 33 | while x < len(data): 34 | out= open("/tmp/SOD","w") 35 | out.write(data[x:]) 36 | out.flush() 37 | out.close() 38 | (exitstatus, outtext) = commands.getstatusoutput("openssl pkcs7 -text -print_certs -in /tmp/SOD -inform DER") 39 | if not exitstatus and len(outtext) > 0: 40 | print 'PKCS7 certificate found at offset %d:' % x 41 | print 42 | print outtext 43 | os._exit(False) 44 | x += 1 45 | os._exit(True) 46 | -------------------------------------------------------------------------------- /test.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AdamLaurie/RFIDIOt/88f2ef9f8e02d0b1e4a03fcd5aa52e3c6ab0dc73/test.txt -------------------------------------------------------------------------------- /testacg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | xterm -T 'ACG port /dev/ttyUSB0' -e python ./multiselect.py -s 9600 -l /dev/ttyUSB0 -R RFIDIOt.rfidiot.READER_ACG & 4 | -------------------------------------------------------------------------------- /testfrosch-serial.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | xterm -T 'Frosch port /dev/ttyS0' -e python ./multiselect.py -s 9600 -l /dev/ttyS0 -R RFIDIOt.rfidiot.READER_FROSCH & 4 | -------------------------------------------------------------------------------- /testfrosch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | xterm -T 'Frosch port /dev/ttyUSB0' -e python ./multiselect.py -s 9600 -l /dev/ttyUSB0 -R RFIDIOt.rfidiot.READER_FROSCH & 4 | -------------------------------------------------------------------------------- /testlahf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | xterm -T 'LAHF port /dev/ttyUSB0' -e python ./multiselect.py -s 9600 -l /dev/ttyUSB0 -R RFIDIOt.rfidiot.READER_ACG & 4 | xterm -T 'LAHF port /dev/ttyUSB1' -e python ./multiselect.py -s 9600 -l /dev/ttyUSB1 -R RFIDIOt.rfidiot.READER_ACG & 5 | -------------------------------------------------------------------------------- /transit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # transit.py - generate / decode FDI Matalec Transit 500 and Transit 999 UIDs 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2009, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import os 27 | import string 28 | 29 | try: 30 | card= rfidiot.card 31 | except: 32 | print "Couldn't open reader!" 33 | os._exit(True) 34 | 35 | args= rfidiot.args 36 | help= rfidiot.help 37 | 38 | card.info('transit v0.1b') 39 | 40 | precoded= False 41 | 42 | if not help and len(args) > 0 and len(args[0]) == 64: 43 | print "\nDecode: ", 44 | card.TRANSITIDPrint(args[0]) 45 | if len(args) == 2: 46 | if args[1] == 'WRITE': 47 | precoded= True 48 | else: 49 | print 'Unrecognised option: ' + args[1] 50 | os._exit(True) 51 | else: 52 | print 53 | os._exit(False) 54 | 55 | if not help and ((len(args) > 0 and len(args[0]) == 8) or precoded): 56 | if precoded: 57 | out= args[0] 58 | else: 59 | print "\nEncode: ", 60 | out= card.TRANSITIDEncode(args[0]) 61 | print out 62 | if (len(args) == 2 and args[1] == 'WRITE') or precoded: 63 | while True: 64 | # Q5 must be forced into Q5 mode to be sure of detection so try that first 65 | if card.readertype == card.READER_ACG: 66 | card.settagtype(card.Q5) 67 | card.select() 68 | if card.readertype == card.READER_ACG: 69 | if not card.tagtype == card.Q5: 70 | card.settagtype(card.ALL) 71 | card.waitfortag('Waiting for blank tag...') 72 | print ' Tag ID: ' + card.data 73 | if card.tagtype == card.Q5: 74 | x= string.upper(raw_input(' *** Warning! This will overwrite TAG! Proceed (y/n)? ')) 75 | if x == 'N': 76 | os._exit(False) 77 | if x == 'Y': 78 | break 79 | else: 80 | x= raw_input(' Incompatible TAG! Hit to retry...') 81 | writetag= True 82 | print 83 | else: 84 | writetag= False 85 | # now turn it all back to 4 byte hex blocks for writing 86 | outbin= '' 87 | outhex= ['','','','',''] 88 | # control block for Q5: 89 | # carrier 32 (2 * 15 + 2) 90 | # rf/? (don't care) - set to 00 91 | # data not inverted 92 | # manchester 93 | # maxblock 2 94 | print ' Q5 Control Block: ', 95 | q5control= '6000F004' 96 | print q5control 97 | for x in range(0,len(out),8): 98 | outbin += chr(int(out[x:x + 8],2)) 99 | for x in range(0,len(outbin),4): 100 | print ' Q5 Data Block %02d:' % (x / 4 + 1), 101 | outhex[x / 4 + 1]= card.ToHex(outbin[x:x+4]) 102 | print outhex[x / 4 + 1] 103 | if writetag == True: 104 | print 105 | outhex[0]= q5control 106 | for x in range(2,-1,-1): 107 | if(x != 0): 108 | print " Writing block %02x:" % x, 109 | if not card.writeblock(x,outhex[x]): 110 | # we expect a Q5 to fail after writing the control block as it re-reads 111 | # it before trying to verify the write and switches mode so is now no longer in Q5 mode 112 | if x == 0: 113 | print ' Control: ' + outhex[x] 114 | print 115 | print ' Done!' 116 | else: 117 | print 'Write failed!' 118 | os._exit(True) 119 | else: 120 | print outhex[x] 121 | if card.readertype == card.READER_ACG: 122 | card.settagtype(card.ALL) 123 | print 124 | os._exit(False) 125 | print 126 | print sys.argv[0] + ' - Q5 encode / decode TRANSIT compliant IDs' 127 | print '\nUsage: ' + sys.argv[0] + ' [OPTIONS] [WRITE]' 128 | print 129 | print '\tIf a single 64 Bit BINARY UID is provided, it will be decoded according to the TRANSIT standard.' 130 | print '\tAlternatively, specifying a 8 HEX digit UID will encode the 64 Bit BINARY with LRC and sentinels.' 131 | print 132 | print '\tIf the WRITE option is specified, a Q5 will be programmed to emulate a TRANSIT tag.' 133 | print 134 | os._exit(True) 135 | -------------------------------------------------------------------------------- /unique.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # unique.py - generate EM4x02 and/or UNIQUE compliant IDs 4 | # these can then be written to a Q5 tag to emulate EM4x02 5 | # by transmitting data blocks 1 & 2 (MAXBLOCK == 2), 6 | # or Hitag2 in Public Mode A with data stored in blocks 7 | # 4 and 5. 8 | # 9 | # Adam Laurie 10 | # http://rfidiot.org/ 11 | # 12 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 13 | # For non-commercial use only, the following terms apply - for all other 14 | # uses, please contact the author: 15 | # 16 | # This code is free software; you can redistribute it and/or modify 17 | # it under the terms of the GNU General Public License as published by 18 | # the Free Software Foundation; either version 2 of the License, or 19 | # (at your option) any later version. 20 | # 21 | # This code is distributed in the hope that it will be useful, 22 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | # GNU General Public License for more details. 25 | # 26 | 27 | 28 | import rfidiot 29 | import sys 30 | import os 31 | import string 32 | import time 33 | 34 | try: 35 | card= rfidiot.card 36 | except: 37 | print "Couldn't open reader!" 38 | os._exit(True) 39 | 40 | args= rfidiot.args 41 | help= rfidiot.help 42 | 43 | card.info('unique v0.1l') 44 | 45 | # Q5 config block 46 | Q5CFB='e601f004' 47 | # Hitag2 config block 48 | H2CFB= card.HITAG2_PUBLIC_A + card.HITAG2_TRANSPORT_TAG 49 | 50 | if len(args) < 1 or len(args) > 3 or help: 51 | print 52 | print sys.argv[0] + ' - generate EM4x02 and/or UNIQUE compliant ID data blocks' 53 | print '\nUsage: ' + sys.argv[0] + ' [OPTIONS] [\"WRITE\"]' 54 | print ' ' + sys.argv[0] + ' [OPTIONS] <\"CLONE\">' 55 | print 56 | print '\t10 digit HEX ID will be translated to valid data for blocks 1 & 2' 57 | print '\tfor a Q5 tag running in EM4x02 emulation mode, and blocks 4 & 5 for' 58 | print '\ta Hitag2, where TYPE is U for UNIQUE code and E for EM4x02. For ' 59 | print '\tguidance, standard emulation control blocks (0 & 3 respectively)' 60 | print '\twill also be displayed.' 61 | print 62 | print '\tIf the optional WRITE argument is specified, programming a Q5 or' 63 | print '\tHitag2 tag will be initiated.' 64 | print 65 | print '\tIf the single word CLONE is specified, the reader will scan for' 66 | print '\ta Unique tag and then wait for a suitable blank to be presented' 67 | print '\tfor writing. No prompting will take place before the target is' 68 | print '\toverwritten.' 69 | os._exit(True) 70 | 71 | 72 | if len(args) == 1 and string.upper(args[0]) == "CLONE": 73 | type= 'UNIQUE' 74 | clone= True 75 | card.settagtype(card.EM4x02) 76 | card.waitfortag('Waiting for Unique tag...') 77 | id= card.uid 78 | idbin= card.UniqueToEM(card.HexReverse(id)) 79 | else: 80 | clone= False 81 | if len(args[1]) != 10: 82 | print 'ID must be 10 HEX digits!' 83 | os._exit(True) 84 | id= args[1] 85 | 86 | if args[0] == 'E': 87 | type= 'EM4x02' 88 | idbin= card.UniqueToEM(card.HexReverse(id)) 89 | else: 90 | if args[0] == 'U': 91 | type= 'UNIQUE' 92 | idbin= card.ToBinaryString(card.ToBinary(id)) 93 | else: 94 | if not clone: 95 | print 'Unknown TYPE: ' + args[0] 96 | os._exit(True) 97 | 98 | 99 | out= card.Unique64Bit(idbin) 100 | manchester= card.BinaryToManchester(out) 101 | db1= '%08x' % int(out[:32],2) 102 | db2= '%08x' % int(out[32:64],2) 103 | print 104 | print ' ' + type + ' ID: ' + id 105 | print ' Q5 ID: ' + '%08x' % int(idbin[:32],2) 106 | if type == 'EM4x02': 107 | print ' UNIQUE ID: ' + '%10x' % int(idbin,2) 108 | else: 109 | print ' EM4x02 ID: ' + ('%10x' % int(card.UniqueToEM(id),2))[::-1] 110 | print ' Binary traceablility data: ' + out 111 | print ' Manchester Encoded: ' + manchester 112 | print 113 | print ' Q5 Config Block (0): ' + Q5CFB 114 | print ' Data Block 1: ' + db1 115 | print ' Data Block 2: ' + db2 116 | print 117 | print ' Hitag2 Config Block (3): ' + H2CFB 118 | print ' Data Block 4: ' + db1 119 | print ' Data Block 5: ' + db2 120 | 121 | if (len(args) == 3 and string.upper(args[2]) == 'WRITE') or clone: 122 | # check for Q5 first` 123 | if card.readertype == card.READER_ACG: 124 | card.settagtype(card.Q5) 125 | if not card.select(): 126 | card.settagtype(card.ALL) 127 | while not (card.tagtype == card.Q5 or card.tagtype == card.HITAG2): 128 | card.waitfortag('Waiting for blank tag (Q5 or Hitag2)...') 129 | print 'Tag ID: ' + card.uid 130 | if not clone: 131 | x= string.upper(raw_input(' *** Warning! This will overwrite TAG! Proceed (y/n)? ')) 132 | if x != 'Y': 133 | os._exit(False) 134 | # allow blank to settle 135 | time.sleep(2) 136 | print 'Writing...' 137 | if card.tagtype == card.Q5: 138 | if not card.writeblock(0,Q5CFB) or not card.writeblock(1,db1) or not card.writeblock(2,db2): 139 | print 'Write failed!' 140 | os._exit(True) 141 | if card.tagtype == card.HITAG2: 142 | if card.readertype == card.READER_ACG: 143 | card.login('','',card.HITAG2_TRANSPORT_RWD) 144 | if not card.writeblock(3,H2CFB) or not card.writeblock(4,db1) or not card.writeblock(5,db2): 145 | print 'Write failed!' 146 | os._exit(True) 147 | card.settagtype(card.EM4x02) 148 | card.select() 149 | print 'Card ID: ' + card.uid 150 | print ' Unique ID: ' + card.EMToUnique(card.uid) 151 | print 'Done!' 152 | card.settagtype(card.ALL) 153 | os._exit(False) 154 | -------------------------------------------------------------------------------- /upload2cosmo.gpsh: -------------------------------------------------------------------------------- 1 | // script to install epassport.cap to cosmo card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | establish_context 4 | // edit the following line to match your PCSC reader 5 | //card_connect -readerNumber 2 6 | card_connect -reader "OMNIKEY CardMan 5x21 00 01" 7 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 8 | //card_connect -reader "ACS ACR 38U-CCID 00 00" 9 | select -AID A0000001510000 10 | open_sc -security 3 -mac_key 404142434445464748494A4B4C4D4E4F -enc_key 404142434445464748494A4B4C4D4E4F -kek_key 404142434445464748494A4B4C4D4E4F // Open secure channel 11 | delete -AID A00000024710 12 | install -file epassport.cap -priv 2 13 | card_disconnect 14 | release_context 15 | -------------------------------------------------------------------------------- /upload2jcop.gpsh: -------------------------------------------------------------------------------- 1 | // script to install epassport.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | establish_context 4 | // edit the following line to match your PCSC reader 5 | //card_connect -readerNumber 2 6 | //card_connect -reader "OMNIKEY CardMan 5x21 00 01" 7 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 8 | card_connect 9 | //card_connect -reader "ACS ACR 38U-CCID 00 00" 10 | select -AID A000000003000000 11 | open_sc -security 3 -mac_key 404142434445464748494A4B4C4D4E4F -enc_key 404142434445464748494A4B4C4D4E4F -kek_key 404142434445464748494A4B4C4D4E4F // Open secure channel 12 | delete -AID A00000024710 13 | install -file epassport.cap -priv 2 14 | card_disconnect 15 | release_context 16 | -------------------------------------------------------------------------------- /upload2nokia.gpsh: -------------------------------------------------------------------------------- 1 | // script to install epassport.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | // note that the secure element must be unlocked, see the Nokia website at 3 | // http://www.forum.nokia.com/info/sw.nokia.com/id/a796065d-fa6a-449f-b3de-70d46ff99f19/NFC_Unlock.zip.html 4 | mode_211 5 | establish_context 6 | // edit the following line to match your PCSC reader 7 | //card_connect -readerNumber 3 8 | //card_connect -reader "OMNIKEY CardMan 5x21 00 01" 9 | card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 10 | select -AID A000000003000000 11 | open_sc -security 3 -keyver 42 -mac_key 404142434445464748494a4b4c4d4e4f -enc_key 404142434445464748494a4b4c4d4e4f -kek_key 404142434445464748494a4b4c4d4e4f 12 | delete -AID A00000024710 13 | install -file epassport.cap -priv 2 14 | card_disconnect 15 | release_context 16 | -------------------------------------------------------------------------------- /upload2smartcafe.gpsh: -------------------------------------------------------------------------------- 1 | // script to install epassport.cap to jcop card using gpshell (http://sourceforge.net/projects/globalplatform/) 2 | mode_211 3 | establish_context 4 | // edit the following line to match your PCSC reader 5 | //card_connect -readerNumber 2 6 | //card_connect -reader "OMNIKEY CardMan 5x21 (USB iClass Reader) 00 01" 7 | card_connect 8 | select -AID A000000003000000 9 | open_sc -scp 2 -scpimpl 0x15 -security 1 -keyind 0 -keyver 0 -keyDerivation emvcps11 -key 404142434445464748494A4B4C4D4E4F 10 | delete -AID A00000024710 11 | install -file epassport.cap -priv 2 12 | card_disconnect 13 | release_context 14 | -------------------------------------------------------------------------------- /writelfx.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # writelfx.py - read and then write all sectors from a LFX reader 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2009, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | import rfidiot 24 | import sys 25 | import os 26 | 27 | try: 28 | card= rfidiot.card 29 | except: 30 | print "Couldn't open reader!" 31 | os._exit(True) 32 | 33 | args= rfidiot.args 34 | help= rfidiot.help 35 | 36 | Q5Mod= { '000':'Manchester',\ 37 | '001':'PSK 1',\ 38 | '010':'PSK 2',\ 39 | '011':'PSK 3',\ 40 | '100':'FSK 1 (a = 0)',\ 41 | '101':'FSK 2 (a = 0)',\ 42 | '110':'Biphase',\ 43 | '111':'NRZ / direct'} 44 | 45 | card.info('writelfx v0.1c') 46 | 47 | # force card type if specified 48 | if len(args) > 0: 49 | print 'Setting tag type:', args[0] 50 | card.settagtype(args[0]) 51 | else: 52 | card.settagtype(card.ALL) 53 | card.select() 54 | ID= card.uid 55 | print 'Card ID: ' + ID 56 | print 'Tag type: ' + card.LFXTags[card.tagtype] 57 | 58 | # set key if specified 59 | if len(args) > 1: 60 | key= args[1] 61 | else: 62 | key= '' 63 | 64 | # Login to Hitag2 65 | if card.tagtype == card.HITAG2 and card.readertype == card.READER_ACG: 66 | if not key: 67 | key= card.HITAG2_TRANSPORT_RWD 68 | print ' Logging in with key: ' + key 69 | if not card.login('','',key): 70 | print 'Login failed!' 71 | os._exit(True) 72 | 73 | # Interpret EM4x05 ID structure 74 | if card.tagtype == card.EM4x05: 75 | card.FDXBIDPrint(ID) 76 | 77 | # Q5 cards can emulate other cards, so check if this one responds as Q5 78 | if card.tagtype == card.EM4x02 or card.tagtype == card.Q5 or card.tagtype == card.EM4x05: 79 | print ' Checking for Q5' 80 | card.settagtype(card.Q5) 81 | card.select() 82 | Q5ID= card.uid 83 | if card.tagtype == card.Q5: 84 | print ' Q5 ID: ' + Q5ID 85 | print 86 | card.readblock(0) 87 | print ' Config Block: ', 88 | print card.ToHex(card.binary) 89 | print ' Config Binary: ', 90 | configbin= card.ToBinaryString(card.binary) 91 | print configbin 92 | print ' Reserved: ' + configbin[:12] 93 | print ' Page Select: ' + configbin[12] 94 | print ' Fast Write: ' + configbin[13] 95 | print ' Data Bit Rate n5: ' + configbin[14] 96 | print ' Data Bit Rate n4: ' + configbin[15] 97 | print ' Data Bit Rate n3: ' + configbin[16] 98 | print ' Data Bit Rate n2: ' + configbin[17] 99 | print ' Data Bit Rate n1: ' + configbin[18] 100 | print ' Data Bit Rate n0: ' + configbin[19] 101 | print ' (Field Clocks/Bit: %d)' % (2 * int(configbin[14:20],2) + 2) 102 | print ' Use AOR: ' + configbin[20] 103 | print ' Use PWD: ' + configbin[21] 104 | print ' PSK Carrier Freq: ' + configbin[22] + configbin[23] 105 | print ' Inverse data out: ' + configbin[24] 106 | print ' Modulation: ' + configbin[25] + configbin[26] + configbin[27] + " (%s)" % Q5Mod[configbin[25] + configbin[26] + configbin[27]] 107 | print ' Maxblock: ' + configbin[28] + configbin[29] + configbin[30] + " (%d)" % int (configbin[28] + configbin[29] + configbin[30],2) 108 | print ' Terminator: ' + configbin[31] 109 | print 110 | # Emulated ID is contained in 'traceability data' 111 | print ' Traceability Data 1: ', 112 | card.readblock(1) 113 | td1= card.binary 114 | # to test a hardwired number, uncomment following line (and td2 below) 115 | # td1= chr(0xff) + chr(0x98) + chr(0xa6) + chr(0x4a) 116 | print card.ToHex(td1) 117 | print ' Traceability Data 2: ', 118 | card.readblock(2) 119 | td2= card.binary 120 | # don't forget to set column parity! 121 | # td2= chr(0x98) + chr(0xf8) + chr(0xc8) + chr(0x06) 122 | print card.ToHex(td2) 123 | print ' Traceability Binary: ', 124 | tdbin= card.ToBinaryString(td1 + td2) 125 | print tdbin 126 | # traceability is broken into 4 bit chunks with even parity 127 | print 128 | print ' Header:', 129 | print tdbin[:9] 130 | print ' Parity (even)' 131 | print ' D00-D03: ' + tdbin[9:13] + ' ' + tdbin[13] 132 | print ' D10-D13: ' + tdbin[14:18] + ' ' + tdbin[18] 133 | print ' D20-D23: ' + tdbin[19:23] + ' ' + tdbin[23] 134 | print ' D30-D33: ' + tdbin[24:28] + ' ' + tdbin[28] 135 | print ' D40-D43: ' + tdbin[29:33] + ' ' + tdbin[33] 136 | print ' D50-D53: ' + tdbin[34:38] + ' ' + tdbin[38] 137 | print ' D60-D63: ' + tdbin[39:43] + ' ' + tdbin[43] 138 | print ' D70-D73: ' + tdbin[44:48] + ' ' + tdbin[48] 139 | print ' D80-D83: ' + tdbin[49:53] + ' ' + tdbin[53] 140 | print ' D90-D93: ' + tdbin[54:58] + ' ' + tdbin[58] 141 | print ' ' + tdbin[59:63] + ' ' + tdbin[63] + ' Column Parity & Stop Bit' 142 | # reconstruct data bytes 143 | d0= chr(int(tdbin[9:13] + tdbin[14:18],2)) 144 | d1= chr(int(tdbin[19:23] + tdbin[24:28],2)) 145 | d2= chr(int(tdbin[29:33] + tdbin[34:38],2)) 146 | d3= chr(int(tdbin[39:43] + tdbin[44:48],2)) 147 | d4= chr(int(tdbin[49:53] + tdbin[54:58],2)) 148 | print 149 | print ' Reconstructed data D00-D93 (UNIQUE ID): ', 150 | card.HexPrint(d0 + d1 + d2 + d3 + d4) 151 | # set ID to Q5ID so block reading works 152 | ID= Q5ID 153 | print 154 | else: 155 | print ' Native - UNIQUE ID: ' + card.EMToUnique(ID) 156 | 157 | sector = 0 158 | print 159 | print ' Writing...' 160 | print 161 | while sector < card.LFXTagBlocks[card.tagtype]: 162 | print ' sector %02x: ' % sector, 163 | if card.readblock(sector): 164 | print card.data, 165 | if not card.writeblock(sector,card.data): 166 | print 'Write failed' 167 | else: 168 | print 'OK' 169 | else: 170 | print 'Read error: ' + card.errorcode 171 | sector += 1 172 | print 173 | 174 | # set reader back to all cards 175 | card.settagtype(card.ALL) 176 | card.select() 177 | print 178 | os._exit(False) 179 | 180 | -------------------------------------------------------------------------------- /writemifare1k.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # writemifare1k.py - write all blocks on a mifare standard tag 4 | # 5 | # Adam Laurie 6 | # http://rfidiot.org/ 7 | # 8 | # This code is copyright (c) Adam Laurie, 2006, All rights reserved. 9 | # For non-commercial use only, the following terms apply - for all other 10 | # uses, please contact the author: 11 | # 12 | # This code is free software; you can redistribute it and/or modify 13 | # it under the terms of the GNU General Public License as published by 14 | # the Free Software Foundation; either version 2 of the License, or 15 | # (at your option) any later version. 16 | # 17 | # This code is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | 23 | 24 | import rfidiot 25 | import sys 26 | import random 27 | import string 28 | import os 29 | 30 | try: 31 | card= rfidiot.card 32 | except: 33 | print "Couldn't open reader!" 34 | os._exit(True) 35 | 36 | args= rfidiot.args 37 | help= rfidiot.help 38 | 39 | card.info('writemifare1k v0.1f') 40 | card.select() 41 | print 'Card ID: ' + card.uid 42 | while True: 43 | x= string.upper(raw_input('\n*** Warning! This will overwrite all data blocks! Proceed (y/n)? ')) 44 | if x == 'N': 45 | os._exit(False) 46 | if x == 'Y': 47 | break 48 | 49 | sector = 1 50 | while sector < 0x10: 51 | for type in ['AA', 'BB', 'FF']: 52 | card.select() 53 | print ' sector %02x: Keytype: %s' % (sector, type), 54 | if card.login(sector,type,'FFFFFFFFFFFF'): 55 | for block in range(3): 56 | print '\n block %02x: ' % ((sector * 4) + block), 57 | if len(args) == 1: 58 | data= args[0] 59 | else: 60 | data = '%032x' % random.getrandbits(128) 61 | print 'Data: ' + data, 62 | if card.writeblock((sector * 4) + block,data): 63 | print ' OK' 64 | elif card.errorcode: 65 | print 'error %s %s' % (card.errorcode , card.ISO7816ErrorCodes[card.errorcode]) 66 | elif type == 'FF': 67 | print 'login failed' 68 | print '\r', 69 | sys.stdout.flush() 70 | sector += 1 71 | print 72 | print 73 | os._exit(False) 74 | --------------------------------------------------------------------------------