Advertisement: Support JavaWorld, click here!
December 1997
HOME FEATURES COLUMNS NEWS & REVIEWS TIPS Q&A JW RESOURCES ABOUT JW

Java Developer

Smart cards: A primer

Develop on the Java platform of the future

Summary
This article, the first in a new Java Developer series on smart cards, will introduce you to smart card hows and whys. All you need is a smart card, a card reader, and software that lets you communicate with the card, and you can begin developing a real-world application. This article includes: a package to manipulate smart cards using ISO 7816; a demonstration of how to read and write data to a memory smart card using the Gemplus reader and a Gemplus smart card; and a discussion of some of the applications that make use of smart card memory features. Future articles will use cards by different manufacturers. We'll also touch on smart card standards.

With this first article in the series, we will lay the groundwork for future articles with a discussion of the new and emerging standard called OpenCard. Future articles will deal with security cards and electronic purse cards. Finally, this article will teach you some of the basics about smart card software architectures. (3,500 words)

By Rinaldo Di Giorgio


Smart cards have been getting a lot of buzz lately on the Web, at the JavaOne conference last April (four sessions dealt with the technology), on the big network news stations, and on CNN. In this article we'll bring the smart card to life with a real-world smart-card example. The techniques presented here will allow you to start building Java applications that are smart-card enabled.

We'll focus on two types of smart cards: memory smart cards, which can be viewed as minuscule removable read/write disks with optional security; and processor cards, which can be viewed as miniature computers with an input and output port. Future articles will cover processor cards in greater depth.

As the meat of the article, we'll develop a simple prototype for reading and writing data to a smart card. We will discuss a drug prescription card, which keeps a list of all your prescriptions and tracks your insurance, prescription plans, and other useful info. Later articles will expand on the idea of the prescription card.

You'll notice that a recurrent theme that runs throughout this series on smart cards is the need for a security framework to prevent rogue plug-ins, ActiveX components, and so on from getting at your personal and/or corporate info-goodies. To this end, the demonstration of how to read and write data to a smart card included in this article will provide you with persistent, secure (and portable) storage.

What is a smart card?
You can think of the smart card as a "credit card" with a "brain" on it, the brain being a small embedded computer chip. This card-computer can be programmed to perform tasks and store information, but note that the brain is little -- meaning that the smart card's power falls far short of your desktop computer.

Smart cards currently are used in telephone, transportation, banking, and healthcare transactions, and soon -- thanks to developers like you -- we'll begin to see them used in Internet applications. Smart cards are already being used extensively in Japan and Europe and are gaining popularity in the U.S. In fact, three significant events have occurred recently in the smart card industry in this country:

PC/SC
Microsoft and several other companies introduced PC/SC, a smart card application interface for communicating with smart cards from Win32-based platforms for personal computers. PC/SC does not currently support non-Win32-based systems and may never do so. We will discuss this in greater detail later on.

OpenCard Framework
OpenCard is an open standard that provides inter-operability of smart card applications across NCs, POS, desktops, laptops, set tops, and so on. OpenCard promises to provide 100% pure Java smart card applications. Smart card applications often are not pure because they communicate with an external device and/or use libraries on the client. (As a side note, 100% pure applications could exist without OpenCard, but without it, developers would be using home-grown interfaces to smart cards.) OpenCard also provides developers with an interface to PC/SC for use of existing devices on Win32 platfroms.

JavaCard
JavaCard was introduced by Schlumberger and submitted as a standard by JavaSoft recently. Schlumberger has the only Java card on the market currently, and the company is the first JavaCard licensee. A smart card with the potential to set the overall smart card standard, JavaCard is comprised of standard classes and APIs that let Java applets run directly on a standard ISO 7816 compliant card. JavaCards enable secure and chip-independent execution of different applications.

Note:
Although this article focuses on smart cards, it is important to note that you are not limited to these kinds of devices. Personally, I prefer the "Ibuttons" device being produced by Dallas Semiconductor. It is small and portable like a credit card, but so much handier. Why? You don't have to dig out your wallet in search of a card; Ibuttons is right there, on your finger. Yes, it's a ring!

While contactless versions of the smart card do exist (see below for more information on this), I think the Ibuttons, functional-jewelry type of device could be quite profitable. For more information on Ibuttons, see the Resources section. By the way, the Java Commerce Team demonstrated a "JavaRing" at Java Internet Business Expo (JIBE) in New York last August. You can read about this in the article in Fortune magazine (again, see the Resources section).

Why use a smart card?
What are the advantages of using a smart card? Well, a smart card:

