My ENIGMAtic Java Ring

Using the model of an old wartime encryption machine, find out how to fashion your own secret encoder ring

For me, the highlight of the JavaOne Developer Conference in San Francisco last March was Dallas Semiconductor's iButton with Java -- aka the Java Ring, a wearable computer that ran Java. It allegedly had a high-performance encryption engine, an exciting prospect indeed, until I discovered that the encryption unit wasn't accessible on the ring. Dallas Semiconductor later confirmed that it couldn't be enabled at all, which really dampened my enthusiasm for the whole concept.

I am resourceful though, and since Dallas Semiconductor had promised that a fully functional Java Ring was going to be available eventually, all I needed to do was wait. And while I was waiting, what better to do but learn the ins and outs of programming my new piece of "smart" jewelry?

Of course this pursuit of knowledge did raise the question of what, exactly, I should program into my ring.

I pondered this question for a while, until I came up with what was, for me, the ideal solution: I would program my ring to simulate the most important piece of cryptographic equipment used in the second World War -- the German ENIGMA machine. The ENIGMA was used by German commanders to encrypt all of their important plans and orders to the field marshalls. But first I had to figure out what the heck an APDU was!

The Java Card applet model

The Java Ring is in fact a Java smart card, and the ring's virtual machine is based on the Java virtual machine (JVM) that was proposed as the Java Card 2.0 standard. I've seen some wonderful technical discussions on how to program these devices (see the Resources section for pointers), but, to be perfectly honest, the descriptions were quite opaque to me. I was looking for linkages between the JVM on the ring and the JVM on a PC and finding nothing beyond descriptions of a rather peculiar serial interface that connected them. I then realized that what really connected the ring to the "outside" world was not a serial port but a network protocol. Allow me to explain.

The Java Card architecture has taken client/server architectures to a new place -- one where the "server" is a small piece of software on an extremely small system, and the client is a potentially huge piece of software on a potentially much larger system. The network protocol is encapsulated in packets that are called application program data units, or APDUs for short.

Unlike packets in the TCP/IP world, these APDU packets don't carry any sort of addressing information. Instead, they are implicitly addressed to the computer on the other end of the serial link. However, like their big-brother packets in the TCP/IP world, APDUs do carry a few bytes that are common to all packets. These can be used by the smart card infrastructure to decide when to send the APDUs to the server on the smart card, and when to interpret them directly.

This understanding provided an answer to one of my first questions about the Java Ring: How come a broken applet doesn't make the ring unusable? The answer is that the smart card runtime code gets the first crack at decoding the APDUs as they arrive on the serial interface. Further, there are predefined APDUs that tell the runtime to select an applet, delete applets, load applets, and so on. Thus, errant applets are simply deleted by the developer once it's ascertained that they aren't responding correctly to the APDUs they receive.

The structure of a smart card applet then became clear: The applet sits in a virtual loop, like a network service waiting for packets to arrive on its network interface. The method that handles this loop is named process and is one of four required smart card applet methods. The other three are install, select, and deselect.

