My ENIGMAtic Java Ring

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

1 2 3 4 Page 3
Page 3 of 4
  • 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);
    }
Related:
1 2 3 4 Page 3
Page 3 of 4