JavaTM Cryptography Extension 1.2

API Specification & Reference


Introduction

Cryptographic Concepts
Encryption and Decryption
Password-Based Encryption
Cipher
Key Agreement
Message Authentication Code

Core Classes
The Cipher Class
The Cipher Stream Classes
The CipherInputStream Class
The CipherOutputStream Class
The KeyGenerator Class
The SecretKeyFactory Class
The SealedObject Class
The KeyAgreement Class
The Mac Class

Installing Providers for JCE 1.2

JCE Keystore

Code Examples
Using Encryption
Using Password-Based Encryption
Using Key Agreement


Appendix A: Standard Names

Appendix B: SunJCE Default Keysizes

Appendix C: SunJCE Keysize Restrictions

Appendix D: Sample Programs
Diffie-Hellman Key Exchange between 2 Parties
Diffie-Hellman Key Exchange between 3 Parties
Blowfish Example
HMAC-MD5 Example

Introduction

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

The JavaTM Cryptography Extension (JCE) 1.2 provides a framework and implementations for encryption, key generation and key agreement, and Message Authentication Code (MAC) algorithms. Support for encryption includes symmetric, asymmetric, block, and stream ciphers. The software also supports secure streams and sealed objects.

JCE 1.2 is designed so that other cryptography libraries can be plugged in as a service provider, and new algorithms can be added seamlessly.

JCE 1.2 supplements the Java Development Kit 1.2 (JDKTM), which already includes interfaces and implementations of message digests and digital signatures. JCE 1.2 is provided as an extension to the JavaTM platform.

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 1.2 API covers:

JCE 1.2 comes standard with a provider named "SunJCE", which must be installed and which supplies the following cryptographic services:

Cryptographic 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 (ciphertext) meaningless to a third-party who does not know the key. Decryption is the inverse process: that of taking ciphertext and a short key string, and producing cleartext.

Password-Based Encryption

Password-Based Encryption (PBE) derives an encryption key from a password. In order to make the task of getting from password to key very time-consuming for an attacker, most PBE implementations will mix in a random number, known as a salt, to create the key.

Cipher

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

Key Agreement

Key agreement is a protocol by which 2 or more parties can establish the same cryptographic keys, without having to exchange any secret information.

Message Authentication Code

A Message Authentication Code (MAC) provides a way to check the integrity of information transmitted over or stored in an unreliable medium, based on a secret key. Typically, message authentication codes are used between two parties that share a secret key in order to validate information transmitted between these parties.

A MAC mechanism that is based on cryptographic hash functions is referred to as HMAC. HMAC can be used with any cryptographic hash function, e.g., MD5 or SHA-1, in combination with a secret shared key. HMAC is specified in RFC 2104.

Core Classes

Installing Providers for JCE 1.2

Cryptographic providers for JCE 1.2 are installed and configured in much the same way as cryptographic providers for the JDK. The only difference is that when you install a JCE 1.2 provider other than the default "SunJCE" (which comes standard with JCE 1.2), you also need to make sure that JCE 1.2 is installed. More information about installing and configuring providers can be found in the Installing Providers section of the JavaTM Cryptography Architecture API Specification & Reference document.

Note that although the "SunJCE" provider is supplied with every JCE 1.2 installation, it still needs to be registered explicitly: either statically or dynamically.

Note that the "SunJCE" provider relies on some of the algorithm implementations supplied by the "SUN" provider, which is the default provider of JDK 1.2. This means that when you install the "SunJCE" provider, you need to make sure that the "SUN" provider is also installed. Note that when you install JDK 1.2 (or JRE 1.2), the "SUN" provider is automatically configured as a static provider.

JCE Keystore

The "SunJCE" provider supplies its own implementation of the java.security.KeyStore class in JDK 1.2. Its implementation employs a much stronger protection of private keys (using password-based encryption with Triple DES) than the keystore implementation supplied by the "SUN" provider in JDK 1.2. (Note that because JDK 1.2 is distributed world-wide in binary and source format, it cannot employ any strong encryption mechanisms.)

In order to take advantage of the keystore implementation of the "SunJCE" provider, you specify "JCEKS" as the keystore type.

You may upgrade your keystore of type "JKS" - this is the name of the keystore type implemented by the "SUN" provider in JDK 1.2 - to a JCE 1.2 keystore of type "JCEKS" by changing the password of a private-key entry in your keystore. Note that once you have upgraded your keystore, your keystore can no longer be accessed without JCE 1.2 installed.

To apply the cryptographically strong(er) key protection supplied by "SunJCE" to a private key named "signkey" in your default keystore, use the following command, which will prompt you for the old and new key passwords:

    keytool -keypasswd -alias signkey -storetype jceks

You may want to change the password back to its old value, using the same command.

