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

  1. Wrong RFID Card tries are limited to 3 without a reset option
  2. All configuration can be done via a serial terminal therefore no need to use Arduino IDE .
  3. All options are selected from a simple menu which requires a password to use.
  4. 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

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.