Important!

Blog moved to https://blog.apdu.fr/

I moved my blog from https://ludovicrousseau.blogspot.com/ to https://blog.apdu.fr/ . Why? I wanted to move away from Blogger (owne...

Friday, March 17, 2017

PC/SC sample in Rust

To continue the list of PC/SC wrappers initiated in 2010 with "PC/SC sample in different languages" I now present a sample in Rust.

pcsc-rust

pcsc-rust is written by Ran Benita since January 2017 and uses the MIT license.

Project web site: https://github.com/bluetech/pcsc-rust

Installation

pcsc-rust is easy to use. Installation is automatic using cargo (the Rust package manager).

Source code

You only need 2 files: one file Cargo.toml indicating the dependency on pcsc-rust, and the source code itself in the default file src/main.rs.

File Cargo.toml:

[package]
name = "hello_world"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]

[dependencies]
pcsc = "0.1"

File src/main.rs:

extern crate pcsc;

use pcsc::*;
use std::str;

fn main() {
    // Establish a PC/SC context.
    let ctx = Context::establish(Scope::User)
        .expect("failed to establish context");

    // List available readers.
    let mut readers_buf = [0; 2048];
    let mut readers = ctx.list_readers(&mut readers_buf)
        .expect("failed to list readers");

    // Use the first reader.
    let reader = readers.next().ok_or(())
        .expect("no readers are connected");
    println!("Using reader: {:?}", reader);

    // Connect to the card.
    let card = ctx.connect(reader, ShareMode::Shared, PROTOCOL_ANY)
        .expect("failed to connect to card");

    // Send an SELECT APDU command.
    let apdu = b"\x00\xA4\x04\x00\x0A\xA0\x00\x00\x00\x62\x03\x01\x0C\x06\x01";
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = card.transmit(apdu, &mut rapdu_buf)
        .expect("failed to transmit APDU to card");
    println!("{:?}", rapdu);

    // Send an COMMAND APDU command.
    let apdu = b"\x00\x00\x00\x00";
    let mut rapdu_buf = [0; MAX_BUFFER_SIZE];
    let rapdu = card.transmit(apdu, &mut rapdu_buf)
        .expect("failed to transmit APDU to card");
    println!("{:?}", rapdu);

    // remove the extra 2 SW bytes at the end
    let text = &rapdu[0 .. rapdu.len()-2];

    // convert to UTF-8 (ASCII in fact)
    println!("{}", str::from_utf8(&text).unwrap());
}

The source code is an adaptation of the already existing pcsc-rust project example: https://github.com/bluetech/pcsc-rust#example

Build

$ cargo build
   Compiling pkg-config v0.3.9
   Compiling bitflags v0.7.0
   Compiling pcsc-sys v0.1.0
   Compiling pcsc v0.1.0
   Compiling hello_world v0.1.0 (file:///Users/rousseau/Documents/sc/HelloWorld%20Rust)
    Finished debug [unoptimized + debuginfo] target(s) in 3.4 secs

Output

$ ./target/debug/hello_world
Using reader: "Gemalto PC Twin Reader"
[144, 0]
[72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 144, 0]
Hello world!

Conclusion

pcsc-rust API seems complete, is easy to use and is well documented.

If you know a PC/SC wrapper that is not yet in my list then please contact me.