See the keytool user guide for more information about keystores and how they are managed.

Code Examples

This section is a short tutorial on how to use some of the major features of the JCE APIs. Complete sample programs that exercise the APIs can be found in Appendix D of this document.

Using Encryption

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 have to instantiate a KeyGenerator for DES. We do not specify a provider, because we do not care about a particular DES key generation implementation. Since we do not initialize the KeyGenerator, a system-provided source of randomness will be used to create the DES key:

    KeyGenerator keygen = KeyGenerator.getInstance("DES");
    SecretKey desKey = keygen.generateKey();

After the key has been generated, the same KeyGenerator object can be re-used to create further keys.

Creating a Cipher

The next step is to create a Cipher instance. To do this, we use one of the getInstance factory methods of the Cipher class. We must specify the name of the requested transformation, which includes the following components, separated by slashes (/):

  • the algorithm name
  • the mode (optional)
  • the padding scheme (optional)

In this example, we create a DES (Data Encryption Standard) cipher in Electronic Codebook mode, with PKCS#5-style padding. We do not specify a provider, because we do not care about a particular implementation of the requested transformation.

The standard algorithm name for DES is "DES", the standard name for the Electronic Codebook mode is "ECB", and the standard name for PKCS#5-style padding is "PKCS5Padding":

    Cipher desCipher;

    // Create the cipher desCipher =
    Cipher.getInstance("DES/ECB/PKCS5Padding");

We use the generated desKey from above to initialize the Cipher object for encryption:

    // Initialize the cipher for encryption
    desCipher.init(Cipher.ENCRYPT_MODE, desKey);

    // Our cleartext
    byte[] cleartext = "This is just an example".getBytes();

    // Encrypt the cleartext
    byte[] ciphertext = desCipher.doFinal(cleartext);

    // Initialize the same cipher for decryption
    desCipher.init(Cipher.DECRYPT_MODE, desKey);

    // Decrypt the ciphertext
    byte[] cleartext1 = desCipher.doFinal(ciphertext);

cleartext and cleartext1 are identical.

Using Password-Based Encryption

In this example, we prompt the user for a password from which we derive an encryption key.

It would seem logical to collect and store the password in an object of type java.lang.String. However, here's the caveat: Objects of type String are immutable, i.e., there are no methods defined that allow you to change (overwrite) or zero out the contents of a String after usage. This feature makes String objects unsuitable for storing security sensitive information such as user passwords. You should always collect and store security sensitive information in a char array instead.

For that reason, the javax.crypto.spec.PBEKeySpec class takes (and returns) a password as a char array.

The following method is an example of how to collect a user password as a char array:

    /**
     * Reads user password from given input stream.
     */
    public char[] readPasswd(InputStream in) throws IOException {
	char[] lineBuffer;
	char[] buf;
	int i;

	buf = lineBuffer = new char[128];

	int room = buf.length;
	int offset = 0;
	int c;

loop:	while (true) {
	    switch (c = in.read()) {
	      case -1: 
	      case '\n':
		break loop;

	      case '\r':
		int c2 = in.read();
		if ((c2 != '\n') && (c2 != -1)) {
		    if (!(in instanceof PushbackInputStream)) {
			in = new PushbackInputStream(in);
		    }
		    ((PushbackInputStream)in).unread(c2);
		} else 
		    break loop;

	      default:
		if (--room < 0) {
		    buf = new char[offset + 128];
		    room = buf.length - offset - 1;
		    System.arraycopy(lineBuffer, 0, buf, 0, offset);
		    Arrays.fill(lineBuffer, ' ');
		    lineBuffer = buf;
		}
		buf[offset++] = (char) c;
		break;
	    }
	}

	if (offset == 0) {
	    return null;
	}

	char[] ret = new char[offset];
	System.arraycopy(buf, 0, ret, 0, offset);
	Arrays.fill(buf, ' ');

	return ret;
    }

