HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

Using Motorola's Java Card to Digitally Sign a Message, by Andrew Webb

Smart card, Java workstation, and cryptography: these are all growing areas of interest in the computing world. There are programmers - from novice to expert - who know each of these technologies. But as the technology world becomes more intertwined, so too do these seemingly disparate technologies. With the introduction of the Java Card it's becoming necessary for smart card developers to know Java and Java developers to know smart cards. And as more transactions are done electronically, everyone will try to find ways of applying cryptography to electronic security. The purpose of this article is to provide a sample solution that brings all three of these technologies together.

Assuming the reader knows what Java is and has at least a vague notion of what a smart card is (a card the size of a credit card containing a microprocessor), it's only necessary to bring the reader up to speed on a Java Card and cryptography. Basically, a Java Card is a specialized type of smart card that's programmed using portable Java applets instead of proprietary commands. Cryptography can be used to digitally sign a message that can be checked, but not created, by those with access to the public key of the sender. The cryptographic algorithm required for this purpose uses a public and private key pair that's created concurrently. The sender uses the private key to encrypt a message, and the receiver uses the public key to decrypt the message. If the public key successfully decrypts the message, the sender must be the proper owner of the private key associated with that public key, therefore proving the identity of the sender.

Simplified High-Level Example
Here's an example of how these three technologies could be combined. Suppose I want to send a message to my stockbroker telling him to sell all my shares of Microsoft. Now my stockbroker wants to make sure it's really me sending the message. So using his Java workstation and a couple of extra cryptography applications, he generates a public/private key pair. He stores the private key on the Java Card and issues it to me.

When I want to send a message to him, I use an applet on the Java Card. It digitally signs the message with the private key and returns a signature to my workstation. I can then e-mail the message with the signature to my stockbroker, who knows the public key (because he generated it). He can then decrypt the signature, ensure that I had sent the message, and sell my shares. Note that the public key can verify the signature, but only the private key can generate it. The advantage of this solution is that anyone with access to the public key can verify the signature, and the public key doesn't have to be kept secret. The private key, however, remains on a secure, portable token - the Java Card.

Goal
The remainder of this article describes how to integrate the various Java-based tools to use public key technology on a Java Card. Included in the sample solution are the steps to generate an asymmetric key pair, load it onto a Java Card, sign a message with a private key on the card, and verify the signature using the public key. The article describes the design of the Java workstation program, Open Card Framework (OCF) Card Service Provider, and the Java Card applet on the Java Card. All other components are off-the-shelf applications that are available on the Internet.

Description of Development Environment and Hardware/Software Layers
Before starting, it's necessary to describe the programming environment used in this sample solution and understand how the layers fit together. Figure 1 shows, in general terms, the software and hardware layers.

Figure 1

Referring to Figure 1, the following is a brief description of how the pieces of the development environment work together.

The Java workstation program calls the JCE Cryptographic provider to generate the RSA key pair. The Java workstation program then calls the OCF Card Service Provider that generates a card command to load the private key. The card command is sent from the OCF Card Service Provider to the OCF CardTerminal. Note that the OCF Card Service Provider is responsible for card-specific operations, while the OCF CardTerminal deals only with commands specific to the smart card reader.

The OCF CardTerminal driver tells the physical reader to send the command to the card. The Java Card OS passes the command to the appropriate applet on the card. The applet handles the command, usually passing data back, calling the Java Card 2.1 API, or changing the state of the applet.

Data returned from the applet travels from the Java Card OS back to the smart card reader, then to the OCF CardTerminal, and finally to the Card service provider.

The OCF Card Service Provider generates card commands that are interpreted by the Java Card applet. The definition of the commands is a shared source between the applet and the card service provider.

More specifically, Figure 2 shows the exact software and hardware development environment used in creating this solution. The actual development environment is important to know should the reader want to attempt the same solution. Some steps may differ depending on the environment used.

Figure 2

The Motorola M-Smart Jade Workbench handles the generation of a CAP file and loads it onto a Motorola Java Card using Visa Open Platform (VOP) 2.0 commands. It can also be used to simulate and test a card applet without using a physical card and reader. It's a commercial product that comes with sample Java Cards and a reader.

The Solution
Now that the relevant background information has been provided, it's time to get down to the actual steps of implementing the solution.

These steps are broken down into two main parts:

  1. Programming for the Java workstation
  2. Programming for the Java Card
Java Program on the workstation or PC
Step 1: Design of the Java workstation program

It's important to first understand that while the Java Developer's Kit 1.2.2 will support the code for calls made to cryptography routines, it currently doesn't have the cryptography functionality built in. Specifically, the Java Cryptography Extension (JCE) has the structure defined to generate an RSA key pair, and there are Open JCE Java Cryptography Extension Provider implementations available from third parties.

The code to generate a key is:

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize( keylen, random);
KeyPair pair = keyGen.generateKeyPair();

In this code, keylen is perhaps 512 bits, and random comes from these steps:

SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
random.setSeed( 1234 );

(Note: Since the seed is set from a constant, this will produce the same key pair each time. This is helpful for testing, but in the real application you'd like to come up with an indeterminate method for initializing the seed.)

To send the key to the card, it must be broken down into its various components, which can be done with this code:

PrivateKey priv = pair.getPrivate()
byte [] enc_key = priv.getEncoded();

enc_key is a byte array that now contains the various key components in PKCS-8 format. The modulus and private exponent that make up the private RSA key can be extracted by using Appendix A as an example. (All appendices in this article can be found at www.JavaDevelopersJournal.com.) The private key is sent to the card using the "samservCardService" class, and the private key is no longer needed on the workstation. The code for this can be found in the file samservCardService.java, which is available on the Motorola Smart Card Web site, www.motorola.com/smartcard/.

Now we have a message, "I will pay Fred 8 dm," that we want to sign with the private key. We simply send the message in a signing command as shown below and receive the result.

ss.Algs( samservCardService.SIGN_OPER,
samservCardService.RSA512PRIV_ALG, (byte)20, 0, data );

The complete code for this can be found in the file javaterm.java on the JDJ web site.

Step 2: Connecting to the Java Card from the Java workstation program
This step focuses on the smart card connectivity. The code below shows how to start the OCF CardTerminal, initialize the samservCardService instance, send an application program data unit (APDU - a message sent to a smart card that tells the card to do something), and then close smart card operations.

SmartCard.start();

CardRequest cr = new CardRequest (CardRequest.ANYCARD, null,
samservCardService.class );
SmartCard sm = SmartCard.waitForCard( cr );

samservCardService ss = (samservCardService) sm.getCardService(
samservCardService.class, true);

ss.SelectApplet(); // Make our Javacard applet run.
SmartCard.shutdown ();

This is a simple version, and more details can be found in the OpenCard Framework 1.2 Programmer's Guide included with OCF.

Step 3: Design of the OCF Card Service Provider code
Two application program data units define the samservCardService: (1) select algsapp and (2) AlgsOperate. The operations associated with the AlgsOperate APDU include Load Key (modulus), Load Key (exponent), Encrypt, Decrypt, Sign, Verify, and Show Key.

The Java Card applet on the card has to support those two commands, while the samservCardService simply generates the commands and sends them to the OCF CardTerminal using the member function sendCommandAPDU(). A CardChannel must be obtained from the inherited member functions allocateCardChannel(), getCardChannel(), and releaseCardChannel().

The code below shows how a member function of a class that extends "CardService" can send an APDU to a card via an OCF driver.

public void SelectApplet() /* Select the "algsapp" Javacard applet */
throws CardTerminalException
{
byte[] SelAid= { (byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07,
(byte)0x61, (byte)0x6c, (byte)0x67, (byte)0x73, (byte)0x61,
(byte)0x70, (byte)0x70 };

CommandAPDU capdu = new CommandAPDU( SelAid, 12 );
try {
allocateCardChannel();
rapdu = getCardChannel().sendCommandAPDU
( capdu );
} finally {
releaseCardChannel();
}
}

Step 4: Checking the signature with the public key
Now that the message has been signed using the private key, it can be verified by decrypting the signature with the public key. Before doing this, it's necessary to jump ahead and understand what was done on the card. This is explained in detail in Step 1 of the Java Card Applet found on the JDJ Web site. In the meantime Figure 3 shows what happens as the message (or data) is sent to the Java Card and the signature is generated.

Figure 3

The Java applet on the card automatically hashes the message before encrypting it and returning the signature.

Cipher rsa_ciph = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsa_ciph.init( Cipher.DECRYPT_MODE, pair.getPublic() );
rsa_ciph.doFinal( sig_of_data, sig_off, sig_len, de_sig );

The code above decrypts the signature, and the result is the SHA-1 hash of the original data in the byte array de_sig. Since we can't "unhash" this to verify that it matches the original message, we can hash the original data ourselves. If the SHA-1 hash of the original data matches the decrypted hash returned by the Java Card, we've verified that the public key is the one associated with the private key. The code below shows how to generate an SHA hash of the original data. If the signature is correct, the hash in de_sig and the recomputed hash should be equal. The hash is either in the first 20 bytes of de_sig or directly after a 15-byte SHA-1 identifier.

MessageDigest sha = MessageDigest.getInstance("SHA");
sha.update( data ); byte[] hash = sha.digest()

Step 5: Building and running the Java workstation program using the Sun JDK
The following files, available as part of the OCF installation, must be in your Java classpath: base-core.jar, base-opt.jar, jce1_2-do.jar, and jce.zip

When using the OCF-provided PC/SC driver, you also need \OpenCard\OCF1.2\lib in the OS path to pick up the OCF pc/sc dlls, and you must reference terminals-windows.jar and pcsc-wrapper.jar in the Java classpath. (Naturally, you also need a functional PC/SC installation.)

Assuming that CPATH contains all the relevant jars and zips, the JDK commands in the listing below will build the java class file and combine the CardService and its factory into a jar file.

javac -classpath %CPATH% javaterm.java
cd samserv
javac -classpath %CPATH% samservCardService.java samservCardServiceFactory.java
cd ..
jar cvf samserv.jar samserv\samservCardService.class
samserv\samservCardServiceFactory.class

The path environment variable includes C:\;\JDK1.2.2\BIN;C:\ OPENCARD\OCF1.2\LIB. The command java -cp %CPATH% javaterm will then produce the output shown in Appendix B.

Java Card Applet
Now that the steps from the Java workstation side have been explained, it's time to take a look at what's happening at the card level.

Step 1: Design of the Java Card 2.1 applet
The details of the Java Card 2.1 runtime environment are covered in Sun's Java Card 2.1.1 Runtime Environment (JCRE) Specification. Briefly though, the algs class extends the applet and handles the input and output of the APDU. After an APDU has arrived in the buffer the Java Card environment calls the process (APDU apdu) function. The member variables of algs are held in persistent storage, while local variables use the stack.

Under the constructor Algs(), the cryptographic member variables are created with their defining parameters, such as key size, and the type and hashing for the signature. Naturally, they have to be in agreement with the parameters used on the terminal side.

The process() method has a switch that contains the essential cryptographic manipulations of loading the private key and using it to encrypt and sign data. In all cases we use the data from the incoming command as it's sent to the card.

Step 2: Building the Java Card applet with the Sun JDK, using a .jar file from Motorola
The commands shown below are those needed to build a jar file from the algs.java file.

javac -g -classpath "\program files\M-Smart JADE\jcapi.jar" algs.java
cd ..
jar cvf algs/algs.jar algs/algs.class
cd algs

To convert the JAR file into a CAP file, which is the file used to load the applet into the card, use M-Smart Jade Workbench. A CAP file is specified in Sun's jcvmSpec.pdf, section 6.

Notice that the jcapi.jar (Java Card API) came from the installation directory of the Motorola M-Smart Jade Workbench.

Step 3: Generating and loading the CAP file using the Motorola M-Smart Jade Workbench
To build the .CAP, you start Jade, and select Card | Jupiter. Note: You can't run Jade on a Windows PC if PC/SC is locking the serial port. The symptom is that Jupiter doesn't appear below simulator on the card menu, so you must disable PC/SC while Jade is running as follows:

WNT Control Panel | Services | Smart Card Resource Manager stop Control Panel | Services | CHIPDRIVE SCARD Service stop

W98 Run msinfo32.exe, and choose System configuration utility from the tools menu. In the Startup tab disable SCardSrv and TwkCardSvr then reboot.

Select Tools | Generate Cap File. Browse for your jar file, click Parse, then enter the AID for the applet and package. The first five bytes of the package AID must be the same as the applet AID. The example applet uses "algsapp" and "algsa" for the applet and package, respectively. (" means use the ascii characters; you could also enter 61 6C 67 73 61 70 70, if you prefer.) Browse for your cap file destination, entering the filename if it's the first time you're generating the CAP file. Then click on Generate CAP.

If the card already has an old version of the applet, select Card | Delete and remove the applet and then the package.

Then select Card | Load and Install, and browse for the CAP file. Enter your heap size and wait a bit. (The example applet has a heap of 1500.)

Summary
The main purpose of this article was to demonstrate how to use a Java Card smart card with Java. This was accomplished by giving a sample solution using the Java cards built-in RSA cryptography functionality to generate an RSA signature. Obviously, you can do much more with a Java Card, but hopefully you will have a starting point of information and sources to get you started.

Future applications that integrate Java, smart cards, and cryptography are up to you!

Author Bio
Andrew Webb is a staff engineer at Motorola World Wide Smart Card Division and holds a BS in applied mathematics from Carnegie-Mellon University. [email protected]

Download Assoicated Source Files (Zip format - 13.5 KB)

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.