Android: аутентификация с помощью NXP MiFare Ultralight C

Я больше недели пытался заставить телефон Android аутентифицироваться с помощью Mifare Ultralight C. Я подтвердил, что могу писать в тег (записав на незащищенную страницу памяти, а затем прочитав то, что я написал). Я также могу писать на ключевые страницы (44-47) и записал 0x00 для всех 16 ключевых байтов.

Когда я пытаюсь пройти аутентификацию, ниже приведен пример данных, задействованных во время одного обмена — это из журнала, записанного моим приложением. Может ли кто-нибудь сказать мне, если я делаю что-то неправильно? Я AM не разглашаю информацию и имею доступ к полным листам данных. Обратите внимание, что приведенные ниже шестнадцатеричные строки, очевидно, являются удобочитаемыми версиями отправляемых и получаемых данных, которые в коде состоят из массивов байтов.

Отправить команду аутентификации

Received rndB: 8A5735694D9D7542

Key: 00000000000000000000000000000000

IV: 0000000000000000

Decrypted rndB: EF340C62E1B866D4

rndB': 340C62E1B866D4EF

rndA: 6E262630E299F94F

rndA+rndB': 6E262630E299F94F340C62E1B866D4EF

Key: 00000000000000000000000000000000

IV: 8A5735694D9D7542

ek(RndA+rndB'): E36C6C46FAAC60BA45DDF5F5A0802C79

После отправки 0xAF + E36C6C46FAAC60BA45DDF5F5A0802C79 у меня сразу теряется связь с тегом. Я просмотрел лист данных и прочитал все сообщения, которые я могу найти здесь. Я также просмотрел код libfreefare и, честно говоря, не могу понять, что я делаю неправильно.

Техническая поддержка NXP не отвечала.

Любые идеи? Я в растерянности.


person Matt Redmond    schedule 17.10.2013    source источник
comment
Я нашел примеры в NXP Application Note AN0945 очень поучительными и полезными для отладки моего собственного кода.   -  person NFC guy    schedule 19.10.2013
comment
Большое спасибо! Я пропустил это, потому что это документ DESFire, и я не обратил внимания на эту папку в DocStore. Я только что скачал, и это выглядит многообещающе. Еще раз спасибо - я очень ценю ваш вклад.   -  person Matt Redmond    schedule 21.10.2013
comment
NFCGuy — Вы (или кто-либо из ваших знакомых) успешно выполнили сквозную аутентификацию с помощью Ultralight-C с помощью устройства Android?   -  person Matt Redmond    schedule 24.10.2013
comment
Да, это, безусловно, можно сделать. См., например, этот комментарий и это приложение   -  person NFC guy    schedule 24.10.2013
comment
Спасибо, парень с NFC. Я не думаю, что приложение NXP действительно аутентифицируется с помощью тега. Он просто читает незащищенную память. Их комментарий: Обратите внимание, что на основе содержащихся в таких приложениях механизмов безопасности наше приложение не предоставляет доступ к фактически содержащимся данным. Я наткнулся на ту ветку, на которую вы ссылались, и увидел заключительные комментарии Мигеля. Я бы очень хотел, чтобы был способ связаться с ним. Я хотел бы знать, что я делал неправильно.   -  person Matt Redmond    schedule 25.10.2013
comment
Я могу подтвердить, что приложение NXP действительно пытается выполнить аутентификацию (с нулевым ключом и ключом, используемым в образцах карт: BREAKMEIFYOUCAN!). Я только что проверил ваши расчеты выше, и они все верны! Итак, мое первое предположение заключается в том, что карта, с которой вы тестируете, имеет другой настроенный ключ. Другой вариант заключается в том, что вы выполняете одноэтапный код, что может привести к тому, что устройство Android выполнит проверку присутствия промежуточного тега, мешая протоколу аутентификации.   -  person NFC guy    schedule 25.10.2013
comment
Интересный. Огромное спасибо за проверку моих данных. Хорошо, я собираюсь немного изменить свой код и посмотреть, есть ли что-то, что заставляет «дроида» выполнять эту проверку присутствия. Еще раз спасибо за проверку моей работы - это снимает огромный вопросительный знак и помогает сосредоточить мои усилия на продвижении вперед. Я очень ценю вашу щедрость с вашим временем.   -  person Matt Redmond    schedule 25.10.2013
comment
Пожалуйста. Не уверен, имеет ли это значение (не должно), но лично я всегда использую rndA = 0 (все нули) из-за лени.   -  person NFC guy    schedule 29.10.2013
comment
Теперь работает! Спасибо, парень из NFC, за всю вашу помощь — я очень ценю вашу щедрость, потраченную на ваше время.   -  person Matt Redmond    schedule 07.11.2013
comment
@NFCguy Вам определенно следует использовать случайный вызов / одноразовый номер rndA - в противном случае можно клонировать карту из подслушанной аутентификации с помощью эмулятора.   -  person vlp    schedule 23.09.2016
comment
@NFCguy или OP, не могли бы вы опубликовать ответ на вопрос, объясняющий окончательное решение? Это может помочь будущим посетителям ответить на этот вопрос.   -  person MarioDS    schedule 31.01.2017


Ответы (1)


Ниже приведен пример кода Java для выполнения аутентификации Ultralight-C, как описано в MF0ICU2 / MIFARE Ultralight C — Документ IC для бесконтактного билета (глава 7.5.5 — Аутентификация 3DES, стр. 15):

public void authenticate(byte[] key) throws CardException {
    System.out.println("AUTHENTICATE");
    byte[] encRndB = transmitRaw(new byte[] { 0x1A, 0x00 });
    if((encRndB.length!=9)||(encRndB[0]!=AF)) {
        throw new RuntimeException("Invalid response!");
    }
    encRndB=Arrays.copyOfRange(encRndB, 1, 9);
    System.out.println(" - EncRndB: " + toHex(encRndB));
    byte[] rndB = desDecrypt(key, encRndB);
    System.out.println(" - RndB: " + toHex(rndB));
    byte[] rndBrot = rotateLeft(rndB);
    System.out.println(" - RndBrot: " + toHex(rndBrot));
    byte[] rndA = new byte[8];
    generateRandom(rndA);
    System.out.println(" - RndA: " + toHex(rndA));
    byte[] encRndArotPrime = transmitRaw(ArrayUtils.addAll(new byte[] {AF}, desEncrypt(key, ArrayUtils.addAll(rndA, rndBrot))));
    if((encRndArotPrime.length!=9)||(encRndArotPrime[0]!=0x00)) {
        throw new RuntimeException("Invalid response!");
    }
    encRndArotPrime=Arrays.copyOfRange(encRndArotPrime, 1, 9);
    System.out.println(" - EncRndArot': " + toHex(encRndArotPrime));
    byte[] rndArotPrime = desDecrypt(key, encRndArotPrime);
    System.out.println(" - RndArot': " + toHex(rndArotPrime));
    if(!Arrays.equals(rotateLeft(rndA), rndArotPrime)) {
        throw new RuntimeException("Card authentication failed");
    }
}

protected static SecureRandom rnd = new SecureRandom();
protected static void generateRandom(byte[] rndA) {
    rnd.nextBytes(rndA);
}

protected byte[] desEncrypt(byte[] key, byte[] data) {
    return performDes(Cipher.ENCRYPT_MODE, key, data);
}
protected byte[] desDecrypt(byte[] key, byte[] data) {
    return performDes(Cipher.DECRYPT_MODE, key, data);
}
private byte[] iv = new byte[8];
protected byte[] performDes(int opMode, byte[] key, byte[] data) {
    try {
        Cipher des = Cipher.getInstance("DESede/CBC/NoPadding");
        SecretKeyFactory desKeyFactory = SecretKeyFactory.getInstance("DESede");
        Key desKey = desKeyFactory.generateSecret(new DESedeKeySpec(ArrayUtils.addAll(key, Arrays.copyOf(key, 8))));
        des.init(opMode, desKey, new IvParameterSpec(iv));
        byte[] ret = des.doFinal(data);
        if(opMode==Cipher.ENCRYPT_MODE) {
            iv=Arrays.copyOfRange(ret, ret.length-8, ret.length);
        } else {
            iv=Arrays.copyOfRange(data, data.length-8, data.length);
        }
        return ret;
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
        throw new RuntimeException(e);
    }
}

protected static byte[] rotateLeft(byte[] in) {
    return ArrayUtils.add(Arrays.copyOfRange(in, 1, 8), in[0]);
}

Примечание. В этом коде используется язык Apache Commons.

person vlp    schedule 19.06.2017