Freetime + RFID Reader = Linux RFID Pluggable Authentication Module
Hey everyone! I had some freetime last night and I noticed that I have several RFID cards and and RFID reader and I almost do nothing with them. After thinking a little bit about what I can do with RFID reader, I came up with an idea! NFC RFID Linux PAM (Pluggable Authentication Module)! So next time for logging into my computer, user should have an RFID card, otherwise, even entering correct username+password combination, will not work.
So first I started by taking a look at my RFID reader's SDK files, unfortunately I had D-Logic uFR RFID Reader, not so popular one. Also all of their SDK was written in Pascal, so in Linux you can build it using Lazarus and possible with Delphi in Windows. Anyway, I asked company about C++ SDK header files, but I didn't get a response, it didn't stop me. I decided to read Pascal code and do some reverse engineering and rewriting SDK somehow for my own use in C++.
So basically this is what I had in Pascal:
function ReaderOpen:DL_STATUS;external libdll; function LinearRead(aucData:PByte; usLinearAddress: Word; usDataLength: Word; var lpusBytesReturned: Word; ucKeyMode: Byte; ucReaderKeyIndex: Byte): DL_STATUS; external libdll; function LinearWrite(const aucData:PByte; usLinearAddress: Word; usDataLength: Word; var lpusBytesWritten: Word; ucKeyMode: Byte; ucReaderKeyIndex: Byte):DL_STATUS; external libdll; function ReaderClose:DL_STATUS;external libdll;
I started my research and I started reading all pascal data types and their sizes. Word translates to short in C, PByte translates to unsigned char *, Byte translates to unsigned char, etc. There is not much resources for Pascal, seems like it's not so popular, honestly I don't like it either.
Anyway, after understanding about data type translations, I decided to dynamically load and resolve function pointers from SDK lib file and call them, so I ended up having this code:
long (*ReaderOpen)(void); long (*ReaderClose)(void); long (*LinearRead)(PBYTE, short, short, short*, unsigned char, unsigned char); handle = dlopen ("/usr/local/lib/libuFCoder1x64.so", RTLD_LAZY); ReaderOpen = dlsym (handle, "ReaderOpen"); ReaderClose = dlsym (handle, "ReaderClose"); LinearRead = dlsym (handle, "LinearRead");
So actually this did the trick. So I thought about the design, how to use and involve RFID cards into authentication. I decided to encrypt an string with AES256, store encrypted file in disk with proper permissions to read it, then store encryption key in RFID card. Now PAM module will read the key from RFID card, if key was able to decrypt secret file and reveal secret message, access will be granted, otherwise, even entering correct username/password will not help.
For AES encryption, simply I used OpenSSL libraries. I wrote two seperate applications, one for encrypting secret message and storing encrypted data in disk and writing encryption key into RFID card and the other one will be the PAM module itself which will read key from RFID card and try to decrypt secret file.
You can see source code here
For now it only works with my RFID reader (d-logic), if you want me to write additional code to support your RFID reader, simply email me SDK files of your RFID reader and I'll take care of it in some free time.