Updated on 2026-08-14

This commit is contained in:
Tangem 2020-02-23 08:57:45 +03:00
parent 8f04c58c69
commit 1fa4b60614
4 changed files with 116 additions and 115 deletions

View file

@ -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.

View file

@ -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()
}
}
}

View file

@ -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()
}
}
}

View file

@ -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]