diff --git a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt index 1fc2521d2d..a6b99184ec 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CheckWalletCommand.kt @@ -1,12 +1,13 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.tasks.TaskError @@ -38,12 +39,11 @@ class CheckWalletCommand( ) : CommandSerializer() { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { - val tlvData = listOf( - Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()), - Tlv(TlvTag.CardId, cardId.hexToBytes()), - Tlv(TlvTag.Challenge, challenge) - ) - return CommandApdu(Instruction.CheckWallet, tlvData) + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) + tlvBuilder.append(TlvTag.CardId, cardId) + tlvBuilder.append(TlvTag.Challenge, challenge) + return CommandApdu(Instruction.CheckWallet, tlvBuilder.serialize()) } override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): CheckWalletResponse? { diff --git a/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt b/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt index aad7f01b1b..92ee3d0d90 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CommandSerializer.kt @@ -1,6 +1,6 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.toInt diff --git a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt index 833795cbbf..3a30ae478b 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt @@ -1,12 +1,13 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.tasks.TaskError @@ -42,16 +43,12 @@ class CreateWalletCommand( ) : CommandSerializer() { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { - val tlvData = mutableListOf( - Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()), - Tlv(TlvTag.CardId, cardId.hexToBytes()), - Tlv(TlvTag.Pin2, cardEnvironment.pin2.calculateSha256()) - ) - if (cardEnvironment.cvc != null) { - tlvData.add(Tlv(TlvTag.Cvc, cardEnvironment.cvc)) - } - - return CommandApdu(Instruction.CreateWallet, tlvData) + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) + tlvBuilder.append(TlvTag.CardId, cardId) + tlvBuilder.append(TlvTag.Pin2, cardEnvironment.pin2) + tlvBuilder.append(TlvTag.Cvc, cardEnvironment.cvc) + return CommandApdu(Instruction.CreateWallet, tlvBuilder.serialize()) } override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): CreateWalletResponse? { diff --git a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt index f8c3feaf7f..5c44515412 100644 --- a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt @@ -1,12 +1,13 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.tasks.TaskError @@ -23,7 +24,7 @@ class PurgeWalletResponse( ) : CommandResponse /** -* This command deletes all wallet data. If Is_Reusable flag is enabled during personalization, + * This command deletes all wallet data. If Is_Reusable flag is enabled during personalization, * If Is_Reusable flag is disabled, the card switches to ‘Purged’ state. * ‘Purged’ state is final, it makes the card useless. @@ -34,12 +35,11 @@ class PurgeWalletCommand( ) : CommandSerializer() { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { - val tlvData = mutableListOf( - Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()), - Tlv(TlvTag.CardId, cardId.hexToBytes()), - Tlv(TlvTag.Pin2, cardEnvironment.pin2.calculateSha256()) - ) - return CommandApdu(Instruction.PurgeWallet, tlvData) + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) + tlvBuilder.append(TlvTag.CardId, cardId) + tlvBuilder.append(TlvTag.Pin2, cardEnvironment.pin2) + return CommandApdu(Instruction.PurgeWallet, tlvBuilder.serialize()) } override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): PurgeWalletResponse? { diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt index d12548c92f..bacd0a3023 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt @@ -1,11 +1,12 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.calculateSha256 import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.tasks.TaskError @@ -296,19 +297,16 @@ class Card( class ReadCommand : CommandSerializer() { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { + val tlvBuilder = TlvBuilder() /** * [CardEnvironment] stores the pin1 value. If no pin1 value was set, it will contain * default value of ‘000000’. * In order to obtain card’s data, [ReadCommand] should use the correct pin 1 value. * The card will not respond if wrong pin 1 has been submitted. */ - val tlvData = mutableListOf(Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256())) - - cardEnvironment.terminalKeys?.let { terminalKeys -> - Tlv(TlvTag.TerminalPublicKey, terminalKeys.publicKey) - } - - return CommandApdu(Instruction.Read, tlvData) + tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) + tlvBuilder.append(TlvTag.TerminalPublicKey, cardEnvironment.terminalKeys?.publicKey) + return CommandApdu(Instruction.Read, tlvBuilder.serialize()) } override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): Card? { @@ -349,7 +347,7 @@ class ReadCommand : CommandSerializer() { private fun deserializeCardData(tlvData: List): CardData? { val cardDataTlvs = tlvData.find { it.tag == TlvTag.CardData }?.let { - Tlv.tlvListFromBytes(it.value) + Tlv.deserialize(it.value) } if (cardDataTlvs.isNullOrEmpty()) return null diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt index 3772d178c8..076d89f66d 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadIssuerDataCommand.kt @@ -1,12 +1,13 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.tasks.TaskError @@ -54,11 +55,10 @@ class ReadIssuerDataCommand( ) : CommandSerializer() { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { - val tlvData = listOf( - Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()), - Tlv(TlvTag.CardId, cardId.hexToBytes()) - ) - return CommandApdu(Instruction.ReadIssuerData, tlvData) + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) + tlvBuilder.append(TlvTag.CardId, cardId) + return CommandApdu(Instruction.ReadIssuerData, tlvBuilder.serialize()) } override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): ReadIssuerDataResponse? { diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt index a81a179f49..0b8848c4d5 100644 --- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt @@ -1,12 +1,13 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.crypto.sign @@ -50,17 +51,16 @@ class SignCommand(private val hashes: Array, private val cardId: Stri } override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { - val tlvData = mutableListOf( - Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()), - Tlv(TlvTag.Pin2, cardEnvironment.pin2.calculateSha256()), - Tlv(TlvTag.CardId, cardId.hexToBytes()), - Tlv(TlvTag.TransactionOutHashSize, byteArrayOf(hashSizes.toByte())), - Tlv(TlvTag.TransactionOutHash, dataToSign) - ) + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) + tlvBuilder.append(TlvTag.Pin2, cardEnvironment.pin2) + tlvBuilder.append(TlvTag.CardId, cardId) + tlvBuilder.append(TlvTag.TransactionOutHashSize, byteArrayOf(hashSizes.toByte())) + tlvBuilder.append(TlvTag.TransactionOutHash, dataToSign) + tlvBuilder.append(TlvTag.Cvc, cardEnvironment.cvc) - addTerminalSignature(cardEnvironment, tlvData) - - return CommandApdu(Instruction.Sign, tlvData) + addTerminalSignature(cardEnvironment, tlvBuilder) + return CommandApdu(Instruction.Sign, tlvBuilder.serialize()) } /** @@ -70,11 +70,11 @@ class SignCommand(private val hashes: Array, private val cardId: Stri * TerminalTransactionSignature parameter containing a correct signature of raw data to be signed made with TerminalPrivateKey * (this key should be generated and securily stored by the application). */ - private fun addTerminalSignature(cardEnvironment: CardEnvironment, tlvData: MutableList) { + private fun addTerminalSignature(cardEnvironment: CardEnvironment, tlvBuilder: TlvBuilder) { cardEnvironment.terminalKeys?.let { terminalKeyPair -> val signedData = dataToSign.sign(terminalKeyPair.privateKey) - tlvData.add(Tlv(TlvTag.TerminalTransactionSignature, signedData)) - tlvData.add(Tlv(TlvTag.TerminalPublicKey, terminalKeyPair.publicKey)) + tlvBuilder.append(TlvTag.TerminalTransactionSignature, signedData) + tlvBuilder.append(TlvTag.TerminalPublicKey, terminalKeyPair.publicKey) } } diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt index 7c8e27ef4f..dc36a1a927 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt @@ -1,6 +1,6 @@ package com.tangem.commands -import com.tangem.CardEnvironment +import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -8,6 +8,7 @@ import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.hexToBytes import com.tangem.common.extensions.toByteArray import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvMapper import com.tangem.common.tlv.TlvTag import com.tangem.tasks.TaskError @@ -37,17 +38,14 @@ class WriteIssuerDataCommand( ) : CommandSerializer() { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { - val tlvData = mutableListOf( - Tlv(TlvTag.Pin, cardEnvironment.pin1.calculateSha256()), - Tlv(TlvTag.CardId, cardId.hexToBytes()), - Tlv(TlvTag.IssuerData, issuerData), - Tlv(TlvTag.IssuerDataSignature, issuerDataSignature) - ) - if (issuerDataCounter != null) { - tlvData.add(Tlv(TlvTag.IssuerDataCounter, issuerDataCounter.toByteArray())) - } + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, cardEnvironment.pin1) + tlvBuilder.append(TlvTag.CardId, cardId) + tlvBuilder.append(TlvTag.IssuerData, issuerData) + tlvBuilder.append(TlvTag.IssuerDataSignature, issuerDataSignature) + tlvBuilder.append(TlvTag.IssuerDataCounter, issuerDataCounter) - return CommandApdu(Instruction.WriteIssuerData, tlvData) + return CommandApdu(Instruction.WriteIssuerData, tlvBuilder.serialize()) } override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): WriteIssuerDataResponse? { 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 f13c726438..450618ced5 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 @@ -1,8 +1,6 @@ package com.tangem.common.apdu -import com.tangem.EncryptionMode -import com.tangem.common.tlv.Tlv -import com.tangem.common.tlv.toBytes +import com.tangem.common.EncryptionMode import java.io.ByteArrayOutputStream /** @@ -15,7 +13,7 @@ import java.io.ByteArrayOutputStream class CommandApdu( private val ins: Int, - private val tlvList: List, + private val tlvs: ByteArray, private val cla: Byte = ISO_CLA, private val p1: Byte = 0x00, @@ -28,12 +26,12 @@ class CommandApdu( constructor( instruction: Instruction, - tlvList: List, + tlvs: ByteArray, encryptionMode: EncryptionMode = EncryptionMode.NONE, encryptionKey: ByteArray? = null ) : this( instruction.code, - tlvList, + tlvs, encryptionMode = encryptionMode, encryptionKey = encryptionKey ) @@ -51,13 +49,7 @@ class CommandApdu( private fun toBytes(): ByteArray { - val data = if (tlvList.isNotEmpty()) { - tlvList.toBytes() - } else { - byteArrayOf() - } - - val lc = data.size + val lc = tlvs.size val byteStream = ByteArrayOutputStream() byteStream.write(cla.toInt()) @@ -66,7 +58,7 @@ class CommandApdu( byteStream.write(p2.toInt()) if (lc != 0) { writeLength(byteStream, lc) - byteStream.write(data) + byteStream.write(tlvs) } return byteStream.toByteArray() } 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 c85f2ab9ba..e98c78874b 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 @@ -27,7 +27,7 @@ class ResponseApdu(private val data: ByteArray) { fun getTlvData(encryptionKey: ByteArray? = null): List? { return when { data.size <= 2 -> null - else -> Tlv.tlvListFromBytes(data.copyOf(data.size - 2)) + else -> Tlv.deserialize(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 f17ab7e3cb..2c20fa64e0 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 @@ -53,13 +53,13 @@ class Tlv { } - fun tlvListFromBytes(mData: ByteArray): List? { + fun deserialize(mData: ByteArray): List? { val tlvList = mutableListOf() val stream = ByteArrayInputStream(mData) - var tlv: Tlv? = null + var tlv: Tlv? do { try { - tlv = Tlv.tlvFromBytes(stream) + tlv = tlvFromBytes(stream) if (tlv != null) tlvList.add(tlv) } catch (e: IOException) { Log.e(this::class.java.simpleName,"TLVError: " + e.message) @@ -73,10 +73,10 @@ class Tlv { } -fun List.toBytes(): ByteArray = - this.map { it.toBytes() }.reduce { arr1, arr2 -> arr1 + arr2 } +fun List.serialize(): ByteArray = + this.map { it.serialize() }.reduce { arr1, arr2 -> arr1 + arr2 } -fun Tlv.toBytes(): ByteArray { +fun Tlv.serialize(): ByteArray { val tag = byteArrayOf(this.tag.code.toByte()) val length = getLengthInBytes(this.value.size) val value = if (this.value.isNotEmpty()) this.value else byteArrayOf(0x00) diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt new file mode 100644 index 0000000000..6ec643d00a --- /dev/null +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvBuilder.kt @@ -0,0 +1,15 @@ +package com.tangem.common.tlv + +class TlvBuilder { + private val tlvs = mutableListOf() + private val encoder = TlvEncoder() + + internal inline fun append(tag: TlvTag, value: T?) { + if (value == null) return + + tlvs.add(encoder.encode(tag, value)) + } + + fun serialize(): ByteArray = tlvs.serialize() + +} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt new file mode 100644 index 0000000000..3db20cd2eb --- /dev/null +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvEncoder.kt @@ -0,0 +1,81 @@ +package com.tangem.common.tlv + +import com.tangem.commands.* +import com.tangem.common.extensions.* +import com.tangem.tasks.TaskError +import java.time.Year +import java.util.* + +class TlvEncoder { + internal inline fun encode(tag: TlvTag, value: T?): Tlv { + if (value != null) { + return Tlv(tag, encodeValue(value, tag)) + } else { + throw TaskError.SerializeCommandError("Encoding error. Value for tag $tag is null") + } + } + + private inline fun encodeValue(value: T, tag: TlvTag): ByteArray { + return when (tag.valueType()) { + TlvValueType.HexString -> { + typeCheck(tag) + return if (tag == TlvTag.Pin || tag == TlvTag.Pin2) { + (value as String).calculateSha256() + } else { + (value as String).hexToBytes() + } + } + TlvValueType.Utf8String -> { + typeCheck(tag) + (value as String).toByteArray() + } + TlvValueType.IntValue -> { + typeCheck(tag) + (value as Int).toByteArray() + } + TlvValueType.BoolValue -> { + typeCheck(tag) + throw ConversionException("Usopported operation: Boolean to ByteArray for tag $tag") + } + TlvValueType.ByteArray -> { + typeCheck(tag) + value as ByteArray + } + TlvValueType.EllipticCurve -> { + typeCheck(tag) + (value as EllipticCurve).curve.plus("\\0").toByteArray() + } + TlvValueType.DateTime -> { + typeCheck(tag) + val calendar = Calendar.getInstance().apply { time = (value as Date) } + val year = calendar.get(Calendar.YEAR) + val month = calendar.get(Calendar.MONTH) + 1 + val day = calendar.get(Calendar.DAY_OF_MONTH) + return year.toByteArray() + month.toByteArray() + day.toByteArray() + } + TlvValueType.ProductMask -> { + typeCheck(tag) + byteArrayOf( + (value as ProductMask).code + ) + } + TlvValueType.SettingsMask -> { + typeCheck(tag) + (value as SettingsMask).rawValue.toByteArray() + } + TlvValueType.CardStatus -> { + typeCheck(tag) + (value as CardStatus).code.toByteArray() + } + TlvValueType.SigningMethod -> { + typeCheck(tag) + (value as SigningMethod).rawValue.toByteArray() + } + } + } + + private inline fun typeCheck(tag: TlvTag) { + if (T::class != ExpectedT::class) + throw WrongTypeException("Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}") + } +} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt b/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt index ca292d37f4..92ca2a8885 100644 --- a/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt +++ b/tangem-core/src/main/java/com/tangem/common/tlv/TlvTag.kt @@ -108,7 +108,7 @@ enum class TlvTag(val code: Int) { */ fun valueType(): TlvValueType { return when (this) { - CardId, Pin, Batch -> TlvValueType.HexString + CardId, Pin, Pin2, Batch -> TlvValueType.HexString ManufactureId, Firmware, IssuerId, BlockchainId, TokenSymbol, TokenContractAddress -> TlvValueType.Utf8String CurveId -> TlvValueType.EllipticCurve 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 index f2228f497b..61d6ea71d3 100644 --- a/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt +++ b/tangem-core/src/test/java/com/tangem/common/apdu/CommandApduTest.kt @@ -2,7 +2,9 @@ package com.tangem.common.apdu import com.google.common.truth.Truth.assertThat import com.tangem.common.extensions.calculateSha256 +import com.tangem.common.extensions.toHexString import com.tangem.common.tlv.Tlv +import com.tangem.common.tlv.TlvBuilder import com.tangem.common.tlv.TlvTag import org.junit.Test @@ -11,12 +13,13 @@ 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 pin = "000000" + val tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, pin) val commandApdu = CommandApdu( Instruction.Read, - mutableListOf(Tlv(TlvTag.Pin, pinInBytes))) - + tlvBuilder.serialize() + ) 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) @@ -27,17 +30,18 @@ class CommandApduTest { @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 pin = "000000" 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 tlvBuilder = TlvBuilder() + tlvBuilder.append(TlvTag.Pin, pin) + tlvBuilder.append(TlvTag.TerminalPublicKey, terminalPublicKey) val commandApdu = CommandApdu( Instruction.Read, - mutableListOf( - Tlv(TlvTag.Pin, pinInBytes), - Tlv(TlvTag.TerminalPublicKey, terminalPublicKey))) + tlvBuilder.serialize() + ) 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, diff --git a/tangem-core/src/test/java/com/tangem/common/tlv/TlvMapperTest.kt b/tangem-core/src/test/java/com/tangem/common/tlv/TlvMapperTest.kt index 3666e03120..2c8334e752 100644 --- a/tangem-core/src/test/java/com/tangem/common/tlv/TlvMapperTest.kt +++ b/tangem-core/src/test/java/com/tangem/common/tlv/TlvMapperTest.kt @@ -11,12 +11,12 @@ class TlvMapperTest { private val rawData = 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) - private val tlvData = Tlv.tlvListFromBytes(rawData) + private val tlvData = Tlv.deserialize(rawData) private val tlvMapper = TlvMapper(tlvData!!) private val cardDataRaw: ByteArray = tlvMapper.map(TlvTag.CardData) - private val cardDataMapper = TlvMapper(Tlv.tlvListFromBytes(cardDataRaw)!!) + private val cardDataMapper = TlvMapper(Tlv.deserialize(cardDataRaw)!!) @Test fun `map optional when value is present`() { @@ -88,7 +88,7 @@ class TlvMapperTest { @Test fun `map SigningMethods set of methods returns correct value`() { - val localMapper = TlvMapper(Tlv.tlvListFromBytes("070195".hexToBytes())!!) + val localMapper = TlvMapper(Tlv.deserialize("070195".hexToBytes())!!) val signingMethod: SigningMethod = localMapper.map(TlvTag.SigningMethod) assertThat(signingMethod.contains(SigningMethod.signHash)) diff --git a/tangem-core/src/test/java/com/tangem/common/tlv/TlvTest.kt b/tangem-core/src/test/java/com/tangem/common/tlv/TlvTest.kt index 4dcdecf66a..b0dc16ccc1 100644 --- a/tangem-core/src/test/java/com/tangem/common/tlv/TlvTest.kt +++ b/tangem-core/src/test/java/com/tangem/common/tlv/TlvTest.kt @@ -17,7 +17,7 @@ class TlvTest { -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123, -55, -94, 3) - assertThat(tlvs.toBytes()) + assertThat(tlvs.serialize()) .isEqualTo(expected) } @@ -34,7 +34,7 @@ class TlvTest { -55, -94, 3, 1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 22, 16, -82, -78, -31, 34, 66, -19, -86, -1, 26, 8, 100, -126, -74, 20, -28, 83) - assertThat(tlvs.toBytes()) + assertThat(tlvs.serialize()) .isEqualTo(expected) } @@ -44,7 +44,7 @@ class TlvTest { -10, -111, 34, -34, 67, -13, 95, 5, 122, -104, -115, -106, 25, -10, -45, 19, -124, -123, -55, -94, 3) - val tlvs = Tlv.tlvListFromBytes(bytes) + val tlvs = Tlv.deserialize(bytes) assertThat(tlvs) .isNotNull() @@ -65,7 +65,7 @@ class TlvTest { -55, -94, 3, 1, 8, -53, 34, 0, 0, 0, 2, 115, 116, 22, 16, -82, -78, -31, 34, 66, -19, -86, -1, 26, 8, 100, -126, -74, 20, -28, 83) - val tlvs = Tlv.tlvListFromBytes(bytes) + val tlvs = Tlv.deserialize(bytes) assertThat(tlvs) .isNotNull() @@ -91,12 +91,12 @@ class TlvTest { @Test fun `Bytes to TLVs, wrong values`() { val bytes = byteArrayOf(0) - val tlvs = Tlv.tlvListFromBytes(bytes) + val tlvs = Tlv.deserialize(bytes) assertThat(tlvs) .isNull() val bytes1 = byteArrayOf(0, 0, 0, 0, 0, 0, 0) - val tlvs1 = Tlv.tlvListFromBytes(bytes1) + val tlvs1 = Tlv.deserialize(bytes1) assertThat(tlvs1) .isNull() }