diff --git a/tangem-core/src/main/java/com/tangem/CardManager.kt b/tangem-core/src/main/java/com/tangem/CardManager.kt index 7a453944fb..f5d064d4e9 100644 --- a/tangem-core/src/main/java/com/tangem/CardManager.kt +++ b/tangem-core/src/main/java/com/tangem/CardManager.kt @@ -265,6 +265,10 @@ class CardManager( fun personalize(config: CardConfig, cardId: String, callback: (result: TaskEvent) -> Unit) { + if (this.config.issuer == null) { + callback(TaskEvent.Completion(TaskError.IssuerIsRequired())) + return + } val personalizationCommand = PersonalizeCommand(config, cardId) val task = SingleCommandTask(personalizationCommand) task.performPreflightRead = false @@ -316,7 +320,10 @@ class CardManager( val terminalKeys = if (config.linkedTerminal) terminalKeysService?.getKeys() else null return CardEnvironment( cardId = cardId, - terminalKeys = terminalKeys + terminalKeys = terminalKeys, + manufacturerKeyPair = config.manufacturerKeyPair, + acquirerKeyPair = config.acquirerKeyPair, + issuer = config.issuer ) } diff --git a/tangem-core/src/main/java/com/tangem/Config.kt b/tangem-core/src/main/java/com/tangem/Config.kt index 2d1193e176..2067f61920 100644 --- a/tangem-core/src/main/java/com/tangem/Config.kt +++ b/tangem-core/src/main/java/com/tangem/Config.kt @@ -1,6 +1,12 @@ package com.tangem +import com.tangem.commands.personalization.entities.Issuer +import com.tangem.common.KeyPair + class Config( val linkedTerminal: Boolean = true, - val issuerPublicKey: ByteArray? = null + val issuerPublicKey: ByteArray? = null, + val manufacturerKeyPair: KeyPair? = null, + val acquirerKeyPair: KeyPair? = null, + val issuer: Issuer? = null ) \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt index 25bd22b4ba..6bcdd815a5 100644 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/personalization/PersonalizeCommand.kt @@ -3,9 +3,7 @@ package com.tangem.commands.personalization import com.tangem.commands.Card import com.tangem.commands.CardData import com.tangem.commands.CommandSerializer -import com.tangem.commands.personalization.entities.Acquirer import com.tangem.commands.personalization.entities.Issuer -import com.tangem.commands.personalization.entities.Manufacturer import com.tangem.common.CardEnvironment import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction @@ -32,9 +30,15 @@ import com.tangem.tasks.TaskError class PersonalizeCommand(private val config: CardConfig, private val cardId: String) : CommandSerializer() { override fun serialize(cardEnvironment: CardEnvironment): CommandApdu { + if (cardEnvironment.issuer == null || cardEnvironment.manufacturerKeyPair == null) { + throw TaskError.SerializeCommandError() + } return CommandApdu( Instruction.Personalize, - serializePersonalizationData(cardId, config), + serializePersonalizationData( + cardId, config, + cardEnvironment.issuer, cardEnvironment.manufacturerKeyPair.privateKey, + cardEnvironment.acquirerKeyPair?.publicKey), encryptionKey = devPersonalizationKey ) } @@ -95,7 +99,10 @@ class PersonalizeCommand(private val config: CardConfig, private val cardId: Str ) } - private fun serializePersonalizationData(cardId: String, config: CardConfig): ByteArray { + private fun serializePersonalizationData(cardId: String, config: CardConfig, + issuer: Issuer, manufacturerPrivateKey: ByteArray, + acquirePublicKey: ByteArray? + ): ByteArray { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.CardId, cardId) @@ -113,24 +120,27 @@ class PersonalizeCommand(private val config: CardConfig, private val cardId: Str tlvBuilder.append(TlvTag.NewPin2, config.pin2) tlvBuilder.append(TlvTag.NewPin3, config.pin3) tlvBuilder.append(TlvTag.CrExKey, config.hexCrExKey) - tlvBuilder.append(TlvTag.IssuerDataPublicKey, Issuer.dataPublicKey) - tlvBuilder.append(TlvTag.IssuerTransactionPublicKey, Issuer.transactionPublicKey) + tlvBuilder.append(TlvTag.IssuerDataPublicKey, issuer.dataKeyPair.publicKey) + tlvBuilder.append(TlvTag.IssuerTransactionPublicKey, issuer.transactionKeyPair.publicKey) - tlvBuilder.append(TlvTag.AcquirerPublicKey, Acquirer.publicKey) - - tlvBuilder.append(TlvTag.CardData, serializeCardData(cardId, config.cardData)) + tlvBuilder.append(TlvTag.AcquirerPublicKey, acquirePublicKey) + tlvBuilder.append( + TlvTag.CardData, serializeCardData(cardId, config.cardData, issuer, manufacturerPrivateKey) + ) return tlvBuilder.serialize() } - private fun serializeCardData(cardId: String, cardData: CardData): ByteArray { + private fun serializeCardData( + cardId: String, cardData: CardData, + issuer: Issuer, manufacturerPrivateKey: ByteArray): ByteArray { val tlvBuilder = TlvBuilder() tlvBuilder.append(TlvTag.Batch, cardData.batchId) tlvBuilder.append(TlvTag.ProductMask, cardData.productMask) tlvBuilder.append(TlvTag.ManufactureDateTime, cardData.manufactureDateTime) - tlvBuilder.append(TlvTag.IssuerId, Issuer.id) + tlvBuilder.append(TlvTag.IssuerId, issuer.id) tlvBuilder.append(TlvTag.BlockchainId, cardData.blockchainName) @@ -139,9 +149,9 @@ class PersonalizeCommand(private val config: CardConfig, private val cardId: Str tlvBuilder.append(TlvTag.TokenContractAddress, cardData.tokenContractAddress) tlvBuilder.append(TlvTag.TokenDecimal, cardData.tokenDecimal) } - - tlvBuilder.append(TlvTag.CardIdManufacturerSignature, cardId.hexToBytes().sign(Manufacturer.devPrivateKey)) - + tlvBuilder.append( + TlvTag.CardIdManufacturerSignature, cardId.hexToBytes().sign(manufacturerPrivateKey) + ) return tlvBuilder.serialize() } diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt deleted file mode 100644 index 60bf33e774..0000000000 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Acquirer.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.tangem.commands.personalization.entities - -import com.tangem.common.extensions.hexToBytes -import com.tangem.crypto.CryptoUtils - -object Acquirer { - val privateKey = "21222324252627284771ED81F2BACF57479E4735EB1405083927372D40DA9E92".hexToBytes() - val publicKey: ByteArray by lazy { CryptoUtils.generatePublicKey(privateKey) } -} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt index 50ada2281c..f82889be6a 100644 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt +++ b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Issuer.kt @@ -1,18 +1,10 @@ package com.tangem.commands.personalization.entities -import com.tangem.common.extensions.hexToBytes -import com.tangem.crypto.CryptoUtils +import com.tangem.common.KeyPair -object Issuer { - - val name = "TANGEM SDK" - val id = name + "\u0000" - val dataPrivateKey = "11121314151617184771ED81F2BACF57479E4735EB1405083927372D40DA9E92".hexToBytes() - - val dataPublicKey: ByteArray by lazy { CryptoUtils.generatePublicKey(dataPrivateKey) } - - val transactionPrivateKey = - "11121314151617184771ED81F2BACF57479E4735EB1405081918171615141312".hexToBytes() - - val transactionPublicKey: ByteArray by lazy { CryptoUtils.generatePublicKey(transactionPrivateKey) } -} \ No newline at end of file +data class Issuer( + val name: String, + val id: String, + val dataKeyPair: KeyPair, + val transactionKeyPair: KeyPair +) \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt b/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt deleted file mode 100644 index cbe77110ab..0000000000 --- a/tangem-core/src/main/java/com/tangem/commands/personalization/entities/Manufacturer.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.tangem.commands.personalization.entities - -object Manufacturer { - val devPrivateKey = byteArrayOf( - 0x1B.toByte(), 0x48.toByte(), 0xCF.toByte(), 0xD2.toByte(), 0x4B.toByte(), 0xBB.toByte(), 0x5B.toByte(), 0x39.toByte(), - 0x47.toByte(), 0x71.toByte(), 0xED.toByte(), 0x81.toByte(), 0xF2.toByte(), 0xBA.toByte(), 0xCF.toByte(), 0x57.toByte(), - 0x47.toByte(), 0x9E.toByte(), 0x47.toByte(), 0x35.toByte(), 0xEB.toByte(), 0x14.toByte(), 0x05.toByte(), 0x08.toByte(), - 0x39.toByte(), 0x27.toByte(), 0x37.toByte(), 0x2D.toByte(), 0x40.toByte(), 0xDA.toByte(), 0x9E.toByte(), 0x92.toByte() - ) - - val devPublicKey = byteArrayOf(0x04, - 0xBA.toByte(), 0xB8.toByte(), 0x6D.toByte(), 0x56.toByte(), 0x29.toByte(), 0x8C.toByte(), 0x99.toByte(), 0x6F.toByte(), - 0x56.toByte(), 0x4A.toByte(), 0x84.toByte(), 0xFC.toByte(), 0x88.toByte(), 0xE2.toByte(), 0x8A.toByte(), 0xED.toByte(), - 0x38.toByte(), 0x18.toByte(), 0x4B.toByte(), 0x12.toByte(), 0xF0.toByte(), 0x7E.toByte(), 0x51.toByte(), 0x91.toByte(), - 0x13.toByte(), 0xBE.toByte(), 0xF4.toByte(), 0x8C.toByte(), 0x76.toByte(), 0xF3.toByte(), 0xDF.toByte(), 0x3A.toByte(), - 0xDC.toByte(), 0x30.toByte(), 0x35.toByte(), 0x99.toByte(), 0xB0.toByte(), 0x8A.toByte(), 0xC0.toByte(), 0x5B.toByte(), - 0x55.toByte(), 0xEC.toByte(), 0x3D.toByte(), 0xF9.toByte(), 0x8D.toByte(), 0x93.toByte(), 0x38.toByte(), 0x57.toByte(), - 0x3A.toByte(), 0x62.toByte(), 0x42.toByte(), 0xF7.toByte(), 0x6F.toByte(), 0x5D.toByte(), 0x28.toByte(), 0xF4.toByte(), - 0xF0.toByte(), 0xF3.toByte(), 0x64.toByte(), 0xE8.toByte(), 0x7E.toByte(), 0x8F.toByte(), 0xCA.toByte(), 0x2F.toByte() - ) -} \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/common/CardEnvironment.kt b/tangem-core/src/main/java/com/tangem/common/CardEnvironment.kt index c556f427b3..bc507bf9a2 100644 --- a/tangem-core/src/main/java/com/tangem/common/CardEnvironment.kt +++ b/tangem-core/src/main/java/com/tangem/common/CardEnvironment.kt @@ -1,5 +1,7 @@ package com.tangem.common +import com.tangem.commands.personalization.entities.Issuer + /** * Contains data relating to a Tangem card. It is used in constructing all the commands, @@ -12,7 +14,10 @@ data class CardEnvironment( val terminalKeys: KeyPair? = null, var encryptionMode: EncryptionMode = EncryptionMode.NONE, var encryptionKey: ByteArray? = null, - val cvc: ByteArray? = null + val cvc: ByteArray? = null, + val manufacturerKeyPair: KeyPair? = null, + val acquirerKeyPair: KeyPair? = null, + val issuer: Issuer? = null ) { companion object { diff --git a/tangem-core/src/main/java/com/tangem/tasks/Task.kt b/tangem-core/src/main/java/com/tangem/tasks/Task.kt index 1f901a543e..b585cd3023 100644 --- a/tangem-core/src/main/java/com/tangem/tasks/Task.kt +++ b/tangem-core/src/main/java/com/tangem/tasks/Task.kt @@ -135,12 +135,18 @@ sealed class TaskError(val code: Int) : Exception() { class UnknownError : TaskError(6000) - //Issuer Data Errors + //Specific Command Errors /** * This error is returned when [ReadIssuerDataTask] or [ReadIssuerExtraDataTask] expects a counter * (when the card's requires it), but the counter is missing. */ class MissingCounter : TaskError(7001) + + /** + * This error is returned when [com.tangem.commands.personalization.PersonalizeCommand] is attempted + * without [com.tangem.commands.personalization.entities.Issuer] being set in the [com.tangem.Config]. + */ + class IssuerIsRequired : TaskError(7002) } /** diff --git a/tangem-demo/src/main/java/com/tangem/tangemtest/extensions/CardConfig.kt b/tangem-demo/src/main/java/com/tangem/tangemtest/extensions/CardConfig.kt index 1b409eddd3..5412ab7c15 100644 --- a/tangem-demo/src/main/java/com/tangem/tangemtest/extensions/CardConfig.kt +++ b/tangem-demo/src/main/java/com/tangem/tangemtest/extensions/CardConfig.kt @@ -5,7 +5,6 @@ import android.content.Context import com.tangem.commands.* import com.tangem.commands.personalization.CardConfig import com.tangem.commands.personalization.NdefRecord -import com.tangem.commands.personalization.entities.Issuer import java.util.* fun CardConfig.Companion.init(application: Application): CardConfig { @@ -48,7 +47,7 @@ fun CardConfig.Companion.init(application: Application): CardConfig { tokenSymbol = tokenSymbol, tokenContractAddress = tokenContractAddress, tokenDecimal = tokenDecimal, - issuerName = Issuer.id, + issuerName = null, manufactureDateTime = Calendar.getInstance().time, manufacturerSignature = null) @@ -121,9 +120,6 @@ fun CardConfig.Companion.init(application: Application): CardConfig { pin3 = preferences.getString("personalization_pin3", "123") ?: "123", hexCrExKey = preferences.getString("personalization_CrEx_Key", "00112233445566778899AABBCCDDEEFFFFEEDDCCBBAA998877665544332211000000111122223333444455556666777788889999AAAABBBBCCCCDDDDEEEEFFFF"), - issuerName = Issuer.id, - acquirerName = "TANGEM SDK", - ndefRecords = ndefs ) } \ No newline at end of file