Как изменить uid карты rfid

Добрый день! Есть модуль RС522, хочу использовать его для системы доступа, но во всех примерах которые есть в сети используют только UID карты, Слышал...
  1. Добрый день! Есть модуль RС522, хочу использовать его для системы доступа, но во всех примерах которые есть в сети используют только UID карты, Слышал что это не совсем безопасно, поэтому хочу сменить на карте ключ (допустим ключ B) чтобы можно было записывать и считывать с карты информацию для идентификации только по этому ключу. В сети внятной информации не нашел. Может кто подскажет как это делать?

  2. Не совсем понятно что Вам надо? На русскийпереведите? Вы хотите карты клонировать? Чем UID небезопасен?

  3. Наоборот, хочу защититься от возможного клонирования.

    Ну, утверждают что можно незаметно прочитать карту и узнать UID. Поэтому рекомендуют в имеющийся на карте блок записать дополнительный код и закрыть считывание из этого блока ключом. Установленные на этих картах по умолчанию ключи всем известны. Вот я и хочу узнать как можно изменить хотя бы один из двух ключей и защитить блок с записанной информацией этим ключом.

  4. Скажи проще — есть академический интерес. А клонировать…кому надо, тот клонирует. Выбор защитного ключа — это тоже целая история.


    mifar и Airbus нравится это.

  5. Не давать карту в чужие руки. Считывает максимум с 2—3 сантиметров. Если в кожанном чехле то только при касании.Прочитать карту незаметно нельзя от слова совсем. Это уже Паранойя. Даже в банках идентификация сотрудников и операций обычными rfid метками 125 кгц. Других вариантов не знаю хотя вопросом клонирования карт/симок/кодов занимался. Посмотрите на сайте фрикерклуб.ру может там чтото новое за год появилось? Если Вы хотите закрыть считывание то как будете проходить?

  6. Я это уже заметил. И поэтому все больше склоняюсь что ну его нафиг этот геморрой со сменой ключей.

    Но для себя все-таки разобраться хотелось бы как это работает. Вдруг когда-нибудь пригодится.

  7. Тогда изучайте протоколы, принцип работы все есть в сети. Я копировал симки, карты с магнитной полосой, ключи но все это требует физического доступа к носителю. До сих пор есть мультисим и парочка клонов электронных пропусков на rfid картах.А устройства можно купить а можно сделать.Вот чувак сделал прикольный копир на Ардуино.

  8. Я в сети натыкался на статью с описанием, как это сделать. Так с ходу не найду.

    Как по мне, вот такое выглядит куда более цивильно:

    upload_2021-1-5_18-14-56.png

  9. Для майфер классика у NXP есть (и был с принятия стандарта) в открытом доступе MIFARE Classic EV1 1K
    Карта разделена размечена на сектора, каждый сектор поделен на блоки данных и один служебный блок, т.н. sector trailer, который содержит два ключа A, B и access bits — биты определяющие на каком ключе (A или B) разрешены операции чтения/записи/увеличения/уменьшения для блока сектора.

    Пример для использовании карты (карт) для контроля доступа и учета количества проходов:
    При персонализации кары разрешаем чтение и уменьшение значения блока на ключе A или B, а запись и увеличение только на ключе B.
    Валидатору отдаем ключ А, он может только считать значение, либо уменьшить на единицу (списать проход).

  10. Мне бы конкретный пример, допустим, как сменить заводской ключ 0xFF на 0х11, в трейлер первого сектора установить биты разрешающие запись/чтение данных только в первом блоке этого сектора и только на ключе В. А то тем что удалось найти боюсь запороть карту.

  11. В контроле доступа это не применяется и никогда не будет применяться. Весь учёт только внешний.

  12. Полагаю речь идет о хакинге карты Метро? Или не только Метро?

  13. На эмиссии в миллионы карт (контроль доступа на общественном транспорте) обеспечить онлайн контроль для десятков тысяч валидаторов — чрезвычайно дорогое решение,
    дешевле «заряжать» карты прописывая количество проходов на карту.
    Сначала платим либо кассиру либо удаленно через интернеты, после либо кассир либо сами прикладываем карту к считывателю и активируем пополнение.

    Если «Весь учёт только внешний» то никаких активаций не требовалось бы однако.

  14. Второй раз повторяю — никакого хакинга. Этим вопросом заинтересовался когда увидел совет b707 Где то на этом ресурсе попадалось аналогичное высказывание, но не найду, столько перелопатил что уже не помню в какой теме и от кого.

    Вот конкретно пример реализации чего я хотел бы найти

    Последнее редактирование: 6 янв 2021

  15. Можно запороть установив для аксесс биты для трейлера запрещающие перезапись самих аксесс битов, остальное, если вы ключи не забыли, не страшно.
    Для расчета можно воспользоваться калькулятором, перед записью трейлера ещё раз проверяем аксесс биты что записываем по спеке производителя, калькулятор хорошо, но проверить не помешает.

  16. Это разновидность платёжной системы, причём не очень удачной. Но учёт то ведётся.

Автор: Nich1con

Технология RFID (Радиочастотная идентификация) позволяет при помощи радиосигнала быстро и безопасно передавать данные между специальными “считывателями” и “метками” – карточками, брелоками, браслетами и т.д. на небольшом расстоянии.
Одно из широко известных развитий технологии – NFC, при помощи которого можно оплачивать покупки или подключать устройства бесконтактно. Нам же доступны менее сложные, но не менее полезные и интересные применения, о которых будет сказано ниже.

Применение


Комплект RFID модуль + метки может быть использован:

  • Как часть самодельных охранных систем
  • При создании простых электронных замков (метка является ключом)
  • В системах контроля доступа (однократный, многократный пропуск)
  • В качестве электронного “кошелька” внутри собственного предприятия
  • В роли интерактивного предмета в квестах и т.д.

Железо


RFID работает в нескольких частотных диапазонах, в свою очередь RFID модули и метки можно поделить на низкочастотные “LF” (125 кгц) и высокочастотные “HF” (13,56 MHz), существуют так же и ультравысокочастотные “UHF”, но они нас не интересуют.

Наиболее распространенные RFID Arduino-модули основаны на микросхеме MFRC522, работающей с HF метками 13,56 МГц. Поиск модулей и библиотек производится по этому же имени.

Существует два типа модулей MFRC522, с которыми вы скорее всего столкнетесь:

Отвечая на главный вопрос – не смотря на значительную разницу в размере, ощутимой разницы в работе модулей нет, можно брать любой. В комплекте к модулю как правило уже идет несколько меток.

Библиотеки


Для работы с модулем MFRC522 понадобится библиотека https://github.com/miguelbalboa/rfid. Библиотека тяжелая, индусская и имеет немало проблем, но достойных альтернатив просто нет – несколько других “облегченных” библиотек значительно уступают в функциональности и удобстве использования.

Подключение


Модуль MFRC522 подключается по аппаратному интерфейсу SPI, выбранная библиотека предоставляет следующую таблицу подключения к Arduino:

Сигнал Модуль MFRC522  UNO/NANO Leonardo Pro micro Mega
Reset RST D9 RST/ISCP-5 RST D5
Chip select SDA (SS) D10 D10 D10 D53
MOSI MOSI D11 ISCP-4 D16 D51
MISO MISO D12 ISCP-1 D14 D50
SCK SCK D13 ISCP-3 D15 D52
  • Контакты модуля RST и SDA (SS) указываются в скетче – можно использовать любые.
  • У Leonardo подключение производится к 6-ти контактному ICSP разъему программатора.

Пример подключения модуля к Arduino Nano:

О RFID метках


Прежде всего самая сложная для понимания, но и самая важная часть – работа с RFID метками. В комплекте с модулем идут пара меток MIFARE Classic 1K, как понятно из названия – на 1 килобайт (на самом деле меньше, но об этом позже).

Чтобы изучить организацию памяти такой метки, можно воспользоваться примером из библиотеки, открыв Примеры > MFRC522 > DumpInfo. Однако для вашего удобства я подготовил вот такую карту:

Обратите внимание – память организована в виде 16-ти секторов, по 4 блока каждый. Итого – 64 блока по 16 Байт, как раз набегает 1 Килобайт. Деление по секторам носит скорее условный характер, так как адресация в памяти будет производиться по блокам.

Все сектора кроме нулевого имеют одинаковое строение – 3 блока данных + 1 блок безопасности, так называемый sector trailer. Каждый из этих блоков может быть прочитан и перезаписан (при соблюдении условий), исключение составляет нулевой блок (сектор 0).

Нулевой блок хранит в себе уникальный ID “UID”, тип метки и прочую информацию, записанную заводом-изготовителем. Нулевой сектор не может быть перезаписан, если речь идет о “классических” метках, к которым относятся комплектные с модулем. Таким образом UID позволяет отличить две с виду идентичные метки. UID как правило состоит из 4х байт, свободно считываемых из метки. Важно: китайский рынок может предложить вам “перезаписываемые” метки, UID в которых можно менять, путем перезаписи нулевого блока. Если в вашей системе используется только UID – учтите возможность очень простого копирования UID в метки-болванки (в том числе злоумышленниками).

Блоком безопасности является каждый 4й блок, каждый блок безопасности отвечает за свой сектор (предыдущие 3 блока данных) – он хранит 2 ключа доступа по 6 байт (ключи A и B), а также специальные “Access bits” (Биты доступа), грубо говоря настройки доступа. Ключи A и B могут быть использованы для аутентификации и последующего доступа к блокам данных в пределах сектора. То есть да, для того чтобы получить доступ к любому из блоков внутри сектора необходимо “разблокировать” этот сектор, при помощи одного из ключей.

Поэтому будьте уверены, если производитель позаботился о смене секретных ключей в своих RFID метках – скопировать или как-нибудь изменить содержимое штатными средствами вы уже не сможете, а ведь так хотелось? Идем дальше.