Types of smart cards
As mentioned above, this article will focus on two types of smart cards -- memory and process. In all, there are five types of smart cards:

  1. memory cards
  2. processor cards
  3. electronic purse cards
  4. security cards
  5. JavaCard
Smart cards are a personal piece of hardware that must communicate with some other device to gain access to a display device or a network. Cards can be plugged into a reader, commonly referred to as a card terminal, or they can operate using RF radio frequencies.

Smart cards can communicate with a reader or receiver (see the section on readers below for more on these two terms) in one of two forms:

Contact smart cards -- The connection is made when the reader contacts a small gold chip on the front of the card.

Contactless smart cards -- These can communicate via an antenna, eliminating the need to insert and remove the card by hand. With a contactless card, all you have to do is get close to a receiver, and the card will begin communicating with it. Contactless cards can be used in applications in which card insertion/removal may be impractical or in which speed is important.

Some manufacturers are making cards that function in both contact and contactless modes.

Create a development environment for building smart card apps
In order to develop smart card applications, you need a few things, namely: a smart card reader; software to communicate with the reader as well as some software to communicate with the card that has been plugged into the reader; and, of course, smart cards and smart-card hardware.

Smart card reader
To communicate with a smart card or develop an application that is smart-card capable, you must have a reader. The reader provides a path for your application to send and receive commands from the card. There are many types of readers on the market, the most prevalent being the serial, PCCard, and keyboard models. (Keyboard models pop up here and there; expect them to be directly available from the large PC makers by June 1998.)

This article uses serial readers to support the devices. A serial reader connects to a computer's serial port. Note that the code provided also supports a PCCard reader; most laptops come with PCCard slots built in.

Each manufacturer provides a different protocol for speaking to a reader. Once you can communicate with the reader, there is one protocol for communicating with a smart card: Communication with a smart card is based on the APDU format. (The APDU format is discussed below.) For information on purchasing your own reader, see the "Gemplus smart card readers" heading in the Resources section.

Software for communicating with the reader
A number of object-oriented classes are needed for the smart card example included in this article. These are:

Smart cards and smart card hardware
As noted at the beginning of the article, in order to develop the smart card application here, you need smart card hardware and some smart cards. You can purchase smart card development kits from a number of companies, including Gemplus and Schlumberger.

For those of you who already have readers, you should be able to use your reader by supplying an implementation of an interface class that we will discuss later. As mentioned above, before we can communicate with the card, we must be able to communicate with the reader, and just as there are many different cards, there are many different readers.

Important smart card standards
An important piece of the smart card application development puzzle is the standard protocols. Basically, the application communicates with the reader, which in turn talks to the smart card using a standards protocol -- in our case, the International Standards Organization (ISO) 7816 protocol.

As with any new technology, there are so many standards for smart cards that you may find yourself discouraged and overwhelmed. Achieving a basic understanding of the following standards will enable you to develop applications with the confidence that you are not ignoring something basic to using smart cards. For some systems, however, special standards come into play. I have broken the whole standards thing down into "horizontal" and "vertical" standards: Horizontal standards can be used by all applications, while vertical standards are specific to a system.

Horizontal standards

Vertical standards
I am always amazed that such a small piece of plastic could require so much documentation reading and demand so much knowledge on the part of the developer!

Because such a high level of expertise is necessary with smart cards, there is a market for developers to supply Beans-capable products that implement a vertical standard using the horizontal standard for the market you're looking to sell to. This means that you could develop beans that use various combinations of the horizontal standards, like OpenCard, to implement a specific application using some other industry standard for commerce or any other application.

Communicate with smart cards from a Java applet or application
You know what you need to connect up all the hardware. Now we need to understand how to use some APIs that will allow us to send commands from an application to a reader. (The reader, in turn, communicates with the card, thereby acting as the intermediary before sending the data to the card.) The smart card reader wiggles the gold contact points and transfers the data. The card will do something with the data and return it to the reader, which will then return the data to the application. So where are all these bytes as they are moving from your application to the card?

As mentioned above, the application communicates with the reader, which in turn talks to the smart card using the standards discussed above. Basically, as smart card technology developed, a smart card standard was proposed by ISO. The standard defined mechanical and electrical characteristics as well as the protocol for communicating with the card. Pointers to the relevant ISO documents are listed in the Resources section. Unfortunately, the ISO group was unable to provide a standard for communicating with the reader. So, in order to send a command to a card, first you need to find the command that the card supports, wrap this command in an ISO command packet, and then wrap this new command in the wrapper required for the reader in question. The example application provided here performs all of this layering for you.

