- public static byte[] doChalResp(IsoDep isoTag, int slot,
- byte[] challenge) throws CRException {
- try {
- isoTag.connect();
- byte[] resp = isoTag.transceive(selectApdu);
- int length = resp.length;
- if (resp[length - 2] != (byte)0x90 ||
- resp[length - 1] != 0x00) {
- throw new CRException(String.format(
- "NFC select error code: %02x:%02x",
- resp[length - 2], resp[length - 1]));
- }
- byte[] crApdu = new byte[69];
- crApdu[0] = 0x00; // CLA
- crApdu[1] = 0x01; // INS
- switch (slot) {
- case 1: crApdu[2] = SLOT_CHAL_HMAC1; break; // P1
- case 2: crApdu[2] = SLOT_CHAL_HMAC2; break; // P1
- }
- crApdu[3] = 0x00; // P2
- crApdu[4] = 63; // Lc
- System.arraycopy(challenge, 0, crApdu, 5,
- challenge.length); // Payload
- crApdu[crApdu.length-1] = 22; // Le
- resp = isoTag.transceive(crApdu);
- length = resp.length;
- if (resp[length - 2] != (byte)0x90 ||
- resp[length - 1] != 0x00) {
- throw new CRException(String.format(
- "NFC CR error code: %02x:%02x",
- resp[length - 2], resp[length - 1]));
- }
- if (length != 22) {
- throw new CRException(String.format(
- "NFC wrong response size: got %d, need 20",
- length-2));
- }
- return Arrays.copyOf(resp, length-2);
- } catch (TagLostException e) {
- throw new CRException("NFC connection lost", e);
- } catch (IOException e) {
- throw new CRException("NFC I/O: " + e.getMessage(), e);
+ public static ArrayList<String> doChalResp(IsoDep isoTag, int slot,
+ ArrayList<String> cset)
+ throws IOException, CRException {
+ byte[] challenge = unhex(cset.get(0));
+ if (challenge.length > 127) {
+ throw new CRException(String.format(
+ "NFC challenge size too big: %d",
+ challenge.length));
+ }
+ if (slot != 1 && slot != 2) {
+ throw new CRException(String.format(
+ "NFC Yubikey slot is %d, can be 1 or 2",
+ slot));
+ }
+ byte[] resp = isoTag.transceive(selectApdu);
+ int length = resp.length;
+ if (resp[length - 2] != (byte)0x90 ||
+ resp[length - 1] != 0x00) {
+ throw new CRException(String.format(
+ "NFC select error code: %02x:%02x",
+ resp[length - 2], resp[length - 1]));
+ }
+ byte[] crApdu = new byte[6+challenge.length];
+ crApdu[0] = 0x00; // CLA
+ crApdu[1] = 0x01; // INS
+ switch (slot) {
+ case 1: crApdu[2] = SLOT_CHAL_HMAC1; break; // P1
+ case 2: crApdu[2] = SLOT_CHAL_HMAC2; break; // P1
+ }
+ crApdu[3] = 0x00; // P2
+ crApdu[4] = (byte)challenge.length; // Lc
+ System.arraycopy(challenge, 0, crApdu, 5,
+ challenge.length); // Payload
+ crApdu[5+challenge.length] = 22; // Le
+ resp = isoTag.transceive(crApdu);
+ length = resp.length;
+ if (resp[length - 2] != (byte)0x90 ||
+ resp[length - 1] != 0x00) {
+ throw new CRException(String.format(
+ "NFC CR error code: %02x:%02x",
+ resp[length - 2], resp[length - 1]));
+ }
+ if (length <= 2) {
+ throw new CRException(String.format(
+ "NFC wrong response size: only %d bytes",
+ length-2));
+ }
+ ArrayList<String> rset = new ArrayList<String>();
+ rset.add(hex(Arrays.copyOf(resp, length-2)));
+ return rset;
+ }
+
+ private static String hex(byte[] a) {
+ StringBuilder sb = new StringBuilder();
+ if (a == null) return "<null>";
+ for (byte b: a) sb.append(String.format("%02x", b&0xff));
+ return sb.toString();
+ }
+
+ private static byte[] unhex(String s) {
+ int len = s.length();
+ if ((len % 2) != 0) return null;
+ byte[] b = new byte[len / 2];
+ for (int i = 0; i < len; i += 2) {
+ b[i / 2] = (byte)Integer.parseInt(
+ s.substring(i,i+2), 16);