Restricted-channel multicast in Java

How a desktop stock-ticker app was converted into a secure system, using an applet running on a smart card device

This article describes the modifications made to an existing multicast application during research and development at Sun Microsystems. The goal was to convert an application bundled with Java Reliable Multicast Service (JRMS) to something we are calling a restricted-channel system. In a restricted-channel system, the multicast server transmits encrypted information that can be deciphered only by authorized multicast client programs or multicast client programs operating under authorized conditions. For security reasons, a Java Card was chosen as the device on which to perform decryption. The program performing the decryption was run by the smart card chip itself. The system envisioned in this project is a complete one, where both decryption and payment are handled by the Java Card device. This article also demonstrates the use of the Java Card as a "purse," performing debit and credit card functions and actually "holding" money.

Over the past month we have been working on a project to create a prototype for a restricted-channel multicast system using rudimentary Java Card encryption. Multicast describes a system in which one message is transmitted to many listeners at the same time. On the Internet, or any network with a bus architecture, every machine on the network receives all packets -- no matter who the packets are meant for. This situation is invisible to users because a network node ignores any packets not specifically addressed to it. However, there is a special "multicast address" reserved on the Internet for communication intended for many recipients.

In this restricted-channel system, the multicast server transmits encrypted information, which can only be deciphered by either: (a) authorized multicast client programs, or (b) multicast client programs operating under authorized conditions, such as those submitting payment for the service.

Our goal has been to investigate the feasibility of creating such a system using the Java Reliable Multicast Service (JRMS). Reliable multicast is distinguished from standard multicast in that any and all packets transmitted over the network must be received correctly, or the client will ask the server to continually retransmit until a correct packet is received. (TCP, the reliable unicast protocol used by the Internet, and UDP, its unreliable cousin, may be more familiar to some readers). For our project, we chose to take an existing demo system, designed merely to illustrate a possible use for JRMS, and change it into a restricted-channel system. The original client end of the system was a desktop stock-ticker window, implemented using standard Abstract Windowing Toolkit (AWT) classes and a JRMS multicast client socket. The original server provided the channel content (stock quotes) through a JRMS server socket. For the purposes of the demo only, the stock quotes were obtained either from a disk file or from a public Web site (Yahoo), which was parsed and retransmitted as multicast data.

Restricted-channel multicast

Why restricted-channel multicast? More than one person has asked us this. One possible application we've repeatedly invoked is the model of a reserved-for-top-executives information service within a corporation -- possibly a stock ticker or other, more sensitive information. However, other models exist.

For multicast services that require payment, you must have a restricted-channel system in place -- to prevent theft of service. Some sort of cryptosystem is the best way to implement a restricted channel. Even if payment is not an issue, a strong enough encryption scheme could allow even military or governmental multicast applications, where security is required for other reasons. Work orders could be multicast in realtime to different stations with a restricted-channel system. Software updates could be sent automatically over the Net to a large customer base. Upper-level management of large corporations could send updates on specials to restaurant franchise local managers, or warehouse managers.

The crucial aspect of our system is that our decryption applet runs directly on the Java Ring, not on the host system. If a ring or card stores only a key, the security of that key will be compromised during transmission to the decrypting process running on the host system. A serial port can be tapped or monitored, and within the operating system of a traditional user-interfaced, multi-interfaced, and/or distributed system -- such as a workstation or PC -- opportunities abound for theft of a key. In many respects, a Java Ring, and to a lesser extent a Java Card, presents an information cul-de-sac: There is only one point of information ingress or egress, and no user interface or distributed system. Smart cards offer even more functionality because they house a true computer -- with erasable and rewritable memory, a processor, and an operating system. Smart cards furnish a way for programs that use ultra-sensitive data to begin, execute, and finish without ever allowing any of the sensitive information to leave the cul-de-sac.

The majority of our modifications to the stock-ticker multicast system were on the client side. We elected to use a rudimentary (bitwise logical NOT) encryption scheme so that we could focus our efforts more strongly on the specifics of integrating on-ring decryption with an existing multicast system. Within the next four months, smart cards and rings implementing the Java Card spec will be available that perform 1024-bit key encryption.

While modifying the application, we found very little problematic code. Of a set of small problems, the largest was simply that of monitoring card and ring removal and reflecting this in program output. This problem was partially solved by the Open Card API itself.

One modification we made was to insert stubs (that is, program fragments with only limited functionality, meant to be filled in later by fully-developed code) for a smart card purse. This purse had a simple balance field and a debit method, which, when appropriate, threw an OutOfMoney exception. The stubs, unlike the decryption engine, did not run on the card. They will be replaced by a true Java Card purse in future versions.

The code

The sun.jrms.stock package originally contained three java files -- one debugging interface, and source for two executable classes: StockViewer and StockServer. My modifications were retitled SecureStockViewer and SecureStockServer, and were added to this package. Also available was the sunlabs.javacard.DecoderRing class for use by the SecureStockViewer. DecoderRing handled all direct access to the ring, using Dallas Semiconductor's iButton package imports, OpenCard imports, and so on. Additionally, I included a few inner classes and small outer classes, mostly to either override AWT methods or to provide stubs for the purse and for the DecoderRing class (so the front end of the program could be debugged when no ring was available).

