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.
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.
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:
- Programming for the Java workstation
- 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.
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. andrew.webb@motorola.com
Download Assoicated Source Files (Zip format - 13.5 KB)