Contents Previous Next Index

Chapter   6

The SATSA-CRYPTO Optional Package


The SATSA-CRYPTO Optional Package allows applications to use cryptographic tools like message digests, digital signatures, and ciphers. These tools give applications the ability to support commerce, safeguard information, and protect privacy.

SATSA-CRYPTO is a subset of the J2SE platform Java Cryptography Extension (JCE). For more information on JCE, see http://java.sun.com/products/jce/.

This chapter describes how to use SATSA-CRYPTO from your own applications. It is not a comprehensive tutorial on cryptographic concepts, although it does include some introductory explanations. For a more detailed introduction to the concepts, read this article:

MIDP Application Security 1: Design Concerns and Cryptography
http://developers.sun.com/techtopics/mobility/midp/articles/security1/

For deeper coverage, try Bruce Schneier’s excellent Applied Cryptography (Wiley, 1995).

SATSA-CRYPTO provides an API for three cryptographic tools:

The classes and interfaces of SATSA-CRYPTO are located in the same packages as the J2SE platform JCE: java.security, java.security.spec, javax.crypto, and javax.crypto.spec.

Using Ciphers

A cipher is useful for keeping data secret. The cipher takes regular data, the plaintext, and converts it into an unreadable form, called ciphertext. This process is encryption. The cipher can also decrypt ciphertext to restore the original plaintext.

A cipher is valuable because you can encrypt sensitive information, like credit card numbers or your Aunt May’s medical records. As ciphertext, the data can be safely transmitted over an insecure medium like the Internet. At the receiving end, you can use the cipher to decrypt the ciphertext and retrieve the original information.

Cryptographic ciphers use keys to make unique ciphertext. Only the same key, or a matching key, will decrypt the ciphertext and restore the plaintext. A symmetric cipher uses the same key for encryption and decryption. An asymmetric cipher uses one key for encryption and a matched key for decryption. The matched set of keys is called a key pair. One key in a key pair, the public key, can be freely distributed and used by other parties for verification. The other part of the key pair, the private key, must be kept secret.

Ciphers use a mathematical algorithm to encrypt and decrypt data. Some of the widely known cipher algorithms are AES, DES, and RC4.

Streams, Blocks, Padding, and Modes

A stream cipher encrypts one byte at a time. A block cipher encrypts a block of bytes in a single operation.

Because plaintext is not always an even multiple of the block size, padding may be added to the plaintext. Padding is extra bytes of data that fill up the empty space in a block. Several standard padding schemes describe what values are placed in the padding bytes.

Block ciphers can operate in different modes. A mode describes exactly how plaintext is transformed into ciphertext and back again. In the simplest mode, each block of plaintext is encrypted to one block of ciphertext. More complicated modes use some combination of the current plaintext block and previous ciphertext as the input to the cipher. Some modes require an initialization vector, which is combined with the very first block of plaintext as input to the cipher.

Working with Keys

Cryptography is based on mathematics. In essence, keys are numbers that are used in cryptographic algorithms. Different algorithms use different kinds of keys.

SATSA-CRYPTO provides three ways to think about a key:

Keys are typically stored in encoded form on some form of persistent storage. At runtime, the application loads a key as a byte array, then converts it into a key object that can be used with the rest of the API.

The way you convert byte stream representations of keys to key objects depends on the type of key.

For symmetric cipher keys, you can create an implementation of KeySpec using a byte array. If the KeySpec class implements the Key interface, the object can be used directly as a key. For example, the SecretKeySpec class can be used to create DES keys from byte arrays.

For asymmetric keys, a public key can be extracted by constructing a KeySpec implementation from a byte array. Then you can use a KeyFactory object to extract the public key from the KeySpec. An example later in this chapter illustrates the technique.

Using Ciphers in SATSA-CRYPTO

SATSA-CRYPTO encapsulates cryptographic ciphers in the javax.crypto.Cipher class. Cipher is surprisingly easy to use:

  1. Create a Cipher instance for the algorithm you want to use. You can also specify a mode and a padding scheme in this step.
  2. Initialize the Cipher with a key and a flag that indicates whether the Cipher will be encrypting or decrypting.
  3. Feed data to the Cipher using the update() method.
  4. Send the last data to the Cipher with the doFinal() method.

Rather than instantiate a Cipher directly, use a factory method, getInstance(), to request an instance that corresponds to a particular algorithm. Pass getInstance() an algorithm name or a combination of an algorithm name, mode, and padding. If the underlying implementation has a matching implementation, a new Cipher object is created and returned. Otherwise, a NoSuchAlgorithmException is thrown.

The following example demonstrates several of these techniques.

It begins by constructing a DES secret key from a byte array using a SecretKeySpec. It creates a Cipher based on the DES algorithm in Electronic Code Book (ECB) mode, with no padding. The cipher is initialized for encryption using the secret key. Finally, this example encrypts a small plaintext message. For a complete example that uses SATSA-CRYPTO, see Appendix D.

