Blog van vandaag gaat " down the Rabbit Hole" zoals beloofd en we omgaan met de internals van de MiFare Proximity Integrated Contactloze kaarten (ANP) Nummer. We kijken naar de details en nemen een kijkje op de functies.
Veel Kaartlezer- Projecten waarmee mf522 chipset wordt gebruikt als basis voor de Arduino die ik persoonlijk al heb gezien, helaas noch in de beveiligingstechnologie, noch in mogelijkheden gebruik maken van wat de Mifare Classic kaart biedt ons in functies.
Deze projecten zijn beperkt tot het lezen van de unieke ID (UUID) van de kaart, die vrij kan worden gelezen voor elke kaartlezer en mobiele telefoon, en om het te controleren tegen een lijst van toegestane UUID's. Als deze in de lijst is opgenomen, wordt de kaart als geldig beschouwd.
Ook in onze vorige delen we maken gebruik van dit principe. We willen dit veranderen met onze blog vermelding vandaag en sla gegevens veilig op onze MiFare Classic kaart.
Vanwege het kaarttype "MiFare Classic" dat in dit project wordt gebruikt (let ook op deze notitie), kunnen we onze eigen informatie van de kaart opslaan en beschermen tegen onbevoegd lezen of wijzigen.
Hiervoor heeft de fabrikant al 16 sectoren (0-15) met elk 4 * 16 bytes, met uitzondering van sector 0 , 3 * 16 bytes vrij kunnen worden beschreven. 16 bytes van elke sector worden sectortrailers genoemd en gebruikt om de 2 sectorsleutels te deponeren en de toegangsmatrix te definiëren.
De 16 bytes van een sector trailer zijn als volgt verdeeld:
6 bytes - eerste sectorsleutel
6 bytes - tweede sectorsleutel
4 bytes - definitie van toegangsmachtigingen
We willen nu de voor- en achternaam van ons versleuteld op onze kaart opslaan. Om dit te doen, definiëren we een sector (1-15) via de constante ... die we hiervoor willen gebruiken. Ik koos sectorblok 1 in de code.
De voornaam moet zich in het tweede veld van 16 bytes en de achternaam in het derde veld van 16 bytes bevindt. Het eerste veld van 16 bytes is gereserveerd voor toekomstige extensies.
We hebben ook een belangrijke definitie nodig, die we opslaan in de MiFareClassicKeyTable-structuur.
Wijzig dit blok (2x 6 bytes) met uw eigen sleutelmateriaal tijdens de replica en sla het op een veilige plaats op, anders zal iedereen die dit project kent met het sleutelmateriaal dat in de code in platte tekst wordt vermeld uw kaart lezen en uw eigen geldig lezen! kan kaarten maken voor uw apparaatbediening.
Kleine spoiler: We zullen dit sleutelmateriaal ook weer nodig hebben in een latere voortzetting van de serie. Houd er rekening mee dat u de kaart beschrijft en de beveiligingsopties wijzigt. Als gevolg hiervan is de kaart mogelijk niet meer bruikbaar voor andere doeleinden!
Nadat we het sleutelmateriaal hebben gewijzigd, uploaden we de volgende code naar ons ESP:
#include <Spi.H> #include <MFRC522.H> #include <ESP8266WiFi.H> #include <WiFiClient.h> #include <ESP8266WebServer.H> #include <ESP8266mDNS.H> #include <Eeprom.H> #include <Fs.H> Neem de SPIFFS-bibliotheek op #define RST_PIN 5 SPI Reset-pin (D1-uitvoer) #define RELAIS_PIN 16 Relais (D0-uitgang) [LOW Active] - Ook interne LED in de buurt van USB-poort #define SS_PIN 15 SPI Slave Select Pin #define RGBLED_R 2 Rood (D4-uitvoer) #define RGBLED_G 0 Groen (D3 output) - Ook interne LED op de ESP module #define RGBLED_B 4 Blauw (D2-uitvoer) #define WiFiPwdLen WiFiPwdLen 25 Maximale WiFi-wachtwoordlengte #define STANameLen STANamelen 20 Maximale WiFi SSID lengte #define ESPHostNamelen 20 Maximum aantal tekens ESPHostName #define Keya Waar PICC-vlagdefinitie #define Keyb Keyb Valse PICC-vlagdefinitie #define LED_BUILTIN 16 #define PIN_WIRE_SDA 4 #define PIN_WIRE_SCL 5 #define USED_Sector 1 Kaartsector gebruikt voor authenticatie- en configuratiegegevens (geldig: 1- 15) ADC_MODE(ADC_TOUT); Configureer analoge invoer A0 naar extern. ADC_TOUT (voor externe spanning), ADC_VCC (voor systeemspanning). MFRC522 mfrc522(SS_PIN, RST_PIN); Instantie van MFRC522 maken MFRC522::MIFARE_Key Sleutel; ESP8266WebServer Server(80); Instantie maken van webservers Struct WiFieeprom { Char ESPHostName[ESPHostNamelen]; Char APSTAName[STANameLen STANamelen]; STATION Naam om connect, indien ontopgericht Char WiFiPwd WiFiPwd[WiFiPwdLen WiFiPwdLen]; WiFiPAszwaard, indien definded Char ConfigValid (ConfigValid)[3]; Als Config Vaild is, is tag "TK" vereist" }; Struct MifareClassicKeyTable { Byte Key_A[6] = {0x22,0x44,0xFA 0xFA,0xAB 0xAB,0x90,0x11}; Sleutel voor PICC-kaart u wijzigen. Byte Key_B[6] = {0xFE,0xE1,0xAA,0x3D,0xDF,0x37}; Sleutel voor PICC-kaart u wijzigen. Char ConfigValid (ConfigValid)[3]; Als Config Vaild is, is tag "TK" vereist" }; MifareClassicKeyTable MifareClassicKey; WiFieeprom MyWiFiConfig MyWiFiConfig; Wereldwijd gebruikte variabelen Bool Resultaat = Valse; Bool LearnNewCard = Valse; Bool EraseCard = Valse; Bool ExpirdateActive = Valse; Tekenreeks Achternaam; Tekenreeks Givenname; Tekenreeks Vervaldatum; Tekenreeks Temp; Unsigned Lange Sessionid; Unsigned Lange PCD_ServiceCall_Handler = 0; Unsigned Lange PCD_WatchDog_Handler = 0; uint8_t Gegevensbuffer[18] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; Void Setup() { pinMode(RST_PIN,Output); digitalWrite(RST_PIN,Hoge); pinMode(RELAIS_PIN,Output); pinMode(RGBLED_R,Output); pinMode(RGBLED_G,Output); pinMode(RGBLED_B,Output); digitalWrite(RELAIS_PIN,Hoge); Relais inactief SetRGBLed(255,0,255,Valse); Led Color Purple Initalization Begin Seriële.Beginnen(115200); Serial communicatie met de pc initialiseren met 115200 Baud Seriële.println(""); Temp = "ATSN:"+ Tekenreeks(Ihb.getChipId()); Seriële.println(Temp); Serial.print("ADC-waarde:"); Serial.println(analogRead(A0)); Spi.Beginnen(); Spi-communicatie initialiseren PCDHardReset(); Sessionid = millis(); Resultaat = startWiFiClient startWiFiClient(); InitalizeHTTPServer(); SetRGBLed(0,0,255,Valse); Led Color Blue Initalization voltooid ESP.wdtEnable(WDTO_4S); Watchdog starten } Start Helper/ Optimalisatiefuncties ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************** Void SetRGBLed(Byte RedValue RedValue,Byte Groene waarde,Byte BlueValue,Booleaanse SlowFade) Funkion voor het regelen van de RGB Led { digitalWrite(RGBLED_R,Lage); digitalWrite(RGBLED_G,Lage); digitalWrite(RGBLED_B,Lage); Als (RedValue RedValue == 255) { digitalWrite(RGBLED_R,Hoge); } Als (Groene waarde == 255) { digitalWrite(RGBLED_G,Hoge); } Als (BlueValue == 255) { digitalWrite(RGBLED_B,Hoge); } } Stop Helper/ Optimalisatiefuncties ******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************* Start Functions Webserver ********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** Cookie base routines zijn gebaseerd op GIT fragment: //https://github.com/esp8266/ESPWebServer/blob/master/examples/SimpleAuthentification/SimpleAuthentification.ino Bool is_authentified() { Als (Server.Hasheader("Cookie")){ Cookie gevonden Temp = Server.Header("Cookie"); Serial.println(temp); Tekenreeks SessionStr SessionStr = Tekenreeks(Ihb.getChipId()) + "=" + Tekenreeks(Sessionid); Opbrengst(); Als (Temp.Indexof(SessionStr SessionStr) != -1) { Webverificatie geslaagd Temp = ""; Terug Waar; } } Webverificatie is mislukt Temp = ""; Sessionid = millis(); Terug Valse; } Void handleLogin(){ Tekenreeks Msg; Tekenreekscookie = server.header("Cookie"); Serial.println(cookie); Als (Server.hasArg hasArg("LOSKOPPELEN")){ Verbinding gebruiker ontkoppelen; Server.sendHeader("Locatie","/login"); Server.sendHeader("Cache-Control","no-cache"); Sessionid = millis(); Temp = Tekenreeks(Ihb.getChipId()) + "= NA ; HttpOnly ; SameSite=Strict"; Server.sendHeader("Stel cookie",Temp); Temp = ""; Server.Verzenden(301); Opbrengst(); Terug; } Als (Server.hasArg hasArg("GEBRUIKERSNAAM") && Server.hasArg hasArg("WACHTWOORD")){ Temp = Tekenreeks(Ihb.getChipId()); Als (Server.Slechte("GEBRUIKERSNAAM") == "Admin" && Server.Slechte("WACHTWOORD") == Temp ){ Server.sendHeader("Locatie","/"); Server.sendHeader("Cache-Control","no-cache"); Sessionid = millis(); Temp = Tekenreeks(Ihb.getChipId()) + "=" + Tekenreeks(Sessionid) + "; HttpOnly ; SameSite=Strict"; Server.sendHeader("Stel cookie",Temp); Temp = ""; Server.Verzenden(301); Opbrengst(); Terug; } Msg = "<script>alert('Verkeerde gebruikersnaam of wachtwoord !'); </script>"; } CSS_Header_Template(); Opbrengst(); Temp = "<head><title>Login</title><head><body><DIV ALIGN=CENTER>"; Server.sendContent(Temp); Temp = "<h2>Registratie bij kaartlezer RC522</h2><body><br><br><br>table border=0 bgcolor=black><<tr><th><DIV ALIGN=RIGHT>"; Server.sendContent(Temp); Temp = "<formulieractie='/login'-methode='post'>Gebruikersnaam: <invoertype=tekst Naam='GEBRUIKERSNAAM' Grootte=17 vereist><br>"; Server.sendContent(Temp); Temp = "Wachtwoord: <input type=password Name='PASSWORD' Size=17 required><br><br><<br><br><button type=submit' "; Server.sendContent(Temp); Temp = "naam='Login_Button' value='1' style='hoogte: 30px; breedte: 100px' >Login</button><br></th></tr></form></DIV></table>"; Server.sendContent(Temp); Temp = "<br><SMALL>Om in te loggen moet cookies voor deze website worden toegestaan.</SMALL>"; Server.sendContent(Temp); Temp = Msg + "</DIV></body></HTML>"; Server.sendContent(Temp); Temp = ""; } Void handleNotFound() { Sessionid = millis(); Temp = "Pagina niet gevonden.; Temp += "URI: "; Temp += Server.Uri(); Temp += "AnMethod: "; Temp += (Server.Methode() == HTTP_GET)?"GET":"POST"; Temp += "AnArguments: "; Temp += Server.Args(); Temp += "Een"; Voor (uint8_t I.=0; I.<Server.Args(); I.++){ Temp += " " + Server.argName(I.) + ": " + Server.Slechte(I.) + "Een"; } Opbrengst(); Server.Verzenden(404, "tekst/vlakte", Temp); Temp = ""; } Void handleErasePICC() { Als (!is_authentified()) { Server.sendHeader("Locatie","/login"); Server.sendHeader("Cache-Control","no-cache"); Server.Verzenden(301); Opbrengst(); Terug; } CSS_Header_Template(); Opbrengst(); Temp = "<head><title>Kaartlezer RC522</title><head><body>"; Server.sendContent(Temp); HtmlNavStructure(); Temp = "<script>alert('Houd de kaart nu voor de lezer verwijderd!'); </script>"; Server.sendContent(Temp); Opbrengst(); SetRGBLed(0,255,255,Valse); Led-kleurcyaanprogrammeermodus EraseCard = Waar; Temp = "</body></html>"; Server.sendContent(Temp); Server.Client().Stoppen(); Temp = ""; } Void handleNewPICC() { Als (!is_authentified()) { Server.sendHeader("Locatie","/login"); Server.sendHeader("Cache-Control","no-cache"); Server.Verzenden(301); Terug; } Als (Server.hasArg hasArg("Achternaam") && Server.hasArg hasArg("Givenname")) { Achternaam = Server.Slechte("Achternaam"); Givenname = Server.Slechte("Givenname"); Vervaldatum = Server.Slechte("ExpDate"); Als (Server.hasArg hasArg("ExpDateOption")) { ExpirdateActive = Waar; } Anders { ExpirdateActive = Valse; } Temp = "<script>alert('Houd de nieuwe kaart nu voor de lezer!'); </script>"; Server.sendContent(Temp); SetRGBLed(255,255,0,Valse); Led-kleur gele programmeermodus LearnNewCard = Waar; Opbrengst(); Terug; } CSS_Header_Template(); Opbrengst(); Temp = "<head><title>Kartenleser RC522</title><head><body>"; Server.sendContent(Temp); HtmlNavStructure(); Temp = ""; Temp = "<br><br><br><br><table border=0 ALIGN=CENTER><th>"; Server.sendContent(Temp); Temp = "<table border=1 bgcolor = black><form action='/newPICC' method='post'>"; Server.sendContent(Temp); Temp = "<tr><th>Karteninhaber:<br><div ALIGN=RIGHT>"; Server.sendContent(Temp); Temp = "Vorname: <input type=text Name='Surname' Size=17 maxlenght=16 placeholder='Max' required><br>"; Server.sendContent(Temp); Temp = "Nachname: <input type=text Name='Givenname' Size=17 maxlenght=16 placeholder='Mustermann' required><br>"; Server.sendContent(Temp); Temp = "</div></th><th>Kartenmetadaten:<br><DIV ALIGN=RIGHT>"; Server.sendContent(Temp); Temp = "<input Name='ExpDateOption' TYPE=checkbox WAARDE=1 >Ablaufdatum:<invoertype=datum Naam='ExpDate' Grootte = 17 >"; Server.sendContent(Temp); Temp = "<br><th><tr><th></table><br>"; Server.sendContent(Temp); Temp = "<button type='submit' name='NewCard' value='1' style='height: 30px; breedte: 200px' >Neue Smartcard erstellen</button>"; Server.sendContent(Temp); Temp = "<br></form></tr></th></table>"; Server.sendContent(Temp); Temp = "</body></html>"; Server.sendContent(Temp); Server.Client().Stoppen(); Opbrengst(); Temp = ""; } Void handleRoot() { Als (!is_authentified()){ Server.sendHeader("Locatie","/login"); Server.sendHeader("Cache-Control","no-cache"); Server.Verzenden(301); Terug; } HTML-inhoud CSS_Header_Template(); Opbrengst(); Temp = "<head><title>Kartenleser RC522</title><head><body>"; Server.sendContent(Temp); HtmlNavStructure(); Temp = "<div ALIGN=CENTER><br><br><br><br><BIG>Willkommen auf der Smartkartenleser RC522 Webseite.</BIG><br>"; Server.sendContent(Temp); Temp = "Resetgrund: " + Tekenreeks(Ihb.getResetReason()) + "<br>"; Server.sendContent(Temp); Temp = "Freier Heapspeicher: " + Tekenreeks(Ihb.getFreeHeap()) + " Bytes<br>"; Server.sendContent(Temp); Temp = "Int. Flash: " + Tekenreeks(Ihb.getFlashChipRealSize()) + " Bytes<br>"; Server.sendContent(Temp); Resultaat = mfrc522.PCD_PerformSelfTest(); mfrc522.PCD_Init(); Initialisiere MFRC522 Lesemodul mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); Setzt Antenne auf max. Empfang Empfang Empfang mfrc522.PCD_AntennaOn(); Opbrengst(); Als (Resultaat) {Temp = "RC522 PCD-Status: OK<br>"; } Anders {Temp = "RC522 PCD-Status: Fehler!<br>"; } Server.sendContent(Temp); Temp = "CPU-ID: " + Tekenreeks(Ihb.getChipId()) + " @ " + Tekenreeks(Ihb.getCpuFreqMHz getCpuFreqMHz()) + " MHz<br>"; Server.sendContent(Temp); Temp = "<br>Sie sind erfolgreich angemeldet !<br><br><form action='/login' methode='get'>"; Server.sendContent(Temp); Temp = "<button type='submit' name='DISCONNECT' value='YES' style='height: 30px; breedte: 200px' >Afmelden</button>"; Server.sendContent(Temp); Temp = "</form></div></body></html>"; Server.sendContent(Temp); Als (Server.hasArg hasArg("Reboot") ) Opnieuw opstarten van systeem { ESP.wdtFeed(); Ihb.wdtUitschakelen(); Temp = "<script>alert('Das System startet JETZT neu.'); </script>"; Server.sendContent(Temp); Server.Client().Stoppen(); Opbrengst(); Temp = ""; Ihb.Opnieuw instellen(); Vertraging(4000); } Server.Client().Stoppen(); Temp = ""; } Void CSS_Header_Template() Formatvorlage für alle internen ESP Webseiten. https://wiki.selfhtml.org/wiki/CSS { Server.setContentLength(CONTENT_LENGTH_UNKNOWN); Temp = ""; Server.Verzenden (200, "tekst/html", Temp); Temp = "<! DOCTYPE HTML PUBLIC '-/-/W3C/DTD HTML 4.01 Transitional/EN'><html lang='de'><meta charset='UTF-8'>"; Server.sendContent(Temp); Temp = "<style type='text/css'>*{marge: 0;padding: 0;} body{background:black;color:darkorchid;font-size: 16px;" ; server. sendContent(temp); temp = font-family: sans-serif,arial;}. nav{width: 1300px;hoogte: 30px;marge: 0 auto;randstraal: 5px;}"; Server.sendContent(Temp); Temp = "ul li{list-style: none;width: 200px;line-height: 60px;position: relative;background: darkorchid;" ; server. sendContent(temp); temp = "box-shadow: 0px 2px 5px 0px 0px grijs;tekst-align: center;float: left;background-color: #010000;} ul li ul{"; Server.sendContent(Temp); Temp = "positie: absoluut;}. nav > ul > li:nth-of-type(1){border-radius: 5px 0px 0px 5px;}. nav > ul > li:nth-of-type(5)"; Server.sendContent(Temp); Temp = "{border-radius: 0px 5px 5px 0px;} ul li a{kleur: rgb(182, 18, 18);width: 200px;height: 58px;display: inline-block;" ; server. sendContent(temp); temp = tekstdecoratie: geen;} ul li a:hover{font-weight: bold;border-bottom: 2px solid #fff;} ul li ul{display: none;}"; Server.sendContent(Temp); Temp = ".nav ul li:hover ul{display: block;}. fa{marge-rechts: 5px;}. container{breedte: 1000px;hoogte: 200px;" ; server. sendContent(temp); temp = "margin: 0 auto;padding:20px 20px;} @media scherm en (maximale breedte: 480px){header{width: 100%;}"; Server.sendContent(Temp); Temp = ".nav{display: none;width: 100%;height: auto;} ul li{breedte: 100%;float: geen;} ul li a{breedte: 100%;" ; server. sendContent(temp); temp = "display: block;} ul li ul{positie: statisch;} ul li ul li a{achtergrond: #222;}. fa-list.modify{display: block;}"; Server.sendContent(Temp); Temp = ".container{breedte: 100%;hoogte: auto;} body{overflow-x:hidden;}} </stijl>"; Server.sendContent(Temp); Temp = ""; } Void HtmlNavStructure() { Temp = "<div class='menu'><nav class='nav'><ul>"; Server.sendContent(Temp); Temp = "<li><a href='#'>System</a>"; Server.sendContent(Temp); Temp = "<ul><li><a href="/nl">Informatie</a></li>"; Server.sendContent(Temp); Temp = "<li><a href="/nl/? Reboot=YES">Neustart</a></li>"; Server.sendContent(Temp); Temp = "</ul>"; Server.sendContent(Temp); Temp = "</li><li><a href='#'>PICC</a>"; Server.sendContent(Temp); Temp = "<ul><li><a href="/nl/newPICC">Neue Karte erstellen</a></li>"; Server.sendContent(Temp); Temp = "<li><a href="/nl/erasePICC">Karte löschen</a></li></ul>"; Server.sendContent(Temp); Temp = "</li>"; temp = "</li><li><a href='#'>Ereignisprotokoll</a></li>"; Server.sendContent(Temp); Temp = "</ul></nav></div>"; Server.sendContent(Temp); Temp = ""; } Void InitalizeHTTPServer() { Bool initok = Valse; Const Char * koptoetsen[] = {"User-Agent","Cookie"} ; Kop zum Tracken size_t headerkeyssize = grootte van(koptoetsen)/grootte van(Char*); Kop zum Tracken Server.Op("/", handleRoot); Server.Op("/login", handleLogin); Server.Op("/newPICC", handleNewPICC); Server.Op("/erasePICC", handleErasePICC); Server.onNotFound ( handleNotFound ); Server.collectHeaders(koptoetsen, headerkeyssize );Server anweisen, diese zu Tracken Server.Beginnen(); Webserver starten } ******************** Eindfuncties webserver ************************************************************************************************************************************************************************************ ******************* Startfuncties WiFi Management ***************************************************************************************************************************************************************** Funktion von https://www.az-delivery.de/blogs/azdelivery-blog-fur-arduino-und-raspberry-pi/wps-mit-dem-esp8266?ls=de Bool startWPS() { Bool wpsSucces = Wifi.beginWPSConfig(); Als(wpsSucces) { Muss nicht immer erfolgreich heißen! Nach einem Timeout ist die SSID leer Tekenreeks newSSID = Wifi.Ssid(); Als(newSSID.Lengte() > 0) { Nur wenn eine SSID gefunden wurde waren wir erfolgreich Opbrengst(); Seriële.println("ATWPS:OK"); referenties opslaan(); Referenties opslaan bij EEPROM } Anders { Seriële.println("ATWPS:NOK"); } } Terug wpsSucces; } Bool startWiFiClient startWiFiClient() { Bool WiFiClientGestart = Valse; size_t A0_ADCValue = 0; Byte I = 0; Byte connRes connRes = 0; Seriële.setDebugOutput(Valse); Zu Debugzwecken aktivieren. Wifi.Hostname("CrdRdr41667"); Wifi.softAPdisconnect(Waar); Wifi.Verbreken(); Wifi.Modus(WIFI_STA); Als(loadCredentials()) { Wifi.Beginnen(MyWiFiConfig MyWiFiConfig.APSTAName, MyWiFiConfig MyWiFiConfig.WiFiPwd WiFiPwd); Terwijl (( connRes connRes != 3 ) En( connRes connRes != 4 ) En (I != 30)) als connRes == 0 "IDLE_STATUS - change Statius" { I++; Serial.print("."; Connect vorgang auf der seriellen Schnittstelle beobachten ESP.wdtFeed(); Vertraging(500); Opbrengst(); connRes connRes = Wifi.waitForConnectResult(); } Als (connRes connRes == 4 ) { als het wachtwoord onjuist is Seriële.println("ATWIFI:PWDERR"); Wifi.Verbreken(); } Als (connRes connRes == 6 ) { module is niet geconfigureerd in stationsmodus Seriële.println("ATWIFI:STAERR"); Wifi.Verbreken(); } } Als(Wifi.Status() == WL_CONNECTED) { ESP.wdtFeed(); Seriële.Afdrukken("ATIP:"); Seriële.println(Wifi.localIP()); Wifi.setAutoReconnect(Waar); Stel in of de module probeert opnieuw verbinding te maken met een toegangspunt voor het geval de verbinding wordt verbroken. MDNS-responder instellen Als (!Mdns.Beginnen("CrdRdr41667")) { Seriële.println("ATMDNS:NOK"); } Anders { Mdns.addService("http", "tcp", 80); } WiFiClientGestart = Waar; } Anders { A0_ADCValue = analoogLezen(A0); Wir waren nicht erfolgreich, daher starten wir WPS, wenn WPS Taster an A0 während des Resets gedrückt ist Als (A0_ADCValue > 499) { Als(startWPS()) { ESP.wdtFeed(); Vertraging(500); Wifi.Verbreken(); Wifi.Modus(WIFI_STA); Wifi.Beginnen(Wifi.Ssid().c_str(), Wifi.Psk().c_str()); ESP.wdtFeed(); WiFiClientGestart = Waar; } Anders { WiFiClientGestart = Valse; Wifi.Verbreken(); } } Anders { Wifi.Verbreken(); } } WiFi.printDiag(Serieel); Zu Debugzwecken aktivieren. Terug WiFiClientGestart; } ******************** Eindfuncties WiFi Management **************************************************************************************************************************************************************** ******************* Startfuncties WiFi-referenties opslaan bij EEPROM ******************** Bool loadCredentials() { Bool RetValue; Eeprom.Beginnen(512); Eeprom.Toevoegen(0,MyWiFiConfig MyWiFiConfig); Eeprom.Einde(); Als (Tekenreeks(MyWiFiConfig MyWiFiConfig.ConfigValid (ConfigValid)) == "TK") { RetValue = Waar; } Anders { RetValue = Valse; WLAN Settings nicht gefunden. } ESP.wdtFeed(); Terug RetValue; } Void referenties opslaan() Speichere WLAN geloofsbrieven auf EEPROM { size_t I; Voor (I = 0 ; I < grootte van(MyWiFiConfig MyWiFiConfig) ; I++) Loeschen der alten Konfiguration { Eeprom.Schrijven(I, 0); } Voor (I = 0 ; I < STANameLen STANamelen ; I++) Loeschen der alten Konfiguration { MyWiFiConfig MyWiFiConfig.WiFiPwd WiFiPwd[I] = 0; } Voor (I = 0 ; I < WiFiPwdLen WiFiPwdLen ; I++) Loeschen der alten Konfiguration { MyWiFiConfig MyWiFiConfig.APSTAName[I] = 0; } Temp = Wifi.Ssid().c_str(); I = Temp.Lengte(); Temp.toCharArray(MyWiFiConfig MyWiFiConfig.APSTAName,I+1); Temp = Wifi.Psk().c_str(); I = Temp.Lengte(); Temp.toCharArray(MyWiFiConfig MyWiFiConfig.WiFiPwd WiFiPwd,I+1); Temp = ""; strncpy strncpy(MyWiFiConfig MyWiFiConfig.ConfigValid (ConfigValid) , "TK", grootte van(MyWiFiConfig MyWiFiConfig.ConfigValid (ConfigValid)) ); Eeprom.Beginnen(512); Eeprom.zet(0, MyWiFiConfig MyWiFiConfig); Eeprom.Commit(); Eeprom.Einde(); ESP.wdtFeed(); } ******************** EINDfuncties StoreCredentialsto EEPROM ****************************************************************************************************************************************** ****************** Start functies Cardservices **************************************************************************************************************************************************************** Void PCDHardReset() { digitalWrite(RST_PIN,Lage); Vertraging(200); digitalWrite(RST_PIN,Hoge); mfrc522.PCD_Reset(); mfrc522.PCD_Init(); Initialisiere MFRC522 Lesemodul mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); Setzt Antenne auf max. Empfang Empfang Empfang mfrc522.PCD_AntennaOn(); } Booleaanse CardAuthenticate(Booleaanse ABKey ABKey, Byte Sector,Byte Ikey[6]) { Const Byte sectorsleutelbaar [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63}; Byte statusA; statusA = 0; Voor (Int A = 0; A < 6;A++) { Sleutel.keyByte[A] = Ikey[A]; } Sleutel A Als (ABKey ABKey) { statusA = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, sectorsleutelbaar[Sector], &Sleutel, &(mfrc522.Uid)); Als (statusA != MFRC522::STATUS_OK) { Seriële.println("ATAUTH:ERR_A"); Terug Valse; } } Sleutel B Anders Als (Niet ABKey ABKey) { statusA = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B,sectorsleutelbaar[Sector], &Sleutel, &(mfrc522.Uid)); Als (statusA != MFRC522::STATUS_OK) { Seriële.println("ATAUTH:ERR_B"); Terug Valse; } } Terug Waar; } WriteData . gebruikt Global Variable DataBuffer voor datareturn Booleaanse CardDataWrite CardDataWrite(Byte Sector,Byte Blok,Byte Waarde[16]) { Byte Status; Byte schrijfvector; Byte sectorsleutelbaar [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63}; schrijfvector = Sector * 4 + Blok -1 ; Voor (Byte A = 0; A < 16; A++) { Als (schrijfvector == sectorsleutelbaar[A]) { Serial.println("NAK"; Terug Valse; } } Status = mfrc522.MIFARE_Write(schrijfvector, Waarde, 16); Als (Status != MFRC522::STATUS_OK) { Seriële.println("ATPCD:W_ERR"); Serial.println(mfrc522. GetStatusCodeName(status)); Terug Valse; } Anders { Serial.print("OK"); Terug Waar; } } Leesgegevens - gebruikt Globale variabele databuffer voor gegevensretour Booleaanse CardDataRead(Byte Sector,Byte Blok) { Byte statusi; Byte leesvector; Const Byte sectorsleutelbaar [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63}; Byte Formaat = 18; leesvector = Sector * 4 + Blok -1 ; Voor (Byte A = 0; A < 16; A++) { Als (leesvector == sectorsleutelbaar[A]) { Seriële.println("ATPCD:R_ERR"); Terug Valse; } } statusi = mfrc522.MIFARE_Read(leesvector, Gegevensbuffer, &Formaat); Als (statusi != MFRC522::STATUS_OK) { Seriële.println("ATPCD:R_ERR"); Terug Valse; } Anders { Terug Waar; } } Booleaanse ResetCardtoDefault() { Byte Ikey[16]; Byte Status,I; Byte schrijfvector; Const Byte sectorsleutelbaar [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63}; schrijfvector = sectorsleutelbaar[USED_Sector]; Als (CardAuthenticate(KEYB,USED_Sector,MifareClassicKey.Key_B)) Sector Autenticate voor WRITE Access { Voor (I = 0; I <= 16; I++) { Gegevensbuffer[I] = 0; } Als (!(CardDataWrite CardDataWrite(USED_Sector,1,Gegevensbuffer))) { Terug Valse; } Voor (I = 0; I <= 16; I++) { Gegevensbuffer[I] = 0; } Als (!(CardDataWrite CardDataWrite(USED_Sector,2,Gegevensbuffer))) { Terug Valse; } Voor (I = 0; I <= 16; I++) { Gegevensbuffer[I] = 0; } Als (!(CardDataWrite CardDataWrite(USED_Sector,3,Gegevensbuffer))) { Terug Valse;} } Voor (Byte I = 0; I <= 16; I++) { Ikey[I] = 255; } Standaardsleutel laden voor alle sectoren Ikey[6] = 0xFF; Standaardinstelling voor Access Bits Ikey[7] = 0x07; // Ikey[8] = 0x80; // Ikey[9] = 0x69; Status = mfrc522.MIFARE_Write(schrijfvector, Ikey, 16); Als (Status != MFRC522::STATUS_OK) { Terug Valse; } Terug Waar; } Booleaanse SetSectorAccessControl (Byte Sector,Byte Akey[6],Byte Bkey Bkey[6]) { Byte Ikey[16]; Byte Status; Byte schrijfvector; Const Byte sectorsleutelbaar [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63}; schrijfvector = sectorsleutelbaar[Sector]; 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; Data block 0-3 Toegangsvoorwaarden: Key B schrijven / Key A Lezen Ikey[7] = 0x77; KEY A & KEY B & Acces Bits Schrijven:Key B / Key A Leestoegang Bits Ikey[8] = 0x88; Calculator: http://calc.gmss.ru/Mifare1k/ Ikey[9] = 0x69; Fixer Wert - > standaard hex 69 Ikey[10] = Bkey Bkey[0]; Ikey[11] = Bkey Bkey[1]; Ikey[12] = Bkey Bkey[2]; Ikey[13] = Bkey Bkey[3]; Ikey[14] = Bkey Bkey[4]; Ikey[15] = Bkey Bkey[5]; Status = mfrc522.MIFARE_Write(schrijfvector, Ikey, 16); Als (Status != MFRC522::STATUS_OK) { Seriële.println("ATPCD:W_KEY_ERR"); Terug Valse; }Anders { Terug Waar; } } Booleaanse CheckforDefaultCardKey () { Byte tkey[6]; Booleaanse Kaartresultaat; Byte leesvector; Byte statusi; Const Byte sectorsleutelbaar [16] = {3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63}; Byte Formaat = 18; Voor (Byte I = 0; I <= 6; I++) { tkey[I] = 255; } Standaardsleutel laden voor alle sectoren Kaartresultaat = Waar; Als (!CardAuthenticate(Keya,USED_Sector,tkey)) { Kaartresultaat = Valse; }; leesvector = sectorsleutelbaar[USED_Sector]; statusi = mfrc522.MIFARE_Read(leesvector, Gegevensbuffer, &Formaat); Als (statusi != MFRC522::STATUS_OK) { Kaartresultaat = Valse; } als (!) (DataBuffer[7] = 0x07) & (DataBuffer[7] = 0x80)) { CardResult = false; }; Terug Kaartresultaat; } Booleaanse WriteNewMiFareClassicPICC () { Byte tkey[6]; Byte I,A; Booleaanse Kaartresultaat; Als (CheckforDefaultCardKey()) { Voor (I = 0; I <= 6; I++) { tkey[I] = 255; } Standaardsleutel laden voor alle sectoren Voor (I = 0; I <= 16; I++) { Gegevensbuffer[I] = 0; } Variabele buffer wissen Kaartresultaat = Waar; Als (CardAuthenticate(Keya,USED_Sector,tkey)) Sector Autenticate { Serial.println("Auth Sec 0 OK"); Als (Achternaam.Lengte() > 15) { A = 15; } Anders { A = Achternaam.Lengte();} Als (Achternaam.Lengte() > 0) { Voor (I = 0; I <= 16; I++) { Gegevensbuffer[I] = 0; } Voor (I = 0; I <= A; I++) { Gegevensbuffer[I] = Achternaam[I]; } Als (!(CardDataWrite CardDataWrite(USED_Sector,2,Gegevensbuffer))) { Kaartresultaat = Valse; } Sector 0 Blok 2 Vorname mit Key A schreiben } Als (Givenname.Lengte() > 15) { A = 15; } Anders { A = Givenname.Lengte(); } Als (Givenname.Lengte() > 0) { Voor (I = 0; I <= 16; I++) { Gegevensbuffer[I] = 0; } Voor (I = 0; I <= A; I++) { Gegevensbuffer[I] = Givenname[I]; } Als (!(CardDataWrite CardDataWrite(USED_Sector,3,Gegevensbuffer))) { Kaartresultaat = Valse; } Sector 0 Blok 3 Nachname mit Key A schreiben } Als (!(SetSectorAccessControl (USED_Sector,MifareClassicKey.Key_A,MifareClassicKey.Key_B))) { Kaartresultaat = Valse; } (bytesector,byte Akey[6],byte Bkey[6]) } Anders { Kaartresultaat = Valse; Terug Kaartresultaat; } } Anders { Kaartresultaat = Valse; Terug Kaartresultaat; } Als (Kaartresultaat) { Serial.println("PICC geschreven"; Kaartresultaat = Waar; } Anders { Serial.println("PICC niet leeg"); Kaartresultaat = Valse; } Opbrengst(); Terug Kaartresultaat; } Booleaanse ReadMiFareClassicPICC () { Booleaanse Kaartresultaat; Byte I,A ; Kaartresultaat = Waar; Als (CardAuthenticate(Keya,USED_Sector,MifareClassicKey.Key_A)) Sector Autenticate met LEES Sleutel A { Givenname = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; Tijdelijke aanduiding Achternaam = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa; Tijdelijke aanduiding Voor (I = 0; I < 18; I++) { Gegevensbuffer[I] = 0; } Variabele buffer wissen Als (CardDataRead(USED_Sector,2)) Feld Vorname auslesen { Voor (I = 0; I < 16; I++) { Achternaam[I] = Char(Gegevensbuffer[I]); } } Anders { Terug Valse; } Voor (I = 0; I < 18; I++) { Gegevensbuffer[I] = 0; } Variabele buffer wissen Als (CardDataRead(USED_Sector,3)) Feld Nachname auslesen { Voor (I = 0; I < 16; I++) { Givenname[I] = Char(Gegevensbuffer[I]); } } Anders { Terug Valse; } } Anders { Terug Valse; } Seriële.Afdrukken ("ATAUTH_S:"); Seriële.println (Achternaam); Seriële.Afdrukken ("ATAUTH_G:"); Seriële.println (Givenname); Terug Waar; } Void CardServer() { #define PCD_Poll_Interval 400 #define PCD_Watchdog_Interval 60000 Als (millis() - PCD_ServiceCall_Handler >= PCD_Poll_Interval) { PCD_ServiceCall_Handler = millis(); Als (mfrc522.PICC_IsNewCardPresent()) PICC = nabijheid geïntegreerde circuitkaart = kontaktlose Chipkarte { mfrc522.PICC_ReadCardSerial(); Opbrengst(); Unterscheidung nach Kartentyp 0x08 für MIFARE Classic 1K 0x18 für MIFARE Classic 4K 0x11 für MIFARE PLUS Als (mfrc522.Uid.Sak == 0x08 || mfrc522.Uid.Sak == 0x18) { MiFare_Classic_Processor START (mfrc522.uid.sak); Nur ausführen wenn Eine Mifare Classic Karte vor den Leser gehalten wurde. Byte tkey[6]; Voor (Byte I = 0; I <= 6; I++) { tkey[I] = 255; } Standaardsleutel laden voor alle sectoren Als(LearnNewCard) neue Karte soll angelernt werden. { Als (WriteNewMiFareClassicPICC()) { SetRGBLed(0,255,0,Valse); } Anders { SetRGBLed(255,0,0,Valse); } } Anders Als (EraseCard) KartenDaten sollen gelöscht werden. { Als (ResetCardtoDefault()) { SetRGBLed(0,255,0,Valse); } Anders { SetRGBLed(255,0,0,Valse); } } Anders { Als (ReadMiFareClassicPICC()) { Karte gültig ! Bool PinState= digitaalLezen(RELAIS_PIN); PinState = !PinState; digitalWrite(RELAIS_PIN, PinState); SetRGBLed(0,255,0,Valse); Led Grün } Anders { SetRGBLed(255,0,0,Valse); } } LearnNewCard = Valse; MiFare_Classic_Processor STOP (mfrc522.uid.sak); } Anders Als (mfrc522.Uid.Sak == 0x00) Mifare Ultralight { SetRGBLed(255,0,0,Valse); } Anders { SetRGBLed(255,0,0,Valse); Serial.print("PICC Type niet ondersteund. Type:"); Serial.println(mfrc522.uid.sak); Erweiterung: evtl andere Kartentypen } mfrc522.PCD_StopCrypto1(); mfrc522.PICC_HaltA(); Vertraging(2000); SetRGBLed(0,0,255,Valse); Led Farbe Blau Leser ist in Grundzustand } } Als (millis() - PCD_WatchDog_Handler >= PCD_Watchdog_Interval) { PCD_WatchDog_Handler = millis(); Resultaat = mfrc522.PCD_PerformSelfTest(); Opbrengst(); mfrc522.PCD_Init(); Initialiseer MFRC522 Leesmodule opnieuw mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); Stelt antenne op max. ontvangst mfrc522.PCD_AntennaOn(); Opbrengst(); Als (!(Resultaat)) { PCDHardReset(); Seriële.println("ATPCD:ERR_H"); } } } Stop functies CardServices *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** Void Lus() Hoofdlus { CardServer(); Kaartlezer om specifieke aanvragen af te handelen Opbrengst(); Server.handleClient(); Aanvragen voor webserver bewerken ESP.wdtFeed(); Watchdog. Uitschakelen met "wdt_disable();" }
De Wlan-verbindingsgegevens blijven behouden omdat we deze in een niet-vluchtig geheugen in de vorige schets hebben opgeslagen.
Maar hoe werkt de authenticatie van de kaart nu?
Simpel gezegd, bij het houden van een MiFare Classic kaart (dit is van tevoren gecontroleerd), de kaartlezer module probeert te lezen een sector die alleen kan worden gelezen met een geldige sleutel.
Als de actie is geslaagd, worden de voornaam en achternaam van de naamvelden voorgelezen en wordt de kaart als geldig herkend. (relais is ingeschakeld) Als verificatie mislukt of de verkeerde sleutel wordt gebruikt, wordt de kaart afgewezen als ongeldig.
Het onderscheid tussen "kaart geldig of kaart ongeldig" op deze eigenschap geeft ons de volgende voordelen:
Meerdere kaarten kunnen recht hebben op een lezer op hetzelfde moment, zonder welke elke kaart moet worden bekend gemaakt aan de lezer op voorhand door UUID.
Verschillende kaartlezers kunnen worden bediend met een kaart op hetzelfde moment zonder dat elke kaartlezer al weten elke kaart op voorhand via UUID.
Door de sectordefinitie of het sleutelmateriaal te variëren, kunnen "toestemmingscirkels" worden gevormd.
We zijn nu het creëren van onze eerste autorisatiekaart. Om dit te doen, na het inloggen op het menu-item "PICC", dan "Maak een nieuwe kaart" en klik erop. We zien de volgende pagina:
We voeren een voor- en achternaam in de aangewezen velden in en drukken op de knop 'Maak een smartcard maken'
De LED kleurt geel. We hebben nu een LEERE!! Mifare Classic kaart voor de lezer en wacht kort tot de LED groen wordt. Dat is het! Vanaf nu kunnen we deze kaart gebruiken als geautoriseerde kaart voor onze lezer.
Als we deze kaart willen ongeldig maken, gaan we na het inloggen op het menu-item PICC onder 'Kaart verwijderen' en klikken erop. -- Na het bericht:
we houden de eerder geautoriseerde kaart terug voor de lezer. Dit is dan ongeldig.
Veel plezier met het recreëren van ons tot het volgende deel.