1 package org.average.nfcauthcr;
3 import java.lang.String;
4 import java.io.IOException;
5 import java.util.Arrays;
7 import android.nfc.NfcAdapter;
8 import android.nfc.Tag;
9 import android.nfc.TagLostException;
10 import android.nfc.tech.IsoDep;
12 import org.average.nfcauthcr.CRException;
16 // This is a CCID APDU, ISO 7816-4.
17 // 00 A4 04 00 xx AID - GlobalPlatform - SELECT
18 // Lc, send data = 07: A0 00 00 05 27 20 01
20 private static final byte[] selectApdu =
21 {0x00, (byte) 0xA4, 0x04, 0x00, 0x07, (byte) 0xA0,
22 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x00};
24 private static final byte SLOT_CHAL_HMAC1 = 0x30;
25 private static final byte SLOT_CHAL_HMAC2 = 0x38;
27 public static byte[] doChalResp(IsoDep isoTag, int slot,
28 byte[] challenge) throws CRException {
31 byte[] resp = isoTag.transceive(selectApdu);
32 int length = resp.length;
33 if (resp[length - 2] != (byte)0x90 ||
34 resp[length - 1] != 0x00) {
35 throw new CRException(String.format(
36 "NFC select error code: %02x:%02x",
37 resp[length - 2], resp[length - 1]));
39 byte[] crApdu = new byte[69];
40 crApdu[0] = 0x00; // CLA
41 crApdu[1] = 0x01; // INS
43 case 1: crApdu[2] = SLOT_CHAL_HMAC1; break; // P1
44 case 2: crApdu[2] = SLOT_CHAL_HMAC2; break; // P1
46 crApdu[3] = 0x00; // P2
48 System.arraycopy(challenge, 0, crApdu, 5,
49 challenge.length); // Payload
50 crApdu[crApdu.length-1] = 22; // Le
51 resp = isoTag.transceive(crApdu);
53 if (resp[length - 2] != (byte)0x90 ||
54 resp[length - 1] != 0x00) {
55 throw new CRException(String.format(
56 "NFC CR error code: %02x:%02x",
57 resp[length - 2], resp[length - 1]));
60 throw new CRException(String.format(
61 "NFC wrong response size: got %d, need 20",
64 return Arrays.copyOf(resp, length-2);
65 } catch (TagLostException e) {
66 throw new CRException("NFC connection lost", e);
67 } catch (IOException e) {
68 throw new CRException("NFC I/O: " + e.getMessage(), e);