Restriction d'accès à des appareils par Contactless Card avec NodeMCU et le module RC522 la partie 4 – Down the Rabbit le Va chercher

, aujourd'hui, de Blog, il est, comme promis, "down the Rabbit Hole" et nous traitons avec les Rouages de la MiFare Badges Integrated Contactless Cards (PICC) Série. Nous partons de l'Particularités, et de regarder et les Fonctions en détail.

De nombreux Card Reader- Projets, avec le MF522 Chipset comme Base nous l' Arduino que j'ai personnellement déjà vu, utilisez malheureusement ni la Sécurité, ni dans les Possibilités de ce que nous Mifare Classic Carte de Fonctionnalités.

Ces Projets se limitent à l'librement pour chaque Lecteur de cartes et Téléphones lisible ID Unique universel (UUID) de la Carte et une Liste des permis de l'UUID contre à vérifier. Est-ce inclus dans la Liste, la Carte est considérée comme valide.

Dans nos Parties précédentes , nous faire de ce Principe d'Utilisation. C'est ce que nous avons aujourd'hui, notre Blog de modifier et de Données sécurisés sur notre MiFare Classic Carte.

Par ce Projet partagé de Type "MiFare Classic" (s'il vous plaît également à cette Remarque), nous pouvons propre, de nous donnée des Informations, à partir de la Carte mémoire et contre non autorisée de lire ou de modifier les protéger.

Pour ce faire, le Fabricant a déjà sur la Carte 16 Secteurs (0-15) 4 * 16 Octets présents dans lesquelles, à l'Exception du Secteur 0 , 3 * 16 Octets libres peuvent être décrits. 16 Octets de chaque Secteur, Secteur Trailer appelé et pour le Rangement des 2 Sektorenschlüssel et Zugriffsmatrixdefinition utilisé.

Les 16 Octets d'un Secteur Trailer sont réparties comme suit:
6 Octets - premier Sektorenschlüssel
6 Octets - deuxième Sektorenschlüssel
4 Octets - Zugriffsberechtigungsdefinition

Nous voulons sur notre Carte maintenant le Nom et le Prénom de nous un mot de passe crypté. Pour ce faire, nous définissons un Secteur (1-15) sur la Constante ... pour nous et pour ce faire, utilisez le souhaitez. J'ai dans le Code Sektorenblock 1 est sélectionné.

Le Prénom est prévu au second 16 Octets de la Zone, et le Nom de famille dans le troisième 16 Octets Champ. La première de 16 Octets Champ est réservé pour des Extensions ultérieures.

Qui avons-nous besoin d'une Schlüsseldefinition, nous avons dans la Structure MiFareClassicKeyTable déposer.

S'il vous plaît modifier ce Bloc (2x 6 Octets) lors de la Réplique nécessairement avec salle de Clé et les stocke à vous dans un Endroit sûr, sinon n'importe qui, ce Projet connaît dans le Code en Clair, ladite Clé de votre Carte lire et propre valide! Cartes pour votre contrôle de périphérique peut créer.

Petit Spoiler: en plus, nous, ce matériel de base lors de la Suite de la Série à nouveau besoin. Merci de continuer à respecter, de la Carte décrit et d'options de change. Ainsi, la Carte est peut-être pas pour d'autres Utilisations utilisable!

Nous invitons, après Modification, du matériel de clé suivants Code sur nos ESP élevé:

 

#include <SPI.h>
#include <MFRC522.h>
#include <ESP8266WiFi.h>
//#include <WiFiClient.h> 
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <EEPROM.h>
#include <FS.h>           // Include the SPIFFS library

#define RST_PIN     5     // SPI Broche Reset (D1 Sortie)
#define RELAIS_PIN  16    // Relais (D0 Sortie) [Active LOW] - Internes LED, à proximité du Port USB
#define SS_PIN      15    // SPI Slave Select Pin

#define RGBLED_R    2     // Rouge (D4 Sortie) 
#define RGBLED_G    0     // Vert (D3 Sortie des internes LED sur le Module ESP
#define RGBLED_B    4     // Bleu (D2 Sortie)

#define WiFiPwdLen   25   // Maximum de longueur de mot de passe WiFi
#define STANameLen 20     // Maximale WiFi SSIDlänge
#define ESPHostNameLen 20 // Nombre Maximal de Caractères ESPHostName

#define KEYA true         // Définition du drapeau PICC
#define KEYB faux        // Définition du drapeau PICC

#define LED_BUILTIN 16
#define PIN_WIRE_SDA 4 
#define PIN_WIRE_SCL 5 

#define USED_Sector 1  // Secteur de carte utilisé pour les données d'authentification et de configuration (valide: 1 à 15)

ADC_MODE(ADC_TOUT);   // Configurez l'entrée analogique A0 sur externe. ADC_TOUT (pour tension externe), ADC_VCC (pour tension système). 
MFRC522 mfrc522(SS_PIN, RST_PIN);   // Créer une instance du MFRC522
MFRC522::MIFARE_Key clé;
ESP8266WebServer serveur(80);        // Créer une instance de serveur Web

struct WiFiEEPromData   {     char ESPHostName[ESPHostNameLen];      char APSTAName[STANAMELEN]; // Nom de la STATION à connecter, si défini     char WiFiPwd[WiFiPwdLen]; // WiFiPAssword, si défini     char ConfigValid[3]; // Si Config est Vaild, le tag "TK" est requis "   };    struct MiFareClassicKeyTable   {    octet Key_A[6] = {0x22,0x44,0xFA,0xAB,0x90,0x11};   // Veuillez changer la clé de la carte PICC.     octet Key_B[6] = {0xFE,0xE1,0xAA,0x3D,0xDF,0x37};   // Veuillez changer la clé de la carte PICC.     char ConfigValid[3]; // Si Config est Vaild, le tag "TK" est requis "   };    MiFareClassicKeyTable MiFareClassicKey;
WiFiEEPromData MyWiFiConfig;

// Variables utilisées mondialement
bool Résultat  = faux;
bool LearnNewCard = faux;
bool EraseCard = faux; 
bool ExpirationDateActive = faux;
String Nom de famille;
String Givenname;
String ExpirationDate;
String temp;
non signé longue SessionID;
non signé longue PCD_ServiceCall_Handler = 0;
non signé longue PCD_WatchDog_Handler = 0;
uint8_t DataBuffer[18]  = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };


nul configuration()     {    pinMode(RST_PIN,SORTIE);   digitalWrite(RST_PIN,ÉLEVÉ);   pinMode(RELAIS_PIN,SORTIE);   pinMode(RGBLED_R,SORTIE);   pinMode(RGBLED_G,SORTIE);   pinMode(RGBLED_B,SORTIE);   digitalWrite(RELAIS_PIN,ÉLEVÉ);    // relais inactif   SetRGBLed(255,0,255,faux);       // La couleur LED pourpre commence l'initialisation   Série.commencer(115200);               // Initialise la communication série avec le PC avec 115200 bauds   Série.println("");   temp = "ATSN:"+ String(ESP.getChipId());   Série.println(temp);   // Serial.print ("Valeur ADC:"); Serial.println (analogRead (A0));   SPI.commencer();                      // Initialiser la communication SPI   PCDHardReset();   SessionID = millis();    Résultat  = startWiFiClient();     InitalizeHTTPServer();   SetRGBLed(0,0,255,faux);       // L'initialisation de la couleur bleue de la LED est terminée   //ESP.wdtEnable(WDTO_4S); // Démarrer le chien de garde   }


// ******************* Démarrer les fonctions d'aide / d'optimisation ************************ ********

nul SetRGBLed(octet RedValue,octet GreenValue,octet BlueValue,booléen SlowFade)  // Fonction de contrôle de la led RGB
{   digitalWrite(RGBLED_R,FAIBLE);       digitalWrite(RGBLED_G,FAIBLE);   digitalWrite(RGBLED_B,FAIBLE);    si (RedValue == 255)   { digitalWrite(RGBLED_R,ÉLEVÉ); }      si (GreenValue == 255) { digitalWrite(RGBLED_G,ÉLEVÉ); }   si (BlueValue == 255)  { digitalWrite(RGBLED_B,ÉLEVÉ); }    }

// ******************* Stop Helper / Fonctions d'optimisation ************************ *********

// ******************* Démarrer les fonctions Serveur Web ************************** *****************

// Les routines de base des cookies sont basées sur un extrait de GIT:
//https://github.com/esp8266/ESPWebServer/blob/master/examples/SimpleAuthentification/SimpleAuthentification.ino
bool is_authentified()
{     si (serveur.hasHeader("Cookie")){       // Cookie trouvé      temp = serveur.en-tête("Cookie");       //Serial.println(temp);      String SessionStr = String(ESP.getChipId()) + "=" + String(SessionID);      rendement();      si (temp.indexOf(SessionStr) != -1) {         // Authentification Web réussie        temp = "";        retour vrai;       }     }        // Échec de l'authentification Web    temp = "";    SessionID = millis();    retour faux; 
} 

nul handleLogin(){   String msg;   // String cookie = server.header ("Cookie");   //Serial.println(cookie);   si (serveur.hasArg("DÉCONNECTER")){     // Utilisateur de déconnexion;     serveur.sendHeader("Emplacement","/login");     server.sendHeader("Cache-Control","no-cache");     SessionID = millis();     temp = String(ESP.getChipId()) + "= NA ; HttpOnly ; SameSite=Strict";     server.sendHeader("Set-Cookie",temp);     temp = "";     serveur.send(301);     yield();     return;   }   if (serveur.hasArg("USERNAME") && server.hasArg("PASSWORD")){     temp = String(ESP.getChipId());     if (serveur.arg("USERNAME") == , "admin" &&  server.arg("PASSWORD") == temp ){       serveur.sendHeader("Location","/");       server.sendHeader("Cache-Control","no-cache");       SessionID = millis();       temp = String(ESP.getChipId()) + "=" + String(Idsession) + "; HttpOnly ; SameSite=Stricte";       serveur.sendHeader("Set-Cookie",temp);       temp = "";       serveur.envoyer(301);       rendement();       de retour;     }   msg = "<script>alert('Falscher Benutzername oder falsches mot de passe !');</script>";   }    CSS_Header_Template();    rendement();    temp = "<head><title>Login</title></head><body><DIV ALIGN=CENTER>";    serveur.sendContent(temp);    temp = "<h2> " Anmeldung un Kartenleser RC522</h2><corps><br><br><table border=0 bgcolor=black><tr><th><DIV ALIGN=RIGHT>";    serveur.sendContent(temp);    temp = "<form action='/login' method='post'>Benutzername: <input type=text Name='nom d'utilisateur' Size=17 required><br>";    serveur.sendContent(temp);    temp = "mot de passe: <input type=password Name= "PASSWORD" Size=17 required><br><br><br><button type= "submit"";    serveur.sendContent(temp);    temp = "nom='Login_Button' value='1' style='height: 30px; width: 100px' >Login</bouton><br></th></tr></form></DIV></table>";    serveur.sendContent(temp);    temp = "<br><SMALL>Damit die " Anmeldung funktioniert, sind Cookies für diese Webseite zu erlauben.</SMALL>";      serveur.sendContent(temp);    temp = msg + "</DIV></body></HTML>";    serveur.sendContent(temp);    temp = "";
}

vide handleNotFound()    {   SessionID = millis();   temp = "Page nicht gefunden.\n\n";   temp += "URI: ";   temp += serveur.uri();   temp += "\nMethod: ";   temp += (serveur.méthode() == HTTP_GET)?"GET",:"POST";   temp += "\nArguments: ";   temp += serveur.args();   temp += "\n";   pour (u_int8_t je=0; je<serveur.args(); je++){     temp += " " + serveur.argName(je) + ": " + serveur.arg(i) + "\n";   }   rendement();   serveur.envoyer(404, "text/plain", temp);   temp = "";   }



vide handleErasePICC()
{   si (!is_authentified())     {     serveur.sendHeader("Emplacement","/login");     serveur.sendHeader("Cache-Control","no-cache");     serveur.envoyer(301);     rendement();     de retour;     }     CSS_Header_Template();   rendement();   temp = "<head><title>Kartenleser RC522</title></head><body>";   serveur.sendContent(temp);   HtmlNavStructure();   temp = "<script>alert('Bitte JETZT die zu löschende Karte vor den Leser halten!');</script>";      serveur.sendContent(temp);    rendement();   SetRGBLed(0,255,255,false);       //Led Couleur cyan Programmierungsmodus   EraseCard = vrai;         temp = "</body></html>";   serveur.sendContent(temp);   serveur.client().arrêter();   temp = "";
}


vide handleNewPICC()
{   si (!is_authentified())     {     serveur.sendHeader("Emplacement","/login");     serveur.sendHeader("Cache-Control","no-cache");     serveur d'.envoyer(301);     de retour;     }   si (serveur.hasArg("Nom de famille") && serveur.hasArg("Givenname"))   {      Nom = du serveur.arg("Nom de famille");     Givenname = serveur.arg("Givenname");     ExpirationDate = serveur.arg("ExpDate");     si (serveur.hasArg("ExpDateOption")) { ExpirationDateActive = vrai; } d'autre { ExpirationDateActive = faux; }     temp = "<script>alert('Bitte JETZT die neue Karte vor den Leser halten!');</script>";        serveur.sendContent(temp);      SetRGBLed(255,255,0,false);       //Led Couleur Gelb Programmierungsmodus     LearnNewCard = vrai;     rendement();     de retour;       }         CSS_Header_Template();   rendement();   temp = "<head><title>Kartenleser RC522</title></head><body>";   serveur.sendContent(temp);   HtmlNavStructure();   temp = "";   temp = "<br><br><br><br><table border=0 ALIGN=CENTER><th>";   serveur.sendContent(temp);   temp = "<table border=1 bgcolor = black><form action='/newPICC' method='post'>";   serveur.sendContent(temp);   temp = "<tr><th>Karteninhaber:<br><div ALIGN=RIGHT>";   serveur.sendContent(temp);   temp = "Vorname: <input type=text Name='Nom' Size=17 maxlenght=16 espace réservé='Max' required><br>";   serveur.sendContent(temp);   temp = "Nachname: <input type=text Name='Prénom' Size=17 maxlenght=16 placeholder='Smith' required><br>";   serveur.sendContent(temp);   temp = "</div></th><th>Kartenmetadaten:<br><DIV ALIGN=RIGHT>";   serveur.sendContent(temp);       temp = "<input Name='ExpDateOption' TYPE=checkbox VALUE=1 >Ablaufdatum:<input type= "date" Name='ExpDate' Size = 17 >";   serveur.sendContent(temp);   temp = "<br><th><tr><th></table><br>";   serveur.sendContent(temp);   temp = "<button type='submit' name='NewCard' value='1' style='height: 30px; width: 200px' >Neue carte à puce erstellen</bouton>";   serveur.sendContent(temp);   temp = "<br / ></form></tr></th></table>";   serveur.sendContent(temp);   temp = "</body></html>";   serveur.sendContent(temp);   serveur.client().arrêter();   de rendement();     temp = "";
}

vide handleRoot()
{   si (!is_authentified()){     serveur.sendHeader("Emplacement","/login");     serveur.sendHeader("Cache-Control","no-cache");     serveur d'.envoyer(301);     de retour;     }   // Contenu HTML   CSS_Header_Template();   rendement();   temp = "<head><title>Kartenleser RC522</title></head><body>";   serveur.sendContent(temp);   HtmlNavStructure();   temp = "<div ALIGN=CENTER><br><br><br><br><BIG>Willkommen auf der Smartkartenleser RC522 Site.</BIG><br>";   serveur.sendContent(temp);   temp = "Resetgrund: " + Chaîne(ESP.getResetReason()) + "<br>";   serveur.sendContent(temp);   temp = "Freier Heapspeicher: " + Chaîne(ESP.getFreeHeap()) + " Octets<br>";   serveur.sendContent(temp);   temp = "Int. Flash: " + Chaîne(ESP.getFlashChipRealSize()) + " Octets<br>";   serveur.sendContent(temp);   Résultat = mfrc522.PCD_PerformSelfTest();    mfrc522.PCD_Init();                       // Initialisiere MFRC522 Lesemodul   mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); // Setzt Antenne auf max. Empfang   mfrc522.PCD_AntennaOn();    de rendement();   si le (Résultat) {temp = "RC522 PCD-Statut: OK<br>"; } d'autre {temp = "RC522 PCD-Statut: Fehler!<br>"; }    serveur.sendContent(temp);   temp = CPU ID: " + Chaîne(ESP.getChipId()) + " @ " + Chaîne(ESP.getCpuFreqMHz()) + " MHz<br>";    serveur.sendContent(temp);   temp = "<br / >Sie sind erfolgreich angemeldet !<br><br><form action='/login' method= "get">";   serveur.sendContent(temp);   temp = "<button type='submit' name='DÉCONNEXION' value='OUI' style='height: 30px; width: 200px' >Déconnexion</bouton>";   serveur.sendContent(temp);   temp = "</form></div></body></html>";   serveur.sendContent(temp);   si (serveur.hasArg("Reboot") )  // Redémarrage du Système      {     //ESP.wdtFeed();     ESP.wdtDisable();     temp = "<script>alert('Das System startet JETZT neu.');</script>";        serveur.sendContent(temp);     serveur.client().arrêter();     de rendement();     temp = "";     ESP.réinitialiser le();     délai(4000);      }     de serveur de.client().arrêter();   temp = "";
}

vide CSS_Header_Template() // Formatvorlage für alle internen ESP de nos sites web. https://wiki.selfhtml.org/wiki/CSS   {    serveur.setContentLength(CONTENT_LENGTH_UNKNOWN);    temp = "";    serveur.envoyer (200, "text/html", temp);    temp = "<!DOCTYPE HTML PUBLIC "- /- //W3C//DTD HTML 4.01 Transitional//EN "><html lang= " de " ><meta charset='UTF-8'>";    serveur.sendContent(temp);    temp = "<style type='text/css'>*{margin: 0;padding: 0;}body{background:black;color:darkorchid;font-size: 16px;"; serveur.sendContent(temp); temp = "font-family: sans-serif,arial;}.nav{width: 1300px;height: 30px;margin: 0 auto;border-radius: 5px;}";    serveur.sendContent(temp);    temp = "ul li{list-style: none;width: 200px;line-height: 60px;position: relative;fond: darkorchid;"; serveur.sendContent(temp); temp = "box-shadow: 0px 2px 5px 0px gris;text-align: center;float: left;background-color: #010000;}ul li ul{";    serveur.sendContent(temp);    temp = "position: absolute;}.nav > ul > li:nth-of-type(1){border-radius: 5px 0px 0px 5px;}.nav > ul > li:nth-of-type(5)";    serveur.sendContent(temp);    temp = "{border-radius: 0px 5px 5px 0px;}ul li a{color: rgb(182, 18, 18);width: 200px;height: 58px;display: inline-block;"; serveur.sendContent(temp); temp = "text-decoration: none;}ul li a:hover{font-weight: bold;border-bottom: 2px solid #fff;}ul li ul{display: none;}";    serveur.sendContent(temp);    temp = ".nav ul li:hover ul{display: block;}.fa{margin-right: 5px;}.conteneur{width: 1000px;height: 200px;"; serveur.sendContent(temp); temp = "margin: 0 auto;padding:20px 20px;}@media screen and (max-width: 480px){header{width: 100%;}";    serveur.sendContent(temp);    temp = ".nav{display: none;width: 100%;height: auto;}ul li{width: 100%;float: none;}ul li a{width: 100%;"; serveur.sendContent(temp); temp = "display: block;}ul li ul{position: static;}ul li ul li a{background: #222;}.fa-liste.modifier{display: block;}";    serveur.sendContent(temp);    temp = ".conteneur{width: 100%;height: auto;}body{overflow-x:hidden;}}</style>";    serveur.sendContent(temp);    temp = "";   }


vide HtmlNavStructure()   {   temp = "<div class= "menu" ><nav class='nav'><ul>";   serveur.sendContent(temp);   temp = "<li><a href='#'>Système</a>";   serveur.sendContent(temp);   temp = "<ul><li><a href='/'>d'Information</a></li>";   serveur.sendContent(temp);   temp = "<li><a href='/?Reboot=YES'>Neustart</a></li>";   serveur.sendContent(temp);   temp = "</ul>";   serveur.sendContent(temp);   temp = "</li><li><a href='#'>CCIP</a>";   serveur.sendContent(temp);   temp = "<ul><li><a href='/newPICC'>Neue Karte erstellen</a></li>";   serveur.sendContent(temp);   temp = "<li><a href='/erasePICC'>Karte löschen</a></li></ul>";   serveur.sendContent(temp);   temp = "</li>";   //temp = "</li><li><a href='#'>Ereignisprotokoll</a></li>";   serveur.sendContent(temp);   temp = "</ul></nav></div>";   serveur.sendContent(temp);   temp = "";   }       vide InitalizeHTTPServer()    {   bool initok = faux;   const char * headerkeys[] = {"User-Agent","Cookie"} ; //en-Tête zum Tracken   size_t headerkeyssize = sizeof(headerkeys)/sizeof(char*); //en-Tête zum Tracken   serveur.sur("/", handleRoot);   serveur.sur("/login", handleLogin);   serveur.sur("/newPICC", handleNewPICC);   serveur.sur("/erasePICC", handleErasePICC);   serveur.onNotFound ( handleNotFound );   serveur.collectHeaders(headerkeys, headerkeyssize );// Serveur anweisen, diese zu Tracken    serveur de.commencer(); / serveur Web/ start   }        // ******************* Fin des Fonctions de Serveur web *********************************************


// ******************* Les Fonctions De Démarrage WiFi De Gestion *************************************
// Funktion von https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/wps-mit-dem-esp8266?ls=de
bool startWPS() 
{   bool wpsSuccess = WiFi.beginWPSConfig();   si(wpsSuccess) {       // Muss nicht immer erfolgreich heißen! Nach einem Délai ist die SSID leer       Chaîne newSSID = WiFi.SSID();        si(newSSID.longueur() > 0) {         // Nur wenn eine SSID gefunden wurde waren wir erfolgreich          rendement de la();          Série.println("ATWPS:OK");         saveCredentials(); // Enregistrer les informations d'Identification dans la mémoire EEPROM       } d'autre {         Série.println("ATWPS:NOK");       }   }   retour wpsSuccess; 
}

bool startWiFiClient() 
{   bool WiFiClientStarted = faux;   size_t A0_ADCValue = 0;   octet je = 0;   octet connRes = 0;   Série.setDebugOutput(false);  // Zu Debugzwecken aktivieren.    WiFi.nom d'hôte("CrdRdr41667");   WiFi.softAPdisconnect(vrai);   WiFi.déconnecter();   le WiFi.en mode(WIFI_STA);   si(loadCredentials())      {      WiFi.commencer(MyWiFiConfig.APSTAName, MyWiFiConfig.WiFiPwd);      tout (( connRes != 3 ) et( connRes != 4 ) et (j' != 30))  //si connRes == 0 "IDLE_STATUS - changement Statius"       {        j'++;       // Serial.print("."); // Connexion vorgang auf der seriellen Schnittstelle beobachten       //ESP.wdtFeed();       delay(500);       rendement();       connRes  = WiFi.waitForConnectResult();       }      si (connRes == 4 ) { // si le mot de passe est incorrect       Série.println("ATWIFI:PWDERR");             WiFi.déconnecter();       }      si (connRes == 6 ) { // module n'est pas configuré en mode station       de Série.println("ATWIFI:STAERR");       WiFi.déconnecter();       }      }   si(WiFi.statut() == WL_CONNECTED)      {     //ESP.wdtFeed();      Serial.print("de l'AIPRP:");     Série.println(WiFi.localIP());     WiFi.setAutoReconnect(vrai); // Définir si le module va tenter de vous reconnecter à un point d'accès dans le cas où il est déconnecté.     // Le programme d'installation MDNS répondeur     si (!MDNS.commencer("CrdRdr41667"))        {       Série.println("ATMDNS:NOK");       } d'autre { MDNS.addService("http",, "tcp", 80); }        WiFiClientStarted = vrai;     } d'autre      {     A0_ADCValue = analogRead(A0);     //Wir waren nicht erfolgreich, daher starten wir WPS, wenn WPS Dégustateur un A0 während des Réinitialise gedrückt ist     si (A0_ADCValue > 499)       {         si(startWPS())            {             //ESP.wdtFeed();              delay(500);             WiFi.déconnecter();             le WiFi.en mode(WIFI_STA);             WiFi.commencer(WiFi.SSID().c_str(), WiFi.psk().c_str());             //ESP.wdtFeed();              WiFiClientStarted = vrai;           } d'autre           {             WiFiClientStarted = faux;             WiFi.déconnecter();           }       } d'autre       {         WiFi.débrancher();       }    }    //WiFi.printDiag(de Série); // Zu Debugzwecken aktivieren.   retour WiFiClientStarted; 
}
// ******************* FIN des Fonctions WiFi de Gestion *************************************

// ******************* les Fonctions de Démarrage Store WiFi informations d'Identification dans la mémoire EEPROM ******************
bool loadCredentials() 
{
 bool RetValue;
 EEPROM.commencer(512);
 EEPROM.obtenir(0,MyWiFiConfig);
 EEPROM.fin();
 si (la Chaîne(MyWiFiConfig.ConfigValid) == "SAVOIRS traditionnels")    {     RetValue = vrai;   } d'autre   {     RetValue = false; // Paramètres WLAN nicht gefunden.   }   //ESP.wdtFeed();    return RetValue; 
}

vide saveCredentials() // Speichere WLAN informations d'identification de l'auf EEPROM 
{   size_t je;   pour (je = 0 ; je < sizeof(MyWiFiConfig) ; j'++) // Loeschen der alten Konfiguration      {       EEPROM.écrire(je, 0);       }   pour (je = 0 ; je < STANameLen  ; j'++) // Loeschen der alten Konfiguration      {       MyWiFiConfig.WiFiPwd[je] = 0;       }   pour (je = 0 ; je < WiFiPwdLen ; j'++) // Loeschen der alten Konfiguration      {       MyWiFiConfig.APSTAName[je] = 0;       }      temp = WiFi.SSID().c_str();   je = temp.longueur de();   temp.toCharArray(MyWiFiConfig.APSTAName,je+1);    temp = WiFi.psk().c_str();   je = temp.longueur de();   temp.toCharArray(MyWiFiConfig.WiFiPwd,je+1);   temp = "";      strncpy(MyWiFiConfig.ConfigValid , "SAVOIRS traditionnels", sizeof(MyWiFiConfig.ConfigValid) );    EEPROM.commencer(512);   EEPROM.mettre(0, MyWiFiConfig);   EEPROM.commettre();   EEPROM.fin();   //ESP.wdtFeed(); 
}
// ******************* FIN des Fonctions StoreCredentialsto EEPROM ***************************

// ******************* les Fonctions de Démarrage CardServices *************************************


void PCDHardReset()
{   digitalWrite(RST_PIN,FAIBLE);   retard(200);   digitalWrite(RST_PIN,HAUTE);   mfrc522.PCD_Reset();   mfrc522.PCD_Init();                              // Initialisiere MFRC522 Lesemodul   mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); // Setzt Antenne auf max. Empfang   mfrc522.PCD_AntennaOn();
}

boolean CardAuthenticate(boolean ABKey, octet Secteur de l',octet ikey[6])
{
const byte sectorkeytable [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63};
octet situation;
situation = 0;
pour (int un = 0; a < 6;une++)   {   clé.keyByte[un] = ikey[un];   }   // la Clé Un
si (ABKey)   {   situation = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, sectorkeytable[Secteur], &clé, &(mfrc522.uid));   si la (situation != MFRC522::STATUS_OK)     {     Série.println("ATAUTH:ERR_A");     return false;     }       }   // Touche B   d'autre si (pas ABKey)   {   situation = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B,sectorkeytable[Secteur], &clé, &(mfrc522.uid));   si la (situation != MFRC522::STATUS_OK)     {     Série.println("ATAUTH:ERR_B");     return false;     }        }
return true;   }

// WriteData . utilise la Variable Globale DataBuffer pour le Retour de Données
boolean CardDataWrite(octet Secteur de l',octet du bloc,d'octets de la valeur[16])
{
de l'octet d'état;
octet writevector;
octet sectorkeytable [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63};
writevector = Secteur de * 4 + bloc -1 ;
pour les (octets un = 0; un < 16; un++)   {   si (writevector ==  sectorkeytable[un])     {     // Serial.println("NAK");     return false;     }   }
statut = mfrc522.MIFARE_Write(writevector, valeur, 16);
si (le statut de != MFRC522::STATUS_OK)   {   Série.println("ATPCD:W_ERR");   //Série".println(mfrc522.GetStatusCodeName(status));   return false;   } else    {   // Serial.print("OK");   return true;   }   }

// Lecture de Données utilise la Variable Globale DataBuffer pour le Retour de Données
boolean CardDataRead(octet Secteur de l',octet du bloc)
{
d'octets statusi;
octet readvector;
const byte sectorkeytable [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63};
octets de taille = 18;
readvector = Secteur de * 4 + bloc -1 ;
pour les (octets un = 0; un < 16; un++)   {   si (readvector ==  sectorkeytable[une])     {      Série.println("ATPCD:R_ERR");       return false;     }   }
statusi = mfrc522.MIFARE_Read(readvector, DataBuffer, &de taille);
si (statusi != MFRC522::STATUS_OK)   {   Série.println("ATPCD:R_ERR");   return false;   } else    {   return true;   }   }

boolean ResetCardToDefault()
{
octet ikey[16];
octet d'état,je;
octet writevector;
const byte sectorkeytable [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63};
writevector = sectorkeytable[USED_Sector];
si (CardAuthenticate(KEYB,USED_Sector,MiFareClassicKey.Key_B)) // Secteur Autenticate pour l'Accès en ÉCRITURE      {       pour (je = 0; je <= 16; je++) { DataBuffer[je] = 0; }           si (!(CardDataWrite(USED_Sector,1,DataBuffer))) { retourner false; }        pour (je = 0; je <= 16; je++) { DataBuffer[je] = 0; }          si (!(CardDataWrite(USED_Sector,2,DataBuffer))) { retourner false; }       pour (je = 0; je <= 16; je++) { DataBuffer[je] = 0; }          si (!(CardDataWrite(USED_Sector,3,DataBuffer))) { retourner false;}      }
pour (byte i = 0; i <= 16; i++) { ikey[j'] = 255; }  //Chargement de la Clé par Défaut pour tous les Secteurs 
ikey[6] = 0xFF; // Paramètre par Défaut pour l'Accès Bits
ikey[7] = 0x07; // 
ikey[8] = 0x80; // 
ikey[9] = 0x69;    statut = mfrc522.MIFARE_Write(writevector, ikey, 16);
si (le statut de != MFRC522::STATUS_OK)   {   return false;   }
retour vrai;   }

boolean SetSectorAccessControl (octet Secteur de l',octet Akey[6],octet Clef[6])
{
octet ikey[16];
octet d'état;
octet writevector;
const byte sectorkeytable [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63};
writevector = sectorkeytable[Secteur];
ikey[0] = Akey[0];
ikey[1] = Akey[1];
ikey[2] = Akey[2];
ikey[3] = Akey[3];
ikey[4] = Akey[4];
ikey[5] = Akey[5];
ikey[6] = 0x78; // Bloc de Données 0 À 3 Conditions d'Accès: Touche B / écriture de la Clé de Lecture
ikey[7] = 0x77; // la CLÉ UN & TOUCHE B & Acces Bits Écrire:B Clé / Clé d'Un Accès en Lecture Bits
ikey[8] = 0x88; // Calculatrice: http://calc.gmss.ru/Mifare1k/
ikey[9] = 0x69; // Fixateur Wert - > par défaut hex 69
ikey[10] = Clef[0];
ikey[11] = Clef[1];
ikey[12] = Clef[2];
ikey[13] = Clef[3];
ikey[14] = Clef[4];
ikey[15] = Clef[5];
statut = mfrc522.MIFARE_Write(writevector, ikey, 16);
si (le statut de != MFRC522::STATUS_OK)   {   Série.println("ATPCD:W_KEY_ERR");   return false;   }else    {   return true;   }   }

boolean CheckforDefaultCardKey ()
{
octet tkey[6];
boolean CardResult; 
octet readvector;
octet statusi;
const byte sectorkeytable [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63};
octets de taille = 18;
pour les (byte i = 0; i <= 6; i++) { tkey[j'] = 255; }  //Chargement de la Clé par Défaut pour tous les Secteurs 
CardResult = vrai;   si (!CardAuthenticate(KEYA,USED_Sector,tkey)) { CardResult = faux; };
readvector = sectorkeytable[USED_Sector];
statusi = mfrc522.MIFARE_Read(readvector, DataBuffer, &de taille);
si (statusi != MFRC522::STATUS_OK) { CardResult = false; } 
//if (!((DataBuffer[7] = 0x07) & (DataBuffer[7] = 0x80))) { CardResult = false; };
retour CardResult; 
}

boolean WriteNewMiFareClassicPICC ()   {   octet tkey[6];   octet j'ai,un;   booléen CardResult;   si (CheckforDefaultCardKey())     {     pour (je = 0; je <= 6; je++) { tkey[j'] = 255; }  //Chargement de la Clé par Défaut pour tous les Secteurs      pour (je = 0; je <= 16; je++) { DataBuffer[j'] = 0; } // Effacer la Variable Tampon     CardResult = vrai;            si (CardAuthenticate(KEYA,USED_Sector,tkey)) // Secteur Autenticate       {       // Serial.println("Auth Sec 0 OK");        si le (Nom de famille.de la longueur() > 15) { d'une = 15; } autre personne { un = Nom de famille.longueur();}       si le (Nom de famille.de la longueur() > 0)         {         pour (je = 0; je <= 16; je++) { DataBuffer[je] = 0; }             pour (je = 0; je <= un; je++) { DataBuffer[je] = Nom[je]; }            si (!(CardDataWrite(USED_Sector,2,DataBuffer))) { CardResult = false; } //Le secteur 0 du Bloc 2 Vorname mit la Clé Un schreiben         }       si (Givenname.la longueur() > 15) { d'une = 15; } autre personne { un = Prénom.longueur(); }       si (Givenname.la longueur() > 0)         {         pour (je = 0; je <= 16; je++) { DataBuffer[je] = 0; }          pour (je = 0; je <= un; je++) { DataBuffer[je] = Givenname[je]; }          si (!(CardDataWrite(USED_Sector,3,DataBuffer))) { CardResult = false; } //Le secteur 0 du Bloc 3 Nachname mit la Clé Un schreiben         }             si (!(SetSectorAccessControl (USED_Sector,MiFareClassicKey.Key_A,MiFareClassicKey.Key_B))) { CardResult = false; }    // (octets par Secteur,byte Akey[6],byte Clef[6])       } d'autre {               CardResult = faux;              retour CardResult;              }        } d'autre {               CardResult = faux;              retour CardResult;              }          si (CardResult)        {        //Serial.println("PICC écrite");       CardResult = true;       }     else        {        //Serial.println("PICC n'est pas vide");       CardResult = faux;       }     rendement();       de retour CardResult;   }


boolean ReadMiFareClassicPICC ()
{
boolean CardResult;
octet j'ai,un ;
CardResult = vrai;    si (CardAuthenticate(KEYA,USED_Sector,MiFareClassicKey.Key_A)) // Secteur Autenticate avec la Touche de LECTURE d'Un   {   Givenname = "aaaaaaaaaaaaaaaa"; //espace Réservé   Nom de famille = "aaaaaaaaaaaaaaaa"; //espace Réservé   pour (je = 0; je < 18; je++) { DataBuffer[j'] = 0; } // Effacer la Variable Tampon   si (CardDataRead(USED_Sector,2)) // Feld Vorname auslesen     {         pour (je = 0; je < 16; je++) { Nom[je] = char(DataBuffer[j']);  }             } else {             return false;            }     pour (je = 0; je < 18; je++) { DataBuffer[j'] = 0; } // Effacer la Variable Tampon     si (CardDataRead(USED_Sector,3)) // Feld Nachname auslesen       {                pour (je = 0; je < 16; je++) { Givenname[j'] = char(DataBuffer[j']); }              } else {               return false;                 }      } else      {      return false;     }
Série.d'impression ("ATAUTH_S:");
Série.println (Nom);
de Série.de l'impression ("ATAUTH_G:");
de Série.println (Givenname);
return true;
}

void CardServer()
{
#define PCD_Poll_Interval 400
#define PCD_Watchdog_Interval 60000
if (millis() - PCD_ServiceCall_Handler >= PCD_Poll_Interval)    {    PCD_ServiceCall_Handler = millis();        if (mfrc522.PICC_IsNewCardPresent())   // PICC = proximity integrated circuit card = carte à Puce sans contact     {      mfrc522.PICC_ReadCardSerial();       yield();     // Distinction selon le type de carte     // 0x08 pour MIFARE Classic 1K     // 0x18 pour MIFARE Classic 4K     // 0x11 pour MIFARE PLUS     if (mfrc522.uid.sak == 0x08 || mfrc522.uid.sak == 0x18)       {       // MiFare_Classic_Processor START (mfrc522.uid.sak); // exécuter Seulement si Une Mifare Classic Carte devant le Lecteur a été maintenu.       octet tkey[6];        for (octets i = 0; i <= 6; i++) { tkey[i] = 255; }  //Load Default Key for all Sectors        if(LearnNewCard) // la nouvelle Carte doit être initialisée.         {           if (WriteNewMiFareClassicPICC()) { SetRGBLed(0,255,0,false); } else { SetRGBLed(255,0,0,false); }         }       else if (EraseCard)  // les données Cartographiques sont supprimés.         {           if (ResetCardToDefault()) { SetRGBLed(0,255,0,false); } else { SetRGBLed(255,0,0,false); }         }             else         {         if (ReadMiFareClassicPICC())            { // Carte valide !           bool PinState= digitalRead(RELAIS_PIN);           PinState = !PinState;           digitalWrite(RELAIS_PIN, PinState);           SetRGBLed(0,255,0,false);        //Led Vert           } else { SetRGBLed(255,0,0,false); }               }       LearnNewCard = false;                     // MiFare_Classic_Processor STOP (mfrc522.uid.sak);       } else if (mfrc522.uid.sak == 0x00) // Mifare Ultralight       {         SetRGBLed(255,0,0,false);       } else       {         SetRGBLed(255,0,0,false);         //Serial.print("PICC Type not supported. Type:");          //Serial.println(mfrc522.uid.sak); //Extension: éventuellement d'autres Types de cartes       }     mfrc522.PCD_StopCrypto1();     mfrc522.PICC_HaltA();     delay(2000);     SetRGBLed(0,0,255,false);        //Led Couleur Bleu Lecteur est en État     }   }   if (millis() - PCD_WatchDog_Handler >= PCD_Watchdog_Interval)    {    PCD_WatchDog_Handler = millis();    Result = mfrc522.PCD_PerformSelfTest();    yield();    mfrc522.PCD_Init();                       // on Initialise MFRC522 module de lecture de nouveau    mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); // Définit l'Antenne de max. Réception    mfrc522.PCD_AntennaOn();     yield();    if (!(Result))      {       PCDHardReset();       Serial.println("ATPCD:ERR_H");     }    }   }

// ******************* Stop Functions CardServices *************************************


 
void loop()  // Boucle principale
{   CardServer();          // Lecteur de carte et les Demandes spécifiques de modifier   yield();    serveur.handleClient(); // Webserveranfragen modifier    //ESP.wdtFeed(); // Watchdog remise à zéro. Désactiver "wdt_disable();"
}

 

La connexion WI-fi gratuite les données de connexion sont conservées, comme nous, dans le précédent Sketch dans une Mémoire non volatile ont passé.

Comment fonctionne maintenant, mais maintenant l'Authentification de la Carte?

Bref, essaie de Kartenlesermodul lors de la présentation d'une Carte de Type MiFare Classic (ceci est Préalablement Vérifié) le Secteur qui valide Clés lire, lire.

L'Action est réussie, les champs nom, Prénom et Nom de famille lu, et la Carte est reconnue comme valide. (Relais est commuté) Est l'Authentification n'aboutit pas ou est la mauvaise Clé, la Carte comme nulle est rejetée.

La Distinction entre "Carte en cours de validité ou Carte non valide" à ce trait, nous les Avantages suivants:

possibilité d'utiliser simultanément plusieurs Cartes à un Lecteur est en droit, sans chaque Carte au Lecteur l'Avance par UUID pour la faire connaître.

Possibilité d'utiliser simultanément plusieurs lecteurs de cartes avec une Carte de dessert sans chaque Lecteur de cartes, chaque Carte déjà à l'Avance par UUID connaît.

Par la Variation de la Sektorendefinition ou du matériel de clé permet de "Berechtigungskreise" sont formés.

 

Nous pouvons maintenant créer notre première carte de pêche. Pour cela nous allons, lors de la connexion sur le Menu "PICC", puis "créer une nouvelle Carte" et cliquez dessus. Nous voyons à la Page suivante:

Nous donner un Avant et un Nom de famille dans les Champs prévus à cet effet, puis appuyez sur le Bouton "Nouvelle carte à Puce de la création"

, La LED jaune est. Nous avons maintenant un VIDE!! Mifare Classic Carte devant le Lecteur et attendre un peu jusqu'à ce que la LED devienne verte. C'est tout! À partir de maintenant, nous sommes, cette Carte est désormais autorisé de la Carte à notre Lecteur à utiliser.

Nous voulons cette Carte invalide faire, nous allons, après le Login sur le Menu PICC, puis, sous "effacer la carte" et cliquez dessus. -- Après le Message:

nous considérons l'autorisation préalable Carte devant le Lecteur. Ce n'est ensuite pas valide.

Amusez-vous à Construire nous jusqu'à la prochaine Partie.

Esp-8266Pour arduinoProjets pour avancéMaison intelligente

Laisser un commentaire

Tous les commentaires sont modérés avant d'être publiés

Messages de blogs recommandés

  1. Installez maintenant ESP32 via l'administrateur de la carte
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA-Over the Air-ESP Programmation par WiFi