Updated on 2026-08-14
This commit is contained in:
parent
78ac3832a8
commit
5de9753f52
5 changed files with 189 additions and 7 deletions
|
|
@ -177,6 +177,46 @@ class CardManager(
|
|||
runTask(task, cardId, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* This command write some of User_Data, User_ProtectedData, User_Counter and User_ProtectedCounter fields.
|
||||
* User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
|
||||
* The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
|
||||
* from blockchain to accelerate preparing new transaction.
|
||||
* User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
|
||||
* of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
|
||||
* For example, this fields may contain blockchain nonce value.
|
||||
*
|
||||
* Writing of User_Counter and User_Data protected only by PIN1.
|
||||
* User_ProtectedCounter and User_ProtectedData additionaly need PIN2 to confirmation.
|
||||
*/
|
||||
fun writeUserData(
|
||||
cardId: String,
|
||||
userData: ByteArray,
|
||||
userProtectedData: ByteArray? = null,
|
||||
userCounter: Int? = null,
|
||||
userProtectedCounter: Int? = null,
|
||||
callback: (result: TaskEvent<WriteUserDataResponse>) -> Unit
|
||||
) {
|
||||
val writeIssuerDataCommand = WriteUserDataCommand(userData, userProtectedData, userCounter, userProtectedCounter)
|
||||
val task = SingleCommandTask(writeIssuerDataCommand)
|
||||
runTask(task, cardId, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* This command returns two up to 512-byte User_Data, User_Protected_Data and two counters User_Counter and
|
||||
* User_Protected_Counter fields.
|
||||
* User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
|
||||
* The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
|
||||
* from blockchain to accelerate preparing new transaction.
|
||||
* User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
|
||||
* of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
|
||||
* For example, this fields may contain blockchain nonce value.
|
||||
*/
|
||||
fun readUserData(cardId: String, callback: (result: TaskEvent<ReadUserDataResponse>) -> Unit) {
|
||||
val task = SingleCommandTask(ReadUserDataCommand())
|
||||
runTask(task, cardId, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* This command will create a new wallet on the card having ‘Empty’ state.
|
||||
* A key pair WalletPublicKey / WalletPrivateKey is generated and securely stored in the card.
|
||||
|
|
@ -211,8 +251,7 @@ class CardManager(
|
|||
/**
|
||||
|
||||
*/
|
||||
fun <T> runTask(task: Task<T>, cardId: String? = null,
|
||||
callback: (result: TaskEvent<T>) -> Unit) {
|
||||
fun <T> runTask(task: Task<T>, cardId: String? = null, callback: (result: TaskEvent<T>) -> Unit) {
|
||||
if (isBusy) {
|
||||
callback(TaskEvent.Completion(TaskError.Busy()))
|
||||
return
|
||||
|
|
|
|||
|
|
@ -1,5 +1,83 @@
|
|||
package com.tangem.commands
|
||||
|
||||
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.tlv.TlvBuilder
|
||||
import com.tangem.common.tlv.TlvMapper
|
||||
import com.tangem.common.tlv.TlvTag
|
||||
import com.tangem.tasks.TaskError
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
*/
|
||||
class ReadUserDataResponse(
|
||||
/**
|
||||
* CID, Unique Tangem card ID number.
|
||||
*/
|
||||
val cardId: String,
|
||||
|
||||
/**
|
||||
* Data defined by user's App.
|
||||
*/
|
||||
val userData: ByteArray,
|
||||
|
||||
/**
|
||||
* Data defined by user's App (confirmed by PIN2).
|
||||
*/
|
||||
val userProtectedData: ByteArray,
|
||||
|
||||
/**
|
||||
* Counter initialized by user's App and increased on every signing of new transaction
|
||||
*/
|
||||
val userCounter: Int,
|
||||
|
||||
/**
|
||||
* Counter initialized by user's App (confirmed by PIN2) and increased on every signing of new transaction
|
||||
*/
|
||||
val userProtectedCounter: Int
|
||||
|
||||
): CommandResponse {
|
||||
companion object {
|
||||
internal fun fromMapper(mapper: TlvMapper): ReadUserDataResponse = ReadUserDataResponse(
|
||||
cardId = mapper.map(TlvTag.CardId),
|
||||
userData = mapper.map(TlvTag.IssuerData),
|
||||
userProtectedData = mapper.map(TlvTag.IssuerDataSignature),
|
||||
userCounter = mapper.map(TlvTag.IssuerDataCounter),
|
||||
userProtectedCounter = mapper.map(TlvTag.IssuerDataCounter)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This command returns two up to 512-byte User_Data, User_Protected_Data and two counters User_Counter and
|
||||
* User_Protected_Counter fields.
|
||||
* User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
|
||||
* The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
|
||||
* from blockchain to accelerate preparing new transaction.
|
||||
* User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
|
||||
* of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
|
||||
* For example, this fields may contain blockchain nonce value.
|
||||
*/
|
||||
class ReadUserDataCommand: CommandSerializer<ReadUserDataResponse>() {
|
||||
|
||||
override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
|
||||
val serializedTlv = TlvBuilder().apply {
|
||||
append(TlvTag.CardId, cardEnvironment.cardId)
|
||||
append(TlvTag.Pin, cardEnvironment.pin1)
|
||||
}.serialize()
|
||||
|
||||
return CommandApdu(Instruction.ReadIssuerData, serializedTlv)
|
||||
}
|
||||
|
||||
override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): ReadUserDataResponse? {
|
||||
val tlvData = responseApdu.getTlvData() ?: return null
|
||||
|
||||
return try {
|
||||
ReadUserDataResponse.fromMapper(TlvMapper(tlvData))
|
||||
} catch (exception: Exception) {
|
||||
throw TaskError.SerializeCommandError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,64 @@
|
|||
package com.tangem.commands
|
||||
|
||||
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.tlv.TlvBuilder
|
||||
import com.tangem.common.tlv.TlvMapper
|
||||
import com.tangem.common.tlv.TlvTag
|
||||
import com.tangem.tasks.TaskError
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
*/
|
||||
|
||||
class WriteUserDataResponse(
|
||||
/**
|
||||
* CID, Unique Tangem card ID number.
|
||||
*/
|
||||
val cardId: String
|
||||
): CommandResponse
|
||||
|
||||
/**
|
||||
* This command write some of User_Data, User_ProtectedData, User_Counter and User_ProtectedCounter fields.
|
||||
* User_Data and User_ProtectedData are never changed or parsed by the executable code the Tangem COS.
|
||||
* The App defines purpose of use, format and it's payload. For example, this field may contain cashed information
|
||||
* from blockchain to accelerate preparing new transaction.
|
||||
* User_Counter and User_ProtectedCounter are counters, that initial values can be set by App and increased on every signing
|
||||
* of new transaction (on SIGN command that calculate new signatures). The App defines purpose of use.
|
||||
* For example, this fields may contain blockchain nonce value.
|
||||
*
|
||||
* Writing of User_Counter and User_Data protected only by PIN1.
|
||||
* User_ProtectedCounter and User_ProtectedData additionaly need PIN2 to confirmation.
|
||||
*/
|
||||
class WriteUserDataCommand(
|
||||
private val userData: ByteArray? = null,
|
||||
private val userProtectedData: ByteArray? = null,
|
||||
private val userCounter: Int? = null,
|
||||
private val userProtectedCounter: Int? = null
|
||||
): CommandSerializer<WriteUserDataResponse>() {
|
||||
override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
|
||||
val serializedTlv = TlvBuilder().apply {
|
||||
append(TlvTag.CardId, cardEnvironment.cardId)
|
||||
append(TlvTag.Pin, cardEnvironment.pin1)
|
||||
append(TlvTag.UserData, userData)
|
||||
append(TlvTag.UserCounter, userCounter)
|
||||
append(TlvTag.UserProtectedData, userProtectedData)
|
||||
append(TlvTag.UserProtectedCounter, userProtectedCounter)
|
||||
if (userProtectedCounter != null || userProtectedData != null)
|
||||
append(TlvTag.Pin2, cardEnvironment.pin2)
|
||||
}.serialize()
|
||||
return CommandApdu(Instruction.ReadIssuerData, serializedTlv)
|
||||
}
|
||||
|
||||
override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): WriteUserDataResponse? {
|
||||
val tlvData = responseApdu.getTlvData() ?: return null
|
||||
|
||||
return try {
|
||||
WriteUserDataResponse(TlvMapper(tlvData).map(TlvTag.CardId))
|
||||
} catch (exception: Exception) {
|
||||
throw TaskError.SerializeCommandError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,9 @@ enum class Instruction(var code: Int) {
|
|||
Sign(0xFB),
|
||||
PurgeWallet(0xFC),
|
||||
Activate(0xFE),
|
||||
OpenSession(0xFF);
|
||||
OpenSession(0xFF),
|
||||
WriteUserData(0xE0),
|
||||
ReadUserData(0xE1);
|
||||
|
||||
|
||||
companion object {
|
||||
|
|
|
|||
|
|
@ -94,7 +94,6 @@ enum class TlvTag(val code: Int) {
|
|||
|
||||
ProductMask(0x8A),
|
||||
PaymentFlowVersion(0x54),
|
||||
UserCounter(0x2C),
|
||||
|
||||
|
||||
TokenSymbol(0xA0),
|
||||
|
|
@ -107,7 +106,12 @@ enum class TlvTag(val code: Int) {
|
|||
|
||||
TerminalIsLinked(0x58),
|
||||
TerminalPublicKey(0x5C),
|
||||
TerminalTransactionSignature(0x57);
|
||||
TerminalTransactionSignature(0x57),
|
||||
|
||||
UserData(0x2A),
|
||||
UserProtectedData(0x2B),
|
||||
UserCounter(0x2C),
|
||||
UserProtectedCounter(0x2D);
|
||||
|
||||
/**
|
||||
* @return [TlvValueType] associated with a [TlvTag]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue