Считыватель RC522 изменение ключа доступа на карточке?
- Войдите на сайт для отправки комментариев
Пнд, 21/01/2019 - 10:17
Здравствуйте!
Использую считываетль 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); } }
А как-же гугл?
Если есть желание разобраться с протоколом mifare classic, лучше обратиться к первоисточнику.
А как-же гугл?
Спасибо почитал. Я впринципе тот же код использую для записи данных и работет он хорошо, но стоит записать данные типа
053
0x00, 0x00, 0x00, 0x00,
// Дамп заводского
054
0x00, 0x00, 0xFF, 0x07,
// ключа
055
0x80, 0x69, 0xFF, 0xFF,
//
056
0xFF, 0xFF, 0xFF, 0xFF
//
в блок 3, 7, 11, и т.д. как эти сектора перестают считыватся при помощи заводского ключа FF FF FF FF FF FF. Хотя по логике я записываю в эти блоки то же самое что там было до этого, вот только после этого эти блоки перестают считыватся, отсюда и вопрос как правильно менять ключ доступа к секторам карточки?
Сейчас немножко прокомментирую что вы делаете.
Перезаписываете на заводском ключе (FFFFFF) в секторе трейлер, кроме ключа A и B в трейлере хранятся аксесс биты (те что FF 07 80) для доступа к блокам сектора и самого трейлера (т.е. какие операции разрешены read/write/increment/decrement и на каком ключе можно их выполнять на А или на B).
Для трейлера аксесс биты C1.3 C2.3 C3.3 у вас имеют значение 0 0 1 что означает:
Чтение ключа A в трейлере - недопустимо
Запись ключа A в трейлере - на ключе A
Чтение и запись аксесс битов и ключа B - на ключе A
Вы на загруженном заводском ключе A изменили ключ А и после на заводском ключе пытаетесь читать этот трейлер, не получится.
Алексей у меня тоже по этому поводу были сомнения, получается что бы дать полное разрешение нужно вписать (0х00 0х00 0х08) это вроде как дефолтные настройки, поправте меня пожалуйста если не прав.
P.S. Сейчас еще раз посмотрел даташит по битам доступа, получается в полубайтах обязательно должны быть прописаны так же и инверсные занцения?
Ключи A и B используются для разграничения зон ответственности, например используем карту для проезда на транспорте и количество поездок хранятся в определенном блоке какого-то сектора, тогда для этого блока определим аксесс биты 1 1 0 что означает
read - ключ A|B
write - ключ B
increment - ключ B
decrement - ключ A|B
У того, кто "заряжает" карту есть ключи A и B, он может как читать так и записывать,
а валидатору дадим только ключ A, чтоб мог прочесть и списать поездку.
Мне пока не понятно в каких целях хотите использовать карту?
Что хотите делать и на каких ключах? Записывать болки на одном и читать на другом?
Хочу разобратся как правильно работать с карточкой. Задача такая,хочу сделать так скажем не подделываемый ключ если так можно выразится. А точнее мысль такая вопервых поменять пароль на один из секторв с дефолтново на свой и затем писать в одну из ячеек этого сектора один рандомный байт который будет менятся после каждого поднесения карточки к считывателю и он же будет сохранятся в памяти контроллера, таким оброзом нелзя будет наделать дубликатов с этой карточки.
И еще Алексей вопрос, получается этой строкой
053
0x00, 0x00, 0x00, 0x00,
// Дамп заводского
054
0x00, 0x00, 0xFF, 0x07,
// ключа
055
0x80, 0x69, 0xFF, 0xFF,
//
056
0xFF, 0xFF, 0xFF, 0xFF
//
дефолтный ключА я сменил на 00 00 00 00 00 00 и естественно эти сектора перестали читатся дефолтным ключом?
Хочу разобратся как правильно работать с карточкой. Задача такая,хочу сделать так скажем не подделываемый ключ если так можно выразится. А точнее мысль такая вопервых поменять пароль на один из секторв с дефолтново на свой и затем писать в одну из ячеек этого сектора один рандомный байт который будет менятся после каждого поднесения карточки к считывателю и он же будет сохранятся в памяти контроллера, таким оброзом нелзя будет наделать дубликатов с этой карточки.
Если вас это не смущает, меняйте ключ B и пишите/читайте на нем, а для трейлера аксесс биты поставьте 1 0 0 так чтоб и ключ B виден не был, трейлер после этого только на ключе B перезаписать можно будет, смотрите не потеряйте его.
П.С.
Погорячился немножко для '1 0 0' только ключ то перезаписать сможете,
лучше '0 1 1' кроме ключа и аксесс биты изменять можно будет.
Спасибо большое Алексей да класические карточки на 1 кб , потому и хочу добавить один рандомный байт что бы не могли размножать ключи.
Тогда потребуется хранить этот рандом для каждой карты в контроллере и предусмотреть начальную инициализацию, когда контроллер первый раз включили и нужно для каждой карты инициализировать этот рандом.
Да именно так, нужно в районе 300 ключей так что 300 лишних байт не очень моного, праблема даже в другом при быстром пронесении карточки не всегда успевате стабильно записать байт и возникает три состояния 1, байт на карточке остался старый 2, байт записался новый но выдало сообщение об ошибке записи и 3 состояние записалось непонятно что. Вот сейчас думаю как это разрулить максимально эфективно.
Понятно, спасибо за подсказку.
Сценарий у валидатора прост: горит красный - поднеси карту
Проверяем, пишем и проверяем что записали, включаем зеленый.
Если проверка не прошла - до свидания.
Если запись и проверка того, что записали не выполнена - до свидания, и сигнал в секюрити - "Возможно вторжение, карта скомпрометирована"
Или дисциплинировать или отказаться от карт.
Чтоб на пальцах биты не загибать, инверсные у меня не очень получаются, калькулятор для аксесс битов неожиданно нашёлся.
Спасибо Алексей за калькулятор, масив ключей и рандомные байты к ним будут хранится в ОЗУ, ну а если сброс питания будет то по умолчанию будет в масив записаны нули в рандомые байты что будет означать повторную инициализацию рандомного байта на карточке. И еще вопрос, как я понял из даташита отдельно менять байт на карточке нельзя, пишется весь блок целиком так?