Updated on 2026-08-14
This commit is contained in:
parent
6ed8c7d0fb
commit
7e3841c4ef
7 changed files with 40 additions and 16 deletions
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue