NFC RC522 - Смена ключа на карте

Нет ответов
Flash_Haos
Offline
Зарегистрирован: 27.08.2015

Друзья, добрый день!

Кто имел опыт общения с 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;
}