Updated on 2026-08-14

This commit is contained in:
Tangem 2019-10-22 10:57:52 +03:00
parent 6ed8c7d0fb
commit 7e3841c4ef
7 changed files with 40 additions and 16 deletions

View file

@ -9,6 +9,7 @@ import com.tangem.common.tlv.Tlv
import com.tangem.common.tlv.TlvMapper
import com.tangem.common.tlv.TlvTag
import com.tangem.enums.Instruction
import com.tangem.tasks.TaskError
class CheckWalletResponse(
val cardId: String,
@ -45,7 +46,7 @@ class CheckWalletCommand(
mapper.map(TlvTag.Signature)
)
} catch (exception: Exception) {
null
throw TaskError.SerializeCommandError()
}
}

View file

@ -4,6 +4,7 @@ import com.tangem.CardEnvironment
import com.tangem.common.apdu.CommandApdu
import com.tangem.common.apdu.ResponseApdu
import com.tangem.enums.Instruction
import com.tangem.tasks.TaskError
//interface TlvMappable {
// fun responseFromTlv(tlvList: List<Tlv>): CommandResponse?
@ -26,7 +27,7 @@ abstract class CommandSerializer<T : CommandResponse>() {
sealed class CommandEvent {
class Success(val response: Any) : CommandEvent()
class Failure() : CommandEvent()
class Failure(val taskError: TaskError) : CommandEvent()
class UserCancellation : CommandEvent()
}

View file

@ -9,6 +9,8 @@ import com.tangem.common.tlv.TlvMapper
import com.tangem.common.tlv.TlvTag
import com.tangem.data.SettingsMask
import com.tangem.enums.Instruction
import com.tangem.tasks.TaskError
import java.util.*
enum class SigningMethod(val code: Int) {
SignHash(0),
@ -60,9 +62,9 @@ class ReadCardResponse(
val status: CardStatus,
val firmwareVersion: String?,
val cardPublicKey: String?,
val cardPublicKey: ByteArray?,
val settingsMask: SettingsMask?,
val issuerPublicKey: String?,
val issuerPublicKey: ByteArray?,
val curve: EllipticCurve?,
val maxSignatures: Int?,
val signingMethpod: SigningMethod?,
@ -71,14 +73,15 @@ class ReadCardResponse(
val walletRemainingSignatures: Int?,
val walletSignedHashes: Int?,
val health: Int?,
val isActivated: Boolean?,
val isActivated: Boolean,
val activationSeed: ByteArray?,
val paymentFlowVersion: ByteArray?,
val userCounter: Int?,
val terminalIsLinked: Boolean,
//Card Data
val batchId: Int?,
val manufactureDateTime: String?,
val batchId: String?,
val manufactureDateTime: Date?,
val issuerName: String?,
val blockchainName: String?,
val manufacturerSignature: ByteArray?,
@ -127,10 +130,11 @@ class ReadCardCommand(private val pin1: String) : CommandSerializer<ReadCardResp
tlvMapper.mapOptional(TlvTag.RemainingSignatures),
tlvMapper.mapOptional(TlvTag.SignedHashes),
tlvMapper.mapOptional(TlvTag.Health),
tlvMapper.mapOptional(TlvTag.IsActivated),
tlvMapper.map(TlvTag.IsActivated),
tlvMapper.mapOptional(TlvTag.ActivationSeed),
tlvMapper.mapOptional(TlvTag.PaymentFlowVersion),
tlvMapper.mapOptional(TlvTag.UserCounter),
tlvMapper.map(TlvTag.TerminalIsLinked),
tlvMapper.mapOptional(TlvTag.Batch),
tlvMapper.mapOptional(TlvTag.ManufactureDateTime),
@ -144,7 +148,7 @@ class ReadCardCommand(private val pin1: String) : CommandSerializer<ReadCardResp
tlvMapper.mapOptional(TlvTag.TokenDecimal)
)
} catch (exception: Exception) {
null
throw TaskError.SerializeCommandError()
}
}

View file

@ -8,6 +8,12 @@ import kotlin.experimental.and
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
fun ByteArray.toUtf8(): String {
val string = String(this)
if (this.isNotEmpty() && this.last() == 0.toByte()) return string.dropLast(1)
return string
}
fun ByteArray.toInt(): Int {
return when (this.size) {

View file

@ -7,6 +7,7 @@ import com.tangem.commands.SigningMethod
import com.tangem.common.extentions.toDate
import com.tangem.common.extentions.toHexString
import com.tangem.common.extentions.toInt
import com.tangem.common.extentions.toUtf8
import com.tangem.data.SettingsMask
import java.util.*
@ -28,18 +29,22 @@ class TlvMapper(val tlvList: List<Tlv>) {
inline fun <reified T> map(tag: TlvTag): T {
val tlvValue: ByteArray = tlvList.find { it.tag == tag }?.value
?: throw MissingTagException()
?: if (tag.valueType() == TlvValueType.BoolValue && T::class == Boolean::class) {
return false as T
} else {
throw MissingTagException("Tag $tag not found")
}
return when (tag.valueType()) {
TlvValueType.HexString -> {
if (T::class != String::class)
throw WrongTypeException("Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}")
tlvValue.toHexString() as T
tlvValue.toHexString() as T
}
TlvValueType.Utf8String -> {
if (T::class != String::class)
throw WrongTypeException("Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}")
String(tlvValue) as T
tlvValue.toUtf8() as T
}
TlvValueType.IntValue -> {
if (T::class != Integer::class)
@ -59,7 +64,7 @@ class TlvMapper(val tlvList: List<Tlv>) {
TlvValueType.EllipticCurve -> {
if (T::class != EllipticCurve::class)
throw WrongTypeException("Mapping error. Type for tag: $tag must be ${tag.valueType()}. It is ${T::class}")
EllipticCurve.byName(String(tlvValue)) as T
EllipticCurve.byName(tlvValue.toUtf8()) as T
}
TlvValueType.DateTime -> {
if (T::class != Date::class)
@ -89,8 +94,6 @@ class TlvMapper(val tlvList: List<Tlv>) {
SigningMethod.byCode(tlvValue.toInt()) as T
}
}
}
}

View file

@ -1,7 +1,9 @@
package com.tangem.crypto
import com.tangem.commands.EllipticCurve
import net.i2p.crypto.eddsa.EdDSASecurityProvider
import java.security.SecureRandom
import java.security.Security
fun generateRandomBytes(length: Int): ByteArray {
val bytes = ByteArray(length)
@ -18,3 +20,10 @@ fun verify(publicKey: ByteArray, message: ByteArray, signature: ByteArray,
}
fun initCrypto() {
Security.insertProviderAt(org.spongycastle.jce.provider.BouncyCastleProvider(), 1)
Security.addProvider(EdDSASecurityProvider())
}

View file

@ -11,7 +11,7 @@ enum class Status (val code: Int, val description: String){
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"),
NeedEncryption(0x6982, "SW_NEED_ENCRYPTION"),
NeedPause(0x9789, "SW_NEED_PAUSE");
companion object {