Биты доступа позволяют настроить условия доступа и возможности работы каждого блока в отдельности (каждого блока данных + блока безопасности). Наилучшим инструментом в работе с метками MIFARE Classic 1K является вот этот онлайн-калькулятор http://calc.gmss.ru/Mifare1k/. Если хотите разобраться чуть глубже – обязательно полистайте и опробуйте.

Я же хочу сэкономить ваше время, поэтому сразу уточню, что наиболее удачным решением в большинстве ситуаций будет оставить блоки данных в состоянии transport configuration, то есть по умолчанию.

blank

Однако есть возможность настроить блоки на некоторые интересные сценарии, например защитить от записи (конфигурация 1-0-1 или 0-1-0). Или же сделать так, что прочитать блок можно при помощи как ключа A, так и ключа B, а вот для записи обязательно понадобится ключ B (конфигурация 1-0-0), в таком случае можно ограничить права некоторого оборудования и сделать систему безопаснее. И да, конфигурация 1-1-1 превращает блок в кирпич (обратимо).

В примерах ниже мы будем использовать конфигурацию блоков данных по умолчанию (0-0-0) и следующие принципы:

  • Создаем ключ B, значение которого знаем только мы, длина ключа – 6 Байт.
  • Ключ A будет полностью аналогичен ключу B, однако он не будет использоваться.
  • Биты доступа для блоков безопасности будем использовать в конфигурации 0-1-1

blank

Таким образом для всех операций с меткой применяется только ключ B, который невозможно считать из метки (впрочем, как и ключ A), даже если сектор предварительно разблокирован. Если хотите намертво зашить ключи A и B в блок безопасности – подойдет конфигурация 1-0-1, поменять будет уже невозможно. Ну а последняя 1-1-1 конфигурация блока безопасности заблокирует еще и настройки доступа к блокам данных!

Некоторые варианты необратимы, но не переживайте – у вас есть целых 16 попыток! По одной на каждый сектор.

В итоге 3 байта настроек доступа приняли следующие значения: 0x7F 0x07 0x88, байт USER может быть любой.

blank

Важно: изначально ключи A и B от всех секторов метки содержат значение 0xFFFFFFFFFFFF, так что если хотите защитить данные в ваших метках, не забывайте сменить оба ключа! Кстати, нулевой блок и соответственно UID свободно читаются из метки, даже если нулевой сектор был заблокирован секретными ключами.

Ну и последнее, что касается меток – реальный объем пользовательской памяти. Если не создавать костыли, а использовать только блоки для хранения данных – (по 3 блока в 15-ти секторах, и 2 блока в нулевом секторе) получаем 47 доступных блоков по 16 байт или 752 байта, что тоже неплохо.

Начало работы

Подключили модуль, распаковали свежие метки – начинаем работать!

Прежде всего создаем необходимые объекты, инициализируем интерфейс SPI и MFRC522, не забываем про ключ доступа. Изначально все ключи состоят из FF-ок, так что “наполняем” ключ.

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);            // Инициализация Serial
  SPI.begin();                   // Инициализация SPI
  rfid.PCD_Init();               // Инициализация модуля

  for (byte i = 0; i < 6; i++) { // Наполняем ключ
    key.keyByte[i] = 0xFF;       // Ключ по умолчанию 0xFFFFFFFFFFFF
  }
}

void loop() {}

Работу с RFID модулем удобнее всего производить в конце главного цикла программы, сейчас поймете почему. Для отслеживания поднесенной метки библиотека предлагает использовать пару методов с замысловатыми названиями:

if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

Если поднесенная метка успешно считана – программа идет дальше, в противном случае происходит возврат в начало главного цикла, а весь блок кода связанный с RFID пропускается.

В итоге наш скетч имеет следующую структуру:

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);            // Инициализация Serial
  SPI.begin();                   // Инициализация SPI
  rfid.PCD_Init();               // Инициализация модуля

  for (byte i = 0; i < 6; i++) { // Наполняем ключ
    key.keyByte[i] = 0xFF;       // Ключ по умолчанию 0xFFFFFFFFFFFF
  }
}

void loop() {
  // Занимаемся чем угодно
  if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
  if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop
  // Работаем с RFID
}

Теперь давайте идти по порядку, осваивая основные методы для работы с RFID.

Обратите внимание: примеры ниже содержат специальные блоки кода, повышающие стабильность работы, о них подробно сказано в конце статьи.

Чтение UID


Самое простое, что можно сделать с RFID меткой – прочитать UID, в некоторых системах уже этого функционала вполне достаточно, например – в простых электронных замках. Как уже сказано ранее, некоторые метки позволяют сменить UID, в свою очередь запретить считать UID из ваших меток не получится – учтите это при разработке.

Так или иначе пример чтения UID и вывод в порт приведен ниже:

Чтение UID

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);              // Инициализация Serial
  SPI.begin();                     // Инициализация SPI
  rfid.PCD_Init();                 // Инициализация модуля
  rfid.PCD_SetAntennaGain(rfid.RxGain_max);  // Установка усиления антенны
  rfid.PCD_AntennaOff();           // Перезагружаем антенну
  rfid.PCD_AntennaOn();            // Включаем антенну

  for (byte i = 0; i < 6; i++) {   // Наполняем ключ
    key.keyByte[i] = 0xFF;         // Ключ по умолчанию 0xFFFFFFFFFFFF
  }
}

void loop() {
  // Занимаемся чем угодно
  
  static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля!
  if (millis() - rebootTimer >= 1000) {   // Таймер с периодом 1000 мс
    rebootTimer = millis();               // Обновляем таймер
    digitalWrite(RST_PIN, HIGH);          // Сбрасываем модуль
    delayMicroseconds(2);                 // Ждем 2 мкс
    digitalWrite(RST_PIN, LOW);           // Отпускаем сброс
    rfid.PCD_Init();                      // Инициализируем заного
  }

  if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
  if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

  Serial.print("UID: ");
  for (uint8_t i = 0; i < 4; i++) {           // Цикл на 4 итерации
    Serial.print("0x");                       // В формате HEX
    Serial.print(rfid.uid.uidByte[i], HEX);   // Выводим UID по байтам
    Serial.print(", ");
  }
  Serial.println("");
}

После успешного чтения метки, ее UID появляется в массиве rfid.uid.uidByte[] который можно прочитать и использовать.

Чтение блока


Если чтением UID ваш интерес не ограничился – давайте узнаем, как читать блок данных из метки. Прежде чем что-либо читать или писать, необходимо аутентифицировать (разблокировать) сектор, в котором находится интересующий нас блок.

В примерах ниже будем работать с блоком под номером 6 (сектор 1), за первый сектор и соответственно блоки 4, 5 и 6 отвечает блок безопасности под номером 7. То есть запомнили – блок данных 6, блок безопасности 7.

Аутентификацию сектора производит метод PCD_Authenticate(), по умолчанию все манипуляции с меткой возможны при помощи ключа A, а сам процесс аутентификации выглядит следующим образом:

status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid));
if (status != MFRC522::STATUS_OK) {   // Если не окэй
  Serial.println("Auth error");       // Выводим ошибку
  return;
}

Обратите внимание на …KEY_A в первом аргументе и цифру 7 вторым аргументом – это и есть номер блока безопасности. Отслеживать статус не обязательно, но крайне желательно.

После успешной аутентификации можно свободно манипулировать разблокированным сектором, в нашем случае будем читать содержимое методом MIFARE_Read(). Читать нужно в байтовый массив, размером 18 (!) байт, чтение происходит из блока 6 (первый аргумент) и выглядит так:

uint8_t dataBlock[18];                          // Буфер для чтения
uint8_t size = sizeof(dataBlock);               // Размер буфера
status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер
if (status != MFRC522::STATUS_OK) {             // Если не окэй
  Serial.println("Read error");                 // Выводим ошибку
  return;
}

Важно: Не смотря на то, что блоки имеют размер 16 байт, буферный массив создается на 18 байт, а количество байт на чтение передается именно в виде указателя на переменную. В противном случае чтение закончится ошибкой, примите это как факт.

В случае успешного чтения, выведем содержимое блока 6 в монитор порта, все как обычно:

Serial.print("Data:");                          // Выводим 16 байт в формате HEX
for (uint8_t i = 0; i < 16; i++) {
  Serial.print("0x");
  Serial.print(dataBlock[i], HEX);
  Serial.print(", ");
}
Serial.println("");

А завершать работу с меткой нужно при помощи еще двух замысловатых методов:

rfid.PICC_HaltA();                              // Завершаем работу с меткой
rfid.PCD_StopCrypto1();

В итоге полный скетч для чтения блока 6 из новой метки со стандартными ключами выглядит так:

Чтение блока

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);              // Инициализация Serial
  SPI.begin();                     // Инициализация SPI
  rfid.PCD_Init();                 // Инициализация модуля
  rfid.PCD_SetAntennaGain(rfid.RxGain_max);  // Установка усиления антенны
  rfid.PCD_AntennaOff();           // Перезагружаем антенну
  rfid.PCD_AntennaOn();            // Включаем антенну
  for (byte i = 0; i < 6; i++) {   // Наполняем ключ
    key.keyByte[i] = 0xFF;         // Ключ по умолчанию 0xFFFFFFFFFFFF
  }
}

void loop() {
  // Занимаемся чем угодно

  static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля!
  if (millis() - rebootTimer >= 1000) {   // Таймер с периодом 1000 мс
    rebootTimer = millis();               // Обновляем таймер
    digitalWrite(RST_PIN, HIGH);          // Сбрасываем модуль
    delayMicroseconds(2);                 // Ждем 2 мкс
    digitalWrite(RST_PIN, LOW);           // Отпускаем сброс
    rfid.PCD_Init();                      // Инициализируем заного
  }

  if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
  if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

  /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */
  status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid));
  if (status != MFRC522::STATUS_OK) {     // Если не окэй
    Serial.println("Auth error");         // Выводим ошибку
    return;
  }

  /* Чтение блока, указываем блок данных #6 */
  uint8_t dataBlock[18];                          // Буфер для чтения
  uint8_t size = sizeof(dataBlock);               // Размер буфера
  status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер
  if (status != MFRC522::STATUS_OK) {             // Если не окэй
    Serial.println("Read error");                 // Выводим ошибку
    return;
  }

  /* Выводим содержимое блока в Serial */
  Serial.print("Data:");                          // Выводим 16 байт в формате HEX
  for (uint8_t i = 0; i < 16; i++) {
    Serial.print("0x");
    Serial.print(dataBlock[i], HEX);
    Serial.print(", ");
  }
  Serial.println("");

  rfid.PICC_HaltA();                              // Завершаем работу с меткой
  rfid.PCD_StopCrypto1();
}

После поднесения метки в мониторе порта должны отобразиться 16 байт – содержимое прочитанного блока.

Запись блока


При записи все 16 байт записываются в блок единовременно, для чего должен быть заранее подготовлен байтовый массив на 16 Байт, например такой:

uint8_t dataToWrite[16] = {
  0x00, 0x00, 0x00, 0x00,
  0xAA, 0xBB, 0xCC, 0xDD,
  0xAA, 0xBB, 0xCC, 0xDD,
  0x00, 0x00, 0x00, 0x00
};

Как в случае и с чтением, сектор в котором находится нужный блок нужно предварительно аутентифицировать, об этом уже сказано выше, так что переходим непосредственно к записи. Запись производится методом MIFARE_Write(), в отличии от MIFARE_Read() тут все несколько проще – указываем записываемый блок, массив и число 16 (количество байт на запись):

status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6
if (status != MFRC522::STATUS_OK) {             // Если не окэй
  Serial.println("Write error");                // Выводим ошибку
  return;
}

Итоговый скетч записи массива в блок 6 выглядит так:

Запись блока

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);              // Инициализация Serial
  SPI.begin();                     // Инициализация SPI
  rfid.PCD_Init();                 // Инициализация модуля
  rfid.PCD_SetAntennaGain(rfid.RxGain_max);  // Установка усиления антенны
  rfid.PCD_AntennaOff();           // Перезагружаем антенну
  rfid.PCD_AntennaOn();            // Включаем антенну
  for (byte i = 0; i < 6; i++) {   // Наполняем ключ
    key.keyByte[i] = 0xFF;         // Ключ по умолчанию 0xFFFFFFFFFFFF
  }
}

void loop() {
  // Занимаемся чем угодно

  static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля!
  if (millis() - rebootTimer >= 1000) {   // Таймер с периодом 1000 мс
    rebootTimer = millis();               // Обновляем таймер
    digitalWrite(RST_PIN, HIGH);          // Сбрасываем модуль
    delayMicroseconds(2);                 // Ждем 2 мкс
    digitalWrite(RST_PIN, LOW);           // Отпускаем сброс
    rfid.PCD_Init();                      // Инициализируем заного
  }

  if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
  if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

  /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */
  status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid));
  if (status != MFRC522::STATUS_OK) {     // Если не окэй
    Serial.println("Auth error");         // Выводим ошибку
    return;
  }

  /* Запись блока, указываем блок данных #6 */
  uint8_t dataToWrite[16] = {                    // Массив на запись в блок
    0x00, 0x00, 0x00, 0x00,
    0xAA, 0xBB, 0xCC, 0xDD,
    0xAA, 0xBB, 0xCC, 0xDD,
    0x00, 0x00, 0x00, 0x00
  };

  status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6
  if (status != MFRC522::STATUS_OK) {             // Если не окэй
    Serial.println("Write error");                // Выводим ошибку
    return;
  }

  Serial.println("Write OK");                     // Завершаем работу с меткой
  rfid.PICC_HaltA();                              
  rfid.PCD_StopCrypto1();
}

После поднесения метки в мониторе порта должно отобразиться сообщение “Write OK“.

К слову ничто не мешает нам объеденить запись и чтение в одном скетче:

Запись + чтение блока

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);              // Инициализация Serial
  SPI.begin();                     // Инициализация SPI
  rfid.PCD_Init();                 // Инициализация модуля
  rfid.PCD_SetAntennaGain(rfid.RxGain_max);  // Установка усиления антенны
  rfid.PCD_AntennaOff();           // Перезагружаем антенну
  rfid.PCD_AntennaOn();            // Включаем антенну
  for (byte i = 0; i < 6; i++) {   // Наполняем ключ
    key.keyByte[i] = 0xFF;         // Ключ по умолчанию 0xFFFFFFFFFFFF
  }
}

void loop() {
  // Занимаемся чем угодно

  static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля!
  if (millis() - rebootTimer >= 1000) {   // Таймер с периодом 1000 мс
    rebootTimer = millis();               // Обновляем таймер
    digitalWrite(RST_PIN, HIGH);          // Сбрасываем модуль
    delayMicroseconds(2);                 // Ждем 2 мкс
    digitalWrite(RST_PIN, LOW);           // Отпускаем сброс
    rfid.PCD_Init();                      // Инициализируем заного
  }

  if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
  if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

  /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */
  status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid));
  if (status != MFRC522::STATUS_OK) {     // Если не окэй
    Serial.println("Auth error");         // Выводим ошибку
    return;
  }

  /* Запись блока, указываем блок данных #6 */
  uint8_t dataToWrite[16] = {                    // Массив на запись в блок
    0x00, 0x00, 0x00, 0x00,
    0xAA, 0xBB, 0xCC, 0xDD,
    0xAA, 0xBB, 0xCC, 0xDD,
    0x00, 0x00, 0x00, 0x00
  };

  status = rfid.MIFARE_Write(6, dataToWrite, 16); // Пишем массив в блок 6
  if (status != MFRC522::STATUS_OK) {             // Если не окэй
    Serial.println("Write error");                // Выводим ошибку
    return;
  }

  /* Чтение блока, указываем блок данных #6 */
  uint8_t dataBlock[18];                          // Буфер для чтения
  uint8_t size = sizeof(dataBlock);               // Размер буфера
  status = rfid.MIFARE_Read(6, dataBlock, &size); // Читаем 6 блок в буфер
  if (status != MFRC522::STATUS_OK) {             // Если не окэй
    Serial.println("Read error");                 // Выводим ошибку
    return;
  }

  Serial.print("Data:");                          // Выводим 16 байт в формате HEX
  for (uint8_t i = 0; i < 16; i++) {
    Serial.print("0x");
    Serial.print(dataBlock[i], HEX);
    Serial.print(", ");
  }
  Serial.println("");

  rfid.PICC_HaltA();                              // Завершаем работу с меткой
  rfid.PCD_StopCrypto1();
}

Смена ключей безопасности и настройка блоков


Если вы хотите не только уметь читать и писать данные в метки, но и защить хранящуюся там информацию от стороннего вмешательства – необходимо сменить ключи доступа как минимум от тех секторов, в которых вы собираетесь хранить данные, однако в идеале установить новые ключи для всех секторов, чтобы усложнить задачу потенциальным взломащикам.

Для того, чтобы изменить ключи доступа к сектору, необходимо перезаписать блок безопасности, ответственный за данный сектор. В наших примерах фигурировал блок данных под номером и соответственно блок безопасности под номером 7. Задача по смене ключей безопасности сводится к следующим шагам:

  1. Создать байтовый массив на 16 ячеек, включающий:
    • Ключ A
    • Байты настроек доступа
    • Ключ B
  2. Провести аутентификацию выбранного сектора, пока что используя стандартный ключ 0xFFFFFFFFFFFF
  3. Произвести запись подготовленного массива в блок безопасности, в точности так же, как в случае с обычным блоком.

После этого ключи безопасности будут изменены, а мы сможем безопасно хранить данные в одном или нескольких блоках выбранного сектора! Сейчас покажу по шагам.

  1.  Для создания образа блока безопасности (содержимого массива) придется вернуться вверх по тексту и вспомнить, что при выбранных нами настройках сектора, байты доступа получили значения 0x7F 0x07 0x88. Осталось придумать ключи доступа, имеющие длину 6 байт. Я буду использовать ключ 0xABABABABABAB, данный ключ не является безопасным и подходит исключительно для демонстрации! Так же напоминаю, что ключи A и B будут идентичны, однако использоваться будет только ключ B.

blank

  1. 1  После того, как мы определились с настройками сектора (“Access Bits“) и ключами безопасности – создаем нужный байтовый массив:
    uint8_t secBlockDump[16] = {                   // Дамп блока безопасности
      0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,          // < Ключ A
      0x7F, 0x07,  0x88,                           // < Access Bits
      0xFF,                                        // < User байт (любой)
      0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB           // < Ключ B
    };

    Думаю по структуре массива все понятно и вполне наглядно.

  2. Производим аутентификацию сектора, как и раньше. Напомнинаю, что для этого используется блок безопасности 7:
    status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid));
    if (status != MFRC522::STATUS_OK) {     // Если не окэй
      Serial.println("Auth error");         // Выводим ошибку
      return;
    }
  3.  После чего записываем дамп, в тот же блок безопасности – под номером 7:
    status = rfid.MIFARE_Write(7, secBlockDump, 16); // Пишем массив в блок 6
    if (status != MFRC522::STATUS_OK) {              // Если не окэй
      Serial.println("Write error");                 // Выводим ошибку
      return;
    }

Итоговый скетч записи новых ключей и настроек доступа:

