NFC RC522 - Смена ключа на карте
- Войдите на сайт для отправки комментариев
Ср, 27/07/2016 - 09:51
Друзья, добрый день!
Кто имел опыт общения с RC522, подскажите, как поставить кастомный ключ на карту Mifare при её записи?
На всякий случай прикладываю код - смысл устройства в включении реле при прикладывании карты, при этом карта действует только определенное время. Собственно, хочется чтобы карту нельзя было просто клонировать, воспользовавшись заводским ключом.
int deviceGroup = 16;
int masterGroup = 17;
long maxtime = 60;
#define RST_PIN 9 //Настраиваемый пин
#define SS_PIN 10 //Настраиваемый пин
#include <SPI.h>
#include <MFRC522.h>
byte bufferATQA[10];
byte bufferSize = sizeof(bufferATQA);
int cardGroup = 0;
long cardTime = 0;
int masterwaiting = 0;
boolean mastertick = false;
byte sector = 1;
byte valueBlockTime = 5;
byte valueBlockGroup = 6;
byte trailerBlock = 7;
byte buffer[18];
byte size = sizeof(buffer);
long value;
MFRC522::StatusCode status;
MFRC522 mfrc522(SS_PIN, RST_PIN); // Создаем объект MFRC522.
MFRC522::MIFARE_Key key;
void setup() {
Serial.begin(9600);
while (!Serial);
SPI.begin();
mfrc522.PCD_Init();
// Ключ для карты (один и тот же ключ A и B)
// Использовать FFFFFFFFFFFF для заводских настроек карт
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("Welcome to card reader!"));
//включаем порты светодиодов
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
}
void loop() {
delay(1000);
if (masterwaiting) {
IndicationMaster();
masterwaiting = masterwaiting - 1;
}
if ( !rfid_wait_card() || !rfid_authenficate() ) {
Relay(false);
return;
}
formatValueBlock(valueBlockGroup);
formatValueBlock(valueBlockTime);
//проверки на каждое действие по воздуху
cardGroup = rfid_readBlock(valueBlockGroup);
cardTime = rfid_readBlock(valueBlockTime);
if (cardGroup < 0 || cardTime < 0) {
Relay(false);
rfid_stop();
return;
}
Serial.print(F("Card Group = "));
Serial.println(cardGroup);
Serial.print(F("Card Time = "));
Serial.println(cardTime);
if (!masterwaiting) {
//проверяем время и группу на соответствие
if (cardGroup != deviceGroup || cardTime < 1) {
Serial.println("Time or group wrong!");
Relay(false);
}
//если группа карты соответствует группе устройства и время больше нуля
if (cardGroup == deviceGroup && cardTime > 0) {
//записываем уменьшенное время на карту
cardTime = cardTime - 1;
if (!rfid_writeBlock(valueBlockTime, cardTime)) {
rfid_stop();
return;
}
//отображаем время карты и включаем реле
Indication(cardTime*100/maxtime);
Relay(true);
}
//если прислонена мастеркарта
if (cardGroup == masterGroup) {
//включаем режим ожидания карты для перезаписи
IndicationMaster();
//и ставим счетчик ожидания на десять секунд
masterwaiting = 10;
}
}
else {
//если ждём карту для перезаписи
//только если прислонена не мастеркарта
if (cardGroup != masterGroup) {
//записываем максимальное время и номер девайса
if (!rfid_writeBlock(valueBlockTime, maxtime)) {
rfid_stop();
return;
}
if (!rfid_writeBlock(valueBlockGroup, deviceGroup)) {
rfid_stop();
return;
}
//моргаем светодиодами, сигнализируя о успешной записи
IndicationMasterWritten();
masterwaiting = false;
}
}
//заканчиваем работу с картой
rfid_stop();
}
/*
ФУНКЦИИ
*/
boolean rfid_wait_card()
{
// если нет новой карты, то пытаемся разбудить текущую
if ( ! mfrc522.PICC_IsNewCardPresent()) {
mfrc522.PICC_WakeupA(bufferATQA, &bufferSize);
}
// если нет карты - отключить реге
if ( ! mfrc522.PICC_ReadCardSerial()) {
return false;
}
// проверяем карту на совместимость
MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak);
if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI
&& piccType != MFRC522::PICC_TYPE_MIFARE_1K
&& piccType != MFRC522::PICC_TYPE_MIFARE_4K) {
return false;
}
return true;
}
boolean rfid_authenficate()
{
// аутенфикация
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) { return false; }
byte trailerBuffer[] = {
255, 255, 255, 255, 255, 255, // Keep default key A
0, 0, 0,
0,
255, 255, 255, 255, 255, 255}; // Keep default key B
mfrc522.MIFARE_SetAccessBits(&trailerBuffer[6], 0, 6, 6, 3);
// Read the sector trailer as it is currently stored on the PICC
status = mfrc522.MIFARE_Read(trailerBlock, buffer, &size);
if (status != MFRC522::STATUS_OK) { return false; }
// Check if it matches the desired access pattern already;
// because if it does, we don't need to write it again...
if ( buffer[6] != trailerBuffer[6]
&& buffer[7] != trailerBuffer[7]
&& buffer[8] != trailerBuffer[8]) {
// They don't match (yet), so write it to the PICC
status = mfrc522.MIFARE_Write(trailerBlock, trailerBuffer, 16);
if (status != MFRC522::STATUS_OK) { return false; }
}
// Authenticate using key B
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &key, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) { return false; }
return true;
}
void rfid_stop() {
// Halt PICC
mfrc522.PICC_HaltA();
// Stop encryption on PCD
mfrc522.PCD_StopCrypto1();
}
void formatValueBlock(byte blockAddr) {
byte buffer[18];
byte size = sizeof(buffer);
MFRC522::StatusCode status;
status = mfrc522.MIFARE_Read(blockAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) { return; }
if ( (buffer[0] != (byte)~buffer[4])
&& (buffer[1] != (byte)~buffer[5])
&& (buffer[2] != (byte)~buffer[6])
&& (buffer[3] != (byte)~buffer[7])
&& (buffer[0] != buffer[8])
&& (buffer[1] != buffer[9])
&& (buffer[2] != buffer[10])
&& (buffer[3] != buffer[11])
&& (buffer[12] != (byte)~buffer[13])
&& (buffer[12] != buffer[14])
&& (buffer[12] != (byte)~buffer[15])) {
byte valueBlock[] = {
0, 0, 0, 0,
255, 255, 255, 255,
0, 0, 0, 0,
blockAddr, ~blockAddr, blockAddr, ~blockAddr };
status = mfrc522.MIFARE_Write(blockAddr, valueBlock, 16);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("MIFARE_Write() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
}
}
}
void Relay(boolean status) {
if (status) {
Serial.println(F("Relay opened."));
digitalWrite(7, HIGH);
}
else {
Serial.println(F("Relay closed."));
digitalWrite(7, LOW);
if (!masterwaiting) {
Indication(0);
}
}
}
void Indication(int percentage) {
if (percentage > 90) {
PORTD = B01111000;
return;
}
if (percentage >50) {
PORTD = B00111000;
return;
}
if (percentage >25) {
PORTD = B00011000;
return;
}
if (percentage > 0) {
PORTD = B00001000;
return;
}
PORTD = B00000000;
return;
}
void IndicationMaster() {
Serial.println("Master card!");
if (mastertick) {
mastertick = false;
PORTD = B01001000;
}
else {
mastertick = true;
PORTD = B00110000;
}
}
void IndicationMasterWritten() {
delay(250);
PORTD = B01000000;
delay(250);
PORTD = B00100000;
delay(250);
PORTD = B00010000;
delay(250);
PORTD = B00001000;
delay(250);
PORTD = B00000000;
}
long rfid_readBlock(byte valueBlockNumber) {
status = mfrc522.MIFARE_GetValue(valueBlockNumber, &value);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("mifare_GetValue() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return 0;
}
return value;
}
boolean rfid_writeBlock(byte valueBlockNumber, long valueToSet) {
status = mfrc522.MIFARE_SetValue(valueBlockNumber, valueToSet);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("mifare_SetValue() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
return true;
}