io.github.binaryfoo.decoders.apdu.APDUSequenceDecoder.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of emv-bertlv Show documentation
Show all versions of emv-bertlv Show documentation
Some decoders for the data used in EMV credit card transactions.
package io.github.binaryfoo.decoders.apdu
import io.github.binaryfoo.DecodedData
import io.github.binaryfoo.Decoder
import io.github.binaryfoo.decoders.DecodeSession
import java.util.ArrayList
import io.github.binaryfoo.decoders.IssuerPublicKeyDecoder
import io.github.binaryfoo.decoders.SignedStaticApplicationDataDecoder
import io.github.binaryfoo.decoders.ICCPublicKeyDecoder
import io.github.binaryfoo.decoders.SignedDynamicApplicationDataDecoder
import io.github.binaryfoo.decoders.annotator.BackgroundReading
import io.github.binaryfoo.hex.HexDumpElement
import kotlin.collections.firstOrNull
import kotlin.collections.forEach
import kotlin.collections.listOf
import kotlin.text.Regex
import kotlin.text.split
import kotlin.text.substring
import kotlin.text.toUpperCase
class APDUSequenceDecoder(private val replyDecoder: ReplyAPDUDecoder, vararg commandDecoders: CommandAPDUDecoder) : Decoder {
private val _commandDecoders: Array = arrayOf(*commandDecoders)
private val signedDataRecoverers = listOf(
IssuerPublicKeyDecoder(),
ICCPublicKeyDecoder(),
SignedStaticApplicationDataDecoder(),
SignedDynamicApplicationDataDecoder()
)
override fun decode(input: String, startIndexInBytes: Int, session: DecodeSession): List {
var runningStartIndexInBytes = startIndexInBytes
val list = ArrayList()
input.toUpperCase().split(Regex("\\s+")).filter { it.isNotBlank() }.forEach { line ->
try {
val commandDecoder = getCommandDecoder(line)
val decoded: DecodedData
if (commandDecoder != null) {
session.currentCommand = commandDecoder.getCommand()
decoded = commandDecoder.decode(line, runningStartIndexInBytes, session)
decoded.category = "c-apdu"
decoded.backgroundReading = BackgroundReading.readingFor(commandDecoder.getCommand())
} else {
decoded = replyDecoder.decode(line, runningStartIndexInBytes, session)
decoded.category = "r-apdu"
}
decoded.hexDump = HexDumpElement.splitIntoByteLengthStrings(line, runningStartIndexInBytes)
runningStartIndexInBytes = decoded.endIndex
list.add(decoded)
} catch (e: Exception) {
list.add(DecodedData.primitive(line, "Failed to decode: " + e.message, 0, 0))
}
}
postProcess(list, session)
return list
}
private fun getCommandDecoder(input: String): CommandAPDUDecoder? {
val command = APDUCommand.fromHex(input.substring(0, 4))
return _commandDecoders.firstOrNull { it.getCommand() == command }
}
override fun validate(input: String?): String? {
return null
}
override fun getMaxLength(): Int {
return Integer.MAX_VALUE
}
fun postProcess(decoded: List, session: DecodeSession) {
for (processor in signedDataRecoverers) {
try {
processor.decodeSignedData(session, decoded)
} catch(e: Exception) {
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy