Saturday, April 18, 2020

PCSC sample in Scala

Here is a new PCSC sample in Scala language I promised in PC/SC sample in different languages.

JetBrains IntelliJ IDEA can convert source code from Java to Scala when you paste Java code inside a Scala project. I just used this possibility and copy/pasted the previous Java source code presented in "PCSC sample in Java using intarsys smartcard-io".

The same PC/SC wrapper can be used for Scala as for Java and Kotlin.

intarsys smartcard-io

The project intarsys smartcard-io is hosted at https://github.com/intarsys/smartcard-io.
The licence is 3-Clause BSD.

Installation

Installation is easy. Just get the provided is-smartcard-io.jar file from deploy/ directory and the 3 runtime dependencies from lib/ directory.

I have not tried to rebuild the library from source.

Source code

The API is easy to use since it is a direct mapping to the PC/SC WinScard API.

import de.intarsys.security.smartcard.pcsc.nativec._IPCSC
import de.intarsys.security.smartcard.pcsc.{IPCSCCardReader, IPCSCConnection, IPCSCContext, PCSCContextFactory}

object Hello extends App {
  try {
    /* Establish context */
    val context = PCSCContextFactory.get.establishContext

    /* Display the list of readers */
    val readers = context.listReaders
    readers.forEach (reader =>
      println("found " + reader + " named " + reader.getName)
    )

    /* Use the first reader */
    val reader = readers.get(0)

    /* Connect to the card */
    val connection = context.connect(reader.getName, _IPCSC.SCARD_SHARE_SHARED, _IPCSC.SCARD_PROTOCOL_Tx)

    /* Send Select Applet command */
    val select: Array[Byte] = Array(0x00, 0xA4.toByte, 0x04, 0x00, 10, 0xA0.toByte, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01)
    var answer: Array[Byte] = null
    answer = connection.transmit(select, 0, select.length, 256, false)
    println("answer: " + answer.length + " bytes")
    answer.foreach (byte =>
      print(String.format("%02X ",byte))
    )
    println()

    /* Send test command */
    val command: Array[Byte] = Array(0x00, 0x00, 0x00, 0x00)
    answer = connection.transmit(command, 0, command.length, 256, false)
    println("answer: " + answer.length + " bytes")
    answer.foreach (byte =>
      print(String.format("%02X ",byte))
    )
    println()
    for (i <- 0 until answer.length - 2) {
      print(answer(i).toChar)
    }
    println()

    /* Disconnect */
    connection.disconnect(_IPCSC.SCARD_LEAVE_CARD)

    /* Release context */
    context.dispose()
  } catch {
    case e: Exception =>
      println("Ouch: " + e.toString)
  }
}

Output

found pcscreader 0 named Cherry KC 1000 SC Z
answer: 2 bytes
90 00 
answer: 14 bytes
48 65 6C 6C 6F 20 77 6F 72 6C 64 21 90 00 
Hello world!

Conclusion

I have no real merit with this code. It is an automatic translation from Java to Scala by IntelliJ IDEA. I just made some minor manual changes.

This PC/SC wrapper is easy to use and provides access to all the PC/SC functions.
You can use the same PC/SC wrapper with (at least) 3 different languages: Java, Kotlin and Scala. That is nice.