OTG: Fix usb transport
This commit is contained in:
@@ -393,26 +393,6 @@ public class BaseJavacardDevice implements JavacardDevice {
|
|||||||
Arrays.fill(dataToSend, (byte) 0);
|
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
|
* Return fingerprints of all keys from application specific data stored
|
||||||
* on tag, or null if data not available.
|
* on tag, or null if data not available.
|
||||||
|
|||||||
@@ -80,13 +80,14 @@ public class UsbConnectionManager {
|
|||||||
false);
|
false);
|
||||||
Log.d(LOG_TAG, "ACTION_USB_PERMISSION: " + permission + " Device: " + deviceName);
|
Log.d(LOG_TAG, "ACTION_USB_PERMISSION: " + permission + " Device: " + deviceName);
|
||||||
|
|
||||||
interceptIntent(intent);
|
if (permission) {
|
||||||
|
interceptIntent(intent);
|
||||||
|
}
|
||||||
|
|
||||||
context.unregisterReceiver(mUsbReceiver);
|
context.unregisterReceiver(mUsbReceiver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private Handler handler = new Handler(Looper.getMainLooper());
|
|
||||||
|
|
||||||
public UsbConnectionManager(final Activity activity, final OnDiscoveredUsbDeviceListener listener) {
|
public UsbConnectionManager(final Activity activity, final OnDiscoveredUsbDeviceListener listener) {
|
||||||
this.mActivity = activity;
|
this.mActivity = activity;
|
||||||
@@ -98,7 +99,7 @@ public class UsbConnectionManager {
|
|||||||
private static UsbDevice getDevice(UsbManager manager) {
|
private static UsbDevice getDevice(UsbManager manager) {
|
||||||
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
|
||||||
for (UsbDevice device : deviceList.values()) {
|
for (UsbDevice device : deviceList.values()) {
|
||||||
if (device.getVendorId() == 0x1050 && device.getProductId() == 0x0112) {
|
if (device.getVendorId() == 0x1050 && (device.getProductId() == 0x0112 || device.getProductId() == 0x0115)) {
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,9 +140,11 @@ public class UsbConnectionManager {
|
|||||||
|
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
mStopped.set(true);
|
mStopped.set(true);
|
||||||
|
mRunning.release();
|
||||||
try {
|
try {
|
||||||
mActivity.unregisterReceiver(mUsbReceiver);
|
mActivity.unregisterReceiver(mUsbReceiver);
|
||||||
} catch (IllegalArgumentException ignore) {
|
} catch (IllegalArgumentException ignore) {
|
||||||
}
|
}
|
||||||
|
mActivity = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,10 +11,14 @@ import android.support.annotation.Nullable;
|
|||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import org.bouncycastle.util.Arrays;
|
import org.bouncycastle.util.Arrays;
|
||||||
|
import org.bouncycastle.util.encoders.Hex;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
public class UsbTransport implements Transport {
|
public class UsbTransport implements Transport {
|
||||||
private static final int CLASS_SMARTCARD = 11;
|
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 UsbManager mUsbManager;
|
||||||
private final UsbDevice mUsbDevice;
|
private final UsbDevice mUsbDevice;
|
||||||
@@ -22,7 +26,7 @@ public class UsbTransport implements Transport {
|
|||||||
private final UsbEndpoint mBulkIn;
|
private final UsbEndpoint mBulkIn;
|
||||||
private final UsbEndpoint mBulkOut;
|
private final UsbEndpoint mBulkOut;
|
||||||
private final UsbDeviceConnection mConnection;
|
private final UsbDeviceConnection mConnection;
|
||||||
private byte counter = 0;
|
private byte mCounter = 0;
|
||||||
|
|
||||||
public UsbTransport(final UsbDevice usbDevice, final UsbManager usbManager) throws TransportIoException {
|
public UsbTransport(final UsbDevice usbDevice, final UsbManager usbManager) throws TransportIoException {
|
||||||
mUsbDevice = usbDevice;
|
mUsbDevice = usbDevice;
|
||||||
@@ -40,17 +44,60 @@ public class UsbTransport implements Transport {
|
|||||||
mConnection.claimInterface(mUsbInterface, true);
|
mConnection.claimInterface(mUsbInterface, true);
|
||||||
// check result
|
// 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 = {
|
final byte[] iccPowerOn = {
|
||||||
0x62,
|
0x62,
|
||||||
0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00,
|
||||||
0x00,
|
0x00,
|
||||||
counter++,
|
mCounter++,
|
||||||
0x03,
|
0x00,
|
||||||
0x00, 0x00
|
0x00, 0x00
|
||||||
};
|
};
|
||||||
sendRaw(iccPowerOn);
|
sendRaw(iccPowerOn);
|
||||||
receiveRaw();
|
receive();
|
||||||
// Check result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -101,27 +148,58 @@ public class UsbTransport implements Transport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] sendAndReceive(final byte[] data) throws TransportIoException {
|
public byte[] sendAndReceive(byte[] data) throws TransportIoException {
|
||||||
send(data);
|
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;
|
int l = d.length;
|
||||||
byte[] data = Arrays.concatenate(new byte[]{
|
byte[] data = Arrays.concatenate(new byte[]{
|
||||||
0x6f,
|
0x6f,
|
||||||
(byte) l, (byte) (l >> 8), (byte) (l >> 16), (byte) (l >> 24),
|
(byte) l, (byte) (l >> 8), (byte) (l >> 16), (byte) (l >> 24),
|
||||||
0x00,
|
0x00,
|
||||||
counter++,
|
mCounter++,
|
||||||
0x01,
|
0x00,
|
||||||
0x00, 0x00},
|
0x00, 0x00},
|
||||||
d);
|
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 {
|
public byte[] receive() throws TransportIoException {
|
||||||
final byte[] bytes = receiveRaw();
|
byte[] buffer = new byte[mBulkIn.getMaxPacketSize()];
|
||||||
return Arrays.copyOfRange(bytes, 10, bytes.length);
|
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 {
|
private void sendRaw(final byte[] data) throws TransportIoException {
|
||||||
@@ -131,14 +209,18 @@ public class UsbTransport implements Transport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] receiveRaw() throws TransportIoException {
|
private byte getStatus(byte[] bytes) {
|
||||||
byte[] buffer = new byte[1024];
|
return (byte) ((bytes[7] >> 6) & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
int res = mConnection.bulkTransfer(mBulkIn, buffer, buffer.length, TIMEOUT);
|
private void checkXfrBlockResult(byte[] bytes) throws TransportIoException {
|
||||||
if (res < 0) {
|
final byte status = getStatus(bytes);
|
||||||
throw new TransportIoException("USB error, failed to receive response " + res);
|
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