The install method must instantiate a new object that represents the applet. Like the main method in a Java application class, the install method is static so that it can be invoked by the smart card JVM before an object exists (it's invoked directly from the class definition).

In the simplest sense, the select and deselect methods tell the applet to either "get ready" or "go to sleep." Actually, the select method has the option of refusing to be selected. For example, a personal identification number (PIN) or some other authorizing information might need to be passed from the client program to the method (by way of the APDU) before the applet would allow itself to be selected.

The deselect method, on the other hand, doesn't have the ability to deny being deselected -- it provides more of a courtesy to the applet, telling it that it won't be getting any more packets. When a smart card is yanked from the reader before the client is finished, the deselect method isn't even called. The next thing the applet will see will be another invocation of select.

Missing from all of this was, in my mind, support of Java objects. I had hoped that in the APDU one could just dump an object or two and have them show up in the ring. But object support isn't part of the package. Instead you get a byte array that you can copy data into, send, receive, and then copy the data back out of. Not as sophisticated as I might hope, but it's still more than enough for my little encryption engine.

Substitution ciphers and the ENIGMA machine

After determining exactly what an APDU was and was not, I began to design the Java classes that would simulate an ENIGMA machine. Of course I first needed to figure out exactly how an ENIGMA machine worked, but that wasn't too difficult with the World Wide Web at my fingertips.

I surfed around and found pictures, a decent description of how it worked, a Java applet that was a pretty cool emulation of the machine, and even a patent relating to the machine (see Resources for links to these items). I found the patent to be particularly interesting because it was filed in 1944 but it didn't issue until 1976, over thirty years later! Curiously, 1976 is the same year that the U.S. Government officially adopted the Data Encryption Standard (DES) as its official encryption technology of choice. My guess is that the ENIGMA patent was classified as top secret until 1976, when the government stopped using cryptography based on the ENIGMA technology.

The basic algorithm behind the ENIGMA is known as a substitution cipher. A substitution cipher takes each input letter and substitutes a different letter for it. The resulting text looks like gibberish unless you know the secret substitution table that was originally used to scramble the message. This fact makes the ENIGMA a particularly good choice for my ringlet -- the secret decoder rings that we used to get in cereal boxes and Cracker Jacks-brand caramel popcorn were also based on substitution ciphers.

There are two kinds of simple substitution ciphers, algorithmic and mapping.

Algorithmic substitution cipher

In an algorithmic substitution cipher the "key" to the cipher is the algorithm. For example, an algorithmic cipher that has the key "Add 3" would operate as follows:

  • For each letter in the input message, substitute the letter that is three more letters along in the alphabet

  • If the letter is X, Y, or Z, then substitute the letters A, B, and C respectively

When the above cipher is used, the input message, HELLO BOB (this is called the message text) would be translated into the output message KHOOR ERE (called the cipher text). Unfortunately, algorithmic ciphers are pretty easy to decode even without the key, as there are very common letter patterns in the English language. Further, the "rules" associated with English spelling (such as the necessity of having a vowel in every word) and certain common single-character words make the letter relationships fairly apparent. To obscure the obvious relationship of the letters in the output message to the letters in the input message, the output message was often reformatted in a fixed pattern of character groups. Thus the output KHOOR ERE would be reformatted using four-letter groups to be KHOO RERE. The reformatting makes it less obvious where the words begin and end, but it means that the clerk decoding the message has to read it to figure out where to reinsert the spaces.

Another problem with algorithmic ciphers is their construction. The construction of an algorithmic substitution cipher requires that the key be just one algorithm. Once that algorithm is known for one letter, it's known for all letters. This can be used by an adept cryptanalyst who first counts all of the letters in the cipher text, notes the most commonly occurring letter, combines this with the knowledge that the letter E is the most commonly occurring letter in the English language, and then figures out through deduction what the relationship is between the most common character in the cipher text and the letter E. In short order, the algorithm is known and the cipher is broken. The message is then easily decoded.

Mapping substitution cipher

This brings me to the other type of substitution cipher, the mapping cipher. In a mapping cipher, a fixed relationship exists between input characters and output characters, but that relationship is held by a translation table rather than by using an algorithm. For example, let us assume your alphabet consisted of exactly seven letters -- A, B, C, D, E, F, and G -- and you set up a translation table as shown below.

Input characterABCDEFG
Output characterBGEDFCA
Table 1: Character substitution map

If you were to use the message text CAFE BABE and substitute the letters from the table, you would get the cipher text EBCF GBGF. This doesn't look all that different from the algorithmic cipher -- until the cryptanalyst tries to break the code. The advantage of using the table is that while the analyst could find the relationship between the message text letter E and the cipher text letter F using the same statistical method that I described above, that information wouldn't tell her the relationship between the message text letter B and the cipher text letter G. This property, the independence of the relationship between the letters of the message and the encrypted message, makes the mapping cipher stronger -- in the sense that it's harder to break than the algorithmic cipher.

Of course, neither form of these substitution ciphers is particularly strong in the face of a determined attack. And that brings us to the ENIGMA.

How the ENIGMA machine works

The user interface for the original ENIGMA machine consists of a keyboard with 26 keys inscribed with the 26 anglo-roman letters A through Z, and 26 lightbulbs behind transparent windows that are also inscribed with the letters A through Z. The ENIGMA operator presses a key, the ENIGMA machine performs its substitution, and a lightbulb under one of the characters illuminates. The code clerk then copies down the letter associated with the lightbulb and the next letter of the message is "typed." The process is repeated until all characters in the input message have been processed. The magic, of course, goes on inside the machine, which is where the rotors described in the patent come into play.

A rotor is simply a character-substitution map built into hardware. On one side of the rotor there are 26 contacts representing the 26 letters of the alphabet, and those 26 contacts are wired to 26 different contacts on the other side of the rotor. If the lamps had been connected to the 26 contacts on the other side of the rotor, that configuration would have been an implementation of a simple mapping cipher. However, instead of the lamps, the rotor's output connectors are connected to another rotor. The second rotor provides a second mapping. Then, that rotor is connected to yet a third rotor, providing three levels of substitution.

The third rotor in the series is connected to a special fourth rotor called the reflector. The reflector has two properties that make it unlike the other rotors in the system. First, it doesn't rotate (and I'll get to the rotation bit in a minute), and second, its substitution map is symmetric. A symmetric map is one in which the substitutions work bi-directionally. For example, in Table 1 above, the letter A maps to the letter B; however, the letter B does not map to the letter A. Thus, the mapping in Table 1 is asymmetric. In Table 2, shown below, I've created a symmetric mapping.

