JavaTM Cryptography Extension

API Specification & Reference

Last Modified: 27 February 1997


Introduction

This document is intended as a companion to the Java Cryptography Architecture (JCA) API Specification & Reference. References to chapters not present in this document are to chapters in the JCA Specification.

The Java Cryptography Extension (JCE) is a set of APIs to and implementations of cryptographic functionality, including symmetric, asymmetric, stream, and block encryption. It supplements the security functionality of the JCA, which itself includes digital signatures and message digests.

The architecture of the JCE follows the same design principles found elsewhere in the JCA: implementation independence and, whenever possible, algorithm independence. It uses the same "provider" architecture.

The JCE provides both API and implementation. The API covers:

The implemententation extends the JCA "SUN" provider, with implementations of:

Concepts

This section provides a high-level description of the concepts implemented by the API, and the exact meaning of the technical terms used in the API specification.

Encryption and Decryption

Encryption is the process of taking data (called cleartext) and a short string (a key) and producing data meaningless to a third-party who does not know the key (ciphertext). Decryption is the inverse process: that of taking ciphertext and a short key string, and producing cleartext.

Cipher

Encryption is done using a cipher. A cipher is an object capable of carrying out encryption and decryption according to an encryption scheme.

Core Classes and Interfaces.

The Cipher Class

The Cipher class defines behavior for encryption and decryption, including initialization as well as the encryption or decryption operation.

Creating a Cipher Object

Like other engine classes in the API, Cipher objects are created using the getInstance factory methods on the Cipher class. A factory method is a static method that returns an instance of a class, in this case an instance of a Cipher subclass implementing a requested algorithm.

To create a Cipher object, you must specify the encryption algorithm name, with an optional mode and padding scheme separated by "/" characters. You may also specify which provider you want to supply the algorithm.

    public static Cipher getInstance(String algorithm);

public static Cipher getInstance(String algorithm, String provider);

Standard names to be used to specify algorithms are discussed in Appendix A in the Java Cryptography Architecture API Specification & Reference.

Standard names to be used to specify modes and padding schemes are discussed in Appendix A in this document.

The objects returned by factory methods are uninitialized, and must be initialized before they become usable.

Initializing a Cipher Object

Cipher objects are modal objects. This means that a Cipher object is always in a given state, where it may only do one type of operation. States are represented as final integer constants defined on Cipher.

Cipher itself defines three states:

When it is first created, a Cipher object is in the UNINITIALIZED state. Initialization methods are used to initialize a Cipher and cause a state transition. The Cipher class defines two initialization methods, initEncrypt and initDecrypt, which change the state to ENCRYPT and DECRYPT, respectively. They each take a Key instance as an argument:
    public void initEncrypt(Key key);

public void initDecrypt(Key key);

Note that when a cipher object is initialized, it loses all previously-acquired state. In other words, initializing a Cipher is equivalent to creating a new instance of that cipher, and initializing it. For example, if a cipher is first initialized for decryption with a given key, then initialized for encryption, it will lose any state acquired while in decryption mode.

Encrypting and Decrypting Data

To encrypt or decrypt data, simply call one of the crypt methods:

    public byte[] crypt(byte[] in);

public byte[] crypt(byte[] in, int off, int len);

public int crypt(byte[] in, int inOff, int inLen, byte[] out, int outOff);

cryptwill take care of any necessary padding or unpadding, and will allocate new output buffers if none are specified.

The Cipher Stream Classes

Sometimes it is not convenient to have to process data in batch mode, that is, all at once. While doing stream operations, for example, you typically want to process a few bytes at a time, without having to know in advance how long the data is, or whether it is too long to be held in memory all at once. When that is the case, the cipher stream classes should be used.

CipherOutputStream

This class is a FilterOutputStream that encrypts or decrypts the data passing through it.

This class has a constructor that takes a Cipher and an output stream as arguments. The cipher is used to encrypt or decrypt all data supplied via calls to one of the write methods. The encryption/decryption result is written to the output stream.

A buffer is used for receiving the data to be encrypted or decrypted, depending on the state of the Cipher. To supply the bytes that need to be encrypted/decrypted, make one or more calls to one of the write methods. After you have supplied all the data, call flush to ensure final processing is done.

With an encrypter stream, every time a complete block has been supplied via calls to write, the block is encrypted and written to the output stream. When flush is called, the final data is encrypted and the result written to the output stream. If the final data does not comprise a complete block, and the cipher is a padding cipher, the data is padded before encryption. If padding is needed but the cipher is not a padding cipher, an exception is thrown.

With a decrypter stream, every time a complete block plus one byte has been supplied via calls to write, the block is decrypted and written to the output stream. When flush is called, exactly one block should be in the buffer. It is decrypted and written out.

CipherInputStream

This class is a FilterInputStream that encrypts or decrypts the data passing through it. Typically, this stream would be used as a filter to read an encrypted file.

This class has a constructor that takes a Cipher and an input stream as arguments. The cipher is used to encrypt or decrypt all data read through the stream.