Application Protocol Data Units (APDUs)
The basic unit of exchange with a smart card is the APDU packet. The command message sent from the application layer, and the response message returned by the card to the application layer, are called an Application Protocol Data Units (APDU). Communication with the card and the reader is performed with APDUs. An APDU can be considered a data packet that contains a complete instruction or a complete response from a card. To provide this functionality, APDUs have a well-defined structure that is defined in a number of ISO documents belonging to the 7816 specification family.

APDUs consist of the following fields:

Command APDU Format

CLA INS P1 P2 Lc Data Le

Response APDU Format

Data SW1 SW2

The following are some of the classes provided for transporting APDUs and the classes' functions:

Communicating with smart cards
Sun has developed the Java Electronic Commerce Framework (JECF), an extension to the core Java platform that allows developers to easily and rapidly develop electronic commerce applications. JECF provides several classes that support communication with smart cards very easily. (See the Resources section for information on the JECF.)

The card we are working with in this article has one command for reading data and another command for writing data. This card is referred to as a GFM card and is produced by GemPlus. You should be able to use other cards as long as they are ISO 7816-compliant and you have the information on what their APDU commands are. Of course you will also have to do a little programing. The GFM card has memory organized in blocks of 64 bits or 8 bytes. You must carry out reads and writes using modulo 8 arithmetic. In other words, you cannot write 1K directly as one long contiguous write. The Java code we supply here does this for you. Some of the newer cards support larger read/write sizes. So, to write the string "0123456789," you would need to issue two commands with proper indexing of the address. (Yes, smart cards can be very difficult to program.) As memory cards and processor cards merge, many of these restrictions are disappearing.

In order to read the above string, you would then need to issue the "read" command.

The two commands we are going to use are formatted below in terms of an APDU. In our case, we use the following Java methods to read and write the card. The values in the table below demonstrate how to construct an APDU. The structure of the APDU is defined in the GFM programmer's manual.

Location of data Upper Lower
256 0X00 0X00
1023 0X00 0X00
3093 0X00 0X00

"Upper" and "lower" are the high- and low-order bytes of the address. Some examples may help clarify this concept. The table provides the upper and lower values for storing data at the specified addresses. The two methods we have been discussing for communication with a GPM896 smart card are:


ISOCommand(0, 0xD0, 0, upper, lower, 8); // Write 8 bytes to the address

ISOCommand(0, 0xB0, 0, upper, lower, 8); // Read 8 bytes from the address

Communicating with a smart card from a browser
The existence of these three native interfaces indicates the lack of understanding of major corporations of developers' need to have simple APIs that they can remember when they are in a Java environment. If all vendors supported JNI, then at least the interface would remain constant and you would not have to spend hours getting the interface bindings to work. It is true that you would still have to write a small amount of "native code," but there is value in having a consistent interface. I have tried all three APIs above and found JNI to be more consistent than the rest, as well as the easiest to use and implement. The integration with HotJava is the best; with HotJava you can sign the classes that talk to a serial port and use them securely with less hassle than with the other two browsers. Sun has recently announced a new initiative to help browser companies implement new versions of the JDK/JVM.

The precceding discussion revolved around how to communicate with a hardware device that does not have JDK support. In the next few articles we will stop concentrating on the "native interfaces" and use an industry standard API for communicating with smart cards. The standard I am choosing for communication is OpenCard with a PC/SC bridge. I will write my appliations to OpenCard not PC/SC. Why?

As a developer you have many choices. Although generally this is a good thing, it also can lead to increased cost and non-uniform functionality when the choices are APIs that do no span all the platforms you need. So, for example, you could decide to write your smart card applications using PC/SC, which provides support in the Win32 world. This is a bad idea because if yours is a consumer application and it is brought up on WebTV, the screen will flash with the message: "Wait for Pentium version of WebTV." Smart cards are used in markets other than Win32 desktops or CE units. So, what should you do? Write to OpenCard and distance yourself from the lack of consistent JNI bindings in Internet Explorer. In fact, I think it is a wise move to abstract all APIs that only function on one platform.

And now, the real-world application!
It's time now to lay out the scene for a more significant smart card application. In the future, when we pay a visit to the doctor and he or she suggests we take a particular medication, we might be players in the following scenario:

Sounds like a safer system to me than the (primarily) paper-and-pen system in which humans are the link between disparate computer systems. In fact, in Germany, medical smart cards are already in use.

The advantages of the prescription smart card
So what value do smart cards add to traditional prescription plan "cards"? They offer:

In order to provide support for the above process, we need to develop an application that lets us read and write records to the card in a secure manner. The application above simply gives the user the ability to enter data onto the card. For example, your doctor can add your prescription to the card.

Developing the application
In this section you get the code you need to write data to a smart card and read it back. The first action in the program that is trying to read or write data to a memory card is to get a reference to a device that supports a smart card. Once we have the device, we need to write or read the desired string. This is achieved by calling on the methods supplied in CardStrings.java. The prototype classes provided facilitate the programming of smart cards. We've also added a Beans-style event handler to inform us of smart card events such as the insertion of a card. (Thanks to Dan Guinan, senior developer on the JECF, for this last tip.)

Consider the following code fragment from RWString.java:


import java.commerce.smartcards.*;  Packages form JECF to support smart cards
import java.commerce.gemplus.*;
import java.commerce.DeviceManager.*;
import java.awt.event.*;
/**
*  Read and write Gemplus Memory cards. The following cards
*  are supported:
*  GFM 4k
*/
public class RWString {

        public static void main( String args[]) {
                WriteString ws = new WriteString(args);
        }

}

class WriteString  implements ActionListener {

        ISOCardReader   isoReader = null;      
        int                             portNumber;    
        String                  deviceName;    

        public WriteString(String args[]) {

                ////////////////////////////////////
                //      Process the arguments
                ////////////////////////////////////
                for(int i = 0; i < args.length; i++) {
                        if ( args[i].equals("-port") ){
                                portNumber = 0;
                        } else if ( args[i].equals("-device") ) {
                                deviceName = new String ( args[++i] );
                        } else if ( args[i].equals("-help") ) {
                                System.out.println("Usage: string -port # -device COM1 or /dev/ttya" );
                                System.exit(0);
                        }
                }

                SmartCardDetector scDetector = new SmartCardDetector(1000);
                scDetector.addActionListener(this);
                scDetector.startDetection();
        }
        public void actionPerformed(ActionEvent actionEvent) {
                System.out.println("Action Performed: " + actionEvent );
                try {
                        // Open the requested port number
                        SmartCardReader scr = new SmartCardReader();
                        isoReader =  scr.getDefault();
                        isoReader.beginCardSession(GemplusSerialReader.GFM);
                        CardStrings.writeGFMString("01234567" , isoReader );
                        System.out.println(CardStrings.readGFMString(isoReader ) );
                        isoReader.endCardSession();
                } catch(Exception e) {
                        System.out.println( "Exception " + e);
                        e.printStackTrace();
                } finally {
                        try {
                                isoReader.endCardSession();
                        } catch(Exception eFinally) {
                                System.out.println("Could not power Down card perform manual reset");
                        }
                }
        }
}

The class CardStrings provides some utility methods to read and write strings to the card. The strings are stored on the card with a length field of two bytes, followed by six empty bytes, followed by the string data.

As a challenge for those of you who actually get some cards and start programming them, you should be able to modify the methods in Cardstrings to read and write Java objects. This is a more flexible approach than just writing strings. If you write Java objects you can save data without worrying about its format. I wanted to start with something simple that everyone could relate to -- namely, storing some string data on a card.

The following application is a complete example for reading and writing data to a GemPlus GFM card using a GCR400 serial reader. With a little bit of work other readers can be supported. Don't bother doing the work for supporting other readers: Next month we'll be providing an example of how to do this with OpenCard, which is quickly becoming the standard in this area.


package java.commerce.MemoryCards;

import java.io.IOException;
import java.commerce.smartcards.*;
import java.commerce.gemplus.*;

public class CardStrings {
        /**
         * Write a String, since the card is modulo 8 and we are
         * not using serialized objects -- the first two bytes are the
         * length followed by six spare bytes. Strings longer than 4096 - 48
         * bits will be truncated.
        */
        public static void writeGFMString(String s , ISOCardReader isoreader) {
                ISOCommand              wcmd;
                ISOCardinputStream      winput;
                int                     upper,lower;
                short length = (short)s.length();             // Length of the input string
                System.out.println("Length is " + length );
                try {
                        // Write the control section out
                        wcmd = new ISOCommand(0, 0xd0, 0, 0, 8,0);      // Save the length
                        wcmd.data.writeShort( length );              
                        System.out.println("Write out the Length");
                        winput = wcmd.execute(isoreader, new GemplusReaderFailureHandler());
                        // Write the String out
                        int wholeAmount = length/8;                             // Groups of 8
                        int remainder = length % 8;                             // Remainder
                        // Write the String out groups of 8
                        for ( int l = 1; l <= wholeAmount; l++ ) {      
                                System.out.println("Writing 8 bytes at " + (l*8));
                                upper = (l * 8 ) >> 8;
                                lower = ( l * 8 ) & 0xff;
                                wcmd = new ISOCommand(0, 0xd0, upper, lower, 8,0);
                                int index = ( (l-1) * 8 );
                                wcmd.data.writeString(s.substring(index),8);    
                                System.out.println("Write out bytes at " + index);
                                winput = wcmd.execute(isoreader,new GemplusReaderFailureHandler());
                        }      
                        // Write the remainder out
                        upper = ((wholeAmount+1) * 8 ) >> 8;
                        lower = ((wholeAmount+1) * 8 ) & 0xff;
                        wcmd = new ISOCommand(0, 0xd0, upper, lower, remainder,0);
                        int index = ( wholeAmount * 8 );
                        wcmd.data.writeString(s.substring(index),remainder);    
                        winput = wcmd.execute(isoreader,new GemplusReaderFailureHandler());
                } catch ( Exception e ) {
                    System.out.println( "Exception " + e);
                    e.printStackTrace();
                }
            }
        /**
         * Read a String, since the card is modulo 8 and we are
         * not using serialized objects -- the first two bytes are the
         * length followed by six spare bytes. Strings longer than 4096 - 48
         * bits will be truncated.
         */
        public static String readGFMString(ISOCardReader isoreader ) {

                ISOCommand                                  rcmd;
                ISOCardinputStream  rinput;
                int upper,lower;
                short length;
                StringBuffer    sb = new StringBuffer();
                try {
                        // Read the control section
                        rcmd = new ISOCommand(0, 0xb0, 0, 0, 0, 8);     // Read the length
                        rinput = rcmd.execute(isoreader,new GemplusReaderFailureHandler());
                        length = (short)rinput.readShort();
                        System.out.println("The length is: " + length);
                        // Read the String
                        int wholeAmount = length/8;                             // Groups of 8
                        int remainder = length % 8;                             // Remainder
                        // Read the String in groups of 8
                        for ( int l = 1; l <= wholeAmount; l++ ) {      
                                System.out.println("Reading 8 bytes at " + (l*8));
                                upper = (l * 8 ) >> 8;
                                lower = ( l * 8 ) & 0xff;
                                rcmd = new ISOCommand(0, 0xb0, upper, lower, 0, 8);
                                rinput = rcmd.execute(isoreader,new GemplusReaderFailureHandler());
                                sb.append ( rinput.readString(8) );    
                                System.out.println("String to this point:" + sb.toString());
                        }      
                        // Read the remainder
                        upper = ( (wholeAmount+1) * 8 ) >> 8;
                        lower = ( (wholeAmount+1) * 8 ) & 0xff;
                        rcmd = new ISOCommand(0, 0xb0, upper, lower, 0, 8);
                        rinput = rcmd.execute(isoreader,new GemplusReaderFailureHandler());
                        sb.append ( rinput.readString(remainder) );    
                        System.out.println("String to this point:" + sb.toString());
                } catch ( Exception e ) {
                      System.out.println( "Exception " + e);
                      e.printStackTrace();
                      return ( null );
                }
                return ( sb.toString() );
            }
        }

Future articles
In future articles we will discuss ways in which our doctor of the future can securely sign the entry he or she has put on your card, so that the card can function as a valid prescription, even for in-triplicate prescriptions for controlled substances. The application must also support the ability to display your prescription history. This is a feature of an application that can be used by yourself, your pharmacist, emergency personnel, et al. How about storing a MedAlert-style synopsis of your medical history -- surgeries, drug sensitivities, chronic ailments, and so on? The smart card presents numerous possibilities.

Conclusion
This article has provided the foundation for the entire smart card series, which will consist of four articles in JavaWorld. I will be writing three more articles, with the hope of helping you get comfortable with the use of smart cards in your applications. I will use the Java Electronic Commerce Framework (JECF) as a foundation layer for building real solutions. The JECF provides several classes that simplify communication with smart cards. Much of the code and examples come from the JECF. Check the Resources section for a link to download the JECF, which already includes support for smart cards.


About the author
Rinaldo Di Giorgio is a staff engineer for Sun Microsystems in New York City. He currently is working on the integration of many technologies into HotJava and Java, including commerce, database connectivity, portfolio management, and analytical applications for the financial and emerging genetics market. He sees Java as the technology that will minimize two great cost factors in the computer industry: distribution and code development.


Advertisement: Support JavaWorld, click here!


HOME |  FEATURES |  COLUMNS |  NEWS & REVIEWS |  TIPS |  Q&A |  JW RESOURCES |  ABOUT JW |  FEEDBACK

Copyright © 2001 JavaWorld.com, an IDG Communications company