Sun Java Solaris Communities My SDN Account Join SDN
 
Article

MIDP Application Security 4: Encryption in MIDP

 
By Jonathan Knudsen, September 2005  

Download: [source code]

Computer applications use ciphers to protect sensitive information from theft. Encrypted data can be safely transmitted over an insecure network like the Internet. This article shows how encryption protects data from eavesdroppers, then presents a complete example that shows how to use the Bouncy Castle Cryptography APIs to encrypt messages sent between two MIDP devices.

For background on ciphers and encryption, read the first part of this series, Design Concepts and Cryptography.

Contents
 
Network Data Is Easily Stolen
HTTPS Almost Always Gets the Job Done
Bouncy Castle to the Rescue
Make Sure You Know What You're Doing
The Whisper Example
Key Management is Always a Bear
Building the Source Code
Summary
 
Network Data Is Easily Stolen

Data follows a complicated path from a MIDP device to an Internet server, a path that is full of opportunities for eavesdropping. The device itself broadcasts data on radio waves; the intended destination is a cell tower, but an eavesdropper with the proper equipment can pull the data out of the air. Once the data reaches the carrier's land wired network, it can be intercepted by equipment in that network. At some point the data passes from the carrier's land network into the Internet, where it travels through a variety of network equipment. At any point, the data is more or less available to anyone with the correct equipment and knowledge.

Interception tools are readily available. Ethereal, a protocol analyzer, can record all of the data transmitted on an Ethernet network. An eavesdropper with a laptop computer can use Ethereal to record data passing through various points in the Internet.

The following screen shot shows part of the data exchanged between a server and a browser. The highlighted portion shows how the data (an HTML page, in this case) is readily available.

Examining Passing Network Data
Examining Passing Network Data
(Click for the full image.)
HTTPS Almost Always Gets the Job Done

Most of the time, using an HTTPS connection in place of an HTTP connection provides adequate data security. The endpoints of the HTTPS connection agree on a session key that is used to encrypt the remainder of the conversation. After the initial handshake, all data is encrypted. Using Ethereal or a similar tool on an HTTPS connection isn't very useful:

Examining HTTPS Network Data
Examining HTTPS Network Data
(Click for the full image.)

The cryptographic services that HTTPS connections or TLS sockets provide are adequate for most applications. In some cases, however, you may need to provide your own encryption:

  • You may have an end-to-end encryption requirement that is not fully addressed by TLS's client-to-server protocol. For example, your application might need to encrypt data on the MIDlet client and decrypt it in a server component like an enterprise bean. HTTPS would provide encryption between the MIDlet client and the web server, but not between the server and the enterprise bean.

  • If your application data uses a network mechanism other than sockets or HTTP connections, you'll have to supply your own encryption. The example in this article encrypts data transmitted via the Short Message Service (SMS).

For more information on HTTPS and TLS, read Understanding SSL and TLS.

Bouncy Castle to the Rescue

Fortunately you don't have to implement cryptographic algorithms yourself. You can use the Bouncy Castle Cryptography APIs. The hard-working folks at Bouncy Castle provide implementations of many different cryptographic algorithms. There's even a lightweight package that's suitable for MIDP applications.

Using the Bouncy Castle APIs in a MIDP project is a little tricky. You'll need to use an obfuscator, both to reduce the size or your MIDlet suite and to rename some of the Bouncy Castle classes. For the full details, see Authentication in MIDP.

Make Sure You Know What You're Doing

Cryptography is tricky. The Bouncy Castle APIs give you a lot of power, but it's power that can be used well or poorly. It's surprising how easy it is to implement application security badly. If you think you can't wait to add cryptography to your own application, just take a deep breath and step back for a moment. If TLS will meet your needs, use it instead. TLS is a sophisticated and battle-tested protocol with a lot of power and flexibility. One of its biggest advantages is that developers can use it effectively without needing exhaustive cryptographic knowledge.

If TLS really won't do the job for you, then be sure you have a deep enough understanding of cryptography and security to build your own solution. Read lots of books and ask lots of questions. Have others review the system design and source code for security flaws.

The Whisper Example

The example code for this article is the Whisper example, a simple application that uses the Wireless Messaging API (WMA, JSR 120) to send and receive encrypted SMS binary messages.

Distributing keys is a little tricky, but I'll talk about that later. Right now I'll show you how to take the application for a test drive.

The following example was built from the available download and the Bouncy Casle Cryptographic package. Two separate MIDlet suites were built using the Wireless Toolkit, one suite for Fleur and another for Viktor. Fleur's MIDlet suite contains Viktor's name, address and key file. The name and address are contained in the JAD file as the property:

	Whisper-Peer-1: Viktor|5550000
and the JAR file contains Viktor's key in a resource named:
	Peer-5550000.key
Viktor's MIDlet suite is constructed in a similar fashion to contain Fleur's name, address and key file.

You need to run Viktor's MIDlet suite first, because his emulator needs to have the number 5550000. (This is the first number that will be assigned to the emulator when it is run, assuming you are using the toolkit's default settings.) Run Viktor's application by double-clicking on the descriptor file. After it's running, start up Fleur's, which should come up with the number 5550001.

The emulator asks you whether to allow the Whisper example to make network connections. Say yes to everything to continue.

The two emulators look much the same:

Running Two Copies of the Whisper Example
Running Two Copies of the Whisper Example

