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