Input characterABCDEFGH
Output characterBAEGCHDF
Table 2: Symmetric character substitution map

If you look closely at Table 1, you'll notice that I also extended the alphabet in Table 2 by one character, to make the total number of characters even at 8. This extension was necessary because with an odd number of characters, one of the mappings won't be unique (the character will map to itself).

In the case of the ENIGMA, the reflector maps the incoming character to another character, and sends the signal back out to the three rotors -- this time traveling in the opposite direction. I drew a picture of this to illustrate what is happening, shown below in Figure 1.

The third rotor is connected to a reflector that sym- metrically maps the input character to an output character.

The reflector is also significant because in one step it converts the set's substitution from an asymmetric mapping to a symmetric mapping! Thus, if you were to input the letter D by typing it on the keyboard of the machine with the rotors shown in Figure 1, the machine would output the letter F by illuminating the lamp under the letter F. Then, if you typed the letter F on the keyboard, it would illuminate the lamp under the letter D. This means you need only one arrangement of the rotors, which becomes the key, to encrypt a message. That same setting of the rotors will take an encrypted message and output the original message. Of course, the story isn't over quite yet.

With this arrangement of three rotors and a reflector, the input character would undergo seven remappings (three inbound, reflection, and then three outbound) before a lamp was illuminated. However, assuming the substitutions remained the same for every character, even if a character went through ten thousand mappings, the end result would be a simple substitution cipher. This is where the rotating part enters the picture.

As their name implies, one or more of the ENIGMA rotors rotate during the encryption process. When a rotor is rotated by one position, all of the characters in that rotor's character map are shifted by one position. I've created an example of this in Table 3 below.

Input characterABCDEFG
Before rotationBGEDFCA
After rotationABGEDFC
Table 3: The effect of rotation on the character substitution map

In the above table, the rotation has shifted the character map by one position such that the input letter C would map to the letter E before the rotation, but to the letter G after the rotation.

Each ENIGMA rotor has a notch on it that causes the next rotor in the series to move by one position whenever the notch passes by the index character.

The effect of this rotation is that after each character is encrypted, an entirely new character map is used to map the next character. This makes the ENIGMA a composite of both an algorithmic substitution cipher and a mapping substitution cipher. Each character in the output message has its own map associated with it, and because the rotors are moved with each character, the character mapping depends on not only the character value, but its position in the input message as well. This combination makes the ENIGMA cipher much stronger than a simple substitution cipher.

To make the ENIGMA cipher even stronger, the Germans issued their code clerks a total of eight separate rotors, each with its own character mapping. When a message was to be encrypted, the key consisted of the numbers the three rotors should use and the initial rotor position for the selected rotors. No amount of simple cryptanalysis would reveal the message hidden by ENIGMA. The weakness of the ENIGMA was that the rotors were fixed and limited in number. Once the allies had stolen a couple of ENIGMA machines and had a full set of rotors, cracking the code became a matter of trying different combinations of the available rotors until the correct ones were found. Nonetheless, the ENIGMA's clever design was the basis of the strongest level of encryption available for many years after the war ended.

Building an ENIGMA machine in Java

The mechanical design of the ENIGMA machine lends itself to creating an object-oriented version of it in software. The modular nature of rotors connected to each other in series suggests that a good starting point in the design would be to simulate rotors as objects and the ENIGMA machine as an object. The behavior of the rotors is described well -- so the design process will start with the design of a Rotor class.

Rotor design and implementation

Each rotor in the ENIGMA machine is an implementation, in hardware, of a translation table for 26 characters. The rotor consisted of 26 contacts representing the 26 letters, which are wired internally to 26 output contacts that represent the translated characters. Of course, with the rotor limited to 26 characters, there were some difficulties with the messages that were encrypted with the machine.

The design of the original ENIGMA required the person who was using it to decode a message to reformat the text once it was decoded back into individual words. Further, all of the characters were represented as uppercase. Of course, in my ringlet version I didn't want to have to reinsert the spaces, nor recover the original type case of the message, so I decided to "improve" things a bit and have my Rotor class contain both uppercase and lowercase characters, as well as numbers and some punctuation.

The decision to widen the character set led to another problem -- that of generality. Do I limit the character set and only get messages through that contain English, or do I use the full ISO Latin 1 character set, thus enabling encryption of a wider variety of messages? The solution to this problem appeared somewhat unexpectedly in the character set I had chosen initially for my test case. When I initially prototyped my Rotor class, I had the character set defined as follows:

     static final char char_set[] = {
    'A', 'B', 'C', 'D', 'E', 'F', 'G'. 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ' ', '.', '!',
    '?', ',', '(', ')' };

