2024年1月14日 星期日

ESP32(Arduino) + MFRC522 讀寫 固定 secotor , block S50復旦卡鑰匙扣模組

ESP32(Arduino) + MFRC522 讀寫 固定 secotor , block  S50復旦卡鑰匙扣模組


源自於 https://www.cnblogs.com/eagler8/p/15903039.html



/* Wiring RFID RC522 module
==============================================================
GND     = GND   3.3V    = 3.3V
The following table shows the typical pin layout used:
 *             MFRC522      ESP32    
 *             Reader/PCD            
 * Signal      Pin          Pin      
 * ------------------------------------
 * RST/Reset   RST          GPIO27  
 * SPI SS      SDA(SS)      GPIO5    
 * SPI MOSI    MOSI         GPIO23    
 * SPI MISO    MISO         GPIO19    
 * SPI SCK     SCK          GPIO18    
 */
//====================================================


Scan a MIFARE Classic PICC to demonstrate read and write.

Using key (for A and B):FF FF FF FF FF FF 

開始讀卡

PICC type: MIFARE 1KB

The NUID tag is:86 D5 EA 6A 

Card UID: 86 D5 EA 6A

Card SAK: 08

PICC type: MIFARE 1KB

Sector Block   0  1  2  3   4  5  6  7   8  9 10 11  12 13 14 15  AccessBits

  15     63   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         62   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         61   4B 65 65 70  20 48 61 63  6B 69 6E 67  21 00 00 00  [ 0 0 0 ] 

         60   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

  14     59   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         58   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         57   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         56   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

  13     55   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         54   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         53   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         52   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

  12     51   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         50   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         49   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         48   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

  11     47   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         46   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         45   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         44   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

  10     43   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         42   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         41   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         40   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

   9     39   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         38   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         37   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         36   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

   8     35   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ]

         34   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         33   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         32   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ]   

   7     31   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         30   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         29   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         28   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

   6     27   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         26   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         25   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         24   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

   5     23   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         22   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         21   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         20   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

   4     19   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         18   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         17   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         16   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

   3     15   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         14   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         13   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

         12   00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

   2     11   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

         10   2B 39 32 33  30 30 34 34  34 37 37 37  37 20 20 20  [ 0 0 0 ] 

          9   32 38 2D 30  39 2D 31 39  38 39 20 20  20 20 20 20  [ 0 0 0 ] 

          8   4A 68 6F 6E  20 41 62 72  61 68 75 6D  20 20 20 20  [ 0 0 0 ] 

   1     7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

          6   41 6E 74 68  6F 6E 79 20  20 20 20 20  20 20 20 20  [ 0 0 0 ] 

          5   20 20 20 20  20 20 20 20  20 20 20 20  20 20 00 00  [ 0 0 0 ] 

          4   0A 6D 61 72  6B 20 20 20  20 20 20 20  20 20 20 20  [ 0 0 0 ] 

   0      3   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

          2   20 20 20 20  20 20 20 20  20 20 20 20  20 20 00 00  [ 0 0 0 ] 

          1   61 6C 65 78  20 20 20 20  20 20 20 20  20 20 20 20  [ 0 0 0 ] 

          0   86 D5 EA 6A  D3 08 04 00  62 63 64 65  66 67 68 69  [ 0 0 0 ]   


#include <SPI.h>
#include <MFRC522.h>
 
#define RST_PIN 27  // Configurable, see typical pin layout above
#define SS_PIN  5  // Configurable, see typical pin layout above
/* Wiring RFID RC522 module
==============================================================
GND     = GND   3.3V    = 3.3V
The following table shows the typical pin layout used:
 *             MFRC522      ESP32    
 *             Reader/PCD            
 * Signal      Pin          Pin      
 * ------------------------------------
 * RST/Reset   RST          GPIO27  
 * SPI SS      SDA(SS)      GPIO5    
 * SPI MOSI    MOSI         GPIO23    
 * SPI MISO    MISO         GPIO19    
 * SPI SCK     SCK          GPIO18    
 */
//====================================================
MFRC522 mfrc522(SS_PIN, RST_PIN);  // 创建新的RFID实例
MFRC522::MIFARE_Key key;
//====================================================
void setup() {
  Serial.begin(115200); // 設置com port傳輸速率為115200
    while (!Serial);  // 如果com port沒有打開,則閉環下去不進行下面的操作
 
  SPI.begin();    // SPI開始
  mfrc522.PCD_Init(); // Init MFRC522 card
  // using FFFFFFFFFFFFh which is the default at chip delivery from the factory
  for (byte i = 0; i < 6; i++) {
    key.keyByte[i] = 0xFF;
  }
 
  Serial.println(F("掃描卡片開始進行讀或者寫"));
  Serial.print(F("使用A和B作為KEY"));
 
  dump_byte_array(key.keyByte, MFRC522::MF_KEY_SIZE);
 
  Serial.println();
  Serial.println(F("注意,會把資料寫入到卡片 在 sector #1 "));
 
}
//====================================================  
void loop() {
 
  // 尋找新卡片
 
  if ( ! mfrc522.PICC_IsNewCardPresent())
     return;
   // 選擇一張卡片
 
  if ( ! mfrc522.PICC_ReadCardSerial())
     return;
 
  // 顯示卡片的詳細資訊
  Serial.print(F("卡片 UID:"));
  dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
  Serial.println();
  Serial.print(F("卡片類型: "));
 
  MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
  Serial.println(mfrc522.PICC_GetTypeName(piccType));
 
  // 檢查相容性
 
  if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI && piccType != MFRC522::PICC_TYPE_MIFARE_1K && piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
    Serial.println(F("僅僅適合Mifare Classic卡的讀寫"));
    return;
  }
 
  // 我們只使用第二個磁區
  // 覆蓋磁區4
  byte sector     = 1;
  byte blockAddr   = 4;

  byte dataBlock[]  = {
    0x01, 0x02, 0x03, 0x04, // 1, 2,  3, 4,
    0x05, 0x06, 0x07, 0x08, // 5, 6,  7, 8,
    0x00, 0x00, 0x00, 0x00, // 0,0,0,0
    0x00, 0x00, 0x00, 0x00  // 0,0,0,0
   };//寫入的資料定義
 
  byte trailerBlock  = 7;
 
  MFRC522::StatusCode status;
  byte buffer[18];
  byte size = sizeof(buffer);
 
  // 原來的資料
  Serial.println(F("顯示原本的資料..."));
  status = (MFRC522::StatusCode)mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("身份驗證失敗?或者是卡連結失敗"));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
 
  // 顯示整個磁區 sector
 
  Serial.println(F("顯示所有磁區的資料"));
 
  mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
 
  Serial.println();
 
  // 從區塊block讀取數據
 
  Serial.print(F("讀取區塊的資料在:")); Serial.print(blockAddr);
  Serial.println(F("區塊 ..."));
 
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
 
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("讀卡失敗,沒有連接上 "));
    Serial.println(mfrc522.GetStatusCodeName(status));
  }
 
  Serial.print(F("資料內容在第 ")); Serial.print(blockAddr); Serial.println(F(" 區塊:"));
  dump_byte_array(buffer, 16); Serial.println();
  Serial.println();
 
  //開始進行寫入準備
  //寫入前需要校驗Key B
  //Serial.println(F("Authenticating again using key B..."));
  //status = (MFRC522::StatusCode)mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
  Serial.println(F("開始進行寫入準備..."));
  status = (MFRC522::StatusCode)mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("寫入失敗,沒有連接上或者沒有許可權 "));
    Serial.println(mfrc522.GetStatusCodeName(status));
    return;
  }
 
  // Write data to the block
 
  Serial.print(F("在第: ")); Serial.print(blockAddr);
  Serial.println(F(" 區塊中寫入資料..."));
  dump_byte_array(dataBlock, 16); Serial.println();
 
  status = (MFRC522::StatusCode)mfrc522.MIFARE_Write(blockAddr, dataBlock, 16);
 
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("寫入失敗... "));
    Serial.println(mfrc522.GetStatusCodeName(status));
  }
 
  Serial.println();
  //  再次讀取卡中資料,這次是寫入之後的資料
  Serial.print(F("讀取寫入後第")); Serial.print(blockAddr);
  Serial.println(F(" 區塊的資料 ..."));
 
  status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
 
  if (status != MFRC522::STATUS_OK) {
    Serial.print(F("讀取失敗... "));
    Serial.println(mfrc522.GetStatusCodeName(status));
  }
 
  Serial.print(F("區塊 ")); Serial.print(blockAddr); Serial.println(F("資料為 :"));
  dump_byte_array(buffer, 16); Serial.println();
 
     
 
  // 驗證一下資料,要保證寫入前後資料是相等的
  // 通過計算塊中的位元組數量
 
  Serial.println(F("等待驗證結果..."));
  byte count = 0;
 
  for (byte i = 0; i < 16; i++) {
    // 比較一下緩衝區中的資料(我們讀出來的資料) = (我們剛剛寫的資料)
     if (buffer[i] == dataBlock[i])
        count++;
  }
 
  Serial.print(F("匹配的位元組(Byte)數量 = ")); Serial.println(count);
 
  if (count == 16) {
    Serial.println(F("驗證成功 :"));
  } else {
    Serial.println(F("失敗,資料不匹配"));
    Serial.println(F("也許寫入的內容不恰當"));
  }
  Serial.println();
   
 
  // 轉儲磁區資料
  Serial.println(F("寫入後的資料內容為::"));
  mfrc522.PICC_DumpMifareClassicSectorToSerial(&(mfrc522.uid), &key, sector);
  Serial.println();

  // 停止 PICC
  mfrc522.PICC_HaltA();
  //停止加密PCD
  mfrc522.PCD_StopCrypto1();

}
//====================================================  
/**
* 位元組陣列轉儲為串列的十六進位值
*/
/**
 * 這個副程式把讀取到的UID,用16進位顯示出來
 */
