RFID Login software Update !
Following on my previous (project / Guide) RFID login) , i have been working few improvements to the arduino software example. The biggest change is now having a serial terminal based menu interface. Also a few security concerns have been addressed, this includes limiting the number of wrong tries. As with the previous version not for sercuity applications, for hobby use only.
Improvements
- Wrong RFID Card tries are limited to 3 without a reset option
- All configuration can be done via a serial terminal therefore no need to use Arduino IDE .
- All options are selected from a simple menu which requires a password to use.
- Password and two card IDs can be store.
EEPROM Stored Data
Number of failed tries , password and the two card Uids are all stored in the eeprom. Although there is no encryption currently, each character of data is stored in a random location set by the user controlled Eeprom address array. Providing this array of addresses is set in a random sequence it should make it difficult to work out the users password if the whole eeprom was dumped.
How to use
For wiring please see previous (project / Guide) RFID login).
The only Arduino library required is the Arduino library for MFRC522 .
1) Change the optional user setting: menu password and address array .
When compiled and copied to the arduino…
2) Set a serial term to 9600 and arduinos serial port. (Arduino built in Term works ok)
3) Typing in Menu_password (Default = admin) followed by a CRLF will show the menu
4) simply type a menu option followed by a CRLF and then follow instructions
Code
// RFID Login Ver 2.0 with menu Example By Luke (www.ls-homeprojects.co.uk) // Free to use this code how you like but please link my site // Modified example for Arduino library for MFRC522. // Credit to Miguel Balboa for provided a great library and examples ! https://github.com/miguelbalboa/rfid. // Please note this is just a proof of concept Example and should not be used for security applications ! #include "Keyboard.h" #include "HID.h" // This is required for this to work with window 10 #include <SPI.h> #include <MFRC522.h> //This is the only library addition to standard Arduino. #include <EEPROM.h> #define SS_PIN 10 #define RST_PIN 5 MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class MFRC522::MIFARE_Key key; #define MAX_LINE 20 char line[MAX_LINE + 1]; int Menu_mode=0; // 0 =normal menu off , 1=menu , 2=enter password ,3=confirm password , 4=Save new card 1 , 5= Save new card, 8 =reset tries //############################################### settings ############################################################### char* admin_pass = "admin"; //change this int eeprom_loc[] = {10,40,22,33,244,66,5,2,3,55,9,7,31,77,84,20,44,8,99,16,4,12,221,79,68,35,91,52,39,32,22,144,155,167,189,149,88,24,29,59,19,78,15}; //Please modify this array to contain random squence of numbers 1 - 255 for epprom addresses to spread password chars //across the eeprom making it very difficult to work out if someone dumped the whole contents of eeprom. //########################################################################################################################## String pass1 ; boolean print_text = false; int pass_start_loc = 2; // Password loc allow 20 char space for password int card_1_start_loc = 22; int card_2_start_loc = 33; long code1=0; // holds card 1 after load from eeprom long code2=0; // holds card 1 after load from eeprom int tries = 0; // hold card failed tries , 3 max // Init array that will store new NUID byte nuidPICC[3]; void setup() { Serial.begin(9600); ///while (!Serial) { //; // wait for serial port to connect. Needed for native USB port only //} tries = EEPROM.read(eeprom_loc[1]); //Read failed tries at startup code1 = epprom_read(card_1_start_loc).toInt(); //load card 1 id from eeprom code2 = epprom_read(card_2_start_loc).toInt(); //load card 2 id from eeprom delay(500); Keyboard.begin(); delay(500); SPI.begin(); // Init SPI bus rfid.PCD_Init(); // Init MFRC522 } void loop() { menu(); // Run the serial Menu ! // Look for new cards if ( ! rfid.PICC_IsNewCardPresent()) return; // Verify if the NUID has been read if ( ! rfid.PICC_ReadCardSerial()) return; // Serial.print(F("PICC type: ")); MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak); //Serial.println(rfid.PICC_GetTypeName(piccType)); // Check is the PICC of Classic MIFARE type if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI && piccType != MFRC522::PICC_TYPE_MIFARE_1K && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { // Serial.println(F("Your tag is not of type MIFARE Classic.")); return; } if (rfid.uid.uidByte[0] != nuidPICC[0] || rfid.uid.uidByte[1] != nuidPICC[1] || rfid.uid.uidByte[2] != nuidPICC[2] || rfid.uid.uidByte[3] != nuidPICC[3] ) { // Serial.println(F("A new card has been detected.")); // Store NUID into nuidPICC array for (byte i = 0; i < 4; i++) { nuidPICC[i] = rfid.uid.uidByte[i]; } // CONVERT UID into Unsigned int as easier to match up to a saved value. unsigned long UID_unsigned; UID_unsigned = rfid.uid.uidByte[0] << 24; UID_unsigned += rfid.uid.uidByte[1] << 16; UID_unsigned += rfid.uid.uidByte[2] << 8; UID_unsigned += rfid.uid.uidByte[3]; String UID_string = (String)UID_unsigned; long UID_LONG=(long)UID_unsigned; if (Menu_mode==4){ //store card 1 Serial.println("card1 is:"); Serial.println(UID_LONG); epprom_write(UID_string ,card_1_start_loc); delay(2000); } if (Menu_mode==5){ //store card 2 Serial.println("card2 is:"); Serial.println(UID_LONG); epprom_write(UID_string ,card_2_start_loc); delay(2000); } if (tries < 3){ // check if its been less than three wrong cards ! if (UID_LONG == code1|| UID_LONG == code2) { // IF Presented card = stored card 1 or 2 then... type password in ! delay(1000); Keyboard.write(KEY_RETURN); // modify key sequence here for other logins other than windows 8/10 ! delay(1200); Keyboard.print(epprom_read(pass_start_loc)); //keyboard type in your stored password delay(400); Keyboard.write(KEY_RETURN); delay(400); nuidPICC[0] = 0; // Simple fix to allow the same card to work with this rc522 Example } else { delay(1200); Serial.println("wrong card !"); tries = tries + 1; EEPROM.write(eeprom_loc[1], tries ); // write the failed no. of tries to eeprom } } else { Serial.println("too many ties lockout , please reset"); } } else //Serial.println(F("Card read previously.")); // Halt PICC rfid.PICC_HaltA(); // Stop encryption on PCD rfid.PCD_StopCrypto1(); } // reads serial port CR lines boolean lineAvailable(int max_line,char *line){ int c; static int line_idx = 0; //line_idx = 0; static boolean eol = false; if (max_line <= 0) // handle bad values for max_line { eol = true; if (max_line == 0) line[0] = '\0'; } else // valid max_line { if (Serial.available() > 0) { c = Serial.read(); if (c != -1) // got a char -- should always be true { if (c == '\r' || c == '\n'){ eol = true; // lcd.print(c); } else line[line_idx++] = c; if (line_idx >= max_line) eol = true; line[line_idx] = '\0'; // always terminate line, even if unfinished } if (eol) { if (Menu_mode==2){ // mode is input new password if (line_idx > 1){ // check serial line is not empty delay(400); pass1 = line; // store incoming serial line as password Serial.println("please re enter password"); //Serial.println("yourpassword is"); // Serial.println(line); line_idx = 0; // reset for next line eol = false; // get ready for another line delay(1000); Menu_mode=3; // set mode to confirm password ! return true; } } if (Menu_mode==3){ // mode is confirm password if (line_idx > 1){ // check serial line is not empty //Serial.println("yourpassword is"); // Serial.println(line); if (pass1 == line){ // check new serial line is same as prev delay(400); Serial.println("passwords match !"); //delay(1000); epprom_write(line ,pass_start_loc); //store new password print_text = false; } else{ Serial.println("passwords dont match please try again"); Serial.println(); Serial.println(); Serial.println(); Serial.println("please enter new password:"); Menu_mode=2; //enable enter new password again } } } line_idx = 0; // reset for next line eol = false; // get ready for another line return true; } else return false; } } } void epprom_write(String data ,int strt_loc ) { if (Menu_mode > 2) { int loc = 0; int i; int en = 0; en = data.length() + strt_loc; // address for null to terminate data in eeprom for (i = 0; i < data.length() ; i++){ loc = eeprom_loc[i + strt_loc]; delay(200); EEPROM.write(loc, data[i]); //write char } delay(400); EEPROM.write(eeprom_loc[en], 0x00); // terminate data Serial.println(); Serial.println("Save complete"); Serial.println(); delay(900); Menu_mode = 0; //Exit menu system return; } } String epprom_read(int strt_loc ) { char text_p [30]; int loc = 0; int i; int da = 0; int daidx = 0; for (i=0; i < 254; i++){ loc = eeprom_loc[i + strt_loc]; // read from start loc to end of eeprom da = EEPROM.read(loc); if (daidx > 20){ // Simple fix to return 0 if more than 20 chars or a blank eeprom with no null spacing. return "0"; } if (da == 0 ){ // if read null then its the end of word text_p[daidx] = '\0' ; // terminate string return text_p ; // return complete string } else { text_p[daidx] = char(da); // convert byte to char and then add to string daidx = daidx + 1; } } //Serial.println(text_p); } void menu(){ if (lineAvailable(MAX_LINE,line)) //If new serial port line arrives { if (strcmp (line, "prom") == 0) { Serial.println(epprom_read(pass_start_loc)); delay(400); Serial.println(epprom_read(card_1_start_loc)); } if (Menu_mode==0) { if (print_text == false){ Serial.println("please enter admin password to login:"); print_text = true; } } if (strcmp (line, admin_pass) == 0) //if admin pass is typed in { Serial.println("welcome to RFID menu by www.ls-homeprojects.co.uk"); print_text = false; Menu_mode = 1; //enable menu line[0] = 0; // clear serial buffer so cmd is only executed once } //menu if (Menu_mode==1){ if (print_text == false){ //only print once ! Serial.println(); Serial.println("please type an option followed by enter"); Serial.println(); Serial.println("[1] Reset too many rfid tries"); Serial.println("[2] Set new password"); Serial.println("[3] Pair card 1"); Serial.println("[4] Pair card 2"); Serial.println("[x] Exit"); print_text = true; } if (strcmp (line, "1") == 0) { Menu_mode=0; //exit menu tries = 0; //reset tries EEPROM.write(eeprom_loc[1], 0 ); //reset tries in eeprom Serial.print("reset done!"); line[0] = 0; // clear serial buffer so cmd is only executed once return; } if (strcmp (line, "2") == 0) { Serial.println(); Serial.println("please enter new password:"); Menu_mode=2; //enable enter pass mode line[0] = 0; // clear serial buffer so cmd is only executed once } if (strcmp (line, "3") == 0) { Serial.println(); Serial.println("please scan new card 1:"); Menu_mode=4; //enable record card 1 line[0] = 0; // clear serial buffer so cmd is only executed once } if (strcmp (line, "4") == 0) { Serial.println(); Serial.println("please scan new card 2:"); Menu_mode=5; //enable record card 2 line[0] = 0; // clear serial buffer so cmd is only executed once } if (strcmp (line, "x") == 0) { Menu_mode=0; //Exit menu ! line[0] = 0; // clear serial buffer so cmd is only executed once } } } }
COMMENTS