Now, there isn't anything special about the code above; it's a basic character array. However, the code was nearly identical to some I had put in a class to encode mail messages.

The current Internet standard for mail messages is called MIME. The MIME protocol contains a specification for encoding messages that have non-ASCII data, which is called BASE64 encoding. The encoding protocol uses 64 characters to represent binary data. The protocol works by specifying a 6-bit pattern of binary digits to each character. Streams of 8-bit octets (bytes) are specified by using a series of characters. It sounds complicated but it really isn't.

BASE64 encoding solved the problem of how to encode arbitrarily complex data so that it could be sent through an electronic mail system with a limited number of characters. This was the same problem I wanted to solve with my ENIGMA simulator, except that in my case the limited character set was in my rotors. BASE64 encoding would give me a way to encrypt arbitrary messages with my ring. My rotors then became BASE64-based rotors.

With the character set issue decided, I began to build my Rotor class. My first pass at code to encrypt characters is shown below.

// An array to map an input character to a value between 0 and 63 static char char_map[] = {'A', 'B', 'C', 'D', 'E', ... '+', '/'};

// An array of 64 characters in the rotor map char rotor_data[] = { 'Z', 'Q', 'E', 'D', ... ')' };

char encrypt(char a) { int index; for (int i = 0; i < 64; i++) { if (char_map[i] == a) { index = i; break; } } if (next_rotor != null) return next_rotor.encrypt(rotor_data[index]); return rotor_data[index]; }

The code above raised a couple of issues. The first was that the iButton with Java is not very fast, and there was a lot of looping going on. The second issue was that the storage for the character arrays was larger than it needed to be. Instead of 64 bytes, I was using what appeared to be 128 bytes per array, with three rotors and a character map, all which added up to .75 KB just for the rotor data! That was more than 10 percent of the 6.5 KB of space available on the ring.

So I started looking for ways to tighten up the code in order to reduce time and minimize the space required. My thought was to use a String object to hold the rotor data. The advantages of a String object are that the implementation can be optimized for the platform, and there are two methods indexOf and charAt that would let me get to the individual characters and the character's position in the string. Unfortunately, I found out that the Java Card specification doesn't include String in its base class set!

The lack of a String class left me with only one option, which was to use byte arrays. So the Rotor class implements a method, indexOf, that does what String's method does.

The final implementation of the Rotor class is available in the Resources below, but let's look at a the more salient methods from the class.

The first method was an implementation of indexOf, which does what the same method in String does. It's shown below.

   
    private short indexOf(byte v[], byte b) {
        for (short i = 0; i < v.length; i++) {
            if (b == v[i]) return i;
        }
        return 0;
    }

As you can see in the code above, the method indexOf scans a byte array for a given byte. If the routine finds the matching byte, it returns the index of that byte in the passed-in array. If the byte isn't found, the routine returns 0.

Originally, I hadn't intended to return 0. I initially designed the routine to return -1, which is an invalid array index. When I went to debug the code, I found that I had a lot of problems, so I changed it to return a valid index instead.

The next routine implements the reflector mechanism in the rotor.

    
    byte reflect(byte c) {
        short xi;
        xi = indexOf(char_map, c);
        return (reflector[xi]);
    }

The first step maps the character passed in as byte c into an index between 0 and 63. This represents the character code as defined by the BASE64 character set. The next step returns the reflected character from a byte array named reflector. The next two methods implement the forward character translation and the reverse character translation functions of the rotor.

    
    byte reverse(byte c) {
        byte x;
        short xi;
        xi = indexOf(contents, c);
        return (char_map[(xi-index)&0x3f]);
    }
    byte forward(byte c) {
        short xi;
        xi = indexOf(char_map, c);
        return (contents[(xi + index) & 0x3f]);
    }

Both methods accomplish the same mapping from the input character to the BASE64 character value. The next step maps from the contents array instead of from the reflector array. The contents array contains the rotor's character mapping, which defines the encrypting table for the current rotor. Further, the method doesn't use a simple one-to-one mapping; instead it combines the resulting character code with a variable named index, which indicates how many times the rotor has been rotated. Finally, the computed character array is masked with the hex constant 0x3f. This forces the value to be between 0 and 63.

The final method of interest in the Rotor class is the rotate method. This method adjusts the index variable in the Rotor object and then, if the index value is equal to the notch value, the rotate method of the next rotor in the link list is invoked. This is shown in the code below.

   
    public void rotate() {
        if (notch == 0)
            return;
        index = (short)((index + 1) & 0x3f);
        if ((index % notch == 0) && (next != null)) {
            next.rotate();
        }
    }

The variable notch indicates when the rotor should rotate. The Rotor class contains pointers that form a linked list of rotors. When the rotate method is invoked, the variable index is incremented, and if it matches the notch value, the next rotor in the linked list also is rotated.

