Decoding employee RFID tags, let the fun commence


Plant Engineering wanted to include RFID scanners on new equipment but no one had looked at the feasibility of doing this so I saw a small chance for a side project and a play with Python.

All employee passes are embedded with RFID and this is used for clocking in and also door access across the sites. Using a relatively cheap ID-12SLA RFID reader and a python script i was able to not only read the hex string contained in the card but also decode the unique number which is printed on the card.

The string looked similar to the following;

02000F7F4DBB86

After scanning a few cards it became apparent that the hex string length was not consistent, older cards had a longer string but the it was still the last five characters which were unique for each card. This meant it was easy to strip using python's string handling

strlgth = len (code)
EmployeeHEX = code[(strlgth - 5):strlgth]
print strlgth, EmployeeHEX

However to decode the unique number it wasnt quite so simple, it is a multi-part process and whilst the last five characters are unique we are only interested in three of them eg 02000F7F4 DBB 86 it is the DBB that is critical so now we have the last five end digits stored in EmployeeHEX we can obtain just the three we are interested but we need to split them so they can be handled separately.

decodeONE = EmployeeHEX[0:1]
decodeTWO = EmployeeHEX[1:3]

So here we load decodeONE with the letter D and decodeTWO with the letters BB

The reason for the separation of three characters took me a whilst to figure out because initially i applied a straight forward hex translation which did not work but once done it was easy to write the decode routine, first we'll look at the letter D

decodeONE = ord (decodeONE) - ord (\"A\") + 1

What we are doing above is finding out what numerical position the letter is within the alphabet with the starting number of 1 being the letter A so for the hex string I'm working with D is obviously number four.

Next we have to recombine the number with the original hex

EmployeeID = (\"%d%s\") % (decodeONE,decodeTWO)

Here we end up with EmployeeID as 4BB

Finally we can convert this new hex string into decimal;

EmployeeID = int(EmployeeID,16)

The resulting decimal value is 1211 which is equal to the number printed on the card, so you can see it was not simply a hex to dec conversion but one which involved a few more jumps. Now that everything is decoding correctly and numbers match it was time to combine the elements and build a simple program. The whole read/decode program is 27 lines long and that's after the code has been formatted for readability, i'm positive a quicker, shorter code method is possible but as i come from a maintenance background … if it works leave it :)

#
# note originally written for python2
#
import serial
serial = serial.Serial('/dev/ttyUSB0', baudrate=9600)
print ('-- starting --')
code=''
while True:
        data = serial.read().decode('utf-8')
        if data == '\r':
                print('RFID CODE:',code)
                strlgth = len(code)
                EmployeeHEX = code[(strlgth - 5):strlgth]
                print (strlgth, EmployeeHEX)
                decodeONE = EmployeeHEX[0:1]
                decodeTWO = EmployeeHEX[1:3]
                decodeONE = ord (decodeONE) - ord ('A') + 1
                print ('1st character: %s ' % decodeONE)
                print ('2nd character: %s ' % decodeTWO)
                EmployeeID = ('%d%s') % (decodeONE,decodeTWO)
                EmployeeID = int(EmployeeID,16)
                print ('Employee ID: %s ' % EmployeeID)
                code = EmployeeID = EmployeeHEX = decodeONE = decodeTWO = ';'
        else:
                code = code + data

Of course it would have been much simpler to just duplicate the cards or use the transmitted code as is but where is the fun in that plus now i understand how the encoding works in relation to the number on the card and the content of the string. :)

python  rfid 

See also