Как имитировать карточку Mifare Classic 1k с Android? [Дубликат]

Если вы не используете jQuery в своем коде, этот ответ для вас

Ваш код должен быть чем-то вроде этого:

function foo() {
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
    return httpRequest.responseText;
}

var result = foo(); // always ends up being 'undefined'

Феликс Клинг отлично справился с написанием ответа для людей, использующих jQuery для AJAX, я решил предоставить альтернативу для людей, которые этого не делают.

( Примечание. используя новый API fetch, угловые или обещания, я добавил еще один ответ ниже )


То, с чем вы столкнулись

Это краткое резюме «Объяснение проблемы» из другого ответа, если вы не уверены, прочитав это, прочитайте это.

A в AJAX означает асинхронность. Это означает, что отправка запроса (или, скорее, получение ответа) вынимается из обычного потока выполнения. В вашем примере .send немедленно возвращается, а следующий оператор return result; выполняется до того, как функция, которую вы передали, когда был вызван обратный вызов success.

Это означает когда вы возвращаетесь, слушатель, который вы определили, еще не выполнил, что означает, что возвращаемое вами значение не было определено.

Вот простая аналогия

function getFive(){ 
    var a;
    setTimeout(function(){
         a=5;
    },10);
    return a;
}

(Fiddle)

Возвращаемое значение a - undefined так как часть a=5 еще не выполнена. AJAX действует так, вы возвращаете значение до того, как сервер получил возможность сообщить вашему браузеру, что это за значение.

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

function onComplete(a){ // When the code completes, do this
    alert(a);
}

function getFive(whenDone){ 
    var a;
    setTimeout(function(){
         a=5;
         whenDone(a);
    },10);
}

Это называется CPS . В основном, мы передаем getFive действие, которое необходимо выполнить, когда оно завершается, мы сообщаем нашему кодексу, как реагировать, когда событие завершается (например, наш вызов AJAX или в этом случае время ожидания).

Использование будет:

getFive(onComplete);

Который должен предупредить «5» на экране. (Fiddle) .

Возможные решения

Существуют два способа решения этой проблемы:

  1. Сделать AJAX синхронный вызов (позволяет называть его SJAX).
  2. Реструктурируйте свой код для правильной работы с обратными вызовами.

1. Синхронный AJAX - Не делайте этого !!

Что касается синхронного AJAX, не делайте этого! Ответ Феликса вызывает некоторые веские аргументы в пользу того, почему это плохая идея. Подводя итог, он заморозит браузер пользователя, пока сервер не вернет ответ и не создаст очень плохой пользовательский интерфейс. Вот еще краткое резюме из MDN о том, почему:

XMLHttpRequest поддерживает как синхронную, так и асинхронную связь. В общем, однако, асинхронные запросы должны быть предпочтительнее синхронных запросов по причинам производительности.

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

Если вы имеете , вы можете передать флаг: Вот как это сделать:

var request = new XMLHttpRequest();
request.open('GET', 'yourURL', false);  // `false` makes the request synchronous
request.send(null);

if (request.status === 200) {// That's HTTP for 'ok'
  console.log(request.responseText);
}

2. Код реструктуризации

Пусть ваша функция принимает обратный вызов. В примере код foo может быть сделан для принятия обратного вызова. Мы сообщим нашему кодексу, как отреагировали , когда foo завершает работу.

Итак:

var result = foo();
// code that depends on `result` goes here

Становится:

foo(function(result) {
    // code that depends on `result`
});

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

function myHandler(result) {
    // code that depends on `result`
}
foo(myHandler);

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

Теперь давайте определим сам foo, чтобы действовать соответственно

function foo(callback) {
    var httpRequest = new XMLHttpRequest();
    httpRequest.onload = function(){ // when the request is loaded
       callback(httpRequest.responseText);// we're calling our method
    };
    httpRequest.open('GET', "/echo/json");
    httpRequest.send();
}

(скрипка)

Теперь мы сделали нашу функцию foo принять действие, которое будет выполняться, когда AJAX завершится успешно, мы можем продолжить это, проверив, не является ли статус ответа не 200 и действует соответственно (создайте обработчик сбоя и т. д.). Эффективное решение нашей проблемы.

Если вам все еще трудно понять это , прочитайте руководство по началу работы AJAX в MDN.

29
задан Michael Roland 29 July 2014 в 19:07
поделиться

3 ответа

С эмуляцией карт на базе хоста (HCE) в Android 4.4 вы можете эмулировать протокол ISO / IEC 14443-4. Более конкретно, вы можете эмулировать структуры приложений в соответствии с ISO / IEC 7816-4 (при этом приложения эмуляции карт должны выбираться с помощью AID). Кроме того, API не дает вам никаких средств, чтобы указать, следует ли использовать эмуляцию карты с использованием протокола типа A или типа B.

. Что касается эмуляции различных протоколов MIFARE:

  • Протокол MIFARE Ultralight (и дериватов) работает поверх ISO / IEC 14443-3.
  • Протокол MIFARE Classic частично работает поверх ISO / IEC 14443-3 (с некоторым другим обрамлением) , Таким образом, его также невозможно эмулировать MIFARE Classic с помощью Android HCE.
  • Протоколы MIFARE DESFire работают поверх ISO / IEC 14443-4. Существует три варианта протокола DESFire: собственный протокол : поскольку этот протокол не использует APDU в соответствии с ISO / IEC 7816-4, его невозможно эмулировать с помощью Android HCE. обернул собственный протокол : этот протокол использует APDU в соответствии с ISO / IEC 7816-4, однако, как правило, читатели не выдают команду SELECT с использованием DESFire AID при запуске связи с картой в оболочном режиме командной строки , (Примечание. Более новые реализации читателей с большей вероятностью выдают команду SELECT, совместимую с Android HCE, поскольку это также необходимо для некоторых новых продуктов смарт-карт NXP с эмуляцией протокола DESFire.) Протокол ISO : этот протокол основан на ISO / IEC 7816-4 и использует выбор приложений с помощью AID. Таким образом, можно будет эмулировать этот протокол с помощью Android HCE. Некоторым читателям могут потребоваться определенные значения параметров в нижних слоях протокола (например, конкретный каскадный уровень UID, определенное значение ATQA, определенное значение SAK или определенное ATS). Android HCE не имеет никаких средств для установки этих значений. См. Редактирование функциональности эмуляции гостевой карты в Android для возможного подхода к изменению этих значений для определенных корневых устройств и мой ответ на эмуляцию карты на основе хоста с идентификатором фиксированной карты для стратегия для программного изменения этих значений в пользовательском ПЗУ.

Примечание о функции HCE, доступной в CyanogenMod с версии 9.1 до версии 10.2 : Это будет подражать любому ISO / IEC 14443-4 без требования к структуре приложения в соответствии с ISO / IEC 7816-4. Вы даже можете выбрать, хотите ли вы эмулировать протокол типа A или типа B. Поэтому должно быть возможно (хотя я еще не тестировал), чтобы подражать любому из трех протоколов DESFire. Однако даже с функцией HCE CyanogenMod невозможно эмулировать протоколы MIFARE Ultralight или Classic. Более того, также невозможно влиять на параметры протокола низкого уровня, такие как UID, ATQA, SAK или ATS.

49
ответ дан Community 24 August 2018 в 19:37
поделиться

Микросхема MIFARE Ultralight MF0ICU1 (16 страниц по 4 байта каждая) действительно является кошмаром, но не может быть эмулирована на любых интерфейсах NXP, включая PN53x, потому что они связали первый UID байт (UID0) с 0x08 , поэтому это означает, что у тега есть случайный UID (в соответствии со стандартами NXP). Вам понадобится UID0 = 0x04 для эмуляции MIFARE Ultralight.

Существует автономный эмулятор MIFARE Ultralight , который позволяет любое значение для UID0, имеет сброс OTP, блокировку и блокировку блокировки биты. Подробнее см. В руководстве.

3
ответ дан honk 24 August 2018 в 19:37
поделиться

Я провел недели, изучая эту тему год назад, и мой вывод, основанный на текущей реализации: Эмуляция MIFARE Classic возможна, но только через встроенный безопасный элемент этот элемент встроен в чип NFC NFC (чип PN65 встроенный, например, Samsung I9300).

Я смог полностью подражать карте Mifare Classic, используя скрытые функции в библиотеке android_external_libnfc-nxp. Хотя я мог только читать карту, и для ее использования вам нужен доступ к защищенному элементу, где апплет NXP существует в большинстве случаев, эти серверы апплетов являются интерфейсом для управления эмулированными картами.

Хорошим способом продолжить этот поиск будет обратное проектирование приложения кошелька Google.

15
ответ дан Simplect 24 August 2018 в 19:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: