1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
package org.sufficientlysecure.keychain.javacard;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Pair;
import org.bouncycastle.util.Arrays;
public class UsbTransport implements Transport {
private static final int CLASS_SMARTCARD = 11;
private static final int TIMEOUT = 1000; // 1 s
private final UsbManager mUsbManager;
private final UsbDevice mUsbDevice;
private final UsbInterface mUsbInterface;
private final UsbEndpoint mBulkIn;
private final UsbEndpoint mBulkOut;
private final UsbDeviceConnection mConnection;
private byte counter = 0;
public UsbTransport(final UsbDevice usbDevice, final UsbManager usbManager) throws TransportIoException {
mUsbDevice = usbDevice;
mUsbManager = usbManager;
mUsbInterface = getSmartCardInterface(mUsbDevice);
// throw if mUsbInterface == null
final Pair<UsbEndpoint, UsbEndpoint> ioEndpoints = getIoEndpoints(mUsbInterface);
mBulkIn = ioEndpoints.first;
mBulkOut = ioEndpoints.second;
// throw if any endpoint is null
mConnection = mUsbManager.openDevice(mUsbDevice);
// throw if connection is null
mConnection.claimInterface(mUsbInterface, true);
// check result
final byte[] iccPowerOn = {
0x62,
0x00, 0x00, 0x00, 0x00,
0x00,
counter++,
0x03,
0x00, 0x00
};
sendRaw(iccPowerOn);
receiveRaw();
// Check result
}
/**
* Get first class 11 (Chip/Smartcard) interface for the device
*
* @param device {@link UsbDevice} which will be searched
* @return {@link UsbInterface} of smartcard or null if it doesn't exist
*/
@Nullable
private static UsbInterface getSmartCardInterface(final UsbDevice device) {
for (int i = 0; i < device.getInterfaceCount(); i++) {
final UsbInterface anInterface = device.getInterface(i);
if (anInterface.getInterfaceClass() == CLASS_SMARTCARD) {
return anInterface;
}
}
return null;
}
@NonNull
private static Pair<UsbEndpoint, UsbEndpoint> getIoEndpoints(final UsbInterface usbInterface) {
UsbEndpoint bulkIn = null, bulkOut = null;
for (int i = 0; i < usbInterface.getEndpointCount(); i++) {
final UsbEndpoint endpoint = usbInterface.getEndpoint(i);
if (endpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_BULK) {
continue;
}
if (endpoint.getDirection() == UsbConstants.USB_DIR_IN) {
bulkIn = endpoint;
} else if (endpoint.getDirection() == UsbConstants.USB_DIR_OUT) {
bulkOut = endpoint;
}
}
return new Pair<>(bulkIn, bulkOut);
}
@Override
public void release() {
mConnection.releaseInterface(mUsbInterface);
mConnection.close();
}
@Override
public boolean isConnected() {
// TODO: redo
return mUsbManager.getDeviceList().containsValue(mUsbDevice);
}
@Override
public byte[] sendAndReceive(final byte[] data) throws TransportIoException {
send(data);
return receive();
}
public void send(final 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,
0x00, 0x00},
d);
sendRaw(data);
}
public byte[] receive() throws TransportIoException {
final byte[] bytes = receiveRaw();
return Arrays.copyOfRange(bytes, 10, bytes.length);
}
private void sendRaw(final byte[] data) throws TransportIoException {
final int tr1 = mConnection.bulkTransfer(mBulkOut, data, data.length, TIMEOUT);
if (tr1 != data.length) {
throw new TransportIoException("USB error, failed to send data " + tr1);
}
}
private byte[] receiveRaw() throws TransportIoException {
byte[] buffer = new byte[1024];
int res = mConnection.bulkTransfer(mBulkIn, buffer, buffer.length, TIMEOUT);
if (res < 0) {
throw new TransportIoException("USB error, failed to receive response " + res);
}
return Arrays.copyOfRange(buffer, 0, res);
}
}
|