OTG: Fix usb transport
This commit is contained in:
@@ -393,26 +393,6 @@ public class BaseJavacardDevice implements JavacardDevice {
|
||||
Arrays.fill(dataToSend, (byte) 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the key id from application specific data stored on tag, or null
|
||||
* if it doesn't exist.
|
||||
*
|
||||
* @param idx Index of the key to return the fingerprint from.
|
||||
* @return The long key id of the requested key, or null if not found.
|
||||
*/
|
||||
public Long nfcGetKeyId(int idx) throws IOException {
|
||||
byte[] fp = getMasterKeyFingerprint(idx);
|
||||
if (fp == null) {
|
||||
return null;
|
||||
}
|
||||
ByteBuffer buf = ByteBuffer.wrap(fp);
|
||||
// skip first 12 bytes of the fingerprint
|
||||
buf.position(12);
|
||||
// the last eight bytes are the key id (big endian, which is default order in ByteBuffer)
|
||||
return buf.getLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return fingerprints of all keys from application specific data stored
|
||||
* on tag, or null if data not available.
|
||||
|
||||
@@ -80,13 +80,14 @@ public class UsbConnectionManager {
|
||||
false);
|
||||
Log.d(LOG_TAG, "ACTION_USB_PERMISSION: " + permission + " Device: " + deviceName);
|
||||
|
||||
interceptIntent(intent);
|
||||
if (permission) {
|
||||
interceptIntent(intent);
|
||||
}
|
||||
|
||||
context.unregisterReceiver(mUsbReceiver);
|
||||
}
|
||||
}
|
||||
};
|
||||
private Handler handler = new Handler(Looper.getMainLooper());
|
||||
|
||||
public UsbConnectionManager(final Activity activity, final OnDiscoveredUsbDeviceListener listener) {
|
||||
this.mActivity = activity;
|
||||
@@ -98,7 +99,7 @@ public class UsbConnectionManager {
|
||||
private static UsbDevice getDevice(UsbManager manager) {
|
||||
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
||||
for (UsbDevice device : deviceList.values()) {
|
||||
if (device.getVendorId() == 0x1050 && device.getProductId() == 0x0112) {
|
||||
if (device.getVendorId() == 0x1050 && (device.getProductId() == 0x0112 || device.getProductId() == 0x0115)) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
@@ -139,9 +140,11 @@ public class UsbConnectionManager {
|
||||
|
||||
public void onDestroy() {
|
||||
mStopped.set(true);
|
||||
mRunning.release();
|
||||
try {
|
||||
mActivity.unregisterReceiver(mUsbReceiver);
|
||||
} catch (IllegalArgumentException ignore) {
|
||||
}
|
||||
mActivity = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,14 @@ import android.support.annotation.Nullable;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class UsbTransport implements Transport {
|
||||
private static final int CLASS_SMARTCARD = 11;
|
||||
private static final int TIMEOUT = 1000; // 1 s
|
||||
private static final int TIMEOUT = 20 * 1000; // 2 s
|
||||
|
||||
private final UsbManager mUsbManager;
|
||||
private final UsbDevice mUsbDevice;
|
||||
@@ -22,7 +26,7 @@ public class UsbTransport implements Transport {
|
||||
private final UsbEndpoint mBulkIn;
|
||||
private final UsbEndpoint mBulkOut;
|
||||
private final UsbDeviceConnection mConnection;
|
||||
private byte counter = 0;
|
||||
private byte mCounter = 0;
|
||||
|
||||
public UsbTransport(final UsbDevice usbDevice, final UsbManager usbManager) throws TransportIoException {
|
||||
mUsbDevice = usbDevice;
|
||||
@@ -40,17 +44,60 @@ public class UsbTransport implements Transport {
|
||||
mConnection.claimInterface(mUsbInterface, true);
|
||||
// check result
|
||||
|
||||
powerOn();
|
||||
|
||||
setTimings();
|
||||
}
|
||||
|
||||
private void setTimings() throws TransportIoException {
|
||||
byte[] data = {
|
||||
0x6C,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
mCounter++,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
sendRaw(data);
|
||||
data = receive();
|
||||
|
||||
data[0] = 0x61;
|
||||
data[1] = 0x04;
|
||||
data[2] = data[3] = data[4] = 0x00;
|
||||
data[5] = 0x00;
|
||||
data[6] = mCounter++;
|
||||
data[7] = 0x00;
|
||||
data[8] = data[9] = 0x00;
|
||||
|
||||
data[13] = 1;
|
||||
|
||||
sendRaw(data);
|
||||
receive();
|
||||
}
|
||||
|
||||
private void powerOff() throws TransportIoException {
|
||||
final byte[] iccPowerOff = {
|
||||
0x63,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
mCounter++,
|
||||
0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
sendRaw(iccPowerOff);
|
||||
receive();
|
||||
}
|
||||
|
||||
void powerOn() throws TransportIoException {
|
||||
final byte[] iccPowerOn = {
|
||||
0x62,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00,
|
||||
counter++,
|
||||
0x03,
|
||||
mCounter++,
|
||||
0x00,
|
||||
0x00, 0x00
|
||||
};
|
||||
sendRaw(iccPowerOn);
|
||||
receiveRaw();
|
||||
// Check result
|
||||
receive();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,27 +148,58 @@ public class UsbTransport implements Transport {
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] sendAndReceive(final byte[] data) throws TransportIoException {
|
||||
public byte[] sendAndReceive(byte[] data) throws TransportIoException {
|
||||
send(data);
|
||||
return receive();
|
||||
byte[] bytes;
|
||||
do {
|
||||
bytes = receive();
|
||||
} while (isXfrBlockNotReady(bytes));
|
||||
|
||||
checkXfrBlockResult(bytes);
|
||||
return Arrays.copyOfRange(bytes, 10, bytes.length);
|
||||
}
|
||||
|
||||
public void send(final byte[] d) throws TransportIoException {
|
||||
public void send(byte[] d) throws TransportIoException {
|
||||
int l = d.length;
|
||||
byte[] data = Arrays.concatenate(new byte[]{
|
||||
0x6f,
|
||||
(byte) l, (byte) (l >> 8), (byte) (l >> 16), (byte) (l >> 24),
|
||||
0x00,
|
||||
counter++,
|
||||
0x01,
|
||||
mCounter++,
|
||||
0x00,
|
||||
0x00, 0x00},
|
||||
d);
|
||||
sendRaw(data);
|
||||
|
||||
int send = 0;
|
||||
while (send < data.length) {
|
||||
final int len = Math.min(mBulkIn.getMaxPacketSize(), data.length - send);
|
||||
sendRaw(Arrays.copyOfRange(data, send, send + len));
|
||||
send += len;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] receive() throws TransportIoException {
|
||||
final byte[] bytes = receiveRaw();
|
||||
return Arrays.copyOfRange(bytes, 10, bytes.length);
|
||||
byte[] buffer = new byte[mBulkIn.getMaxPacketSize()];
|
||||
byte[] result = null;
|
||||
int readBytes = 0, totalBytes = 0;
|
||||
|
||||
do {
|
||||
int res = mConnection.bulkTransfer(mBulkIn, buffer, buffer.length, TIMEOUT);
|
||||
if (res < 0) {
|
||||
throw new TransportIoException("USB error, failed to receive response " + res);
|
||||
}
|
||||
if (result == null) {
|
||||
if (res < 10) {
|
||||
throw new TransportIoException("USB error, failed to receive ccid header");
|
||||
}
|
||||
totalBytes = ByteBuffer.wrap(buffer, 1, 4).order(ByteOrder.LITTLE_ENDIAN).asIntBuffer().get() + 10;
|
||||
result = new byte[totalBytes];
|
||||
}
|
||||
System.arraycopy(buffer, 0, result, readBytes, res);
|
||||
readBytes += res;
|
||||
} while (readBytes < totalBytes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void sendRaw(final byte[] data) throws TransportIoException {
|
||||
@@ -131,14 +209,18 @@ public class UsbTransport implements Transport {
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] receiveRaw() throws TransportIoException {
|
||||
byte[] buffer = new byte[1024];
|
||||
private byte getStatus(byte[] bytes) {
|
||||
return (byte) ((bytes[7] >> 6) & 0x03);
|
||||
}
|
||||
|
||||
int res = mConnection.bulkTransfer(mBulkIn, buffer, buffer.length, TIMEOUT);
|
||||
if (res < 0) {
|
||||
throw new TransportIoException("USB error, failed to receive response " + res);
|
||||
private void checkXfrBlockResult(byte[] bytes) throws TransportIoException {
|
||||
final byte status = getStatus(bytes);
|
||||
if (status != 0) {
|
||||
throw new TransportIoException("CCID error, status " + status + " error code: " + Hex.toHexString(bytes, 8, 1));
|
||||
}
|
||||
}
|
||||
|
||||
return Arrays.copyOfRange(buffer, 0, res);
|
||||
private boolean isXfrBlockNotReady(byte[] bytes) {
|
||||
return getStatus(bytes) == 2;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user