To send a message in either emulator, choose New. A pop-up screen lets you select a recipient (this simple demonstration provides only one). Enter your message and choose the Send command. Behind the scenes, the Whisper example encrypts your information and sends it as a binary SMS message. The copy of the Whisper example running on the other emulator descrypts and displays the message.

The Whisper example uses a Rijndael cipher with a 128-bit key. The Bouncy Castle APIs include several different implementations of Rijndael. I chose the one that's supposed to use the least memory, org.bouncycastle.crypto.engines.AESLightEngine. I wanted to be able to encrypt messages of any size without worrying about the size of cipher blocks, so I used cipher feedback (CFB) mode and wrapped the resulting object with a StreamCipher adapter:

AESLightEngine blockCipher = new AESLightEngine();
CFBBlockCipher cfbCipher   = new CFBBlockCipher(blockCipher,8);
StreamCipher streamCipher  = new StreamBlockCipher(cfbCipher);

After the cipher is initialized with the appropriate key, encrypting the message is easy (see SendTask.java in the source code download). To foil cryptanalysis, a random block of initialization data is prepended to the message itself to put the cipher into an unpredictable state.

// Create an IV of random data.
byte[] iv           = new byte[blockCipher.getBlockSize()];
mSecureRandom.nextBytes(iv);

// Concatenate the IV and the message.
byte[] messageBytes = mMessage.getBytes("UTF8");
int length          = messageBytes.length + blockCipher.getBlockSize();
byte[] plaintext    = new byte[length];
System.arraycopy(iv, 0, plaintext, 0, iv.length);
System.arraycopy(messageBytes, 0, plaintext, iv.length, messageBytes.length);

// Encrypt the plaintext.
byte[] ciphertext   = new byte[plaintext.length];
streamCipher.init(true, key);
streamCipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0);

On the receiving end, it's just as easy to decrypt the incoming message. See the run() method in WhisperMIDlet.java for details.

The Whisper example does not check the integrity of the transmitted data. If the ciphertext is modified as it passes through the network, it will decrypt into unreadable garbage. The recipient being able to read the message at all is an indication that the message is legitimate. If the Whisper example transmitted data a human could not validate, I'd use a checksum or message digest to check the integrity of the data.

Key Management is Always a Bear

The hard part in this application (and, indeed, any application that uses cryptography) is key management. The Whisper example makes things really easy for the user by building keys into the application itself--but that convenience comes at a cost.

The Whisper example is designed to be configured at deployment time for groups of two or more people. For this article, two versions of the Whisper example were created, one for Viktor, one for Fleur. To a Whisper example user, other users are peers. Peers are listed in the application descriptor by name and number. Viktor's application descriptor, contains a single entry that describes Fleur:

Whisper-Peer-1: Fleur|5550001

When Viktor's copy of the Whisper example initializes, it finds out about Fleur by examining the descriptor. Then it tries to load the key that will be used for communicating with Fleur from a resource file. In Viktor's MIDlet suite JAR, this file is Peer-5550001.key.

Fleur's copy of the Whisper example contains a corresponding entry and key for Viktor.

In the Whisper example, each key is owned, not by a single user, but by a pair of peers. Viktor and Fleur share a single key between them. When he writes a message to her, he uses this key to encrypt the message, and she uses the same key to decrypt it. If Luciano, Placido, and Jose wanted to use the Whisper example,

  • Luciano and Placido use Key 1.
  • Luciano and Jose use Key 2.
  • Placido and Jose use Key 3.

In cryptography terms, the keys are not true secret keys, but shared keys. If you want to use this application, you have to trust your peers to be careful about keeping their keys safe.

If I hoped to sell the Whisper example as a real application, I would set up a server with a simple web interface, where users could enter names and numbers and the server would generate keys and package up individualized versions of the Whisper example for each person.

Care must be taken in distributing the binaries because they include the keys. The normal distribution method for MIDlet suites is HTTP, which is not secure. An eavesdropper could easily extract the shared keys from the binaries as they were transmitted over the network, then use those keys to decrypt messages intercepted later.

One way to keep the keys safe would be to distribute the binaries using HTTPS. Another would be to use HTTP to download the binaries, but use HTTPS to download the keys to the Whisper example client seperately.

Building the Source Code

Building the Whisper example is very similar to building the example for the preceding article in this series. You'll need both the Ant build tool and the ProGuard obfuscator. If you want to create personalized versions of the Whisper example, as I did for Viktor and Fleur, you'll need to edit the descriptors yourself and make sure that the appropriate key files are present in the project's res directory.

If you'd like to generate new keys, that's easy enough too. All you need to do is write out random data to a file. Bear in mind that there's some subtlety to generating random data; for more information, see my own Java Cryptography or Bruce Schneier's comprehensive Applied Cryptography.

The Whisper example expects 128-bit keys (a 16-byte file) but you could modify the application to use 192-bit or 256-bit keys instead.

Summary

Computer applications need encryption to provide data confidentiality. Most applications will be able to use TLS or HTTPS for encryption, but in other cases you will need to provide your own implementation. Encryption is surprisingly easy, and surpisingly compact, if you use the Bouncy Castle APIs. The obfuscated Whisper example is only about 15 KB. The difficult part of the Whisper example is key management. A web application would simplify the configuration and distribution of the Whisper example.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.