Finally, in the Rotor class, there are two arrays of bytes -- one named char_map and one named reflector. Originally, I had initialized them with static initializer code, as shown below.

    static byte char_map[] = {
      'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
      'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
      'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
      'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
    };

The above code was the single biggest headache of the whole design. While it's perfectly legal Java code, I discovered after a lot of debugging that the static initialization of the Rotor class wasn't actually running when my ring applet was loaded. That meant that attempting to access these arrays resulted in ArrayIndexOutOfBoundsException.

Of course, it took many hours of debugging to figure out this problem. What I needed to do then was to manually initialize these arrays -- a major pain. The final class has a method InitCharMap, which is full of lines like

    char_map[0] = 'A';
    char_map[1] = 'B';
    ...
    char_map[63] = '/';

It isn't very good looking but it does get the job done. With the Rotor class designed and working, I then turned to designing the main Enigma class.

Enigma design and implementation

The actual ENIGMA machine provided slots for the rotors it was using to encrypt a message. My Enigma class would contain object references for the Rotor objects in the simulated machine. Further, the Enigma class is the actual ring applet. Therefore, like the applets you would run in a browser, the Enigma class is a subclass of Applet. However, unlike a browser applet, the class is a subclass of javacard.framework.Applet.

The Java Card applets communicate with the client applications on your computer via those APDUs I discussed earlier. Further, the contents of those APDUs have to be defined by you, the programmer. Fortunately, for something like the ENIGMA machine simulator they don't have to be too complicated.

The ADPU has four bytes that are passed to your applet in the APDU header. These are labeled the Class, Instruction, Parameter1, and Parameter2 bytes. For the Enigma class I use only the Class and Instruction bytes. They have been defined as follows:

  • Class 0x85 -- This is the constant I used to identify the APDU as being targeted for my applet

  • Instructions:
    • 0x01 Key -- This instruction tells the applet to set the current key
    • 0x02 Reset -- This instruction tells the applet to reset the rotors to the current key
    • 0x03 Encrypt -- This instruction tells the applet to encrypt the passed-in bytes using the rotors

The actual code for the applet is pretty trivial. The three methods that you must provide are install, select, and process. I'll cover them in that order.

The install method is shown below.

   
    public Enigma() {
        r1 = new Rotor((short) 13, rotor1);
        r2 = new Rotor(r1, (short) 7, rotor2);
        r3 = new Rotor(r2, (short) 3, rotor3);
        register();
    }
    public static void install(APDU apdu) {
        new Enigma();
    }

As you can see, the install method is static to allow it to be invoked directly from the class. This fills the same role as the main method in a Java application. The only requirements on the install method in the Enigma class are that it create an instance of the Enigma class and register it with the ring's firmware.

Within the constructor method for the Enigma class, the rotors are created and linked, and the very important call to register is made. The register method registers the object that was just instantiated with the ring's internal housekeeping code so that you can select it later. In my first version of the Enigma class I forgot to invoke register and nothing worked!

The second method is select, which is even easier; it simply returns true, as shown below.

   
    public boolean select(APDU apdu) {
        return true;
    }

The reason this method is so simple is because it isn't processing the APDU that is passed. In some applets you might include in the APDU a PIN or perhaps some data that was pertinent to the current invocation of the applet. For the Enigma applet, the only required information is the ENIGMA key, and that is set with the process method.

The final and most complicated method is process, shown here:

public void process(APDU apdu) throws ISOException { byte buffer[] = apdu.getBuffer();

// process is called on applet selection but we don't do anything in this applet if ((buffer[ISO.OFFSET_CLA] == SELECT_CLA) && (buffer[ISO.OFFSET_INS] == SELECT_INS)) return;

if (buffer[ISO.OFFSET_CLA] != EN_CLA) { error(apdu, (short)0x1000); return; }

switch (buffer[ISO.OFFSET_INS]) { default: error(apdu, (short)0x1001); return; case EN_INS_KEY: setKey(apdu); break; case EN_INS_RESET: rotorReset(apdu); break; case EN_INS_ENCRYPT: encrypt(apdu); break; } }

As you can see from the code above, the process method is the main point where the calls to the applet are received, identified, and then dispatched.

Within the method body, the first if statement checks to see if the applet was just selected. The ring will call the select method of the applet and then it will call process with the Class and Instruction bytes of the APDU set to indicate a selection message. In this version of process, the message is ignored; you could use it, however, to initialize variables to some initial state, or do other preparatory steps if you needed to.

