From 383f963155534c8d739f717e39f42c8eca73a906 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Oct 2019 11:51:31 +0300 Subject: [PATCH 01/54] Updated on 2026-08-14 --- tangem-card-new/.gitignore | 1 + tangem-card-new/build.gradle | 32 +++++ .../src/main/java/com/tangem/Card.kt | 23 ++++ .../main/java/com/tangem/CardEnvironment.kt | 16 +++ .../com/tangem/CardEnvironmentRepository.kt | 22 ++++ .../src/main/java/com/tangem/CardManager.kt | 53 ++++++++ .../java/com/tangem/CardManagerDelegate.kt | 12 ++ .../src/main/java/com/tangem/CardReader.kt | 7 ++ .../src/main/java/com/tangem/Command.kt | 112 +++++++++++++++++ .../src/main/java/com/tangem/DataStorage.kt | 10 ++ .../src/main/java/com/tangem/Response.kt | 16 +++ .../src/main/java/com/tangem/Task.kt | 114 ++++++++++++++++++ 12 files changed, 418 insertions(+) create mode 100644 tangem-card-new/.gitignore create mode 100644 tangem-card-new/build.gradle create mode 100644 tangem-card-new/src/main/java/com/tangem/Card.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/CardEnvironment.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/CardEnvironmentRepository.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/CardManager.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/CardManagerDelegate.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/CardReader.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/Command.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/DataStorage.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/Response.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/Task.kt diff --git a/tangem-card-new/.gitignore b/tangem-card-new/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/tangem-card-new/.gitignore @@ -0,0 +1 @@ +/build diff --git a/tangem-card-new/build.gradle b/tangem-card-new/build.gradle new file mode 100644 index 0000000000..74697f2588 --- /dev/null +++ b/tangem-card-new/build.gradle @@ -0,0 +1,32 @@ +apply plugin: "kotlin" + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" +} + +sourceCompatibility = "8" +targetCompatibility = "8" + +buildscript { + ext.kotlin_version = '1.3.50' + repositories { + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} +repositories { + mavenCentral() +} +compileKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} +compileTestKotlin { + kotlinOptions { + jvmTarget = "1.8" + } +} diff --git a/tangem-card-new/src/main/java/com/tangem/Card.kt b/tangem-card-new/src/main/java/com/tangem/Card.kt new file mode 100644 index 0000000000..df131c8ad6 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/Card.kt @@ -0,0 +1,23 @@ +package com.tangem + +data class Card( + val cid: String +) { + +// private var CID: ByteArray? = null +// private var status: Status? = null +// private var UID: String? = null +// private var blockchainID: String? = null +// private var manufacturer = Manufacturer.Unknown +// private var manufacturerConfirmed = false +// private var maxSignatures: Int = 0 +// private var remainingSignatures: Int = 0 +// private var PIN: String? = null +// private var pbWalletKey: ByteArray? = null +// private var pbCardKey: ByteArray? = null +// private var pbWalletKeyRar: ByteArray? = null +// private var dtPersonalization: Date? = null +// private var terminalPrivateKey: ByteArray? = null +// private var terminalPublicKey: ByteArray? = null +// private var terminalIsLinked = false +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/CardEnvironment.kt b/tangem-card-new/src/main/java/com/tangem/CardEnvironment.kt new file mode 100644 index 0000000000..7a3194cbcb --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/CardEnvironment.kt @@ -0,0 +1,16 @@ +package com.tangem + + + +data class CardEnvironment( + val pin1: String = DEFAULT_PIN, + val pin2: String = DEFAULT_PIN2, + val terminalPublicKey: ByteArray? = null, + val terminalPrivateKey: ByteArray? = null +) { + + companion object { + const val DEFAULT_PIN = "000000" + const val DEFAULT_PIN2 = "000" + } +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/CardEnvironmentRepository.kt b/tangem-card-new/src/main/java/com/tangem/CardEnvironmentRepository.kt new file mode 100644 index 0000000000..cc3793f8e3 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/CardEnvironmentRepository.kt @@ -0,0 +1,22 @@ +package com.tangem + +class CardEnvironmentRepository(val dataStorage: DataStorage?) { + + var cardEnvironment: CardEnvironment = initCardEnvironment() + set(value) { + if (cardEnvironment != value) { + saveCardEnvirnoment(value) + } + } + + private fun initCardEnvironment(): CardEnvironment { + return CardEnvironment( + dataStorage?.getPin1() ?: CardEnvironment.DEFAULT_PIN, + dataStorage?.getPin2() ?: CardEnvironment.DEFAULT_PIN2 + ) + } + + private fun saveCardEnvirnoment(cardEnvironment: CardEnvironment) { + //TODO: logic for saving fields in persistence storage + } +} diff --git a/tangem-card-new/src/main/java/com/tangem/CardManager.kt b/tangem-card-new/src/main/java/com/tangem/CardManager.kt new file mode 100644 index 0000000000..4abdfe4be8 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/CardManager.kt @@ -0,0 +1,53 @@ +package com.tangem + +open class CardManager( + private val reader: CardReader, + private val cardManagerDelegate: CardManagerDelegate? = null, + dataStorage: DataStorage? = null) { + + private val cardEnvironmentRepository = CardEnvironmentRepository(dataStorage) + + var card: Card? = null + private set + + fun scanCard(callback: (result: TaskResult) -> Unit) { + + val task = ScanTask(cardManagerDelegate, reader) + + runTask(task, cardEnvironmentRepository.cardEnvironment) { + if (it is TaskResult.CommandCompleted && it.resultData is Card) { + this.card = it.resultData + } + callback.invoke(it) + } + } + + fun signTransaction(signCommandData: SignCommandData, + callback: (result: TaskResult) -> Unit) { + val task = SignTask(signCommandData, cardManagerDelegate, reader) + runTask(task, cardEnvironmentRepository.cardEnvironment, callback) + } + + fun runTask(task: Task, environment: CardEnvironment? = null, + callback: (result: TaskResult) -> Unit) { + + task.run(environment ?: cardEnvironmentRepository.cardEnvironment) {result, returnedEnvironment -> + //TODO: environment is kept in Repository + cardEnvironmentRepository.cardEnvironment = returnedEnvironment + callback.invoke(result) + } + } + + fun runCommand(command: Command, + environment: CardEnvironment? = null, + callback: (result: TaskResult) -> Unit) { + val task = BasicTask(command, cardManagerDelegate, reader) + runTask(task, environment, callback) + } +} + +sealed class TaskResult { + data class Success(val resultData: Any) : TaskResult() + data class CommandCompleted(val resultData: Any) : TaskResult() + data class Error(val error: CardError) : TaskResult() +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/CardManagerDelegate.kt b/tangem-card-new/src/main/java/com/tangem/CardManagerDelegate.kt new file mode 100644 index 0000000000..f281c3e857 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/CardManagerDelegate.kt @@ -0,0 +1,12 @@ +package com.tangem + +interface CardManagerDelegate { + + fun showSecurityDelay(seconds: Int) + fun hideSecurityDelay() + fun requestPin(success: () -> String, error: (cardError: CardError) -> CardError) + + fun openNfcPopup() + fun closeNfcPopup() + +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/CardReader.kt b/tangem-card-new/src/main/java/com/tangem/CardReader.kt new file mode 100644 index 0000000000..9557a05e05 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/CardReader.kt @@ -0,0 +1,7 @@ +package com.tangem + +import com.tangem.data.ResponseApdu + +interface CardReader { + fun sendApdu(apduSerialized: ByteArray, callback: (responseApdu: ResponseApdu) -> Unit) +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/Command.kt b/tangem-card-new/src/main/java/com/tangem/Command.kt new file mode 100644 index 0000000000..16a6d73623 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/Command.kt @@ -0,0 +1,112 @@ +package com.tangem + +import com.tangem.data.CommandApdu +import com.tangem.data.ResponseApduParsed +import com.tangem.data.Tlv +import com.tangem.enums.Instruction +import com.tangem.enums.TlvTag + +abstract class Command { + + abstract val instruction: Instruction + abstract val instructionCode: Int + + abstract fun serialize(cardEnvironment: CardEnvironment): CommandApdu + + abstract fun deserialize(responseApduParsed: ResponseApduParsed): TaskResult +} + + +class ReadCardCommand(val pin1: String) : Command() { + + override val instruction = Instruction.Read + override val instructionCode = instruction.code + + override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { + + return CommandApdu( + listOf(Tlv(TlvTag.Pin, TlvTag.Pin.code, pin1.toByteArray())), instruction) + } + + override fun deserialize(responseApduParsed: ResponseApduParsed): TaskResult { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + +} + +class CheckWalletCommand( + val pin1: String, val cid: String, + val challenge: ByteArray, val publicKeyChallenge: ByteArray) : Command() { + + override val instruction = Instruction.CheckWallet + override val instructionCode = instruction.code + + override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun deserialize(responseApduParsed: ResponseApduParsed): TaskResult { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + +} + +class SignCommand(val signCommandData: SignCommandData) : Command() { + + override val instruction = Instruction.Sign + override val instructionCode = instruction.code + + override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + override fun deserialize(responseApduParsed: ResponseApduParsed): TaskResult { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + +} + + + +data class SignCommandData( + val cid: String, + val pin1: String, + val pin2: String, + val cvc: String, + val transactionHash: TransactionHash, + val issuerData: IssuerData, + val terminalPublicKey: ByteArray? = null, + val terminalTransactionSignature: ByteArray? = null + +) + +data class TransactionHash( + val transactionHash: ByteArray, + val transactionRaw: ByteArray, + val hashName: String +) + +data class IssuerData( + val issuerData: ByteArray, + val issuerDataCounter: Int, + val issuerTransactionSignature: ByteArray, + val issuerDataSignature: ByteArray +) + +sealed class CommandData { + data class CheckWalletResponse( + val cid: String, + val salt: ByteArray, + val walletSignature: ByteArray + ) +} + +sealed class CommandResult{ + + data class Success(val data: CommandData) : CommandResult() + data class Error(val error: CardError) : CommandResult() + +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/DataStorage.kt b/tangem-card-new/src/main/java/com/tangem/DataStorage.kt new file mode 100644 index 0000000000..b1c531c671 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/DataStorage.kt @@ -0,0 +1,10 @@ +package com.tangem + +interface DataStorage { + + fun getTerminalPublicKey(): ByteArray? + fun getTerminalPrivateKey(): ByteArray? + fun getPin1(): String? + fun getPin2(): String? + +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/Response.kt b/tangem-card-new/src/main/java/com/tangem/Response.kt new file mode 100644 index 0000000000..56923291f3 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/Response.kt @@ -0,0 +1,16 @@ +package com.tangem + +data class SignResponse( + val cid: String, + val signature: ByteArray, + val remainingSignatures: Int, + val signedHashes: Int +) + + +data class CardError( + val code: Int = 0 +) + + + diff --git a/tangem-card-new/src/main/java/com/tangem/Task.kt b/tangem-card-new/src/main/java/com/tangem/Task.kt new file mode 100644 index 0000000000..4067aeb238 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/Task.kt @@ -0,0 +1,114 @@ +package com.tangem + +abstract class Task(protected val delegate: CardManagerDelegate? = null, private val reader: CardReader) { + + abstract fun run(cardEnvironment: CardEnvironment, + callback: (result: TaskResult, cardEnvironment: CardEnvironment) -> Unit) + + protected fun executeCommand(command: Command, cardEnvironment: CardEnvironment, + callback: (result: TaskResult) -> Unit) { + + reader.sendApdu(command.serialize(cardEnvironment).serialize()) { + val parsedApdu = it.deserialize() + if (parsedApdu == null) callback.invoke(TaskResult.Error(CardError())) + else if (!parsedApdu.statusCompleted()) { + callback.invoke(TaskResult.Error(CardError(parsedApdu.status.code))) + } else { + val response = command.deserialize(parsedApdu) + callback.invoke(response) + } + } + } +} + + +class BasicTask( + private val command: Command, + delegate: CardManagerDelegate? = null, + reader: CardReader) : Task(delegate, reader) { + + override fun run(cardEnvironment: CardEnvironment, + callback: (result: TaskResult, cardEnvironment: CardEnvironment) -> Unit) { + executeCommand(command, cardEnvironment) { + callback.invoke(it, updateEnvironment()) + } + } + + private fun updateEnvironment() : CardEnvironment{ + //TODO: set logic of changing CardEnvironment when needed + return CardEnvironment() + } +} + + +class SignTask(private val signCommandData: SignCommandData, + delegate: CardManagerDelegate? = null, + reader: CardReader) : Task(delegate, reader) { + + private lateinit var callback: (result: TaskResult, cardEnvironment: CardEnvironment) -> Unit + + override fun run(cardEnvironment: CardEnvironment, + callback: (result: TaskResult, cardEnvironment: CardEnvironment) -> Unit) { + + this.callback = callback + + delegate?.openNfcPopup() + val signCommand = SignCommand(signCommandData) + + executeCommand(signCommand, cardEnvironment) { + delegate?.closeNfcPopup() + run { callback(it, updateEnvironment()) } + } + } + + private fun updateEnvironment() : CardEnvironment{ + //TODO: set logic of changing CardEnvironment when needed + return CardEnvironment() + } +} + + +class ScanTask(delegate: CardManagerDelegate? = null, reader: CardReader) : Task(delegate, reader) { + + private lateinit var card: Card + + override fun run(cardEnvironment: CardEnvironment, + callback: (result: TaskResult, cardEnvironment: CardEnvironment) -> Unit) { + + delegate?.openNfcPopup() + val readCommand = ReadCardCommand(cardEnvironment.pin1) + executeCommand(readCommand, cardEnvironment) { + + if (it is TaskResult.Success) { + card = it.resultData as Card + val checkWalletCommand = prepareCheckWalletCommand(cardEnvironment) + + executeCommand(checkWalletCommand, cardEnvironment) { + delegate?.closeNfcPopup() + //TODO: pass check wallet response data + run { callback(it, updateEnvironment()) } + } + } else { + //TODO: Handle error + } + } + } + + private fun updateEnvironment() : CardEnvironment{ + //TODO: set logic of changing CardEnvironment when needed + return CardEnvironment() + } + + private fun prepareCheckWalletCommand(cardEnvironment: CardEnvironment): CheckWalletCommand { + val challenge = generateChallenge() + return CheckWalletCommand( + cardEnvironment.pin1, + card.cid, + challenge, + byteArrayOf()) + } + + private fun generateChallenge(): ByteArray { + return byteArrayOf() + } +} \ No newline at end of file From 6317358ac7d4b2fab584d824fab0abf09738f261 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Oct 2019 12:37:15 +0300 Subject: [PATCH 02/54] Updated on 2026-08-14 --- .../main/java/com/tangem/data/CommandApdu.kt | 75 +++++++++++++++++ .../main/java/com/tangem/data/ResponseApdu.kt | 34 ++++++++ .../src/main/java/com/tangem/data/Tlv.kt | 31 +++++++ .../main/java/com/tangem/data/TlvParser.kt | 55 ++++++++++++ .../main/java/com/tangem/enums/Instruction.kt | 23 +++++ .../src/main/java/com/tangem/enums/Status.kt | 21 +++++ .../src/main/java/com/tangem/enums/TlvTag.kt | 84 +++++++++++++++++++ 7 files changed, 323 insertions(+) create mode 100644 tangem-card-new/src/main/java/com/tangem/data/CommandApdu.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/data/ResponseApdu.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/data/Tlv.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/data/TlvParser.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/enums/Instruction.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/enums/Status.kt create mode 100644 tangem-card-new/src/main/java/com/tangem/enums/TlvTag.kt diff --git a/tangem-card-new/src/main/java/com/tangem/data/CommandApdu.kt b/tangem-card-new/src/main/java/com/tangem/data/CommandApdu.kt new file mode 100644 index 0000000000..0ec5f29219 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/data/CommandApdu.kt @@ -0,0 +1,75 @@ +package com.tangem.data + +import com.tangem.enums.Instruction + +class CommandApdu( + val tlvList: List, + val instruction: Instruction, + val p1: Int = 0x00, + val p2: Int = 0x00, + val encryptionKey: ByteArray? = null, + val rawInstruction: ByteArray = byteArrayOf()) { + + val cla = ISO_CLA + + + fun serialize(): ByteArray { + + var length = 4 // CLA, INS, P1, P2 + + val data = if (tlvList.isNotEmpty()) { + tlvList.toBytes() + } else { + byteArrayOf() + } + + val lc = data.size + + if (data.isNotEmpty()) { + length += 1 // LC + if (lc >= 256) + length += 2 + length += data.size // DATA + } + + val apdu = ByteArray(length) + + var index = 0 + apdu[index] = cla + index++ + apdu[index] = instruction.code.toByte() + index++ + apdu[index] = p1.toByte() + index++ + apdu[index] = p2.toByte() + index++ + if (lc != 0) { + if (lc < 256) { + apdu[index] = lc.toByte() + index++ + } else { + apdu[index] = 0 + index++ + apdu[index] = (lc shr 8).toByte() + index++ + apdu[index] = (lc and 0xFF).toByte() + index++ + } + + System.arraycopy(data, 0, apdu, index, data.size) + index += data.size + } + return apdu + + + } + + + private fun encrypt() { + + } + + companion object { + const val ISO_CLA = 0x00.toByte() + } +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/data/ResponseApdu.kt b/tangem-card-new/src/main/java/com/tangem/data/ResponseApdu.kt new file mode 100644 index 0000000000..1d859869e1 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/data/ResponseApdu.kt @@ -0,0 +1,34 @@ +package com.tangem.data + +import com.tangem.enums.Status + +class ResponseApdu(val data: ByteArray) { + + private val tlvParser = TlvParser() + + fun deserialize(encryptionKey: ByteArray? = null): ResponseApduParsed? { + + if (data.size < 2) return null + + if (data.size == 2) return ResponseApduParsed(parseStatus(data[0], data[1]), emptyList()) + + val tlvList = tlvParser.fromBytes(data.copyOf(data.size - 2)) + val sw1 = data[data.size - 2] + val sw2 = data[data.size -1] + return ResponseApduParsed(parseStatus(sw1, sw2), tlvList) + } + + private fun parseStatus(sw1: Byte, sw2: Byte): Status { + val code = (0x00FF and sw1.toInt()) shl 8 or (0x00FF and sw2.toInt()) + return Status.byCode(code) + } + + private fun decrypt(encryptionKey: ByteArray) { + + } + +} + +data class ResponseApduParsed(val status: Status, val tlvList: List? = null, val parsingError: String? = null) { + fun statusCompleted(): Boolean = status == Status.ProcessCompleted +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/data/Tlv.kt b/tangem-card-new/src/main/java/com/tangem/data/Tlv.kt new file mode 100644 index 0000000000..450801ccdf --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/data/Tlv.kt @@ -0,0 +1,31 @@ +package com.tangem.data + +import com.tangem.enums.TlvTag + +class Tlv(val tag: TlvTag, val tagCode: Int, val value: ByteArray = byteArrayOf()) + +fun List.toBytes(): ByteArray = + this.map { it.toBytes() }.reduce { arr1, arr2 -> arr1 + arr2 } + +fun Tlv.toBytes(): 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) + return tag + length + value +} + +private fun getLengthInBytes(tlvLength: Int): ByteArray { + return if (tlvLength < 0) { + if (tlvLength > 0xFE) { + byteArrayOf( + 0xFF.toByte(), + (tlvLength shr 8 and 0xFF).toByte(), + (tlvLength and 0xFF).toByte() + ) + } else { + byteArrayOf((tlvLength and 0xFF).toByte()) + } + } else { + byteArrayOf() + } +} diff --git a/tangem-card-new/src/main/java/com/tangem/data/TlvParser.kt b/tangem-card-new/src/main/java/com/tangem/data/TlvParser.kt new file mode 100644 index 0000000000..06e0839e5c --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/data/TlvParser.kt @@ -0,0 +1,55 @@ +package com.tangem.data + +import com.tangem.enums.TlvTag +import java.io.ByteArrayInputStream +import java.io.IOException + +class TlvParser { + + fun readFromStream(stream: ByteArrayInputStream): Tlv? { + val code = stream.read() + if (code == -1) return null + var len = stream.read() + if (len == -1) + throw IOException("Can't read TLV") + if (len == 0xFF) { + val lenH = stream.read() + if (lenH == -1) + throw IOException("Can't read TLV") + len = stream.read() + if (len == -1) + throw IOException("Can't read TLV") + len = len or (lenH shl 8) + } + val value = ByteArray(len) + if (len > 0) { + if (len != stream.read(value)) { + throw IOException("Can't read TLV") + } + } + val tag = TlvTag.byCode(code) + return Tlv(tag, code, value) + } + + fun fromBytes(data: ByteArray): List { + val tlvList = mutableListOf() + val stream = ByteArrayInputStream(data) + var tlv: Tlv? = null + do { + try { + tlv = readFromStream(stream) + if (tlv != null) tlvList.add(tlv) + } catch (e: IOException) { + throw IOException("TLVError: " + e.message) + } + + } while (tlv != null) + return tlvList + } + + + fun parseTlv(data: ByteArray) { + + + } +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/enums/Instruction.kt b/tangem-card-new/src/main/java/com/tangem/enums/Instruction.kt new file mode 100644 index 0000000000..a7ea9c4d2f --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/enums/Instruction.kt @@ -0,0 +1,23 @@ +package com.tangem.enums + +enum class Instruction(var code: Int) { + Unknown(0x00), + Read(0xF2), + VerifyCard(0xF3), + ValidateCard(0xF4), + VerifyCode(0xF5), + WriteIssuerData(0xF6), + GetIssuerData(0xF7), + CreateWallet(0xF8), + CheckWallet(0xF9), + SwapPIN(0xFA), + Sign(0xFB), + PurgeWallet(0xFC), + Activate(0xFE), + OpenSession(0xFF); + + + companion object { + fun byCode(code: Int): Instruction = values().find { it.code == code } ?: Unknown + } +} \ No newline at end of file diff --git a/tangem-card-new/src/main/java/com/tangem/enums/Status.kt b/tangem-card-new/src/main/java/com/tangem/enums/Status.kt new file mode 100644 index 0000000000..4a6b8922f2 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/enums/Status.kt @@ -0,0 +1,21 @@ +package com.tangem.enums + +enum class Status (val code: Int, val description: String){ + + ProcessCompleted(0x9000, "SW_PROCESS_COMPLETED"), + InvalidParams(0x6A86, "SW_INVALID_PARAMS"), + ErrorProcessingCommand(0x6286, "SW_ERROR_PROCESSING_COMMAND"), + InvalidState(0x6985, "SW_INVALID_STATE"), +// PinsNotChanged(ProcessCompleted.code, ProcessCompleted.description), + Pin1Changed(ProcessCompleted.code + 0x0001, "SW_PIN1_CHANGED"), + Pin2Changed(ProcessCompleted.code + 0x0002, "SW_PIN2_CHANGED"), + PinsChanged(ProcessCompleted.code + 0x0003, "SW_PINS_CHANGED"), + InsNotSupported(0x6D00, "SW_INS_NOT_SUPPORTED"), + NeedEnctryption(0x6982, "SW_NEED_ENCRYPTION"), + NeedPause(0x9789, "SW_NEED_PAUSE"); + + companion object { + fun byCode(code: Int): Status = values().find { it.code == code } ?: InvalidParams + } + +} diff --git a/tangem-card-new/src/main/java/com/tangem/enums/TlvTag.kt b/tangem-card-new/src/main/java/com/tangem/enums/TlvTag.kt new file mode 100644 index 0000000000..62625b6fd0 --- /dev/null +++ b/tangem-card-new/src/main/java/com/tangem/enums/TlvTag.kt @@ -0,0 +1,84 @@ +package com.tangem.enums + +enum class TlvTag(val code: Int) { + Unknown(0x00), + CardID(0x01), + Status(0x02), + CardPublicKey(0x03), + CardSignature(0x04), + CurveID(0x05), + HashAlgID(0x06), + SigningMethod(0x07), + MaxSignatures(0x08), + PauseBeforePin2(0x09), + SettingsMask(0x0A), + CardData(0x0C), + NdefData(0x0D), + Health(0x0F), + + Pin(0x10), + Pin2(0x11), + NewPin(0x12), + NewPin2(0x13), + NewPinHash(0x14), + NewPin2Hash(0x15), + Challenge(0x16), + Salt(0x17), + ValidationCounter(0x18), + Cvc(0x19), + + SessionKeyA(0x1A), + SessionKeyB(0x1B), + Pause(0x1C), + + ManufactureId(0x20), + ManufacturerSignature(0x21), + + IssuerDataPublicKey(0x30), + IssuerTransactionPublicKey(0x31), + IssuerData(0x32), + IssuerDataSignature(0x33), + IssuerTransactionSignature(0x34), + IssuerDataCounter(0x35), + + IsActivated(0x3A), + ActivationSeed(0x3B), + ResetPin(0x36), + + CodePageAddress(0x40), + CodePageCount(0x41), + CodeHash(0x42), + + TrOutHash(0x50), + TrOutHashSize(0x51), + TrOutRaw(0x52), + + WalletPublicKey(0x60), + Signature(0x61), + RemainingSignatures(0x62), + SignedHashes(0x63), + + Firmware(0x80), + Batch(0x81), + ManufactureDateTime(0x82), + IssuerId(0x83), + BlockchainId(0x84), + ManufacturerPublicKey(0x85), + CardIdManufacturerSignature(0x86), + + TokenSymbol(0xA0), + TokenContractAddress(0xA1), + TokenDecimal(0xA2), + Denomination(0xC0), + ValidatedBalance(0xC1), + LastSignDate(0xC2), + DenominationText(0xC3), + + TerminalIsLinked(0x58), + TerminalPublicKey(0x5C), + TerminalTransactionSignature(0x57); + + companion object { + fun byCode(code: Int): TlvTag = values().find { it.code == code } ?: Unknown + } +} \ No newline at end of file From 0645cffc2552db6205a33ea0e64196a79381014f Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Oct 2019 17:00:09 +0300 Subject: [PATCH 03/54] Updated on 2026-08-14 --- .idea/gradle.xml | 1 + settings.gradle | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.idea/gradle.xml b/.idea/gradle.xml index b832f99832..cc3c87b7d6 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -11,6 +11,7 @@ diff --git a/settings.gradle b/settings.gradle index 9fc098f7fa..fa49a0b1c1 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':tangem-sdk', ':server-android', ':tangem-card' +include ':app', ':tangem-sdk', ':server-android', ':tangem-card', ':tangem-card-new' From 72a2623faaa289ef496e4bfa86a8eba85a68c0f7 Mon Sep 17 00:00:00 2001 From: Tangem Date: Tue, 1 Oct 2019 17:09:37 +0300 Subject: [PATCH 04/54] Updated on 2026-08-14 --- .idea/gradle.xml | 2 + build.gradle | 2 +- settings.gradle | 2 +- tangem-sdk-new/.gitignore | 1 + tangem-sdk-new/build.gradle | 47 +++++++++ tangem-sdk-new/consumer-rules.pro | 0 tangem-sdk-new/proguard-rules.pro | 21 ++++ tangem-sdk-new/src/main/AndroidManifest.xml | 5 + .../BasicCardManagerDelegate.kt | 36 +++++++ .../tangem_sdk_new/NfcLifecycleObserver.kt | 28 ++++++ .../com/tangem/tangem_sdk_new/NfcManager.kt | 99 +++++++++++++++++++ .../com/tangem/tangem_sdk_new/NfcReader.kt | 43 ++++++++ .../src/main/res/values/strings.xml | 3 + 13 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 tangem-sdk-new/.gitignore create mode 100644 tangem-sdk-new/build.gradle create mode 100644 tangem-sdk-new/consumer-rules.pro create mode 100644 tangem-sdk-new/proguard-rules.pro create mode 100644 tangem-sdk-new/src/main/AndroidManifest.xml create mode 100644 tangem-sdk-new/src/main/java/com/tangem/tangem_sdk_new/BasicCardManagerDelegate.kt create mode 100644 tangem-sdk-new/src/main/java/com/tangem/tangem_sdk_new/NfcLifecycleObserver.kt create mode 100644 tangem-sdk-new/src/main/java/com/tangem/tangem_sdk_new/NfcManager.kt create mode 100644 tangem-sdk-new/src/main/java/com/tangem/tangem_sdk_new/NfcReader.kt create mode 100644 tangem-sdk-new/src/main/res/values/strings.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml index cc3c87b7d6..54d04b46b3 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -13,6 +13,8 @@