Compare commits

...

1 commit

Author SHA1 Message Date
3a349bf0ca
refactor 2025-02-26 13:07:26 +08:00
4 changed files with 52 additions and 27 deletions

View file

@ -40,20 +40,24 @@ class OmapiApduInterface(
override fun logicalChannelOpen(aid: ByteArray): Int { override fun logicalChannelOpen(aid: ByteArray): Int {
val channel = session.openLogicalChannel(aid)!! val channel = session.openLogicalChannel(aid)!!
val id = index.getAndAdd(1) val id = index.addAndGet(1)
channels[id] = channel channels[id] = channel
return id return id
} }
override fun logicalChannelClose(handle: Int) { override fun logicalChannelClose(handle: Int) {
val channel = channels[handle] val channel = channels[handle]
check(channel != null) { "Channel $handle does not exist" } check(channel != null) {
"Invalid logical channel handle $handle"
}
channel.close() channel.close()
} }
override fun transmit(handle: Int, tx: ByteArray): ByteArray { override fun transmit(handle: Int, tx: ByteArray): ByteArray {
val channel = channels[handle] val channel = channels[handle]
check(channel != null) { "Channel $handle does not exist" } check(channel != null) {
"Invalid logical channel handle $handle"
}
if (runBlocking { verboseLoggingFlow.first() }) { if (runBlocking { verboseLoggingFlow.first() }) {
Log.d(TAG, "OMAPI APDU: ${tx.encodeHex()}") Log.d(TAG, "OMAPI APDU: ${tx.encodeHex()}")

View file

@ -23,6 +23,11 @@ class UsbApduInterface(
override var atr: ByteArray? = null override var atr: ByteArray? = null
override val valid: Boolean
get() = channels.isNotEmpty()
private var channels = mutableSetOf<Int>()
override fun connect() { override fun connect() {
ccidDescription = UsbCcidDescription.fromRawDescriptors(conn.rawDescriptors)!! ccidDescription = UsbCcidDescription.fromRawDescriptors(conn.rawDescriptors)!!
@ -76,10 +81,15 @@ class UsbApduInterface(
return -1 return -1
} }
channels.add(channelId)
return channelId return channelId
} }
override fun logicalChannelClose(handle: Int) { override fun logicalChannelClose(handle: Int) {
check(channels.contains(handle)) {
"Invalid logical channel handle $handle"
}
// CLOSE LOGICAL CHANNEL // CLOSE LOGICAL CHANNEL
val req = manageChannelCmd(false, handle.toByte()) val req = manageChannelCmd(false, handle.toByte())
val resp = transmitApduByChannel(req, handle.toByte()) val resp = transmitApduByChannel(req, handle.toByte())
@ -87,15 +97,16 @@ class UsbApduInterface(
if (!isSuccessResponse(resp)) { if (!isSuccessResponse(resp)) {
Log.d(TAG, "CLOSE LOGICAL CHANNEL failed: ${resp.encodeHex()}") Log.d(TAG, "CLOSE LOGICAL CHANNEL failed: ${resp.encodeHex()}")
} }
channels.remove(handle)
} }
override fun transmit(handle: Int, tx: ByteArray): ByteArray { override fun transmit(handle: Int, tx: ByteArray): ByteArray {
check(channels.contains(handle)) {
"Invalid logical channel handle $handle"
}
return transmitApduByChannel(tx, handle.toByte()) return transmitApduByChannel(tx, handle.toByte())
} }
override val valid: Boolean
get() = atr != null
private fun isSuccessResponse(resp: ByteArray): Boolean = private fun isSuccessResponse(resp: ByteArray): Boolean =
resp.size >= 2 && resp[resp.size - 2] == 0x90.toByte() && resp[resp.size - 1] == 0x00.toByte() resp.size >= 2 && resp[resp.size - 2] == 0x90.toByte() && resp[resp.size - 1] == 0x00.toByte()

View file

@ -18,7 +18,10 @@ class TelephonyManagerApduInterface(
const val TAG = "TelephonyManagerApduInterface" const val TAG = "TelephonyManagerApduInterface"
} }
override var valid: Boolean = false override val valid: Boolean
get() = channels.isNotEmpty()
private var channels = mutableSetOf<Int>()
override fun connect() { override fun connect() {
// Do nothing // Do nothing
@ -32,35 +35,31 @@ class TelephonyManagerApduInterface(
val hex = aid.encodeHex() val hex = aid.encodeHex()
val channel = tm.iccOpenLogicalChannelByPortCompat(port.card.physicalSlotIndex, port.portIndex, hex, 0) val channel = tm.iccOpenLogicalChannelByPortCompat(port.card.physicalSlotIndex, port.portIndex, hex, 0)
if (channel.status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR || channel.channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL) { if (channel.status != IccOpenLogicalChannelResponse.STATUS_NO_ERROR || channel.channel == IccOpenLogicalChannelResponse.INVALID_CHANNEL) {
throw IllegalArgumentException("Cannot open logical channel $hex via TelephonManager on slot ${port.card.physicalSlotIndex} port ${port.portIndex}") throw IllegalArgumentException("Cannot open logical channel $hex via TelephonyManager on slot ${port.card.physicalSlotIndex} port ${port.portIndex}")
} }
valid = true channels.add(channel.channel)
return channel.channel return channel.channel
} }
override fun logicalChannelClose(handle: Int) { override fun logicalChannelClose(handle: Int) {
check(channels.contains(handle)) {
"Invalid logical channel handle $handle"
}
tm.iccCloseLogicalChannelByPortCompat(port.card.physicalSlotIndex, port.portIndex, handle) tm.iccCloseLogicalChannelByPortCompat(port.card.physicalSlotIndex, port.portIndex, handle)
valid = false channels.remove(handle)
} }
override fun transmit(handle: Int, tx: ByteArray): ByteArray { override fun transmit(handle: Int, tx: ByteArray): ByteArray {
check(channels.contains(handle)) {
"Invalid logical channel handle $handle"
}
if (runBlocking { verboseLoggingFlow.first() }) { if (runBlocking { verboseLoggingFlow.first() }) {
Log.d(TAG, "TelephonyManager APDU: ${tx.encodeHex()}") Log.d(TAG, "TelephonyManager APDU: ${tx.encodeHex()}")
} }
val cla = tx[0].toUByte().toInt()
val ins = tx[1].toUByte().toInt()
val p1 = tx[2].toUByte().toInt()
val p2 = tx[3].toUByte().toInt()
val p3 = tx[4].toUByte().toInt()
val p4 = tx.drop(5).toByteArray().encodeHex()
// @formatter:off
val result = tm.iccTransmitApduLogicalChannelByPortCompat( val result = tm.iccTransmitApduLogicalChannelByPortCompat(
port.card.physicalSlotIndex, port.portIndex, handle, port.card.physicalSlotIndex, port.portIndex, handle,
cla, ins, p1, p2, p3, p4 tx,
) )
// @formatter:on
if (runBlocking { verboseLoggingFlow.first() }) if (runBlocking { verboseLoggingFlow.first() })
Log.d(TAG, "TelephonyManager APDU response: $result") Log.d(TAG, "TelephonyManager APDU response: $result")
return result?.decodeHex() ?: byteArrayOf() return result?.decodeHex() ?: byteArrayOf()

View file

@ -111,15 +111,26 @@ fun TelephonyManager.iccCloseLogicalChannelByPortCompat(
} }
fun TelephonyManager.iccTransmitApduLogicalChannelByPortCompat( fun TelephonyManager.iccTransmitApduLogicalChannelByPortCompat(
slotIndex: Int, portIndex: Int, channel: Int, slotIndex: Int,
cla: Int, inst: Int, p1: Int, p2: Int, p3: Int, data: String? portIndex: Int,
): String? = channel: Int,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { tx: ByteArray
): String? {
val cla = tx[0].toUByte().toInt()
val ins = tx[1].toUByte().toInt()
val p1 = tx[2].toUByte().toInt()
val p2 = tx[3].toUByte().toInt()
val p3 = tx[4].toUByte().toInt()
val p4 = tx.drop(5).toByteArray().encodeHex()
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
iccTransmitApduLogicalChannelByPort( iccTransmitApduLogicalChannelByPort(
slotIndex, portIndex, channel, cla, inst, p1, p2, p3, data slotIndex, portIndex, channel,
cla, ins, p1, p2, p3, p4
) )
} else { } else {
iccTransmitApduLogicalChannelBySlot( iccTransmitApduLogicalChannelBySlot(
slotIndex, channel, cla, inst, p1, p2, p3, data slotIndex, channel,
cla, ins, p1, p2, p3, p4
) )
} }
}