X-Git-Url: http://www.average.org/gitweb/?p=YkNeoCR.git;a=blobdiff_plain;f=src%2Forg%2Faverage%2Fnfcauthcr%2FYkNeo.java;h=96f3e0fbb53b776a02444b17f07c8608ca80935f;hp=1537459ba7e7c6ef4513370a844fc8b234194e07;hb=edfc8d9f2aad0bd7c0810d9f67a67e3db4b266c0;hpb=28b4d52dc728ff9016890ff3630d1237f1f2650b diff --git a/src/org/average/nfcauthcr/YkNeo.java b/src/org/average/nfcauthcr/YkNeo.java index 1537459..96f3e0f 100644 --- a/src/org/average/nfcauthcr/YkNeo.java +++ b/src/org/average/nfcauthcr/YkNeo.java @@ -1,41 +1,73 @@ -package org.average.nfcauthcr; +package org.average.ykneocr; import java.io.IOException; +import java.lang.String; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Iterator; import android.nfc.NfcAdapter; import android.nfc.Tag; -import android.nfc.TagLostException; import android.nfc.tech.IsoDep; -import org.average.nfcauthcr.CRException; +import org.average.ykneocr.CRException; public class YkNeo { - // This is a CCID APDU, ISO 7816-4. - // 00 A4 04 00 xx AID - GlobalPlatform - SELECT - // Lc, send data = 07: A0 00 00 05 27 20 01 - // Le, recv data = 00 + // http://forum.yubico.com/viewtopic.php?\ + // f=26&t=1053&sid=2a11c0f97306e4b699bf67502b7a754a + // CCID APDU, ISO 7816-4. + + // Start with Select APDU: + // CLA INS P1 P2 Lc AID Le + // 00 A4 04 00 - GlobalPlatform - Application Select + // Lc = 07 + // A0 00 00 05 27 + // Yubico's RID (Registered application provider IDentifier) + // 20 01 + // PIX (Proprietary application Identifier eXtension) + // for the Yubikey2 applet + // Le = 00 private static final byte[] selectApdu = {0x00, (byte) 0xA4, 0x04, 0x00, 0x07, (byte) 0xA0, 0x00, 0x00, 0x05, 0x27, 0x20, 0x01, 0x00}; + // Application APDUs: + // CLA INS P1 P2 + // 00 01 YK 00 + // YK is the one-byte command&slot code as in the USB interface + // Lc + data bytes follow + // Le is optional private static final byte SLOT_CHAL_HMAC1 = 0x30; private static final byte SLOT_CHAL_HMAC2 = 0x38; - public static final byte[] doChallengeYubiKey(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( - "NFC Error code in the response to select"); + public static ArrayList doChalResp(IsoDep isoTag, int slot, + ArrayList cset) + throws IOException, CRException { + 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])); + } + ArrayList rset = new ArrayList(); + + Iterator itr = cset.iterator(); + while (itr.hasNext()) { + byte[] challenge = unhex((String)itr.next()); + if (challenge.length > 127) { + throw new CRException(String.format( + "NFC challenge size too big: %d", + challenge.length)); } - byte[] crApdu = new byte[69]; + byte[] crApdu = new byte[6+challenge.length]; crApdu[0] = 0x00; // CLA crApdu[1] = 0x01; // INS switch (slot) { @@ -43,22 +75,44 @@ public class YkNeo { case 2: crApdu[2] = SLOT_CHAL_HMAC2; break; // P1 } crApdu[3] = 0x00; // P2 - crApdu[4] = 63; // Lc + crApdu[4] = (byte)challenge.length; // Lc System.arraycopy(challenge, 0, crApdu, 5, challenge.length); // Payload - crApdu[crApdu.length-1] = 22; // Le + 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( - "NFC Error code in the response to CR"); + 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)); } - 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 error", e); + rset.add(hex(Arrays.copyOf(resp, length-2))); + } + + return rset; + } + + private static String hex(byte[] a) { + StringBuilder sb = new StringBuilder(); + if (a == null) return ""; + 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); } + return b; } }