For block ciphers, some buffering of the data received from the input stream is done. The buffer length is the cipher's block size. For stream ciphers, that is, ciphers capable of encrypting or decrypting a byte at a time, no buffering is necessary.

The data is encrypted or decrypted, depending on the initialization state of the Cipher. To get the encryption/decryption result bytes, make one or more calls to the read methods. One read method, with no arguments, returns the next result byte. The other read method returns multiple result bytes at once.

For a buffered decrypter stream, every time the buffer is empty, the stream attempts to read a complete buffer, and blocks until it does. When it has read a buffer, it decrypts it. If the next byte is an EOF and the cipher is a padding/unpadding cipher, the decryption result is then unpadded. If an EOF is encountered before a whole buffer has been read, an exception is thrown.

For a buffered encrypter stream, every time the buffer is empty, the stream attempts to read a complete buffer, and blocks until it does. If it reads a whole buffer without reaching EOF, it encrypts it. If it reaches EOF in the middle of a buffer, and the cipher is a padding cipher, it will pad the buffer, and encrypt it. Otherwise, an exception will be thrown.

Key Generator

A key generator is used to generate secret keys for symmetric algorithms.

Creating a Key Generator

The arguments for creating a key generator are a symmetric encryption algorithm and, optionally, a provider:

    public static KeyGenerator getInstance(String algorithm);

public static KeyGenerator getInstance(String algorithm, String provider);

A KeyGenerator object does not need further initialization.

Creating a Key

To generate a key, simply call the method:

    public Key generateKey(SecureRandom random);

This method will always return the same key, given the same random bytes by the random byte source.

Output Considerations

Some of the crypt methods allow the caller to specify the output buffer into which to encrypt or decrypt the data. In these cases, it is important to pass a buffer that is large enough to hold the result of the encrypted or decrypted data.

Clients should call the Cipher

    public final int outBlockSize(int inLen)
method to determine the size of an output buffer.

Examples

This section is a short tutorial on how to use the major features of the Java Cryptography Extension API.

Simple Encryption Example

This section takes the user through the process of generating a key, creating and initializing a cipher object, encrypting a file, and then decrypting it. Throughout this example, we use the Data Encryption Standard (DES).

Generating a Key

To create a DES key, we first get a DES KeyGenerator, then generate the key:

    SecureRandom random = new SecureRandom(); 
    KeyGenerator keygen = KeyGenerator.getInstance("DES");
    keygen.initialize(random);
    Key key = keygen.generateKey();

Creating a Cipher

The next step is to create a Cipher instance. To do this, use one of the Cipher class's getInstance factory methods. You must specify the algorithm name. Optionally, you may also specify, if applicable:

  • the encryption mode
  • the padding scheme to be used
  • the provider from which to get the implementation

In this example, we create a DES (Data Encryption Standard) cipher, in Cipher Block-Chaining mode, with PKCS#5-style padding. We do not specify a provider.

DES's standard algorithm name is "DES", Cipher Block-Chaining Mode is "CBC" and PKCS#5 padding is "PKCS#5". These are separated by "/" characters, to find the cipher specification: "DES/CBC/PKCS#5".

    /* Create the cipher */

Cipher des = Cipher.getInstance("DES/CBC/PKCS#5");

The variable key is bound to a legal DES key, which may be used for encryption and decryption. The handle to the key must be kept secure, since it is the keystone of the secrecy afforded by the encryption algorithm. With the key, we are able to initialize the object for encryption and decryption.

    /* Initialize the cipher for encryption */ 
    des.initEncrypt(key); 

    byte[] ciphertext = des.crypt(cleartext);
    

/* Initialize the cipher for decryption */ des.initDecrypt(key); byte[] decrypted = des.crypt(ciphertext);

/* Verify that the clear text is identical to the decrypted text */ if (decrypted.length != cleartext.length) return false; for (int i = 0; i < cleartext.length; i++) { if (decrypted[i] != cleartext[i]) return false; } return true;


Appendix A: Standard Names

The API requires and utilizes a set of standard names for various algorithms, padding schemes, providers, etc. This appendix extends the standard set of names defined by Appendix A in the Java Cryptography Architecture API Specification & Reference as follows:

PKCS#5: A name for the padding scheme described in RSA Laboratories Technical Note: Public Key Cryptography Standard (PKCS) 5.

ECB: Electronic Codebook Mode, as defined in the National Institute of Standards and Technology (NIST) Federal Information Processing Standard (FIPS) 81.

CBC: Cipher-Chaining Mode, as defined in NIST FIPS 81.

CFB: Cipher-Feedback Mode, as defined in NIST FIPS 81.

OFB: Output-Feedback Mode, as defined in NIST FIPS 81.


Copyright © 1996, 1997 Sun Microsystems, Inc., 2550 Garcia Ave., Mtn. View, CA 94043-1100 USA. All rights reserved .

Please send comments to: java-security@java.sun.com