In order to use Password-Based Encryption (PBE) as defined in PKCS#5, we have to specify a salt and an iteration count. The same salt and iteration count that are used for encryption must be used for decryption:

    PBEKeySpec pbeKeySpec;
    PBEParameterSpec pbeParamSpec;
    SecretKeyFactory keyFac;

    // Salt
    byte[] salt = {
        (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
        (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
    };

    // Iteration count
    int count = 20;

    // Create PBE parameter set
    pbeParamSpec = new PBEParameterSpec(salt, count);

    // Prompt user for encryption password.
    // Collect user password as char array (using the
    // "readPasswd" method from above), and convert
    // it into a SecretKey object, using a PBE key
    // factory.
    System.err.print("Enter encryption password:  ");
    System.err.flush();
    pbeKeySpec = new PBEKeySpec(readPasswd(System.in));
    keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
    SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

    // Create PBE Cipher
    Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");

    // Initialize PBE Cipher with key and parameters
    pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

    // Our cleartext
    byte[] cleartext = "This is another example".getBytes();

    // Encrypt the cleartext
    byte[] ciphertext = pbeCipher.doFinal(cleartext);

Using Key Agreement

Please refer to Appendix D for sample programs exercising the Diffie-Hellman key exchange between 2 and 3 parties, respectively.


Appendix A: Standard Names

The JCE 1.2 API requires and utilizes a set of standard names for algorithms, algorithm modes, and padding schemes. This specification establishes the following names as standard names. It supplements the list of standard names defined in Appendix A in the JavaTM Cryptography Architecture API Specification & Reference. Note that algorithm names are treated case-insensitive.

Cipher

Algorithm

The following names can be specified as the algorithm component in a transformation when requesting an instance of Cipher:

  • DES: The Digital Encryption Standard as described in FIPS PUB 46-2.

  • DESede: Triple DES Encryption (DES-EDE).

  • PBEWithMD5AndDES: The password-based encryption algorithm as defined in: RSA Laboratories, "PKCS #5: Password-Based Encryption Standard," version 1.5, Nov 1993. Note that this algorithm implies CBC as the cipher mode and PKCS5Padding as the padding scheme and cannot be used with any other cipher modes or padding schemes.

  • Blowfish: The block cipher designed by Bruce Schneier.

Mode

The following names can be specified as the mode component in a transformation when requesting an instance of Cipher:

  • ECB: Electronic Codebook Mode, as defined in: The National Institute of Standards and Technology (NIST) Federal Information Processing Standard (FIPS) PUB 81, "DES Modes of Operation," U.S. Department of Commerce, Dec 1980.

  • CBC: Cipher Block Chaining Mode, as defined in FIPS PUB 81.

  • CFB: Cipher Feedback Mode, as defined in FIPS PUB 81.

  • OFB: Output Feedback Mode, as defined in FIPS PUB 81.

  • PCBC: Plaintext Cipher Block Chaining, as defined by Kerberos.

Padding

The following names can be specified as the padding component in a transformation when requesting an instance of Cipher:

  • NoPadding: No padding.

  • PKCS5Padding: The padding scheme described in: RSA Laboratories, "PKCS #5: Password-Based Encryption Standard," version 1.5, November 1993.

  • SSL3Padding: The padding scheme defined in the SSL Protocol Version 3.0, November 18, 1996, section 5.2.3.2 (CBC block cipher):
        block-ciphered struct {
            opaque content[SSLCompressed.length];
            opaque MAC[CipherSpec.hash_size];
            uint8 padding[GenericBlockCipher.padding_length];
            uint8 padding_length;
        } GenericBlockCipher;
    

    The size of an instance of a GenericBlockCipher must be a multiple of the block cipher's block length.

    The padding length, which is always present, contributes to the padding, which implies that if:

        sizeof(content) + sizeof(MAC) % block_length = 0,
    
    padding has to be (block_length - 1) bytes long, because of the existence of padding_length.

    This make the padding scheme similar (but not quite) to PKCS5Padding, where the padding length is encoded in the padding (and ranges from 1 to block_length). With the SSL scheme, the sizeof(padding) is encoded in the always present padding_length and therefore ranges from 0 to block_length-1.

    Note that this padding mechanism is not supported by the "SunJCE" provider.

KeyAgreement

The following algorithm names can be specified when requesting an instance of KeyAgreement:

KeyGenerator

The following algorithm names can be specified when requesting an instance of KeyGenerator:

KeyPairGenerator

The following algorithm names can be specified when requesting an instance of KeyPairGenerator:

SecretKeyFactory

The following algorithm names can be specified when requesting an instance of SecretKeyFactory:

KeyFactory

The following algorithm names can be specified when requesting an instance of KeyFactory:

AlgorithmParameterGenerator

The following algorithm names can be specified when requesting an instance of AlgorithmParameterGenerator:

AlgorithmParameters

The following algorithm names can be specified when requesting an instance of AlgorithmParameters:

MAC

The following algorithm names can be specified when requesting an instance of Mac:

Keystore Types

The following types can be specified when requesting an instance of KeyStore:


Appendix B: SunJCE Default Keysizes

The SunJCE provider uses the following default keysizes:


Appendix C: SunJCE Keysize Restrictions

The SunJCE provider enforces the following restrictions on the keysize passed to the initialization methods of the following classes:


Appendix D: Sample Programs


Copyright 1996-98 Sun Microsystems, Inc. All Rights Reserved.

Please send comments to: java-security@java.sun.com.
Sun
Java Software
Last modified: Thu Mar 11 14:45:43 PST 1999