Запись блока безопасности

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);              // Инициализация Serial
  SPI.begin();                     // Инициализация SPI
  rfid.PCD_Init();                 // Инициализация модуля
  rfid.PCD_SetAntennaGain(rfid.RxGain_max);  // Установка усиления антенны
  rfid.PCD_AntennaOff();           // Перезагружаем антенну
  rfid.PCD_AntennaOn();            // Включаем антенну
  for (byte i = 0; i < 6; i++) {   // Наполняем ключ
    key.keyByte[i] = 0xFF;         // Ключ по умолчанию 0xFFFFFFFFFFFF
  }
}

void loop() {
  // Занимаемся чем угодно

  static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля!
  if (millis() - rebootTimer >= 1000) {   // Таймер с периодом 1000 мс
    rebootTimer = millis();               // Обновляем таймер
    digitalWrite(RST_PIN, HIGH);          // Сбрасываем модуль
    delayMicroseconds(2);                 // Ждем 2 мкс
    digitalWrite(RST_PIN, LOW);           // Отпускаем сброс
    rfid.PCD_Init();                      // Инициализируем заного
  }

  if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
  if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

  /* Аутентификация сектора, указываем блок безопасности #7 и ключ A */
  status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 7, &key, &(rfid.uid));
  if (status != MFRC522::STATUS_OK) {     // Если не окэй
    Serial.println("Auth error");         // Выводим ошибку
    return;
  }

  /* Запись блока, указываем блок безопасности #7 */
  uint8_t secBlockDump[16] = {                   // Дамп блока безопасности
    0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,          // < Ключ A
    0x7F, 0x07,  0x88,                           // < Access Bits
    0xFF,                                        // < User байт (любой)
    0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB           // < Ключ B
  };

  status = rfid.MIFARE_Write(7, secBlockDump, 16); // Пишем массив в блок 7
  if (status != MFRC522::STATUS_OK) {              // Если не окэй
    Serial.println("Write error");                 // Выводим ошибку
    return;
  }

  Serial.println("Write OK");                     // Завершаем работу с меткой
  rfid.PICC_HaltA();                              
  rfid.PCD_StopCrypto1();
}

Важно: при повторном поднесении метки мы неизбежно получим ошибку аутентификации, это связано с тем, что стандартный ключ больше не подходит к перенастроенному сектору!

Не забываем сменить “наполнение” ключа в void setup(){}:

for (byte i = 0; i < 6; i++) {   // Наполняем ключ
  key.keyByte[i] = 0xAB;         // Пишем свой ключ
}

Так же напоминаю, что отныне для сектора 1 (блоков 4…7) мы используем только ключ B, соответственно и команда аутентификации отныне выглядит чуть иначе:

status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, 7, &key, &(rfid.uid));
if (status != MFRC522::STATUS_OK) {     // Если не окэй
  Serial.println("Auth error");         // Выводим ошибку
  return;
}

Работа с защищенным сектором


Теперь, после того как мы сменили ключи безопасности от сектора 1, в качестве примера будем выводить количество поднесений метки к считывателю в последовательный порт. Количество поднесений хранится в нулевом байте защищенного блока 6 и увеличивается при каждом поднесении:

Инкремент при поднесении

#include <SPI.h>
#include <MFRC522.h>

#define RST_PIN         9        // Пин rfid модуля RST
#define SS_PIN          10       // Пин rfid модуля SS

MFRC522 rfid(SS_PIN, RST_PIN);   // Объект rfid модуля
MFRC522::MIFARE_Key key;         // Объект ключа
MFRC522::StatusCode status;      // Объект статуса

void setup() {
  Serial.begin(9600);              // Инициализация Serial
  SPI.begin();                     // Инициализация SPI
  rfid.PCD_Init();                 // Инициализация модуля
  rfid.PCD_SetAntennaGain(rfid.RxGain_max);  // Установка усиления антенны
  rfid.PCD_AntennaOff();           // Перезагружаем антенну
  rfid.PCD_AntennaOn();            // Включаем антенну

  for (byte i = 0; i < 6; i++) {   // Наполняем ключ B
    key.keyByte[i] = 0xAB;         // Пишем свой ключ
  }
}

void loop() {
  // Занимаемся чем угодно

  static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля!
  if (millis() - rebootTimer >= 1000) {   // Таймер с периодом 1000 мс
    rebootTimer = millis();               // Обновляем таймер
    digitalWrite(RST_PIN, HIGH);          // Сбрасываем модуль
    delayMicroseconds(2);                 // Ждем 2 мкс
    digitalWrite(RST_PIN, LOW);           // Отпускаем сброс
    rfid.PCD_Init();                      // Инициализируем заного
  }

  if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
  if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

  /* Аутентификация сектора, указываем блок безопасности #7 и ключ B */
  status = rfid.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, 7, &key, &(rfid.uid));
  if (status != MFRC522::STATUS_OK) {     // Если не окэй
    Serial.println("Auth error");         // Выводим ошибку
    return;
  }

  /* Чтение блока, указываем блок данных #6 */
  uint8_t dataBlock[18];                           // Буфер
  uint8_t size = sizeof(dataBlock);                // Размер буфера

  status = rfid.MIFARE_Read(6, dataBlock, &size);  // Читаем блок 6
  if (status != MFRC522::STATUS_OK) {              // Если не окэй
    Serial.println("Read error");                  // Выводим ошибку
    return;
  }

  /* Выводим количество поднесений метки */
  Serial.print("Count: ");                         // Выводим количество
  Serial.println(dataBlock[0]);                    // Хранится в нулевом байте массива
  dataBlock[0]++;                                  // Инкремент

  /* Запись блока, указываем блок данных #6 */
  status = rfid.MIFARE_Write(6, dataBlock, 16);    // Пишем массив в блок 6
  if (status != MFRC522::STATUS_OK) {              // Если не окэй
    Serial.println("Write error");                 // Выводим ошибку
    return;
  }

  rfid.PICC_HaltA();                               // Завершаем работу с меткой
  rfid.PCD_StopCrypto1();
}

Количество поднесений ограничено 255, потому что используется лишь 1 Байт, но для примера это и не важно.

Инкремент и декремент


Наболее продвинутые могут обратить внимание на то, что пример выше не имеет смысла, поскольку метки уже имеют функционал инкремента и декремента, позволяющего использовать защищенный блок в качестве электронного кошелька.

Для реализации данного функционала библиотека имеет методы MIFARE_Increment() и MIFARE_Decrement(), однако независимо от установленных байтов доступа данный функционал не показал работоспособность на десятке меток и нескольких модулях. Возможно всему виной поддельные чипы MFRC522, установленные в модули. В любом случае перечисленные методы возвращают ошибку при поднесении метки, а потому и пример для работы не привожу.

Особенности и костыли


Несмотря на то, что данные модули выпускаются много лет, в течение которых дорабатывалась и библиотека, пара модуль + библиотека имеют критическую проблему зависания (!). Через случайный промежуток времени система просто перестает считывать поднесенные метки – помогает только перезагрузка микроконтроллера. Этот критический баг может сыграть злую шутку, при использовании данного комплекта в электронных замках. Что является причиной? На данный момент достоверного ответа нет… однако есть кое-какие решения!

  • Периодическая перезагрузка и повторная инициализация. В главный цикл программы добавляется таймер на millis() с периодом 500…3000 мс, внутри которого производится принудительный сброс и инициализация модуля. Данный код располагается в начале главного цикла программы. Данный костыль является наиболее эффективным в борьбе с зависанием модуля.
    static uint32_t rebootTimer = millis(); // Важный костыль против зависания модуля!
    if (millis() - rebootTimer >= 1000) {   // Таймер с периодом 1000 мс
      rebootTimer = millis();               // Обновляем таймер
      digitalWrite(RST_PIN, HIGH);          // Сбрасываем модуль
      delayMicroseconds(2);                 // Ждем 2 мкс
      digitalWrite(RST_PIN, LOW);           // Отпускаем сброс
      rfid.PCD_Init();                      // Инициализируем заного
    }
  • Принудительная установка усиления и перезагрузка антенны. Полезность сомнительная, однако по некоторым заявлениям библиотека не всегда корректно настраивает антенну после инициализации модуля. Решается добавлением соответствующих строк помимо инициализации модуля в функции void setup(){}:
    rfid.PCD_SetAntennaGain(rfid.RxGain_max);  // Установка усиления антенны
    rfid.PCD_AntennaOff();                     // Перезагружаем антенну
    rfid.PCD_AntennaOn();                      // Включаем антенну
  • Повторное чтение или второй шанс. В примерах выше мы использовали следующую конструкцию для отслеживания поднесенной метки:
if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
if (!rfid.PICC_ReadCardSerial()) return;    // Если метка не читается - вернуться в начало loop

Фокус заключается в добавлении еще одной попытке чтения метки, в случае неудачи. Таким образом наша конструкция принимает следующий вид:

if (!rfid.PICC_IsNewCardPresent()) return;  // Если новая метка не поднесена - вернуться в начало loop
if (!rfid.PICC_ReadCardSerial()) {          // Если метка не читается - пробуем еще раз
  if (!rfid.PICC_ReadCardSerial()) return;  // Все равно не читается - вернуться в начало loop
}

Наиболее эффективным и важным является первый костыль, располагайте его перед работой с модулем, желательно в начале цикла void loop(){}, но ни в коем случае не в прерывании таймера. Однако несмотря на то, что приведенные выше хитрости действительно работают и многократно повышают стабильность работы RFID модуля – в случае с электронными замками и прочими системами контроля доступа рекомендуется иметь резервные способы входа, помимо RFID.

