From 25cafad44a38eb93660cc9c2e374be598bff6a21 Mon Sep 17 00:00:00 2001 From: Tangem Date: Mon, 18 Nov 2019 11:41:32 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../com/tangem/common/apdu/CommandApdu.kt | 2 - .../com/tangem/common/apdu/ResponseApdu.kt | 5 +- .../main/java/com/tangem/common/tlv/Tlv.kt | 6 ++- .../com/tangem/common/apdu/CommandApduTest.kt | 52 +++++++++++++++++++ .../tangem/common/apdu/ResponseApduTest.kt | 44 ++++++++++++++++ .../DefaultCardManagerDelegate.kt | 2 +- .../tangem/tangem_sdk_new/nfc/NfcReader.kt | 7 +-- 7 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt create mode 100644 tangem-core/src/test/java/com/tangem/common/apdu/ResponseApduTest.kt diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt index f72fa4d0ae..f13c726438 100644 --- a/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt +++ b/tangem-core/src/main/java/com/tangem/common/apdu/CommandApdu.kt @@ -59,7 +59,6 @@ class CommandApdu( val lc = data.size - val byteStream = ByteArrayOutputStream() byteStream.write(cla.toInt()) byteStream.write(ins) @@ -73,7 +72,6 @@ class CommandApdu( } private fun writeLength(stream: ByteArrayOutputStream, lc: Int) { - stream.write(0) stream.write(lc shr 8) stream.write(lc and 0xFF) diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt index 6141512855..c85f2ab9ba 100644 --- a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt +++ b/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt @@ -9,7 +9,7 @@ import com.tangem.common.tlv.Tlv * @property sw Status word code, reflecting the status of the response. * @property statusWord Parsed status word. */ -class ResponseApdu(val data: ByteArray) { +class ResponseApdu(private val data: ByteArray) { private val sw1: Int = 0x00FF and data[data.size - 2].toInt() private val sw2: Int = 0x00FF and data[data.size - 1].toInt() @@ -26,8 +26,7 @@ class ResponseApdu(val data: ByteArray) { */ fun getTlvData(encryptionKey: ByteArray? = null): List? { return when { - data.size < 2 -> null - data.size == 2 -> emptyList() + data.size <= 2 -> null else -> Tlv.tlvListFromBytes(data.copyOf(data.size - 2)) } } diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt b/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt index 68063c8d07..15297b0150 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/Tlv.kt @@ -1,5 +1,6 @@ package com.tangem.common.tlv +import com.tangem.Log import java.io.ByteArrayInputStream import java.io.IOException @@ -52,7 +53,7 @@ class Tlv { } - fun tlvListFromBytes(mData: ByteArray): List { + fun tlvListFromBytes(mData: ByteArray): List? { val tlvList = mutableListOf() val stream = ByteArrayInputStream(mData) var tlv: Tlv? = null @@ -61,7 +62,8 @@ class Tlv { tlv = Tlv.tlvFromBytes(stream) if (tlv != null) tlvList.add(tlv) } catch (e: IOException) { - throw TlvMapperException("TLVError: " + e.message) + Log.e(this::class.java.simpleName,"TLVError: " + e.message) + return null } } while (tlv != null) diff --git a/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt b/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt new file mode 100644 index 0000000000..f2228f497b --- /dev/null +++ b/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt @@ -0,0 +1,52 @@ +package com.tangem.common.apdu + +import com.google.common.truth.Truth.assertThat +import com.tangem.common.extensions.calculateSha256 +import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvTag +import org.junit.Test + + +class CommandApduTest { + + @Test + fun `simple READ command to bytes`() { + val pinInBytes = byteArrayOf(-111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115, -10, -111, + 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123, -55, -94, 3) + val commandApdu = CommandApdu( + Instruction.Read, + mutableListOf(Tlv(TlvTag.Pin, pinInBytes))) + + val expected = byteArrayOf(0, -14, 0, 0, 0, 0, 34, 16, 32, -111, -76, -47, 66, -126, 63, 125, + 32, -59, -16, -115, -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, + -45, 19, -124, -123, -55, -94, 3) + + assertThat(commandApdu.apduData) + .isEqualTo(expected) + } + + @Test + fun `READ with terminal key to bytes`() { + val pinInBytes = byteArrayOf(-111, -76, -47, 66, -126, 63, 125, 32, -59, -16, -115, -10, -111, + 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123, -55, -94, 3) + val terminalPublicKey = byteArrayOf(4, 80, -122, 58, -42, 74, -121, -82, -118, 47, -24, 60, + 26, -15, -88, 64, 60, -75, 63, 83, -28, -122, -40, 81, 29, -83, -118, 4, -120, 126, + 91, 35, 82, 44, -44, 112, 36, 52, 83, -94, -103, -6, -98, 119, 35, 119, 22, 16, 58, + -68, 17, -95, -33, 56, -123, 94, -42, -14, -18, 24, 126, -100, 88, 43, -90) + val commandApdu = CommandApdu( + Instruction.Read, + mutableListOf( + Tlv(TlvTag.Pin, pinInBytes), + Tlv(TlvTag.TerminalPublicKey, terminalPublicKey))) + + val expected = byteArrayOf(0, -14, 0, 0, 0, 0, 101, 16, 32, -111, -76, -47, 66, -126, 63, + 125, 32, -59, -16, -115, -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, + -10, -45, 19, -124, -123, -55, -94, 3, 92, 65, 4, 80, -122, 58, -42, 74, -121, -82, -118, + 47, -24, 60, 26, -15, -88, 64, 60, -75, 63, 83, -28, -122, -40, 81, 29, -83, -118, 4, -120, + 126, 91, 35, 82, 44, -44, 112, 36, 52, 83, -94, -103, -6, -98, 119, 35, 119, 22, 16, 58, + -68, 17, -95, -33, 56, -123, 94, -42, -14, -18, 24, 126, -100, 88, 43, -90) + + assertThat(commandApdu.apduData) + .isEqualTo(expected) + } +} \ No newline at end of file diff --git a/tangem-core/src/test/java/com/tangem/common/apdu/ResponseApduTest.kt b/tangem-core/src/test/java/com/tangem/common/apdu/ResponseApduTest.kt new file mode 100644 index 0000000000..0b6f7fc8b9 --- /dev/null +++ b/tangem-core/src/test/java/com/tangem/common/apdu/ResponseApduTest.kt @@ -0,0 +1,44 @@ +package com.tangem.common.apdu + +import com.google.common.truth.Truth.assertThat +import com.tangem.common.tlv.TlvTag +import org.junit.Test + +class ResponseApduTest { + + @Test + fun `get StatusWord returns Unknown`() { + val corruptData = byteArrayOf(0, 0, 0, 0) + val responseApdu = ResponseApdu(corruptData) + assertThat(responseApdu.statusWord) + .isEqualTo(StatusWord.Unknown) + } + + @Test + fun `get StatusWord returns ProcessCompleted`() { + val data = byteArrayOf(0, 0, 0, 0, -112, 0) + val responseApdu = ResponseApdu(data) + assertThat(responseApdu.statusWord) + .isEqualTo(StatusWord.ProcessCompleted) + } + + @Test + fun `corrupt response, getTlvData returns null`() { + val corruptData = byteArrayOf(0, 0, 0) + val responseApdu = ResponseApdu(corruptData) + assertThat(responseApdu.getTlvData()) + .isNull() + } + + @Test + fun `response, getTlvData returns cardId`() { + val data = byteArrayOf(1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 32, 11, 83, 77, 65, 82, 84, 32, 67, 65, 83, 72, 0, 2, 1, 2, -128, 6, 50, 46, 49, 49, 114, 0, 3, 65, 4, -49, 11, -50, -66, -121, -25, -2, 65, 65, -13, 14, 49, 27, -82, -33, -85, -113, 65, 20, 8, -39, -75, 57, 45, 65, -31, 35, 44, 38, 40, 63, -44, 113, -45, -75, -95, -118, 118, 29, 65, 117, -24, -53, 82, -72, 91, -20, -96, -77, -103, -14, -63, 52, -127, -123, -27, -16, -128, -67, -3, -104, -26, -22, 65, 10, 4, 0, 0, 126, 33, 12, 90, -127, 2, 0, 41, -126, 4, 7, -29, 5, 2, -125, 7, 84, 65, 78, 71, 69, 77, 0, -124, 3, 69, 84, 72, -122, 64, 111, -103, 48, -114, -40, 18, -103, 26, -102, -12, -38, -78, -90, -9, -98, 88, -47, -100, -24, 24, -105, -70, -72, 6, 94, -96, -77, 11, -123, -28, -118, 37, 63, 107, -55, -11, 23, -12, 13, -23, -121, -63, 36, -59, 70, 116, 91, -125, -34, -69, 23, -112, 6, 17, 4, -49, 68, -56, 29, -45, 81, 10, 97, 83, 48, 65, 4, -127, -106, -86, 75, 65, 10, -60, 74, 59, -100, -50, 24, -25, -66, 34, 106, -22, 7, 10, -52, -125, -87, -49, 103, 84, 15, -84, 73, -81, 37, 18, -97, 106, 83, -118, 40, -83, 99, 65, 53, -114, 60, 79, -103, 99, 6, 79, 126, 54, 83, 114, -90, 81, -45, 116, -27, -62, 60, -35, 55, -3, 9, -101, -14, 5, 10, 115, 101, 99, 112, 50, 53, 54, 107, 49, 0, 8, 4, 0, 15, 66, 64, 7, 1, 0, 9, 2, 11, -72, 96, 65, 4, -42, -5, -41, -84, -23, 88, 2, 86, -63, -118, -123, -10, -66, -82, -107, -68, -93, 111, 47, 93, -20, -86, 74, 28, 21, 81, 93, -21, -124, -57, -102, 55, 17, 84, -66, -68, -22, -128, 126, -99, -65, -54, -42, 59, -25, -21, -124, 5, 59, -16, -72, 73, 48, 16, -27, 103, -112, -73, 2, 96, -51, 41, -42, 116, 98, 4, 0, 15, 66, 52, 99, 4, 0, 0, 0, 13, 15, 1, 0, -112, 0) + val responseApdu = ResponseApdu(data) + assertThat(responseApdu.getTlvData()) + .isNotNull() + assertThat(responseApdu.getTlvData()) + .isNotEmpty() + assertThat(responseApdu.getTlvData()?.filter { it.tag == TlvTag.Unknown }) + .isEmpty() + } +} \ No newline at end of file diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt index 4985b73cec..8f37eb0c1c 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/DefaultCardManagerDelegate.kt @@ -101,7 +101,7 @@ class DefaultCardManagerDelegate(private val reader: NfcReader) : CardManagerDel } } - override fun requestPin(callback: (result: CompletionResult) -> Unit) { + override fun onPinRequested(callback: (result: CompletionResult) -> Unit) { TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } diff --git a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt index d80afe9c5e..9b54bd9ffe 100644 --- a/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt +++ b/tangem-sdk/src/main/java/com/tangem/tangem_sdk_new/nfc/NfcReader.kt @@ -15,7 +15,8 @@ import com.tangem.tasks.TaskError */ class NfcReader : CardReader { - override var readingActive = false + var readingActive = false + private set var nfcEnabled = false var manager: NfcManager? = null private var isoDep: IsoDep? = null @@ -35,7 +36,7 @@ class NfcReader : CardReader { if (value) { // Stops reading and sends failure callback to a task // if reading is cancelled (when user closes nfc bottom sheet dialog). - readingActive = false + closeSession() callback?.invoke(CompletionResult.Failure(TaskError.UserCancelledError())) } } @@ -43,7 +44,7 @@ class NfcReader : CardReader { var data: ByteArray? = null var callback: ((response: CompletionResult) -> Unit)? = null - override fun startNfcSession() { + override fun openSession() { readingActive = true readingCancelled = false manager?.disableReaderMode()