The second if statement verifies that the Class byte sent to the applet is the hex constant 0x85. This is a safety check to make sure that the client code is creating correctly formatted APDUs. If the applet were revised you could also update the Class byte so that the applet could support "old" clients that used the old Class byte value and "new" clients that used the current value. As long as the Class byte is less than 0xD0, the ring's virtual machine leaves it alone and just passes it along to the applet. If the Class byte value is 0xD0 or greater, it is interpreted by the ring firmware as a command byte.

Finally, the applet uses a switch statement to invoke the appropriate method for a particular APDU. The complete source for this is in the Resources section below. To give you a feel for these methods, however, I'll cover the most complicated one, encrypt.

Processing APDUs is fairly simple: The code first reads any data that was passed in with the APDU, then does whatever it's supposed to do, and finally, optionally, writes data out and sends it back to the client. Network programmers will recognize this sequence as being very similar to that of a remote procedure call. Of course you have the option of using the Parameter1 (p1) and Parameter2 (p2) bytes to send your data as well. If the required data can fit within two bytes, this is an excellent choice.

While debugging this code I discovered that the response code 0x6f00 indicated that the JVM of the ring had thrown an exception that wasn't caught. Later, I deduced that the data value 8 indicated an ArrayOutOfBoundsException. Unfortunately, I couldn't find this documented anywhere.

The encrypt method's code is shown below.

    
    private byte buf[];
    void encrypt(APDU apdu) throws ISOException {
        byte b[] = apdu.getBuffer();
        byte c;
        short bytesRead = apdu.setIncomingAndReceive();
        short len;
        if ((buf == null) || (buf.length < bytesRead)) {
            buf = new byte[bytesRead];
        } 
        len = bytesRead;
        for (int i = 0; i < len; i++) {
            r3.rotate();
            c = b[ISO.OFFSET_CDATA+i];
            c = r3.forward(c);
            c = r2.forward(c);
            c = r1.forward(c);
            c = r1.reflect(c);
            c = r1.reverse(c);
            c = r2.reverse(c);
            c = r3.reverse(c);
            buf[i] = c;
        }
        apdu.setOutgoing();
        apdu.sendBytesLong(buf, (short) 0, len);
    }

The first thing the method does is get a reference to the byte buffer from the APDU, using the APDU method getBuffer. The getBuffer method returns the raw byte buffer from the APDU, allowing this method in the applet to inspect the Instruction and Parameter bytes. Since the process method already has verified that the Class and Instruction bytes are correct, this method simply gets the number of bytes to be encrypted using the setIncomingAndReceive method of APDU, and then encrypts them one byte at a time. It is important to note that the value returned from getBuffer method may be less than the total length of the array. Thus, while you may think that the following two ways of determining length are equivalent, they're not.

    byte b[] = apdu.getBuffer();
    len1 = b.length; // this returns you the length of the buffer being used.
    len2 = apdu.setIncomingAndReceive(); // this gives you the data length.

In the above code, len1 contains the length of the buffer the ring is using at the moment to communicate with the client, whereas on the third line, where len2 is initialized, the number represents the actual number of data bytes in the APDU packet.

After fetching the data from the APDU, the encrypt method implements the ENIGMA encryption loop. This code simulates the "wiring" of the ENIGMA. The first step is to rotate the rotors, which insures a fresh substitution sequence for the character that is to be encrypted.

In what is logically the next step, each rotor is invoked with the byte to encrypt. This loop was originally a recursive call in the Rotor class. However, I encountered problems and thought perhaps my code was exceeding the ring's available stack space, so I rewrote the code to not be recursive. Instead, it takes the output of each operation and passes it on to the next, until all rotors have processed the byte. Once complete, the byte is placed in a buffer to be sent back to the client.

In the final step, the results are sent back to the client using the APDU method sendBytesLong.

Compiling and debugging

This project was quite successful in teaching me a lot of things about my Java Ring. First and foremost, it taught me that it's extremely difficult to debug a problem with no support for strings, and using only a serial port. Every error message had to be a number, and every number had to be remembered throughout the debug operation. But even before I could debug my applet, I had to learn how to get it compiled and loaded into the ring.

I compiled all of my code on a Windows 95 machine, using version .09 of the Java iButtons (JiB) kit (see Resources for a link to this version from Dallas Semiconductor). The README.TXT file explains that you have to put several jar files into your classpath. What the file doesn't tell you is that you'll also have to increase the environment space you give to an MS-DOS window. The environment space setting is under the Memory tab in the MS-DOS command-prompt properties. I changed the environment size from Auto to 4096.

I then wrote a simple BAT file to configure my classpath environment variable. Finally, I added the Sun 1.1.5 version of the Java JDK into my command path. Once that was done, I compiled my ring code using javac and converted it with the Java application BuildJiBlet. It didn't work.

