From 1357ddf95da006586b05c7ba993eace917ce36c1 Mon Sep 17 00:00:00 2001 From: Tangem Date: Thu, 11 Jun 2020 14:40:53 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../src/main/java/com/tangem/CardSession.kt | 38 +++++++++++-------- .../main/java/com/tangem/commands/Command.kt | 18 +++------ .../tangem/commands/CreateWalletCommand.kt | 4 +- .../com/tangem/commands/PurgeWalletCommand.kt | 4 +- .../java/com/tangem/commands/ReadCommand.kt | 4 +- .../java/com/tangem/commands/SignCommand.kt | 4 +- .../tangem/commands/WriteIssuerDataCommand.kt | 4 +- .../commands/WriteIssuerExtraDataCommand.kt | 6 +-- .../tangem/commands/WriteUserDataCommand.kt | 4 +- .../personalization/PersonalizeCommand.kt | 17 ++++++++- .../com/tangem/common/apdu/ResponseApdu.kt | 3 +- .../com/tangem/crypto/EncryptionHelper.kt | 11 ++++++ 12 files changed, 71 insertions(+), 46 deletions(-) diff --git a/tangem-core/src/main/java/com/tangem/CardSession.kt b/tangem-core/src/main/java/com/tangem/CardSession.kt index bd6b041932..8047252521 100644 --- a/tangem-core/src/main/java/com/tangem/CardSession.kt +++ b/tangem-core/src/main/java/com/tangem/CardSession.kt @@ -5,13 +5,10 @@ import com.tangem.commands.OpenSessionCommand import com.tangem.commands.ReadCommand import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu -import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu import com.tangem.common.extensions.calculateSha256 import com.tangem.common.extensions.getType import com.tangem.crypto.EncryptionHelper -import com.tangem.crypto.FastEncryptionHelper -import com.tangem.crypto.StrongEncryptionHelper import com.tangem.crypto.pbkdf2Hash import kotlinx.coroutines.* import kotlinx.coroutines.flow.* @@ -222,9 +219,10 @@ class CardSession( scope.launch { subscription.consumeAsFlow() .filterNotNull() - .map { establishEncryption(apdu.ins) } + .map { establishEncryptionIfNeeded() } .map { apdu.encrypt(environment.encryptionMode, environment.encryptionKey) } .map { encryptedApdu -> reader.transceiveApdu(encryptedApdu) } + .map { responseApdu -> decrypt(responseApdu) } .catch { if (it is TangemSdkError) callback(CompletionResult.Failure(it)) } .collect { result -> subscription.cancel() @@ -233,21 +231,14 @@ class CardSession( } } - private suspend fun establishEncryption(ins: Int): CompletionResult { - - if (environment.encryptionKey != null) return CompletionResult.Success(true) - - if (ins == Instruction.Personalize.code) { - environment.encryptionKey = null + private suspend fun establishEncryptionIfNeeded(): CompletionResult { + if (environment.encryptionMode == EncryptionMode.NONE || environment.encryptionKey != null) { return CompletionResult.Success(true) } - val encryptionHelper: EncryptionHelper = - when (environment.encryptionMode) { - EncryptionMode.NONE -> return CompletionResult.Success(true) - EncryptionMode.FAST -> FastEncryptionHelper() - EncryptionMode.STRONG -> StrongEncryptionHelper() - } + val encryptionHelper = EncryptionHelper.create(environment.encryptionMode) + ?: return CompletionResult.Success(true) + val openSesssionCommand = OpenSessionCommand(encryptionHelper.keyA) val apdu = openSesssionCommand.serialize(environment) @@ -269,4 +260,19 @@ class CardSession( is CompletionResult.Failure -> return CompletionResult.Failure(response.error) } } + + private fun decrypt(result: CompletionResult): CompletionResult { + return when (result) { + is CompletionResult.Success -> { + try { + CompletionResult.Success( + result.data.decrypt(environment.encryptionKey) + ) + } catch (error: TangemSdkError) { + return CompletionResult.Failure(error) + } + } + is CompletionResult.Failure -> result + } + } } \ No newline at end of file diff --git a/tangem-core/src/main/java/com/tangem/commands/Command.kt b/tangem-core/src/main/java/com/tangem/commands/Command.kt index 860b954ebf..3b25619ce6 100644 --- a/tangem-core/src/main/java/com/tangem/commands/Command.kt +++ b/tangem-core/src/main/java/com/tangem/commands/Command.kt @@ -46,7 +46,7 @@ abstract class Command : ApduSerializable, CardSessionRu open fun performPreCheck(card: Card): TangemSdkError? = null - open fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? = error + open fun mapError(card: Card?, error: TangemSdkError): TangemSdkError = error fun transceive(session: CardSession, callback: (result: CompletionResult) -> Unit) { @@ -63,10 +63,10 @@ abstract class Command : ApduSerializable, CardSessionRu when (result) { is CompletionResult.Failure -> { if (session.environment.handleErrors) { - performAfterCheck(session.environment.card, result.error)?.let { - callback(CompletionResult.Failure(it)) - return@transceiveApdu - } + val error = mapError(session.environment.card, result.error) + callback(CompletionResult.Failure(error)) + return@transceiveApdu + } callback(CompletionResult.Failure(result.error)) } @@ -98,13 +98,7 @@ abstract class Command : ApduSerializable, CardSessionRu when (responseApdu.statusWord) { StatusWord.ProcessCompleted, StatusWord.Pin1Changed, StatusWord.Pin2Changed, StatusWord.PinsChanged -> { - try { - val decryptedResponseApdu = - responseApdu.decrypt(session.environment.encryptionKey) - callback(CompletionResult.Success(decryptedResponseApdu)) - } catch (error: TangemSdkError) { - callback(CompletionResult.Failure(error)) - } + callback(CompletionResult.Success(responseApdu)) } StatusWord.NeedPause -> { // NeedPause is returned from the card whenever security delay is triggered. diff --git a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt index 6d0bab7883..87f9f6dcbe 100644 --- a/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/CreateWalletCommand.kt @@ -51,11 +51,11 @@ class CreateWalletCommand : Command() { } } - override fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? { + override fun mapError(card: Card?, error: TangemSdkError): TangemSdkError { if (error is TangemSdkError.InvalidParams) { return TangemSdkError.Pin2OrCvcRequired() } - return null + return error } override fun serialize(environment: SessionEnvironment): CommandApdu { diff --git a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt index 3ec6ff7315..743a93c68a 100644 --- a/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/PurgeWalletCommand.kt @@ -48,11 +48,11 @@ class PurgeWalletCommand : Command() { } } - override fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? { + override fun mapError(card: Card?, error: TangemSdkError): TangemSdkError { if (error is TangemSdkError.InvalidParams) { return TangemSdkError.Pin2OrCvcRequired() } - return null + return error } diff --git a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt index d0efbf78bd..189588a080 100644 --- a/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/ReadCommand.kt @@ -367,11 +367,11 @@ class Card( */ class ReadCommand : Command() { - override fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? { + override fun mapError(card: Card?, error: TangemSdkError): TangemSdkError { if (error is TangemSdkError.InvalidParams) { return TangemSdkError.Pin1Required() } - return null + return error } override fun serialize(environment: SessionEnvironment): CommandApdu { diff --git a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt index b5135be2b3..c5d743975b 100644 --- a/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/SignCommand.kt @@ -63,11 +63,11 @@ class SignCommand(private val hashes: Array) : Command( } } - override fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? { + override fun mapError(card: Card?, error: TangemSdkError): TangemSdkError { if (error is TangemSdkError.InvalidParams) { return TangemSdkError.Pin2OrCvcRequired() } - return null + return error } override fun serialize(environment: SessionEnvironment): CommandApdu { diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt index 68b97dbf54..0b563a018e 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerDataCommand.kt @@ -60,11 +60,11 @@ class WriteIssuerDataCommand( return null } - override fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? { + override fun mapError(card: Card?, error: TangemSdkError): TangemSdkError { if (error is TangemSdkError.InvalidParams && isCounterRequired(card)) { return TangemSdkError.DataCannotBeWritten() } - return null + return error } private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean = diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt index ac71e3c40c..115ebcd1dd 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteIssuerExtraDataCommand.kt @@ -72,7 +72,7 @@ class WriteIssuerExtraDataCommand( return null } - override fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? { + override fun mapError(card: Card?, error: TangemSdkError): TangemSdkError { if (error is TangemSdkError.InvalidParams && isCounterRequired(card)) { return TangemSdkError.DataCannotBeWritten() } @@ -80,7 +80,7 @@ class WriteIssuerExtraDataCommand( card?.settingsMask?.contains(Settings.ProtectIssuerDataAgainstReplay) == true) { return TangemSdkError.OverwritingDataIsProhibited() } - return null + return error } private fun isCounterValid(issuerDataCounter: Int?, card: Card): Boolean = @@ -134,7 +134,7 @@ class WriteIssuerExtraDataCommand( } is CompletionResult.Failure -> { if (session.environment.handleErrors) { - performAfterCheck(session.environment.card, result.error)?.let { + mapError(session.environment.card, result.error)?.let { callback(CompletionResult.Failure(it)) } } diff --git a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt index 8402ad9266..97a406a2d3 100644 --- a/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt +++ b/tangem-core/src/main/java/com/tangem/commands/WriteUserDataCommand.kt @@ -45,11 +45,11 @@ class WriteUserDataCommand(private val userData: ByteArray? = null, private val return null } - override fun performAfterCheck(card: Card?, error: TangemSdkError): TangemSdkError? { + override fun mapError(card: Card?, error: TangemSdkError): TangemSdkError { if (error is TangemSdkError.InvalidParams) { return TangemSdkError.Pin2OrCvcRequired() } - return null + return error } override fun serialize(environment: SessionEnvironment): CommandApdu { 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 2fd86d0e28..643b374a13 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 @@ -1,5 +1,6 @@ package com.tangem.commands.personalization +import com.tangem.CardSession import com.tangem.EncryptionMode import com.tangem.SessionEnvironment import com.tangem.TangemSdkError @@ -9,6 +10,7 @@ import com.tangem.commands.CardStatus import com.tangem.commands.Command import com.tangem.commands.common.CardDeserializer import com.tangem.commands.personalization.entities.* +import com.tangem.common.CompletionResult import com.tangem.common.apdu.CommandApdu import com.tangem.common.apdu.Instruction import com.tangem.common.apdu.ResponseApdu @@ -37,6 +39,18 @@ class PersonalizeCommand( private val acquirer: Acquirer? = null ) : Command() { + override fun run(session: CardSession, callback: (result: CompletionResult) -> Unit) { + val encryptionMode = session.environment.encryptionMode + val encryptionKey = session.environment.encryptionKey + session.environment.encryptionMode = EncryptionMode.NONE + session.environment.encryptionKey = devPersonalizationKey + super.run(session) { result -> + session.environment.encryptionMode = encryptionMode + session.environment.encryptionKey = encryptionKey + callback(result) + } + } + override fun performPreCheck(card: Card): TangemSdkError? { if (card.status != CardStatus.NotPersonalized) { return TangemSdkError.AlreadyPersonalized() @@ -46,11 +60,10 @@ class PersonalizeCommand( override fun serialize(environment: SessionEnvironment): CommandApdu { return CommandApdu(Instruction.Personalize, serializePersonalizationData(config)) - .encrypt(EncryptionMode.NONE, devPersonalizationKey) } override fun deserialize(environment: SessionEnvironment, apdu: ResponseApdu): Card { - return CardDeserializer.deserialize(apdu.decrypt(devPersonalizationKey)) + return CardDeserializer.deserialize(apdu) } private fun serializePersonalizationData(config: CardConfig): ByteArray { diff --git a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt b/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt index bb947d074a..afc869f64a 100644 --- a/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt +++ b/tangem-core/src/main/java/com/tangem/common/apdu/ResponseApdu.kt @@ -39,7 +39,8 @@ class ResponseApdu(private val data: ByteArray) { fun decrypt(encryptionKey: ByteArray?): ResponseApdu { if (encryptionKey == null) return this - if (data.size < 18) throw TangemSdkError.InvalidResponse() + //nothing to decrypt + if (data.size < 18) return this val responseData = data.copyOf(data.size - 2) diff --git a/tangem-core/src/main/java/com/tangem/crypto/EncryptionHelper.kt b/tangem-core/src/main/java/com/tangem/crypto/EncryptionHelper.kt index ab3d97445c..1360914241 100644 --- a/tangem-core/src/main/java/com/tangem/crypto/EncryptionHelper.kt +++ b/tangem-core/src/main/java/com/tangem/crypto/EncryptionHelper.kt @@ -1,5 +1,6 @@ package com.tangem.crypto +import com.tangem.EncryptionMode import org.spongycastle.jce.interfaces.ECPublicKey import java.security.KeyPair import java.security.KeyPairGenerator @@ -11,6 +12,16 @@ interface EncryptionHelper { val keyA: ByteArray fun generateSecret(keyB: ByteArray): ByteArray + + companion object { + fun create(encryptionMode: EncryptionMode): EncryptionHelper? { + return when (encryptionMode) { + EncryptionMode.NONE -> null + EncryptionMode.FAST -> FastEncryptionHelper() + EncryptionMode.STRONG -> StrongEncryptionHelper() + } + } + } } class StrongEncryptionHelper : EncryptionHelper {