/* * ——————————————————————————————————————— * Example to change UID of changeable MIFARE card. * ——————————————————————————————————————— * This is a MFRC522 library example; for further details and other examples see: https://github.com/miguelbalboa/rfid * * This sample shows how to set the UID on a UID changeable MIFARE card. * * @author Tom Clement * @license Released into the public domain. * * Typical pin layout used: * —————————————————————————————— * MFRC522 Arduino Arduino Arduino Arduino Arduino * Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro Pro Micro * Signal Pin Pin Pin Pin Pin Pin * —————————————————————————————— * RST/Reset RST 9 5 D9 RESET/ICSP-5 RST * SPI SS SDA(SS) 10 53 D10 10 10 * SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4 16 * SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1 14 * SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3 15 * * More pin layouts for other boards can be found here: https://github.com/miguelbalboa/rfid#pin-layout */ #include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 // Configurable, see typical pin layout above #define SS_PIN 10 // Configurable, see typical pin layout above MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance /* Set your new UID here! */ #define NEW_UID {0xDE, 0xAD, 0xBE, 0xEF} MFRC522::MIFARE_Key key; void setup() { Serial.begin(9600); // Initialize serial communications with the PC while (!Serial); // Do nothing if no serial port is opened (added for Arduinos based on ATMEGA32U4) SPI.begin(); // Init SPI bus mfrc522.PCD_Init(); // Init MFRC522 card Serial.println(F(«Warning: this example overwrites the UID of your UID changeable card, use with care!«)); // Prepare key — all keys are set to FFFFFFFFFFFFh at chip delivery from the factory. for (byte i = 0; i < 6; i++) { key.keyByte[i] = 0xFF; } } // Setting the UID can be as simple as this: //void loop() { // byte newUid[] = NEW_UID; // if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { // Serial.println(«Wrote new UID to card.»); // } // delay(1000); //} // But of course this is a more proper approach void loop() { // Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle. And if present, select one. if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { delay(50); return; } // Now a card is selected. The UID and SAK is in mfrc522.uid. // Dump UID Serial.print(F(«Card UID:«)); for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? « 0« : « «); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); // Dump PICC type // MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); // Serial.print(F(«PICC type: «)); // Serial.print(mfrc522.PICC_GetTypeName(piccType)); // Serial.print(F(» (SAK «)); // Serial.print(mfrc522.uid.sak); // Serial.print(«)rn»); // if ( piccType != MFRC522::PICC_TYPE_MIFARE_MINI // && piccType != MFRC522::PICC_TYPE_MIFARE_1K // && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { // Serial.println(F(«This sample only works with MIFARE Classic cards.»)); // return; // } // Set new UID byte newUid[] = NEW_UID; if ( mfrc522.MIFARE_SetUid(newUid, (byte)4, true) ) { Serial.println(F(«Wrote new UID to card.«)); } // Halt PICC and re-select it so DumpToSerial doesn’t get confused mfrc522.PICC_HaltA(); if ( ! mfrc522.PICC_IsNewCardPresent() || ! mfrc522.PICC_ReadCardSerial() ) { return; } // Dump the new memory contents Serial.println(F(«New UID and contents:«)); mfrc522.PICC_DumpToSerial(&(mfrc522.uid)); delay(2000); }

Есть карточка, можно на ней перезаписать, с помощью arduino и rfid522 ?


  • Вопрос задан

    более трёх лет назад

  • 2303 просмотра

Пригласить эксперта

От карточки зависит.
В подавляющем большинстве случаев — нельзя.

По стандарту — нельзя.
Но китайцы сказали «если нельзя, но очень хочется — то можно» и выпустили карты поддерживающие перезапись 0 блока.

Со стандартной меткой — нельзя. Но если ввести в поиске <имя_метки> white или <имя_метки> zero, то можно приобрести соответствующую метку или даже взять «за пиво» у наигравшегося.
Только не экспериментируйте в метро с Mifare Zero, ладно?;)


  • Показать ещё
    Загружается…

Сбер

Нижний Новгород

от 220 000 ₽

10 февр. 2023, в 13:40

75000 руб./за проект

10 февр. 2023, в 13:27

2000 руб./за проект

10 февр. 2023, в 13:18

150000 руб./за проект

Минуточку внимания

Offline

Зарегистрирован: 20.05.2014

Здравствуйте!

Использую считываетль RC522  и библиотеку для него от сюда https://github.com/miguelbalboa/rfid

Подскажите как правильно изменить ключ доступа карточки с заводского FF FF FF FF FF FF на другой? В примерах это не показано а найти верную функцию в справочном файле не могу. Попробовал перезаписать ключ с помощю этого кода (с 48 строки) в 1 сектор 7 блок, после чего он перестал считыватся. Хотя по факту как я думаю записал опять же стандартынй ключ  FF FF FF FF FF FF 

Подскажите пожалуйста как это правильно делать?

// Библиотека RC522 взята отсюда: https://github.com/miguelbalboa/rfid
#include <SPI.h>
#include <MFRC522.h>

#define SS_PIN 10
#define RST_PIN 9
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance.
unsigned long uidDec, uidDecTemp;  // Для отображения номера карточки в десятичном формате.
MFRC522::MIFARE_Key keyA;



void setup() {
 Serial.begin(9600); // Initialize serial communications with the PC
 SPI.begin();   // Init SPI bus
 mfrc522.PCD_Init(); // Init MFRC522 card

  // Подготовьте ключ (используется как ключ A и как ключ B)
    // используя FFFFFFFFFFFFh, который используется по умолчанию при поставке чипа с завода
   byte Byte[6]= {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //Ключ пароль на считывание карточки
  for (byte i = 0; i < 6; i++) {   //Закладываем в массив значения ключа который записан в массив Byte
    keyA.keyByte[i] = Byte[i];
   }
   
     
}

void loop() {

   
 if ( ! mfrc522.PICC_IsNewCardPresent()) {
  return;
 }

 // Select one of the cards
 if ( ! mfrc522.PICC_ReadCardSerial()) {
  return;
 }
 // Проверить совместимость
  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("This sample only works with MIFARE Classic cards."));
        return;
    }
// Закладываем адреса сектора  блока куда будем писать данные
   
    byte sector         = 1;
    byte blockAddr      = 7;
    byte dataBlock[]    = {
        0x00, 0x00, 0x00, 0x00, //  Дамп заводского
        0x00, 0x00, 0xFF, 0x07, //  ключа
        0x80, 0x69, 0xFF, 0xFF, //  
        0xFF, 0xFF, 0xFF, 0xFF  // 
    };
    byte trailerBlock   = 7;
    MFRC522::StatusCode status;
    byte buffer[18];
    byte size = sizeof(buffer);

    // Аутентификация с использованием ключа A
   // Serial.println(F("Authenticating using key A..."));
    status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailerBlock, &keyA, &(mfrc522.uid));
    if (status != MFRC522::STATUS_OK) {
        Serial.print(F("PCD_Authenticate() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
    }

       // Аутентификация с использованием ключа B
  //  Serial.println(F("Authenticating again using key B..."));
    status = (MFRC522::StatusCode) mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailerBlock, &keyA, &(mfrc522.uid));
    if (status != MFRC522::STATUS_OK) {
        Serial.print(F("PCD_Authenticate() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
        return;
    }

    // Записать данные в блок
 //   Serial.print(F("Writing data into block ")); 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("MIFARE_Write() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
    }
      Serial.println();

    // Чтение данных из блока (опять же, теперь должно быть то, что мы написали)
    Serial.print(F("Reading data from block ")); Serial.print(blockAddr);
    Serial.println(F(" ..."));
    status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(blockAddr, buffer, &size);
    if (status != MFRC522::STATUS_OK) {
        Serial.print(F("MIFARE_Read() failed: "));
        Serial.println(mfrc522.GetStatusCodeName(status));
    }
    Serial.print(F("Data in block ")); Serial.print(blockAddr); Serial.println(F(":"));
    dump_byte_array(buffer, 16); Serial.println();
/*
   
        for (byte i = 0; i < 4; i++) {
          if (uidCard[i] != mfrc522.uid.uidByte[i]){}
          //  return;           
        }
*/        
 
           // Выдача серийного номера карточки "UID".
  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
    uidDecTemp = mfrc522.uid.uidByte[i];
    uidDec = uidDec*256+uidDecTemp;  
  }  
  Serial.print ("UID DEC = ");
  Serial.println (uidDec);
 
    // Остановить PICC
    mfrc522.PICC_HaltA();
   // Остановить шифрование на PCD
    mfrc522.PCD_StopCrypto1();     
}
// Функция преобразования массива в шеснацетеричнвй вид
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);
    }
}

I have been playing around with my RPi2B (with Jessie), an adafruit breakout board and a RFID-RC522. I followed a guide to make it work, and it works like a charm
Guide for adding RFID-RC522 to RPi2B

I have managed to change the information on the key, from all 00, to 1,2,3 etc, but I can’t change the key used for authentication. The guide says that the key is a default key, only containing hexadecimal 0xFF, but I want to have my own key, especially if I use this to lock a door.

Is this possible?

I have included the code for the files I use.

Read.py for reading tags

#!/usr/bin/env python
# -*- coding: utf8 -*-

import RPi.GPIO as GPIO
import MFRC522
import signal

continue_reading = True

# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
    global continue_reading
    print "Ctrl+C captured, ending read."
    continue_reading = False
    GPIO.cleanup()

# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)

# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()

# Welcome message
print "Welcome to the MFRC522 data read example"
print "Press Ctrl-C to stop."

# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:

    # Scan for cards    
    (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

    # If a card is found
    if status == MIFAREReader.MI_OK:
        print "Card detected"

    # Get the UID of the card
    (status,uid) = MIFAREReader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status == MIFAREReader.MI_OK:

        # Print UID
        print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])

        if uid == [164,1,33,43,175]:
            print "WHITE CARD"

        # This is the default key for authentication
        key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]




        # Select the scanned tag
        MIFAREReader.MFRC522_SelectTag(uid)

        # Authenticate
        status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)

        # Check if authenticated
        if status == MIFAREReader.MI_OK:
            MIFAREReader.MFRC522_Read(8)
            MIFAREReader.MFRC522_StopCrypto1()
        else:
            print "Authentication error"