What I found was that it wasn't that simple. The core classes (like Object) for the smart card version of Java were different than the core classes for the JDK version of Java. Of course javac, the Java compiler in the JDK, is just a Java class -- so it simply invokes Java when it's run. Thus, if I set my classpath to search the smart card classes first, the compiler didn't work! The solution was to use the very specialized compile line for javac shown below:

javac -classpath <a href="C:\Jib\Examples\Classes">C:\Jib\Examples\Classes</a> Enigma.Java Rotor.Java

As you can see, this command explicitly calls out the classes that javac is supposed to use when compiling, but the compiler itself uses classes from your classpath. Because you're specifying the classpath, you either have to include the current directory in the classpath, or you have to specify all the classes you want compiled on the command line. I chose the latter option.

With my compilation problem solved, I used the command line below -- called a jiblet -- to convert my class files into the format recognized by the ring.

java BuildJiBlet . Enigma.jib javaone.jibdb

The syntax tells the BuildJiBlet application to take classes from the current directory (specified as .), put them into the file Enigma.jib, and use the database javaone.jibdb for assembly. The most startling thing about this Java application is how verbose it is. The application will output what appears to be the same output from the javap command.

All of the bytecodes that go into making your jiblet show up here. When the command completes, it reports that about 3,500 bytes have been written out. This is more than half of the ring's memory for just a couple of Java classes!

I haven't yet taken the time to reduce this. However, the wonderful support staff at Dallas Semiconductor pointed out that my initialization of the arrays was producing nearly 1,900 bytes of class file -- so over half of this size is due to that code. Thus, you could cut down on code size considerably by adding a couple of methods to the Enigma applet to load rotor data and reflector data using APDUs instead.

Finally, it was time to load my new ring applet into my Java Ring. This is done using another Java application named apduSender. This application takes a single parameter, which is the port where the blueDot reader is attached. For my setup, I used the java apduSender COM2 command to invoke the apduSender application.

This brings up a simple GUI application that can send any command to the ring. For loading the applet, first I would invoke master erase to clear the ring of all loaded applets.

After clearing the ring I would use "load jiblet" from the File menu to load in a copy of the Enigma.jib file.

Once the applet successfully loads -- and be aware that it takes on the order of 15 to 20 seconds to do so -- the applet is already selected. You can verify that it loaded by using the "getFreeRam" command in the apduSender GUI. If that number hasn't gone down (it will be 0x1300 for an empty ring), you haven't actually loaded your applet.

It was at this point that I really began to suffer the consequences of a limited debugging environment. My first bug wasn't invoking register in the Enigma constructor. This made it impossible to select my applet. The folks at Dallas Semiconductor pointed that one out to me. The next problem was that throwing ISOException in my code crashed the ring.

Yes, even though the sample code showed code fragments like the one that follows, whenever I threw the exception, the ring would stop talking to the apduSender application.

   
if (class != EN_CLA)
throw new ISOException(ISO.CLASS_NOT_SUPPORTED);

This drove me nuts, so I wrote my own error method in the Enigma class, as shown next.

    
    byte test[];
    private void error(APDU apdu, short err) {
        if (test == null)
            test = new byte[5];
        test[0] = (byte) 'E';
        test[1] = (byte) (((err >> 12) & 0xf) + '0');
        if (test[1] > '9') test[1] += 7;
        test[2] = (byte) (((err >> 8) & 0xf) + '0');
        if (test[2] > '9') test[2] += 7;
        test[3] = (byte) (((err >> 4) & 0xf) + '0');
        if (test[3] > '9') test[3] += 7;
        test[4] = (byte) ((err & 0xf) + '0');
        if (test[4] > '9') test[4] += 7;
        apdu.setOutgoing();
        apdu.sendBytesLong(test, (short) 0, (short) test.length);
    }

The error method would take an error number and return a five-character string of the form "Exxxx" where xxxx was replaced with the error number. I could then use error numbers like 0x1000 to 0x1ffff for initialization, 0x2000 to 0x2fff for method invocations, and so on. This code gave me a way to communicate back to myself as to where I had arrived in the execution of the ring applet.

I then began to throw in invocations of the error method to see how far my code had progressed before it hung. I determined that the ISOExceptions were a source of trouble, so I removed them in favor of invocations of my error method. Then I discovered that the results of the encryption were always wrong, and that led me to find out that the initializer in Rotor was not being called. Finally, after all this, I got my first successful encryption and decryption and raised quite a cheer.

Using the Enigma applet

Once you've successfully loaded the Enigma applet, you can use it with the apduSender application. In the future I'll write a nicer client applet to talk to the Enigma applet.

The first step is to select the applet. To select the Enigma applet, you use the Select option in the apduSender application. When the application prompts for the applet to select, enter the string Enigma.

Next, set the key. This can be done by either setting a new key, or resetting the Enigma to the previously set key. To set a new key in the apduSender application, use the process option to bring up a screen that has a form containing the parts of an APDU. Fill in the Class byte with 85 and the Instruction byte with 01. To set a new key in the text box, type in a three-character string. To reset the key to the last key set, fill in the Class byte with 85 and the Instruction byte with 02.

Finally, to encrypt a message, use the process command of apduSender and set the Class byte to 85 and the Instruction byte to 03. Type in the message to encrypt as a string in the text box. Remember that this is a BASE64 string, so you have a limited character set available. Uppercase and lowercase characters are available, but space is not. My first test message was HelloWorld. You'll notice that it takes a bit of time to encrypt the message.

Decrypting a message is identical to encrypting one: select the applet, set or reset the key, and type in the encrypted message. The decrypted message will be output as the result.

Wrapping up

The Java Ring makes an excellent host for my ENIGMA simulation classes. With the ENIGMA classes, this high-tech equivalent of a secret decoder ring is capable of encrypting and decrypting "secret" messages. Further, the ENIGMA algorithm is strong enough that it can't be casually cryptanalyzed. And the key used to encrypt and decrypt the messages never needs to leave the ring, which adds a good deal of security to the system.

This project also served as the motivation I needed to sit down and really program the ring. I find I rarely learn systems well until I use them to accomplish some task.

As I mentioned at the beginning of the article, the ENIGMA algorithm is no longer considered to be weapons grade cryptography. It does provide a good introduction to cryptography, however, and should be studied as part of any serious effort to learn about cryptographic systems. When the next version of the iButton is released, it's expected to support the built-in RSA crypto hardware, which will enable the ring to use much stronger algorithms.

The algorithm I've used can be strengthened by increasing the number of rotors, and by making the rotor material downloadable. Because the definition of the "keying material" for any encryption system includes any data that can be changed from one use of the system to the next, if you do decide to modify the Enigma class to make the rotor data downloadable, the rotor data effectively becomes part of the key itself. If you read the paper referenced below on the efforts to decrypt ENIGMA messages, however, you will see that the simple substitution aspects of the algorithm doomed it to eventual failure. Modern cryptographic systems such as DES, IDEA, and Blowfish are entirely algorithm-based, using mathematical techniques to effectively scramble the data and hide it from prying eyes.

If you have a Java Ring, I encourage you to try out this applet and take the time to understand and modify it. This will give you a better feel for what these rings can and cannot do. Of course, a piece of jewelry that doubles as a privacy protector is also a great conversation piece. In future columns I'll be looking at other applications of the Java Card technology and will design a couple of user interfaces as well.

Chuck McManis currently is a distinguished engineer at FreeGate Corp., a venture-funded startup that is exploring opportunities in the Internet marketplace. Before joining FreeGate, Chuck was a member of the Java Group. He joined the Java Group just after the formation of FirstPerson Inc. and was a member of the portable OS group (the group responsible for the OS portion of Java). Later, when FirstPerson was dissolved, he stayed with the group through the development of the alpha and beta versions of the Java platform. He created the first "all-Java" home page on the Internet when he did the programming for the Java version of the Sun home page in May 1995. He also developed a cryptographic library for Java and versions of the Java class loader that could screen classes based on digital signatures. Before joining FirstPerson, Chuck worked in the operating systems area of SunSoft, developing networking applications. There, he did the initial design of NIS+. Check out his home page.

Learn more about this topic

  • Enigma.java is the ENIGMA applet http://www.javaworld.com/jw-08-1998/indepth/Enigma.java
  • Rotor.java is the implementation of an ENIGMA rotor http://www.javaworld.com/jw-08-1998/indepth/Rotor.java
  • Home page for the Dallas Semiconductor iButton http://www.ibutton.com
  • Pictures of the ENIGMA machine http://www.math.arizona.edu/~dsl/ephotos.htm
  • More pictures of the ENIGMA machine http://cs.oberlin.edu/classes/cs115/lect30n.html
  • A nice description of the ENIGMA machine http://www.math.arizona.edu/~dsl/enigma.htm
  • Another good description of the ENIGMA machine http://www.trincoll.edu/~cpsc/cryptography/enigma.html
  • Java applet that emulates the ENIGMA machine http://www.attlabs.att.co.uk/andyc/enigma/enigma_j.html
  • Patent for the ENIGMA machine http://www.patents.ibm.com/details?patent_number=3984922
  • Breaking the ENIGMA algorithm and decrypting messages that are ENIGMA encrypted http://www.cs.miami.edu/~harald/enigma/enigma.html
  • A description of many modern cryptographic algorithms http://www.mach5.com/crypto/algorithms.html
  • Previous Java In Depth articles http://www.javaworld.com/topicalindex/jw-ti-indepth.html
Join the discussion
Be the first to comment on this article. Our Commenting Policies