Updated on 2026-08-14
This commit is contained in:
parent
8f04c58c69
commit
1fa4b60614
4 changed files with 116 additions and 115 deletions
|
|
@ -177,45 +177,45 @@ 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 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 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.
|
||||
|
|
|
|||
|
|
@ -13,41 +13,41 @@ import com.tangem.tasks.TaskError
|
|||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class ReadUserDataResponse(
|
||||
/**
|
||||
* CID, Unique Tangem card ID number.
|
||||
*/
|
||||
val cardId: String,
|
||||
/**
|
||||
* CID, Unique Tangem card ID number.
|
||||
*/
|
||||
val cardId: String,
|
||||
|
||||
/**
|
||||
* Data defined by user's App.
|
||||
*/
|
||||
val userData: ByteArray,
|
||||
/**
|
||||
* Data defined by user's App.
|
||||
*/
|
||||
val userData: ByteArray,
|
||||
|
||||
/**
|
||||
* Data defined by user's App (confirmed by PIN2).
|
||||
*/
|
||||
val userProtectedData: 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 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
|
||||
/**
|
||||
* 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)
|
||||
)
|
||||
}
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -62,22 +62,22 @@ class ReadUserDataResponse(
|
|||
*/
|
||||
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()
|
||||
override fun serialize(cardEnvironment: CardEnvironment): CommandApdu {
|
||||
val serializedTlv = TlvBuilder().apply {
|
||||
append(TlvTag.CardId, cardEnvironment.cardId)
|
||||
append(TlvTag.Pin, cardEnvironment.pin1)
|
||||
}.serialize()
|
||||
|
||||
return CommandApdu(Instruction.ReadUserData, serializedTlv)
|
||||
}
|
||||
return CommandApdu(Instruction.ReadUserData, serializedTlv)
|
||||
}
|
||||
|
||||
override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): ReadUserDataResponse? {
|
||||
val tlvData = responseApdu.getTlvData() ?: return null
|
||||
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()
|
||||
}
|
||||
}
|
||||
return try {
|
||||
ReadUserDataResponse.fromMapper(TlvMapper(tlvData))
|
||||
} catch (exception: Exception) {
|
||||
throw TaskError.SerializeCommandError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,10 +14,10 @@ import com.tangem.tasks.TaskError
|
|||
*/
|
||||
|
||||
class WriteUserDataResponse(
|
||||
/**
|
||||
* CID, Unique Tangem card ID number.
|
||||
*/
|
||||
val cardId: String
|
||||
/**
|
||||
* CID, Unique Tangem card ID number.
|
||||
*/
|
||||
val cardId: String
|
||||
): CommandResponse
|
||||
|
||||
/**
|
||||
|
|
@ -33,32 +33,33 @@ class WriteUserDataResponse(
|
|||
* 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
|
||||
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.WriteUserData, serializedTlv)
|
||||
}
|
||||
|
||||
override fun deserialize(cardEnvironment: CardEnvironment, responseApdu: ResponseApdu): WriteUserDataResponse? {
|
||||
val tlvData = responseApdu.getTlvData() ?: return null
|
||||
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.WriteUserData, serializedTlv)
|
||||
}
|
||||
|
||||
return try {
|
||||
WriteUserDataResponse(TlvMapper(tlvData).map(TlvTag.CardId))
|
||||
} catch (exception: Exception) {
|
||||
throw TaskError.SerializeCommandError()
|
||||
}
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,10 +108,10 @@ enum class TlvTag(val code: Int) {
|
|||
TerminalPublicKey(0x5C),
|
||||
TerminalTransactionSignature(0x57),
|
||||
|
||||
UserData(0x2A),
|
||||
UserProtectedData(0x2B),
|
||||
UserCounter(0x2C),
|
||||
UserProtectedCounter(0x2D);
|
||||
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