Ответ Android HCE 6A82

В настоящее время я работаю над реализацией HCE для моей Galaxy s4. У меня есть считыватель Omnikey 5321-cl, который поддерживает 7816-4. Мой класс Android выглядит так:

public class NfcHceService extends HostApduService{
private int counter         = 0;

@Override
public void onStart(android.content.Intent intent, int startId)
{
    new Thread(new Runnable() {

        @Override
        public void run()
        {
            while (true)
            {
                Log.d("HCE", String.valueOf(counter));
                counter++;
                try
                {
                    Thread.sleep(1000);
                } catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
        }
    }).run();
}

@Override
public byte[] processCommandApdu(byte[] apdu, Bundle extras)
{
    byte[] response = null;
    if (apdu[2] == 0xA4)
    {
        // return selecting applet
        response = new byte[] { (byte) 0x90, 0x00 };

    }
    return response;
}

@Override
public void onDeactivated(int reason)
{
    android.os.Debug.waitForDebugger();
    Log.d("HCE", "onDeactivated");

}

}

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

private static final byte[] CLA_INS_P1_P2   = { 0x00, (byte) 0xA4, 0x04, 0x00 };
private static final byte[] AID_ANDROID     = { (byte) 0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };

private static byte[] createSelectAidApdu(byte[] aid)
{
    byte[] result = new byte[6 + aid.length];
    System.arraycopy(CLA_INS_P1_P2, 0, result, 0, CLA_INS_P1_P2.length);
    result[4] = (byte) (aid.length);
    System.arraycopy(aid, 0, result, 5, aid.length);
    result[result.length - 1] = 10;
    return result;
}

public static void Create_MF() throws CardException
{

    // --Variable declaration
    Card card = null;
    ResponseAPDU answer = null;
    // ---------------------------------------------

    // --1--Establish connection with the smart card
    TerminalFactory factory = TerminalFactory.getDefault();
    List<CardTerminal> terminals = factory.terminals().list();
    // Use the first terminal
    CardTerminal terminal = terminals.get(1);
    // Connect with the card
    card = terminal.connect("*");
    CardChannel channel = card.getBasicChannel();
    // ---------------------------------------------

    byte[] selectAidApdu = createSelectAidApdu(AID_ANDROID);

    answer = channel.transmit(new CommandAPDU(selectAidApdu));

Мой AID для службы hce — F0010203040506.

Теперь моя проблема заключается в том, что я получаю правильный выбор APDU на своем устройстве Android, который выглядит следующим образом:

> RX: Type 4 Tag Command (13 bytes)
  CLA:0x00
  INS:0xA4(Select)
  P1:0x04(Name)
  P2:0x00(First or Only)
  LC:0x07(7)
  Data(7 bytes)
   00: f0 01 02 03 04 05 06
  Le:0x0A(10)

Но получаю код ответа 6A82. Я так понимаю, это означает, что устройство не находит сервис. Но я не понимаю, почему. Кто-нибудь может помочь?

Манифест:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hce"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
    android:minSdkVersion="19"
    android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce" />
<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <service
        android:name=".NfcHceService"
        android:exported="false"
        android:permission="android.permission.BIND_NFC_SERVICE" >
        <intent-filter>
            <action android:name="android.nfc.cardemulation.HOST_APDU_SERVICE" />
        </intent-filter>
        <meta-data
            android:name="android.nfc.cardemulation.host_apdu_service"
            android:resource="@xml/hce_service" />
    </service>
</application>

And the xml file:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/my_app_hce_service" >
<aid-group
    android:category="other"
    android:description="@string/my_app_aid_group" >
    <aid-filter android:name="F0010203040506" />
</aid-group></host-apdu-service>

Обновить

public static void Create_MF() throws CardException
{

    // --Variable declaration
    Card card = null;
    ResponseAPDU answer = null;
    // ---------------------------------------------

    // --1--Establish connection with the smart card
    TerminalFactory factory = TerminalFactory.getDefault();
    List<CardTerminal> terminals = factory.terminals().list();
    // Use the first terminal
    CardTerminal terminal = terminals.get(1);
    // Connect with the card
    card = terminal.connect("*");
    CardChannel channel = card.getBasicChannel();
    // ---------------------------------------------

    byte[] selectAidApdu = { 0x00, (byte) 0xA4, 0x04, 0x00, 0x07, (byte) 0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; // createSelectAidApdu(AID_ANDROID);

    answer = channel.transmit(new CommandAPDU(selectAidApdu));}

ОБНОВЛЕНИЕ 2

Я попытался реализовать isDefaultServiceForAid(). Но я не уверен, правильно ли я его использую и делает ли он то, что я хочу.

    CardEmulation card = CardEmulation.getInstance(NfcAdapter.getDefaultAdapter(this));
    ComponentName comp = new ComponentName(getApplicationContext(), NfcHceService.class);
    boolean tmp = card.isDefaultServiceForAid(comp, "F0010203040506");

Действительно ли он проверяет AID моего сервиса или делает что-то еще? Я хочу проверить, доступна ли моя служба с помощью AID, который я указал в своем hce_service.xml, который объявлен в моем манифесте.


person miron123    schedule 07.07.2014    source источник
comment
Фрагменты кода в вашем вопросе не соответствуют образцу кода, который вы предоставили в комментариях к ответу ниже. Пожалуйста, обновите вопрос, чтобы он соответствовал фактическому коду, который вы пробовали!   -  person Michael Roland    schedule 09.07.2014
comment
Общий проект — моя последняя версия, и она не сильно отличается. Основная идея осталась прежней, я просто попробовал кое-что с момента моего первоначального сообщения.   -  person miron123    schedule 09.07.2014
comment
Обработка APDU в этом примере проекта и в приведенном выше вопросе сильно отличается!   -  person Michael Roland    schedule 09.07.2014
comment
Ну, это правда, но так как я не могу получить доступ к методу processapdu. Это не было частью вопроса.   -  person miron123    schedule 09.07.2014
comment
Значит, вы не получаете SELECT APDU на телефон? (В отличие от того, что вы написали в своем вопросе...)   -  person Michael Roland    schedule 10.07.2014
comment
Я получаю правильный apdu, но все равно получаю ответ 6a82, а метод processapdu возвращает 9000.   -  person miron123    schedule 10.07.2014
comment
Таким образом, метод processCommandApdu на телефоне вызывается. Поэтому имеет значение, что вы на самом деле делаете в этом методе. Следовательно: Опубликуйте код, который вы действительно используете!   -  person Michael Roland    schedule 10.07.2014
comment
Я обновил класс обслуживания. Поток предназначен только для целей тестирования, потому что я хотел убедиться, что моя служба работает, когда я отправляю команду apdu. И для уточнения: мой метод processApdu никогда не вызывается!!! Но я не понимаю, почему. Я всегда получаю команду APDU 6a82, что означает, что команда не нашла выбранный сервис.   -  person miron123    schedule 14.07.2014
comment
Итак, мы ходим по кругу: как вы узнали, что получаете SELECT APDU на телефон, если не вызывается processCommandApdu?   -  person Michael Roland    schedule 14.07.2014
comment
Потому что я LogCat. Если вы посмотрите на мой исходный пост, я получу запись LogCat, которая выглядит следующим образом: RX: Type 4 Tag Command (13 байтов) CLA:0x00 INS:0xA4(Select) P1:0x04(Name) P2:0x00(First or Only) LC:0x07(7) Данные (7 байт) 00: f0 01 02 03 04 05 06 Le:0x0A(10). Но я получаю только ответ 6a82, который указывает, что служба не найдена.   -  person miron123    schedule 14.07.2014
comment
И вы убедились, что processCommandApdu никогда не вызывается, добавив строку типа Log.d("HCE", "processCommandApdu"); в качестве первой строки кода этого метода?   -  person Michael Roland    schedule 14.07.2014
comment
Да. Но я не понимаю, почему метод не вызывается. Насколько я понимаю, андроиду просто нужна команда выбора apdu с API, и я получаю правильный apdu в своем логарифме, но метод все еще не вызывается   -  person miron123    schedule 14.07.2014
comment
Есть ли в журнале что-нибудь еще, что может иметь отношение к HCE? Кроме if (apdu[2] == 0xA4), который должен быть if (apdu[1] == (byte)0xA4) (обратите внимание как на неправильный индекс, так и на неправильное целочисленное сравнение), и что вы возвращаете null вместо слова состояния в других случаях (чего вам не следует делать), я не вижу ничего плохого в вашем коде (хотя это ничего не меняет, если processCommandApdu все равно не вызывается.   -  person Michael Roland    schedule 14.07.2014
comment
Это правильно, но я просто не знаю, как поступить. Попробовал другой ридер, 50 дифф. СПИД, но все по-прежнему. И у меня нет другого телефона 4.4, поэтому я не могу проверить, если это аппаратная проблема.   -  person miron123    schedule 14.07.2014
comment
Наконец-то я заработал. Я понятия не имею, почему это не сработало раньше, но вчера я перезапустил весь процесс, и он отлично сработал с первой попытки.   -  person miron123    schedule 15.07.2014


Ответы (4)


Ошибка 6A82 означает file not found.

В данном случае это означает, что выбранный вами AID не существует.

Вероятно, это связано с несоответствием между выбранным вами AID, например. f0 01 02 03 04 05 06 и AID, указанный в вашем AndroidManifest.xml

Ссылка на ISO 7816 здесь

Обновление:

Из проверки обновленного кода видно, что вы добавляете еще один байт в конец APDU, то есть 0x10. Попробуйте удалить следующую строку из функции createSelectAidApdu()

result[result.length - 1] = 10;

Кроме того, я не уверен, почему вы установили последний байт равным 10, что равно 16 в десятичном виде. Обратите внимание, что последний байт часто используется для указания объема данных, ожидаемых/запрашиваемых от целевого устройства. Это не всегда требуется, как в случае с командой выбора приложения.

person jim    schedule 07.07.2014
comment
Это одна из первых вещей, которые я проверил, но это не так. Обновленная версия выше - person miron123; 07.07.2014
comment
Это всего лишь длина ответного сообщения, и я уже пытался его не указывать. А вот а8 получил тот же ответ 6а82 - person miron123; 07.07.2014
comment
Хорошо, попробуйте вместо этого объявление массива байтов: byte[] result = new byte[4 + help.length]; - person jim; 07.07.2014
comment
Я попытался использовать собственный массив байтов, который содержит необходимые значения, но все равно получаю код ответа 6A82. Для команды APDU массив байтов должен иметь длину (5 + AID.length). Причина APDU = CLA,INS,P1,P2,AID.length,AID. Я могу оставить только длину ответного сообщения. Любые идеи? - person miron123; 08.07.2014
comment
Обратите внимание, что AID.length должен быть в шестнадцатеричном формате. Попробуйте преобразовать весь массив байтов в шестнадцатеричную строку и проверьте в отладчике. Убедитесь, что длина правильная. Пробовали ли вы удалить приложение с телефона и переустановить, очистить данные и т. д. Кроме того, при вызове card = terminal.connect(*); Вы уверены, что получаете соединение с картой. Можно ли получить ATS с устройства HCE? - person jim; 08.07.2014
comment
Да, я получаю соединение с моим устройством Android и получаю указанную мной команду APDU (в шестнадцатеричной форме). Но почему-то я не могу получить доступ к своему пользовательскому сервису, и я не понимаю, почему бы и нет. - person miron123; 08.07.2014
comment
Ваш xml файл начинается с ‹aid-group›??? Он также должен иметь ‹host-apdu-service .... › - person jim; 08.07.2014
comment
Но не знаю в чем проблема. Я создаю команду APDU на считывателе, и мое устройство Android получает ту же команду APDU, но почему-то ОС Android не идентифицирует мою службу как вызываемую, и из-за этого я получаю ответ 6A82. По крайней мере, я так думаю - person miron123; 08.07.2014
comment
Хорошо, не стесняйтесь поделиться проектом со мной, и я постараюсь помочь вам. - person jim; 08.07.2014
comment
Я не был уверен, как поделиться этим. Я вставил ссылку в дропбокс. Надеюсь, это сработает. dropbox.com/s/0rr8rejwnbr2bm7/Projekt.rar - person miron123; 08.07.2014

Я думаю, что с выбором AID все в порядке. Если у Android нет приложения для AID, он ничего не делает, даже не получает код ошибки.

Я подозреваю, что проблема в том, что приложение возвращает null как сообщение, и поэтому Android, вероятно, отправляет обратно код ошибки.

Следующий оператор if дает отрицательный результат, поскольку apdu[2] на самом деле (байт) 0x04. apdu[1] будет (байт) 0xA4.

byte[] response = null;
if (apdu[2] == 0xA4)
{
    // return selecting applet
    response = new byte[] { (byte) 0x90, 0x00 };

}
return response;
person JavaDeveloper1976    schedule 05.11.2014

Я только что играл с похожей вещью.

Я заметил, что ваш фильтр намерений указывает действие "android.nfc.cardemulation.HOST_APDU_SERVICE", но правильное действие, похоже, "android.nfc.cardemulation.action.HOST_APDU_SERVICE" - см. http://developer.android.com/guide/topics/connectivity/nfc/hce.html для получения подробной информации. .

Используя это действие в фильтре намерений, я успешно запустил службу Android для своего AID.

Удачи!

person Matt Williams    schedule 10.03.2016

У меня только что была похожая проблема - мой AID был правильным на обоих концах, но служба все еще не могла быть найдена.

На официальной странице HCE есть следующий фрагмент:

<service android:name=".MyHostApduService" android:exported="true"
     android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
    <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
</intent-filter>
<meta-data android:name="android.nfc.cardemulation.host_apdu_service"
           android:resource="@xml/apduservice"/>

I noticed that the <intent-filter> did not have a <category> tag. I added this, and suddenly my service could be found! See below:

<intent-filter>
    <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
    <!-- category required!!! this was not included in official android HCE documentation -->
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
person Mike Baxter    schedule 11.11.2016