improve error messages
[YkNeoCR.git] / src / org / average / nfcauthcr / YkNeo.java
1 package org.average.nfcauthcr;
2
3 import java.lang.String;
4 import java.io.IOException;
5 import java.util.Arrays;
6
7 import android.nfc.NfcAdapter;
8 import android.nfc.Tag;
9 import android.nfc.TagLostException;
10 import android.nfc.tech.IsoDep;
11
12 import org.average.nfcauthcr.CRException;
13
14 public class YkNeo {
15
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
19         // Le, recv data = 00
20         private static final byte[] selectApdu =
21                 {0x00, (byte) 0xA4, 0x04, 0x00, 0x07, (byte) 0xA0,
22                  0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x00};
23
24         private static final byte SLOT_CHAL_HMAC1 = 0x30;
25         private static final byte SLOT_CHAL_HMAC2 = 0x38;
26
27         public static final byte[] doChallengeYubiKey(IsoDep isoTag, int slot,
28                                                 byte[] challenge)
29                                 throws CRException {
30                 try {
31                         isoTag.connect();
32                         byte[] resp = isoTag.transceive(selectApdu);
33                         int length = resp.length;
34                         if (resp[length - 2] != (byte)0x90 ||
35                             resp[length - 1] != 0x00) {
36                                 throw new CRException(String.format(
37                                 "NFC select error code: %02x:%02x",
38                                 resp[length - 2], resp[length - 1]));
39                         }
40                         byte[] crApdu = new byte[69];
41                         crApdu[0] = 0x00; // CLA
42                         crApdu[1] = 0x01; // INS
43                         switch (slot) {
44                         case 1: crApdu[2] = SLOT_CHAL_HMAC1; break; // P1
45                         case 2: crApdu[2] = SLOT_CHAL_HMAC2; break; // P1
46                         }
47                         crApdu[3] = 0x00; // P2
48                         crApdu[4] = 63;   // Lc
49                         System.arraycopy(challenge, 0, crApdu, 5,
50                                                 challenge.length); // Payload
51                         crApdu[crApdu.length-1] = 22; // Le
52                         resp = isoTag.transceive(crApdu);
53                         length = resp.length;
54                         if (resp[length - 2] != (byte)0x90 ||
55                             resp[length - 1] != 0x00) {
56                                 throw new CRException(String.format(
57                                 "NFC CR error code: %02x:%02x",
58                                 resp[length - 2], resp[length - 1]));
59                         }
60                         if (length != 22) {
61                                 throw new CRException(String.format(
62                                 "NFC wrong response size: got %d, need 20",
63                                 length-2));
64                         }
65                         return Arrays.copyOf(resp, length-2);
66                 } catch (TagLostException e) {
67                         throw new CRException("NFC connection lost", e);
68                 } catch (IOException e) {
69                         throw new CRException("NFC I/O: " + e.getMessage(), e);
70                 }
71         }
72 }