void dump_byte_array(byte *buffer, byte bufferSize) {
  for (byte i = 0; i < bufferSize; i++) {
    Serial.print(buffer[i] < 0x10 ? " 0" : " ");
    Serial.print(buffer[i], HEX);
  }
}

//====================================================  

   1     7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

          6   41 6E 74 68  6F 6E 79 20  20 20 20 20  20 20 20 20  [ 0 0 0 ] 

          5   20 20 20 20  20 20 20 20  20 20 20 20  20 20 00 00  [ 0 0 0 ] 

          4   0A 6D 61 72  6B 20 20 20  20 20 20 20  20 20 20 20  [ 0 0 0 ] 


寫入後的資料內容為::

   1      7   00 00 00 00  00 00 FF 07  80 69 FF FF  FF FF FF FF  [ 0 0 1 ] 

          6   41 6E 74 68  6F 6E 79 20  20 20 20 20  20 20 20 20  [ 0 0 0 ] 

          5   20 20 20 20  20 20 20 20  20 20 20 20  20 20 00 00  [ 0 0 0 ] 

          4   01 02 03 04  05 06 07 08  00 00 00 00  00 00 00 00  [ 0 0 0 ] 

  因為 寫入次數過多 block4 寫入前與寫入後 才會相同



(若不是 s50 會出現 )

卡片 UID: 46 E3 8B F4

卡片類型: MIFARE 1KB

顯示原本的資料...

身份驗證失敗?或者是卡連結失敗Timeout in communication.




Mifare Classic。這種RFID卡內部有1KB的EEPROM記憶體,為了妥善管理並達到一卡多用的功能,這個記憶體空間被劃分成16個區段(sector),每個區段有4個區塊(block)區段0的區塊0包含卡片的唯一識別碼(UID,也稱為「製造商識別碼」,Manufacturer Code)。

每個區段的區塊3也叫做控制區塊(Sector Trailer, Trailer Block或Security Block),如果把上圖的資料結構想像成16層大樓,控制區塊相當於每一層樓的密碼鎖;進、出該層樓必須先輸入正確的密碼,而且每層樓都有兩組密碼。

控制區塊包含金鑰A和金鑰B兩組密碼(各6位元組),以及存取控制位元(4位元組,但僅使用前3位元組)。

從卡片資料輸出結果可知:

  • 空白卡片的資料區,除了紀錄識別碼的區塊0之外,預設值都是00。
  • 每個區段最後一個區塊,都是控制區塊(Trailer Block,如:屬於區段15的區塊63)。
  • 控制區塊的前6位元組是金鑰A,預設全是0xFF,但顯示成00。
  • 最右邊的AccessBits(直譯為「存取位元」)代表各個區塊的讀寫權限設定,這些參數經過計算之後,存放在控制區塊的第6, 7, 8位元組


金鑰B預設是可見的,金鑰A則因為安全考量,在掃描時,全部顯示成00存取控制位元用於控制區段裡的每個區塊(區塊0到區塊3)是否能被存取、寫入或其他操作,並且決定要透過金鑰A或金鑰B來驗證。0xFF0780是控制區塊的「出廠預設值」,代表:

  • 金鑰A不可見;
  • 若通過金鑰A或金鑰B驗證,即可讀取或寫入該區段的區塊0~2。
  • 若通過金鑰A驗證,可讀取或改寫存取該區段的存取控制位元和金鑰B,也能改寫金鑰A。

每一個sector包含四個block 前三個block為數據區 第四個block為驗證區而第一個sector的裡面block0基本上為卡號跟一些商業資訊放置的區域。這個地方基本上是不可以修改的(除非你買特製的mifare可改UID的卡 台幣大概一張50塊吧)也就是第1 2 block為數據區 3為驗證區 4 5 6 為數據區 7為驗證區 8 9 10為數據區 ..以此類推而驗證區裡面還存有兩組密碼 密碼A跟密碼B 可以用來做不同的驗證。例如說要讀取的話 就要比對密碼A 成功才可以讀取資料 。而寫入的話就要驗證密碼B 成功才能修改資料如此。也就是說 

1.基本上你不能改BLOCK0的所有資料也就是不能改卡號,除非你買特製卡。

2.第3 第7 11 15 19 23 27 31 35 39 43 47 51 55 59 63都是驗證密碼區 不會拿來寫資料

除此之外其他區域都可以拿來寫任何資料

而新卡的話密碼A密碼B大多都會是 FF FF  FF FF FF FF



 
byte blockNum = _sector * 4 + _block;  // 計算區塊的實際編號(0~63)
byte trailerBlock = _sector * 4 + 3;   // 控制區塊編號



沒有留言:

張貼留言

Messaging API作為替代方案

  LINE超好用功能要沒了!LINE Notify明年3月底終止服務,有什麼替代方案? LINE Notify將於2025年3月31日結束服務,官方建議改用Messaging API作為替代方案。 //CHANNEL_ACCESS_TOKEN = 'Messaging ...