The SecureStockViewer (the multicast client) has two main threads: one that downloads stock quotes and decrypts them (the run method), and another that scrolls the ticker display (the scrollmethod). In the initial algorithm, the run method continually downloaded new stock quotes from the multicast stream, converting each set of stock quotes to one long text string and placing it in a String object called message, which was merely a temporary holder for the data. The scrolling thread would display a String object called text. When a text string had finished scrolling completely, the scroll thread would call the following method:

private void
getNewData() {
    if (SecureStockViewer_Debug) {
    System.out.println("SecureStockViewer: getNewData.");
    text = message;
    pos  = 0;

Assigning pos to zero restarts the scroller display at the beginning of text. Download was nearly instantaneous, while scrolling took a few minutes for each text string -- therefore, the program downloaded new stock quotes faster than it could display them. This would not have been a problem if not for the restricted multicast paradigm -- that is, the purse functionality (stubbed out, but still to be accounted for). Users should not have to pay for stock quotes they never see. To fix this problem, I introduced a flag (actually more like a latch) called waitingforscrolltofinish. When the decryption was finished, the download/decrypt method would hold until the scroller was finished as well, and then would charge the user for the download and start the cycle again by getting new stock quotes from the multicast connection.

Ring removal currently is detected in two ways. During decryption, the application detects removal by catching an exception -- any exception -- thrown by the decode method (the method in DecoderRing that sends a byte array, 60 bytes maximum, to the ring for decryption). This seemed at first to be a temporary solution, but further thought uncovered some logical justifications for actually leaving this feature in the design. When someone is paying for a service via a ring, he or she might naturally assume that ring removal should generate an event that halts the scroller and demands reinsertion of the ring. In this application, ring removal is only detected when a decryption attempt is made. Remember that the program was changed so that download and decryption now waits for the scroller to finish. This would leave a gap after decryption but before the scroller finished, meaning that the ring could be removed without stopping the scroller.

Is this a bug?

I say no, because the user is paying per download, not per second of usage. In fact, one could even argue that the user should pay per 60-byte segment decrypted. If the ring is removed during decryption, then the current segment should be dumped, and any previously decrypted segments should be displayed even if a quote is cut off in the middle! This is a very interesting issue, actually, leading to a consideration of the legal implications and discussions on questions such as, What does it mean to pay for something? Unfortunately, the issue is not within the purview of this article.

At present, the ticker halts whenever the ring is removed. After decryption, while the run method is waiting for the scroller to finish, it polls a method in DecoderRing called isDeviceInserted(). (See below for an explanation of how this relates to the Open Card API). To halt the scroller, we created a boolean flag called showErrLabel and a reference of type String called errLabel. If showErrLabel was raised, the scroll method would halt and set the error display to errLabel. The errLabel string has to reflect halt conditions, so it became the responsibility of the code that set the showErrLabel flag to also set this string to some descriptive value. This way, any code anywhere in the object could halt the ticker and display whatever message was necessary.

Another minor addition to the original StockViewer was to the user interface. A simple AWT label indicated how much "money" was left in the purse, which was decremented per download. I implemented a progress meter for the decryption process, indicating what percentage of the received message has been decrypted so far into plain text.

As a note, I was disappointed with the color when the program was run on different monitors. I tried to make the labels appear white on dark grey, with the stock ticker being yellow on black. On some monitors, however, the dark grey appeared more light grey.

Here's the code for the run method, where most of my changes were made. I've removed debugging print statements. Throughout the following explanation of the code for the run method, all commentary appears before the code it is commenting on.

The JRMS multicast packages returns data in UDP packets, hence the DatagramPacket object.

public void
    run() {
        boolean        received;
        DatagramPacket recvPacket  = null;

This is the outer loop, out of which there is no break statement. This thread stays in this method until a System.exit(#):

while (true) {

This flag goes up when a UDP packet is successfully received:

received = false;

If the flag does not go up, the program continues to try the ms.receive() method, as shown below. The ms field is a multicast socket object. This code was unchanged from that in StockViewer.

try {
    recvPacket = ms.receive();
    received   = true;
} catch (SessionDoneException sd) {
} catch (SessionDownException sdwn) {
} catch (IrrecoverableDataException ie) {
} catch (JRMSException se) {
} catch (IOException e) {

Below, allReceivedBytes holds the entire string that is downloaded. blockToDecode is used to hold the n-byte segment that is being sent to the ring for decryption, where n equals maxdecodelength. (In the case of the Dallas Semiconductor Java Ring using our particular applet, n equals 60, but other card or token device systems might allow more or fewer than this number of bytes to be sent to the device at a time.) offsets essentially indicates how many n-byte segments must be sent to the ring to fully decrypt the message.

if (received) {  // UDP packet received with encrypted stock data
    waitingforscrolltofinish = true;
    byte[] allReceivedBytes;
    byte[] blockToDecode = new byte[maxdecodelength];
    int offsets;
    allReceivedBytes = recvPacket.getData();
    offsets = allReceivedBytes.length / maxdecodelength;
1 2 Page 1
Page 1 of 2