Write.py for writing tags

#!/usr/bin/env python
# -*- coding: utf8 -*-

import RPi.GPIO as GPIO
import MFRC522
import signal

continue_reading = True

# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
    global continue_reading
    print "Ctrl+C captured, ending read."
    continue_reading = False
    GPIO.cleanup()

# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)

# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()

# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:

    # Scan for cards    
    (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

    # If a card is found
    if status == MIFAREReader.MI_OK:
        print "Card detected"

    # Get the UID of the card
    (status,uid) = MIFAREReader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status == MIFAREReader.MI_OK:

        # Print UID
        print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])

        # This is the default key for authentication
        key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]

        # Select the scanned tag
        MIFAREReader.MFRC522_SelectTag(uid)

        # Authenticate
        status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
        print "n"

        # Check if authenticated
        if status == MIFAREReader.MI_OK:

            # Variable for the data to write
            data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

            # Fill the data with 0xFF
           # for x in range(0,16):
            #    data.append(0xFF)

            print "Sector 8 looked like this:"
            # Read block 8
            MIFAREReader.MFRC522_Read(8)
            print "n"

            print "Sector 8 will now be filled with data in code:"
            # Write the data
            MIFAREReader.MFRC522_Write(8, data)
            print "n"

            print "It now looks like this:"
            # Check to see if it was written
            MIFAREReader.MFRC522_Read(8)
            print "n"

           # data = []
            # Fill the data with 0x00
            #for x in range(0,16):
             #   data.append(0x00)

            #print "Now we fill it with 0x00:"
            #MIFAREReader.MFRC522_Write(8, data)
            #print "n"

            #print "It is now empty:"
            # Check to see if it was written
            #MIFAREReader.MFRC522_Read(8)
            #print "n"

            # Stop
            MIFAREReader.MFRC522_StopCrypto1()

            # Make sure to stop reading for cards
            continue_reading = False
        else:
            print "Authentication error"

MFRC522.py containing the functions used in the two above

import RPi.GPIO as GPIO
import spi
import signal

class MFRC522:
  NRSTPD = 22

  MAX_LEN = 16

  PCD_IDLE       = 0x00
  PCD_AUTHENT    = 0x0E
  PCD_RECEIVE    = 0x08
  PCD_TRANSMIT   = 0x04
  PCD_TRANSCEIVE = 0x0C
  PCD_RESETPHASE = 0x0F
  PCD_CALCCRC    = 0x03

  PICC_REQIDL    = 0x26
  PICC_REQALL    = 0x52
  PICC_ANTICOLL  = 0x93
  PICC_SElECTTAG = 0x93
  PICC_AUTHENT1A = 0x60
  PICC_AUTHENT1B = 0x61
  PICC_READ      = 0x30
  PICC_WRITE     = 0xA0
  PICC_DECREMENT = 0xC0
  PICC_INCREMENT = 0xC1
  PICC_RESTORE   = 0xC2
  PICC_TRANSFER  = 0xB0
  PICC_HALT      = 0x50

  MI_OK       = 0
  MI_NOTAGERR = 1
  MI_ERR      = 2

  Reserved00     = 0x00
  CommandReg     = 0x01
  CommIEnReg     = 0x02
  DivlEnReg      = 0x03
  CommIrqReg     = 0x04
  DivIrqReg      = 0x05
  ErrorReg       = 0x06
  Status1Reg     = 0x07
  Status2Reg     = 0x08
  FIFODataReg    = 0x09
  FIFOLevelReg   = 0x0A
  WaterLevelReg  = 0x0B
  ControlReg     = 0x0C
  BitFramingReg  = 0x0D
  CollReg        = 0x0E
  Reserved01     = 0x0F

  Reserved10     = 0x10
  ModeReg        = 0x11
  TxModeReg      = 0x12
  RxModeReg      = 0x13
  TxControlReg   = 0x14
  TxAutoReg      = 0x15
  TxSelReg       = 0x16
  RxSelReg       = 0x17
  RxThresholdReg = 0x18
  DemodReg       = 0x19
  Reserved11     = 0x1A
  Reserved12     = 0x1B
  MifareReg      = 0x1C
  Reserved13     = 0x1D
  Reserved14     = 0x1E
  SerialSpeedReg = 0x1F

  Reserved20        = 0x20  
  CRCResultRegM     = 0x21
  CRCResultRegL     = 0x22
  Reserved21        = 0x23
  ModWidthReg       = 0x24
  Reserved22        = 0x25
  RFCfgReg          = 0x26
  GsNReg            = 0x27
  CWGsPReg          = 0x28
  ModGsPReg         = 0x29
  TModeReg          = 0x2A
  TPrescalerReg     = 0x2B
  TReloadRegH       = 0x2C
  TReloadRegL       = 0x2D
  TCounterValueRegH = 0x2E
  TCounterValueRegL = 0x2F

  Reserved30      = 0x30
  TestSel1Reg     = 0x31
  TestSel2Reg     = 0x32
  TestPinEnReg    = 0x33
  TestPinValueReg = 0x34
  TestBusReg      = 0x35
  AutoTestReg     = 0x36
  VersionReg      = 0x37
  AnalogTestReg   = 0x38
  TestDAC1Reg     = 0x39
  TestDAC2Reg     = 0x3A
  TestADCReg      = 0x3B
  Reserved31      = 0x3C
  Reserved32      = 0x3D
  Reserved33      = 0x3E
  Reserved34      = 0x3F

  serNum = []

  def __init__(self,spd=1000000):
    spi.openSPI(speed=spd)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(22, GPIO.OUT)
    GPIO.output(self.NRSTPD, 1)
    self.MFRC522_Init()

  def MFRC522_Reset(self):
    self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE)

  def Write_MFRC522(self,addr,val):
    spi.transfer(((addr<<1)&0x7E,val))

  def Read_MFRC522(self,addr):
    val = spi.transfer((((addr<<1)&0x7E) | 0x80,0))
    return val[1]

  def SetBitMask(self, reg, mask):
    tmp = self.Read_MFRC522(reg)
    self.Write_MFRC522(reg, tmp | mask)

  def ClearBitMask(self, reg, mask):
    tmp = self.Read_MFRC522(reg);
    self.Write_MFRC522(reg, tmp & (~mask))

  def AntennaOn(self):
    temp = self.Read_MFRC522(self.TxControlReg)
    if(~(temp & 0x03)):
      self.SetBitMask(self.TxControlReg, 0x03)

  def AntennaOff(self):
    self.ClearBitMask(self.TxControlReg, 0x03)

  def MFRC522_ToCard(self,command,sendData):
    backData = []
    backLen = 0
    status = self.MI_ERR
    irqEn = 0x00
    waitIRq = 0x00
    lastBits = None
    n = 0
    i = 0

    if command == self.PCD_AUTHENT:
      irqEn = 0x12
      waitIRq = 0x10
    if command == self.PCD_TRANSCEIVE:
      irqEn = 0x77
      waitIRq = 0x30

    self.Write_MFRC522(self.CommIEnReg, irqEn|0x80)
    self.ClearBitMask(self.CommIrqReg, 0x80)
    self.SetBitMask(self.FIFOLevelReg, 0x80)

    self.Write_MFRC522(self.CommandReg, self.PCD_IDLE);  

    while(i<len(sendData)):
      self.Write_MFRC522(self.FIFODataReg, sendData[i])
      i = i+1

    self.Write_MFRC522(self.CommandReg, command)

    if command == self.PCD_TRANSCEIVE:
      self.SetBitMask(self.BitFramingReg, 0x80)

    i = 2000
    while True:
      n = self.Read_MFRC522(self.CommIrqReg)
      i = i - 1
      if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)):
        break

    self.ClearBitMask(self.BitFramingReg, 0x80)

    if i != 0:
      if (self.Read_MFRC522(self.ErrorReg) & 0x1B)==0x00:
        status = self.MI_OK

        if n & irqEn & 0x01:
          status = self.MI_NOTAGERR

        if command == self.PCD_TRANSCEIVE:
          n = self.Read_MFRC522(self.FIFOLevelReg)
          lastBits = self.Read_MFRC522(self.ControlReg) & 0x07
          if lastBits != 0:
            backLen = (n-1)*8 + lastBits
          else:
            backLen = n*8

          if n == 0:
            n = 1
          if n > self.MAX_LEN:
            n = self.MAX_LEN

          i = 0
          while i<n:
            backData.append(self.Read_MFRC522(self.FIFODataReg))
            i = i + 1;
      else:
        status = self.MI_ERR

    return (status,backData,backLen)


  def MFRC522_Request(self, reqMode):
    status = None
    backBits = None
    TagType = []

    self.Write_MFRC522(self.BitFramingReg, 0x07)

    TagType.append(reqMode);
    (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, TagType)

    if ((status != self.MI_OK) | (backBits != 0x10)):
      status = self.MI_ERR

    return (status,backBits)


  def MFRC522_Anticoll(self):
    backData = []
    serNumCheck = 0

    serNum = []

    self.Write_MFRC522(self.BitFramingReg, 0x00)

    serNum.append(self.PICC_ANTICOLL)
    serNum.append(0x20)

    (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,serNum)

    if(status == self.MI_OK):
      i = 0
      if len(backData)==5:
        while i<4:
          serNumCheck = serNumCheck ^ backData[i]
          i = i + 1
        if serNumCheck != backData[i]:
          status = self.MI_ERR
      else:
        status = self.MI_ERR

    return (status,backData)

  def CalulateCRC(self, pIndata):
    self.ClearBitMask(self.DivIrqReg, 0x04)
    self.SetBitMask(self.FIFOLevelReg, 0x80);
    i = 0
    while i<len(pIndata):
      self.Write_MFRC522(self.FIFODataReg, pIndata[i])
      i = i + 1
    self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC)
    i = 0xFF
    while True:
      n = self.Read_MFRC522(self.DivIrqReg)
      i = i - 1
      if not ((i != 0) and not (n&0x04)):
        break
    pOutData = []
    pOutData.append(self.Read_MFRC522(self.CRCResultRegL))
    pOutData.append(self.Read_MFRC522(self.CRCResultRegM))
    return pOutData

  def MFRC522_SelectTag(self, serNum):
    backData = []
    buf = []
    buf.append(self.PICC_SElECTTAG)
    buf.append(0x70)
    i = 0
    while i<5:
      buf.append(serNum[i])
      i = i + 1
    pOut = self.CalulateCRC(buf)
    buf.append(pOut[0])
    buf.append(pOut[1])
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)

    if (status == self.MI_OK) and (backLen == 0x18):
      print("Size: " + str(backData[0]))
      return  backData[0]
    else:
      return 0

  def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum):
    buff = []
    buff.append(authMode)
    buff.append(BlockAddr)
    i = 0
    while(i < len(Sectorkey)):
      buff.append(Sectorkey[i])
      i = i + 1
    i = 0
    while(i < len(serNum)):
      buff.append(serNum[i])
      i = i +1
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT,buff)
    if not(status == self.MI_OK):
      print("AUTH ERROR!!")
    if not (self.Read_MFRC522(self.Status2Reg) & 0x08) != 0:
      print("AUTH ERROR(status2reg & 0x08) != 0")

    return status

  def MFRC522_Read(self, blockAddr):
    recvData = []
    recvData.append(self.PICC_READ)
    recvData.append(blockAddr)
    pOut = self.CalulateCRC(recvData)
    recvData.append(pOut[0])
    recvData.append(pOut[1])
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recvData)
    if not(status == self.MI_OK):
      print("Error while reading!")

    print("Got data size: "+str(backLen))
    i = 0
    if len(backData) == 16:
      print("Sector "+str(blockAddr)+" "+str(backData))

  def MFRC522_Write(self, blockAddr, writeData):
    buff = []
    buff.append(self.PICC_WRITE)
    buff.append(blockAddr)
    crc = self.CalulateCRC(buff)
    buff.append(crc[0])
    buff.append(crc[1])
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buff)
    if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
      status = self.MI_ERR

    print(str(backLen)+" backdata &0x0F == 0x0A "+str(backData[0]&0x0F))
    if status == self.MI_OK:
        i = 0
        buf = []
        while i < 16:
          buf.append(writeData[i])
          i = i + 1
        crc = self.CalulateCRC(buf)
        buf.append(crc[0])
        buf.append(crc[1])
        (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,buf)
        if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
          print("Error while writing")
        if status == self.MI_OK:
          print("Data writen")


  def MFRC522_Init(self):
    GPIO.output(self.NRSTPD, 1)

    self.MFRC522_Reset();


    self.Write_MFRC522(self.TModeReg, 0x8D)
    self.Write_MFRC522(self.TPrescalerReg, 0x3E)
    self.Write_MFRC522(self.TReloadRegL, 30)
    self.Write_MFRC522(self.TReloadRegH, 0)

    self.Write_MFRC522(self.TxAutoReg, 0x40)
    self.Write_MFRC522(self.ModeReg, 0x3D)
    self.AntennaOn()

  def GPIO_CLEEN(self):
    GPIO.cleanup() 