byte[] keyBits = { 
  (byte) 0x2b, (byte) 0x7e, (byte) 0x15, (byte) 0x16, 
  (byte) 0x28, (byte) 0xae, (byte) 0xd2, (byte) 0xa6 
}; 
byte[] plaintext = { 
  (byte)0x01, (byte)0x23, (byte)0x45,  
  (byte)0x67, (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef 
}; 
byte[] ciphertext = new byte[8]; 
 
SecretKeySpec key = new SecretKeySpec(keyBits, 0, keyBits.length, 
    "DES"); 
Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding"); 
cipher.init(Cipher.ENCRYPT_MODE, key); 
int count = cipher.doFinal(plaintext, 0, plaintext.length, 
    ciphertext, 0); 

The next example is slightly more complicated. It uses a DES cipher in Cipher Block Chaining (CBC) mode, in which the previous block of ciphertext is combined with the current block of plaintext before encryption. For the first block of plaintext, there is no previous ciphertext block, so an initialization vector is needed. This example demonstrates how to use IvParameterSpec to pass an initialization vector to a Cipher using one of its init() methods.

byte[] keyBits = { 
  (byte)0x2b, (byte)0x7e, (byte)0x15, (byte)0x16, 
  (byte)0x28, (byte)0xae, (byte)0xd2, (byte)0xa6 
}; 
byte[] ivBits =  { 
  (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04, 
  (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08 
}; 
byte[] plaintext = { 
  (byte)0x01, (byte)0x23, (byte)0x45,  
  (byte)0x67, (byte)0x89, (byte)0xab, (byte)0xcd, (byte)0xef 
}; 
byte[] ciphertext = new byte[8]; 
 
SecretKeySpec key = new SecretKeySpec(keyBits, 0, keyBits.length, 
    "DES"); 
IvParameterSpec iv = new IvParameterSpec(ivBits, 0, ivBits.length); 
Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding"); 
cipher.init(Cipher.ENCRYPT_MODE, key, iv); 
int count = cipher.doFinal(plaintext, 0, plaintext.length, 
    ciphertext, 0); 

The final example shows how to encrypt data using the public key of an RSA key pair. It demonstrates the use of the KeyFactory class to extract a public key from an encoded representation.

byte[] publicKeyBits; 
// Assign publicKeyBits here. 
byte[] plaintext = "This is just an example".getBytes(); 
byte[] ciphertext = new byte[128]; 
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBits); 
KeyFactory kf = KeyFactory.getInstance("RSA"); 
PublicKey publicKey = keyFactory.generatePublic(keySpec); 
Cipher cipher = Cipher.getInstance("RSA"); 
cipher.init(Cipher.ENCRYPT_MODE, publicKey); 
int count = cipher.doFinal(plaintext, 0, plaintext.length, 
    ciphertext, 0); 

Message Digests and Signatures

A message digest is a short value that is constructed by processing an arbitrarily large set of data. It serves as a fingerprint of the data. If you change the data set, even a single bit, then compute the message digest value again, it will be different. Message digests are helpful for ensuring that data has not changed in transit from one place to another. You could use a message digest to check for communications errors, but if you’re worried about attackers, use a digital signature to verify data integrity.

Conceptually, a digital signature is a message digest value that has been encrypted using the private key of a key pair. Why is this useful?

Suppose you want to send this message to your friend:

Meet me at the theater at 10:30.

If you send this message via the Internet, your enemy could intercept the message in a dozen different ways and modify it at will, like this:

Meet me at the restaurant at 7:30.

You could try using a message digest to prevent this kind of tampering. Create a message digest value from the original message, then send the message and the digest value together. Unfortunately, your enemy is pretty sharp and could simply change the message, compute a new digest value from the new message, and send both to your friend. Your friend would see the message and its matching digest and assume the message is correct.

If you digitally sign the message, your enemy cannot change the message undetected. When you create a signature of the message, you encrypt the message digest value with your private key, which is a secret. When your friend receives the message, she uses your public key to decrypt the message, then compares the decrypted digest value with a freshly computed one. If they match, your friend is sure that the message is unaltered.

Your enemy could create a new message and compute a new digest value for it, but he cannot forge your signature because he does not know your private key.

Using Message Digests in SATSA-CRYPTO

Message digests are represented by the java.security.MessageDigest class in SATSA-CRYPTO. The class is easy to use:

  1. Instantiate a MessageDigest object by passing an algorithm name to the getInstance() factory method. (This follows the pattern for Cipher and, as you’ll see later, Signature.)
  2. Process the data that is to be digested by passing it to the update() method.
  3. Retrieve the message digest value with the digest() method.

The following example shows how to calculate a SHA digest value. For a complete example, see Appendix D. Different digest algorithms generate differently sized digest values. The SHA algorithm produces a 20 byte value.

byte[] data = "abc".getBytes(); 
byte[] digest = new byte[20]; 
MessageDigest md = MessageDigest.getInstance("SHA-1"); 
md.update(data, 0, data.length); 
md.digest(digest, 0, 20); 

Verifying Signatures in SATSA-CRYPTO

Digital signatures are represented by the java.security.Signature class. In SATSA-CRYPTO, Signature can be used only to verify signatures, not to generate them. Signature resembles MessageDigest except that it is initialized like Cipher. Follow these steps to use a Signature:

  1. Create a Signature object by passing an algorithm name to the getInstance() factory method.
  2. Initialize the Signature by passing a public key to initVerify().
  3. Process the data that is to be digested by passing it to the update() method.
  4. Pass a previously calculated signature value to verify(). The Signature calculates its own signature value and compares it to the one you supplied. If the two signatures match, the method returns true.

The following example shows how to verify an RSA signature. For a complete example, see Appendix D.

byte[] publicKeyBits; 
// Assign publicKeyBits here. 
X509EncodedKeySpec pks = new X509EncodedKeySpec(publicKeyBits); 
KeyFactory kf = KeyFactory.getInstance("RSA"); 
PublicKey publicKey = kf.generatePublic(pks); 
 
Signature signature = Signature.getInstance("SHA1withRSA"); 
signature.initVerify(publicKey); 
signature.update(kData, 0, kData.length); 
 
boolean pass = signature.verify(kSignature); 
 

 


Contents Previous Next Index SATSA Developer's Guide
SATSA Reference Implementation 1.0