I have been playing around with my RPi2B (with Jessie), an adafruit breakout board and a RFID-RC522. I followed a guide to make it work, and it works like a charm
Guide for adding RFID-RC522 to RPi2B

I have managed to change the information on the key, from all 00, to 1,2,3 etc, but I can’t change the key used for authentication. The guide says that the key is a default key, only containing hexadecimal 0xFF, but I want to have my own key, especially if I use this to lock a door.

Is this possible?

I have included the code for the files I use.

Read.py for reading tags

#!/usr/bin/env python
# -*- coding: utf8 -*-

import RPi.GPIO as GPIO
import MFRC522
import signal

continue_reading = True

# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
    global continue_reading
    print "Ctrl+C captured, ending read."
    continue_reading = False
    GPIO.cleanup()

# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)

# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()

# Welcome message
print "Welcome to the MFRC522 data read example"
print "Press Ctrl-C to stop."

# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:

    # Scan for cards    
    (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

    # If a card is found
    if status == MIFAREReader.MI_OK:
        print "Card detected"

    # Get the UID of the card
    (status,uid) = MIFAREReader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status == MIFAREReader.MI_OK:

        # Print UID
        print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])

        if uid == [164,1,33,43,175]:
            print "WHITE CARD"

        # This is the default key for authentication
        key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]




        # Select the scanned tag
        MIFAREReader.MFRC522_SelectTag(uid)

        # Authenticate
        status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)

        # Check if authenticated
        if status == MIFAREReader.MI_OK:
            MIFAREReader.MFRC522_Read(8)
            MIFAREReader.MFRC522_StopCrypto1()
        else:
            print "Authentication error"

Write.py for writing tags

#!/usr/bin/env python
# -*- coding: utf8 -*-

import RPi.GPIO as GPIO
import MFRC522
import signal

continue_reading = True

# Capture SIGINT for cleanup when the script is aborted
def end_read(signal,frame):
    global continue_reading
    print "Ctrl+C captured, ending read."
    continue_reading = False
    GPIO.cleanup()

# Hook the SIGINT
signal.signal(signal.SIGINT, end_read)

# Create an object of the class MFRC522
MIFAREReader = MFRC522.MFRC522()

# This loop keeps checking for chips. If one is near it will get the UID and authenticate
while continue_reading:

    # Scan for cards    
    (status,TagType) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQIDL)

    # If a card is found
    if status == MIFAREReader.MI_OK:
        print "Card detected"

    # Get the UID of the card
    (status,uid) = MIFAREReader.MFRC522_Anticoll()

    # If we have the UID, continue
    if status == MIFAREReader.MI_OK:

        # Print UID
        print "Card read UID: "+str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3])

        # This is the default key for authentication
        key = [0xFF,0xFF,0xFF,0xFF,0xFF,0xFF]

        # Select the scanned tag
        MIFAREReader.MFRC522_SelectTag(uid)

        # Authenticate
        status = MIFAREReader.MFRC522_Auth(MIFAREReader.PICC_AUTHENT1A, 8, key, uid)
        print "n"

        # Check if authenticated
        if status == MIFAREReader.MI_OK:

            # Variable for the data to write
            data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

            # Fill the data with 0xFF
           # for x in range(0,16):
            #    data.append(0xFF)

            print "Sector 8 looked like this:"
            # Read block 8
            MIFAREReader.MFRC522_Read(8)
            print "n"

            print "Sector 8 will now be filled with data in code:"
            # Write the data
            MIFAREReader.MFRC522_Write(8, data)
            print "n"

            print "It now looks like this:"
            # Check to see if it was written
            MIFAREReader.MFRC522_Read(8)
            print "n"

           # data = []
            # Fill the data with 0x00
            #for x in range(0,16):
             #   data.append(0x00)

            #print "Now we fill it with 0x00:"
            #MIFAREReader.MFRC522_Write(8, data)
            #print "n"

            #print "It is now empty:"
            # Check to see if it was written
            #MIFAREReader.MFRC522_Read(8)
            #print "n"

            # Stop
            MIFAREReader.MFRC522_StopCrypto1()

            # Make sure to stop reading for cards
            continue_reading = False
        else:
            print "Authentication error"

MFRC522.py containing the functions used in the two above

import RPi.GPIO as GPIO
import spi
import signal

class MFRC522:
  NRSTPD = 22

  MAX_LEN = 16

  PCD_IDLE       = 0x00
  PCD_AUTHENT    = 0x0E
  PCD_RECEIVE    = 0x08
  PCD_TRANSMIT   = 0x04
  PCD_TRANSCEIVE = 0x0C
  PCD_RESETPHASE = 0x0F
  PCD_CALCCRC    = 0x03

  PICC_REQIDL    = 0x26
  PICC_REQALL    = 0x52
  PICC_ANTICOLL  = 0x93
  PICC_SElECTTAG = 0x93
  PICC_AUTHENT1A = 0x60
  PICC_AUTHENT1B = 0x61
  PICC_READ      = 0x30
  PICC_WRITE     = 0xA0
  PICC_DECREMENT = 0xC0
  PICC_INCREMENT = 0xC1
  PICC_RESTORE   = 0xC2
  PICC_TRANSFER  = 0xB0
  PICC_HALT      = 0x50

  MI_OK       = 0
  MI_NOTAGERR = 1
  MI_ERR      = 2

  Reserved00     = 0x00
  CommandReg     = 0x01
  CommIEnReg     = 0x02
  DivlEnReg      = 0x03
  CommIrqReg     = 0x04
  DivIrqReg      = 0x05
  ErrorReg       = 0x06
  Status1Reg     = 0x07
  Status2Reg     = 0x08
  FIFODataReg    = 0x09
  FIFOLevelReg   = 0x0A
  WaterLevelReg  = 0x0B
  ControlReg     = 0x0C
  BitFramingReg  = 0x0D
  CollReg        = 0x0E
  Reserved01     = 0x0F

  Reserved10     = 0x10
  ModeReg        = 0x11
  TxModeReg      = 0x12
  RxModeReg      = 0x13
  TxControlReg   = 0x14
  TxAutoReg      = 0x15
  TxSelReg       = 0x16
  RxSelReg       = 0x17
  RxThresholdReg = 0x18
  DemodReg       = 0x19
  Reserved11     = 0x1A
  Reserved12     = 0x1B
  MifareReg      = 0x1C
  Reserved13     = 0x1D
  Reserved14     = 0x1E
  SerialSpeedReg = 0x1F

  Reserved20        = 0x20  
  CRCResultRegM     = 0x21
  CRCResultRegL     = 0x22
  Reserved21        = 0x23
  ModWidthReg       = 0x24
  Reserved22        = 0x25
  RFCfgReg          = 0x26
  GsNReg            = 0x27
  CWGsPReg          = 0x28
  ModGsPReg         = 0x29
  TModeReg          = 0x2A
  TPrescalerReg     = 0x2B
  TReloadRegH       = 0x2C
  TReloadRegL       = 0x2D
  TCounterValueRegH = 0x2E
  TCounterValueRegL = 0x2F

  Reserved30      = 0x30
  TestSel1Reg     = 0x31
  TestSel2Reg     = 0x32
  TestPinEnReg    = 0x33
  TestPinValueReg = 0x34
  TestBusReg      = 0x35
  AutoTestReg     = 0x36
  VersionReg      = 0x37
  AnalogTestReg   = 0x38
  TestDAC1Reg     = 0x39
  TestDAC2Reg     = 0x3A
  TestADCReg      = 0x3B
  Reserved31      = 0x3C
  Reserved32      = 0x3D
  Reserved33      = 0x3E
  Reserved34      = 0x3F

  serNum = []

  def __init__(self,spd=1000000):
    spi.openSPI(speed=spd)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(22, GPIO.OUT)
    GPIO.output(self.NRSTPD, 1)
    self.MFRC522_Init()

  def MFRC522_Reset(self):
    self.Write_MFRC522(self.CommandReg, self.PCD_RESETPHASE)

  def Write_MFRC522(self,addr,val):
    spi.transfer(((addr<<1)&0x7E,val))

  def Read_MFRC522(self,addr):
    val = spi.transfer((((addr<<1)&0x7E) | 0x80,0))
    return val[1]

  def SetBitMask(self, reg, mask):
    tmp = self.Read_MFRC522(reg)
    self.Write_MFRC522(reg, tmp | mask)

  def ClearBitMask(self, reg, mask):
    tmp = self.Read_MFRC522(reg);
    self.Write_MFRC522(reg, tmp & (~mask))

  def AntennaOn(self):
    temp = self.Read_MFRC522(self.TxControlReg)
    if(~(temp & 0x03)):
      self.SetBitMask(self.TxControlReg, 0x03)

  def AntennaOff(self):
    self.ClearBitMask(self.TxControlReg, 0x03)

  def MFRC522_ToCard(self,command,sendData):
    backData = []
    backLen = 0
    status = self.MI_ERR
    irqEn = 0x00
    waitIRq = 0x00
    lastBits = None
    n = 0
    i = 0

    if command == self.PCD_AUTHENT:
      irqEn = 0x12
      waitIRq = 0x10
    if command == self.PCD_TRANSCEIVE:
      irqEn = 0x77
      waitIRq = 0x30

    self.Write_MFRC522(self.CommIEnReg, irqEn|0x80)
    self.ClearBitMask(self.CommIrqReg, 0x80)
    self.SetBitMask(self.FIFOLevelReg, 0x80)

    self.Write_MFRC522(self.CommandReg, self.PCD_IDLE);  

    while(i<len(sendData)):
      self.Write_MFRC522(self.FIFODataReg, sendData[i])
      i = i+1

    self.Write_MFRC522(self.CommandReg, command)

    if command == self.PCD_TRANSCEIVE:
      self.SetBitMask(self.BitFramingReg, 0x80)

    i = 2000
    while True:
      n = self.Read_MFRC522(self.CommIrqReg)
      i = i - 1
      if ~((i!=0) and ~(n&0x01) and ~(n&waitIRq)):
        break

    self.ClearBitMask(self.BitFramingReg, 0x80)

    if i != 0:
      if (self.Read_MFRC522(self.ErrorReg) & 0x1B)==0x00:
        status = self.MI_OK

        if n & irqEn & 0x01:
          status = self.MI_NOTAGERR

        if command == self.PCD_TRANSCEIVE:
          n = self.Read_MFRC522(self.FIFOLevelReg)
          lastBits = self.Read_MFRC522(self.ControlReg) & 0x07
          if lastBits != 0:
            backLen = (n-1)*8 + lastBits
          else:
            backLen = n*8

          if n == 0:
            n = 1
          if n > self.MAX_LEN:
            n = self.MAX_LEN

          i = 0
          while i<n:
            backData.append(self.Read_MFRC522(self.FIFODataReg))
            i = i + 1;
      else:
        status = self.MI_ERR

    return (status,backData,backLen)


  def MFRC522_Request(self, reqMode):
    status = None
    backBits = None
    TagType = []

    self.Write_MFRC522(self.BitFramingReg, 0x07)

    TagType.append(reqMode);
    (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, TagType)

    if ((status != self.MI_OK) | (backBits != 0x10)):
      status = self.MI_ERR

    return (status,backBits)


  def MFRC522_Anticoll(self):
    backData = []
    serNumCheck = 0

    serNum = []

    self.Write_MFRC522(self.BitFramingReg, 0x00)

    serNum.append(self.PICC_ANTICOLL)
    serNum.append(0x20)

    (status,backData,backBits) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,serNum)

    if(status == self.MI_OK):
      i = 0
      if len(backData)==5:
        while i<4:
          serNumCheck = serNumCheck ^ backData[i]
          i = i + 1
        if serNumCheck != backData[i]:
          status = self.MI_ERR
      else:
        status = self.MI_ERR

    return (status,backData)

  def CalulateCRC(self, pIndata):
    self.ClearBitMask(self.DivIrqReg, 0x04)
    self.SetBitMask(self.FIFOLevelReg, 0x80);
    i = 0
    while i<len(pIndata):
      self.Write_MFRC522(self.FIFODataReg, pIndata[i])
      i = i + 1
    self.Write_MFRC522(self.CommandReg, self.PCD_CALCCRC)
    i = 0xFF
    while True:
      n = self.Read_MFRC522(self.DivIrqReg)
      i = i - 1
      if not ((i != 0) and not (n&0x04)):
        break
    pOutData = []
    pOutData.append(self.Read_MFRC522(self.CRCResultRegL))
    pOutData.append(self.Read_MFRC522(self.CRCResultRegM))
    return pOutData

  def MFRC522_SelectTag(self, serNum):
    backData = []
    buf = []
    buf.append(self.PICC_SElECTTAG)
    buf.append(0x70)
    i = 0
    while i<5:
      buf.append(serNum[i])
      i = i + 1
    pOut = self.CalulateCRC(buf)
    buf.append(pOut[0])
    buf.append(pOut[1])
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buf)

    if (status == self.MI_OK) and (backLen == 0x18):
      print("Size: " + str(backData[0]))
      return  backData[0]
    else:
      return 0

  def MFRC522_Auth(self, authMode, BlockAddr, Sectorkey, serNum):
    buff = []
    buff.append(authMode)
    buff.append(BlockAddr)
    i = 0
    while(i < len(Sectorkey)):
      buff.append(Sectorkey[i])
      i = i + 1
    i = 0
    while(i < len(serNum)):
      buff.append(serNum[i])
      i = i +1
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_AUTHENT,buff)
    if not(status == self.MI_OK):
      print("AUTH ERROR!!")
    if not (self.Read_MFRC522(self.Status2Reg) & 0x08) != 0:
      print("AUTH ERROR(status2reg & 0x08) != 0")

    return status

  def MFRC522_Read(self, blockAddr):
    recvData = []
    recvData.append(self.PICC_READ)
    recvData.append(blockAddr)
    pOut = self.CalulateCRC(recvData)
    recvData.append(pOut[0])
    recvData.append(pOut[1])
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, recvData)
    if not(status == self.MI_OK):
      print("Error while reading!")

    print("Got data size: "+str(backLen))
    i = 0
    if len(backData) == 16:
      print("Sector "+str(blockAddr)+" "+str(backData))

  def MFRC522_Write(self, blockAddr, writeData):
    buff = []
    buff.append(self.PICC_WRITE)
    buff.append(blockAddr)
    crc = self.CalulateCRC(buff)
    buff.append(crc[0])
    buff.append(crc[1])
    (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE, buff)
    if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
      status = self.MI_ERR

    print(str(backLen)+" backdata &0x0F == 0x0A "+str(backData[0]&0x0F))
    if status == self.MI_OK:
        i = 0
        buf = []
        while i < 16:
          buf.append(writeData[i])
          i = i + 1
        crc = self.CalulateCRC(buf)
        buf.append(crc[0])
        buf.append(crc[1])
        (status, backData, backLen) = self.MFRC522_ToCard(self.PCD_TRANSCEIVE,buf)
        if not(status == self.MI_OK) or not(backLen == 4) or not((backData[0] & 0x0F) == 0x0A):
          print("Error while writing")
        if status == self.MI_OK:
          print("Data writen")


  def MFRC522_Init(self):
    GPIO.output(self.NRSTPD, 1)

    self.MFRC522_Reset();


    self.Write_MFRC522(self.TModeReg, 0x8D)
    self.Write_MFRC522(self.TPrescalerReg, 0x3E)
    self.Write_MFRC522(self.TReloadRegL, 30)
    self.Write_MFRC522(self.TReloadRegH, 0)

    self.Write_MFRC522(self.TxAutoReg, 0x40)
    self.Write_MFRC522(self.ModeReg, 0x3D)
    self.AntennaOn()

  def GPIO_CLEEN(self):
    GPIO.cleanup() 

Понравилась статья? Поделить с друзьями:
  • Как изменить uid камеры
  • Как изменить ttl на модеме zte
  • Как изменить uid xenforo
  • Как изменить ttl на модеме huawei e8372
  • Как изменить uid mifare