Java Cryptographic Extensions (JCE)


JCE was originally developed as an extension package to include APIs and implementations for cryptographic services that were subject to U.S. export control regulations. JCE provides a provider implementation and related set of API packages to provide support for encryption and decryption, secret key generation, and agreement and message authentication code (MAC) algorithms. The encryption and decryption support includes symmetric, asymmetric, block, and stream ciphers. JCE also provides support for secure streams and sealed objects.

Initially, JCE was made available as an optional package to the JSDK versions 1.2.x and 1.3.x in accordance with U.S. regulations specific to the export of cryptography. Due to changes in the U.S. regulations related to the export of cryptography, JCE has now been integrated into J2SE 1.4.

JCE facilitates the Java platform with cryptographic services and algorithms by providing implementations and interfaces for the following:

  • Cryptographic ciphers used for encryption and decryption

  • Password-based encryption

  • Secret key generation used for symmetric algorithms

  • Creation of sealed objects that are serialized and encrypted

  • Key agreement for encrypted communication among multiple parties

  • MAC algorithms to validate information transmitted between parties

  • Support for PKCS#11 (RSA Cryptographic Token Interface Standard), which allows devices to store cryptographic information and perform cryptographic services. This feature is available in J2SE 5.0 and later versions.

Like JCA, JCE also has the notion of provider implementations and a generic API framework for accessing JCE-supported cryptographic services and implementing related functionalities. It is also designed to provide algorithm- and implementation-independence via a standardized API framework.

Figure 4-3 illustrates the architectural representation of JCE and its cryptographic services.

Figure 4-3. JCE architectural model and its cryptographic services


Let's take a closer look at the JCE provider architecture, core API classes, and its programming model.

JCE Cryptographic Service Provider

Because JCE's design is based on the architectural principles of JCA, like JCA it allows for integration of Cryptographic Service Providers, which implements the JCE-defined cryptographic services from a vendor. JCE also facilitates a pluggable framework architecture that allows qualified JCE providers to be plugged in. As part of the J2SE bundle, the JCE framework provides a default provider implementation named SunJCE, which provides the following cryptographic services and algorithms.

  • Implementation of Ciphers and Encryption algorithms such as DES (FIPS PUB 461), Triple DES, and Blowfish

  • Modes include Electronic Code Book (ECB), Cipher Block Chaining (CBC), Cipher Feedback (CFB), Output Feedback (OFB), and Propagating Cipher Block Chaining (PCBC)

  • Implementation of MAC algorithms such as HMAC-MD5 and HMAC-SHA1 algorithms

  • Key generators for DES, Triple DES, Blowfish, HMAC-MD5, and HMAC-SHA1 algorithms

  • Implementation of the MD5 with DES-CBC password-based encryption (PBE) algorithm

  • Implementation of key agreement protocols based on Diffie-Hellman

  • Implementation of Padding scheme as per PKCS#5

  • Algorithm parameter managers for Diffie-Hellman, DES, Triple DES, Blowfish, and PBE

  • Support for Advanced Encryption Standard (AES)

  • A keystore implementation named JCEKS

The following services and algorithms are introduced as J2SE 5.0 security enhancements:

  • Support for PKCS#11 standard

  • Support for ECC algorithm

  • Support for XML Encryption RSA-OAEP algorithm

  • Integration with Solaris Cryptographic Framework

  • Support for "PBEWithSHA1AndDESede" and "PBEWithSHA1AndRC2_40" Ciphers

  • Support for RC2ParameterSpec

  • Support for RSA encryption to SunJCE provider

  • Support for RC2 and ARCFOUR Ciphers to SunJCE provider

  • Support for HmacSHA256, HmacSHA384 and HmacSHA512

JCE Classes and Interfaces

In J2SE, the JCE API framework exists as part of the javax.crypto package.

JCE Provider classes

JCE employs JCA provider classes, particularly the java.security.Provider and java.security.Security classes that allow querying the cryptographic services offered by the provider. The type of services implemented by the provider are represented using an Engine class available as part of the javax.crypto package.

JCE Engine classes

Like JCA, JCE defines a set of engine classes that provide interfaces to the functionality of cryptographic services. The application interfaces of the engine class implements the SPI. Each engine API class has a corresponding SPI class for which the cryptographic service provider provides an implementation.

The following JCE engine classes are available within J2SE:

  • Cipher (javax.crypto.Cipher): The core of the JCE API, which provides the functionality of a cryptographic cipher for doing encryption and decryption.

  • Cipher Stream classes (javax.crypto.CipherInputStream and javax.crypto.CipherOutputStream): JCE introduced the notion of secure streams, which combine the inputstream and outputstream of a Cipher object.

  • Mac (javax.crypto.Mac): Provides the functionality of a MAC algorithm, which is used to check the integrity of a message based on a secret key transmitted over a network or stored in an unreliable medium

  • KeyGenerator (javax.crypto.KeyGenerator): Provides the functionality of a symmetric key (secret key) generator.

  • SecretKeyFactory (javax.crypto.SecretKeyFactory): Acts as a factory class for SecretKey; operates only on symmetric keys.

  • SealedObject (javax.crypto.SealedObject): Allows creating a serialized object and protects its confidentiality using a cryptographic algorithm.

  • KeyAgreement (javax.crypto.KeyAgreement): Provides the functionality of using KeyAgreement protocols; allows the creation of a KeyAgreement object for each party involved in the key agreement.

Additionally, the javax.crypto.interfaces package provides interfaces for Diffie-Hellman keys, and the javax.crypto.spec provides the key and parameter specifications for the different algorithms such as DES, BlowFish, and Diffie-Hellman.

Understanding the JCE API Programming Model

Let's explore the JCE API programming model and the steps involved in using important JCE API classes and mechanisms. Although the details of using specific algorithms and operations vary, the common steps are as follows:

1.

Get the cryptographic provider.

2.

Obtain the specified Cipher using the getInstance() method.

3.

Get the key generator; use SecretKeyFactory and KeyGenerator to generate the Key object. Random classes and Key specification classes can be used as additional input to the algorithm.

4.

Initialize the Cipher with the init() method.

5.

Encrypt or decrypt the message using update() methods.

6.

Depending about how it was initialized, the process will be finished using the doFinal() method.

In the next section, we will take a look at some commonly applied JCE cryptographic operations such as encryption and decryption with symmetric keys, using block and stream ciphers, password-based encryption, AES, and computing MAC digests.

Encryption and Decryption

Encryption is a cryptographic technique for scrambling a message or files or programs by changing each character string, byte, or bit to another using a mathematical algorithm. A message that is not encrypted is referred to as plaintext or cleartext, and an encrypted message is called ciphertext. Decryption is the reverse process of encryption, which converts the ciphertext back into plaintext. This process generally requires a cryptographic key or code.

Let's walk through the steps involved in using JCE to perform basic encryption and decryption operations. First, we will take a look at the process of generating a Data Encryption Standard (DES) key, creating and initializing a cipher object, encrypting a file, and then decrypting it.

  • Generate a DES Key: To create a DES key, instantiate a KeyGenerator using the getInstance("DES"), and then, to generate the key, use the generateKey() method:

        KeyGenerator kg = KeyGenerator.getInstance("DES");     SecretKey sKey = kg.generateKey(); 

  • Create the Cipher: Use the getInstance() factory method of the Cipher class and specify the name of the requested transformation (algorithm/mode/padding) as input. In the example shown here, we use the DES algorithm, ECB (Electronic code book mode), "PKCS5Padding" PKCS#5 padding:

        Cipher myCipher =       Cipher.getInstance("DES/ECB/PKCS5Padding"); 

  • Initialize the Cipher for encryption: Use the init() method of the Cipher class and initialize the cipher object encryption with ENCRYPT_MODE and secret key. For this example, we use a String object as test data. Use the dofinal() to finish the encrypt operation:

          myCipher.init(Cipher.ENCRYPT_MODE, sKey);     // Test data    String testdata               = "Understanding Encryption & Decryption";       byte[] testBytes = testdata.getBytes();     // Encrypt the testBytes       byte[] myCipherText = myCipher.doFinal(testBytes); 

  • Initialize the Cipher for decryption: Use the init() method of the Cipher class and initialize the cipher object decryption with DECRYPT_MODE and secret key. For this example, use the dofinal() to finish the decrypt operation.

        myCipher.init(Cipher.DECRYPT_MODE, sKey);     // Decrypt the byte array       byte[] myCipherText          = myCipher.doFinal(encryptedText); 

Example 4-7 is a full code example (EncryptDecryptWithBlowFish.java) showing encryption and decryption using the Blowfish algorithm.

Example 4-7. EncryptDecryptWithBlowFish.java
package com.csp.ch4; import java.security.*; import javax.crypto.*; public class EncryptDecryptWithBlowFish {  public static void main (String[] args)                              throws Exception {  if (args.length != 1) {     System.err.println ("Usage: java              EncryptDecryptWithBlowFish <Enter text> ");     System.exit(1);   }  String testData = args[0];  System.out.println("Generating a Blowfish key...");  // Create a key using "Blowfish"    KeyGenerator myKeyGenerator                  = KeyGenerator.getInstance("Blowfish");    keyGenerator.init(128);   // specifying keysize as 128    Key myKey = myKeyGenerator.generateKey();    System.out.println("Key generation Done.");  // Create a cipher using the key    Cipher myCipher       = Cipher.getInstance("Blowfish/ECB/PKCS5Padding");    myCipher.init(Cipher.ENCRYPT_MODE, myKey);    byte[] testBytes = testData.getBytes();  // Perform  encryption    byte[] encryptedText = cipher.doFinal(testBytes);  // Printing out the encrypted data      System.out.println         ("Encryption Done:" + new String(encryptedText));  // Initialize the cipher for DECRYPTION mode      cipher.init(Cipher.DECRYPT_MODE, myKey); // Performing decryption    byte[] decryptedText = cipher.doFinal(encryptedText);    // Printing out the decrypted data    System.out.println("Decryption Done:"                           + new String(decryptedText));    } } 

Using Block Ciphers

A block cipher is a symmetric-key encryption algorithm that encrypts and decrypts a fixed-length block of data (usually 64 bits long) into a block of ciphertext of the same length. To implement block ciphers it becomes important that the data required to be encrypted must be in the multiple of the block size. To fill in the reminder block and to derive the required block size, block ciphers makes use of padding.

Padding defines how to fill out the reminder of a block with random data. During decryption, the encrypted data will be retrieved to the original data and removing the padding. PKCS#5 specifies one of the popular padding schemes and it is defined as a standard by RSA. In the SunJCEProvider the PKCS#5 padding scheme is represented using PKCS5Padding.

In block ciphers to encrypt bigger blocks of data, it makes use of operation "Modes." The modes define how the blocks of plaintext are encrypted to ciphertext and decrypted from ciphertext to plaintext. The SunJCEprovider provides support for commonly used modes such as ECB (Electronic Code Book), OFB (Output feedback), CFB (Cipher Feedback), CBC (Cipher-block chaining), PCBC (Propagating Cipher Block Chaining). For more information about these modes and their characteristics, refer to RSA Security Web site on Cryptography standards [RSASecurity].

Example 4-8 is a Java code fragment showing how to represent an encryption and decryption using a block cipher.

Example 4-8. Encryption and Decryption using a Block cipher
//  Encryption using DES, ECB Mode and PKCS5Padding Scheme try { // 1. Create the cipher using DES algorithm //    ECB Mode and PKCS5Padding scheme       Cipher myCipher =            Cipher.getInstance("DES/ECB/PKCS5Padding");   // 2. Initialize the Cipher       myCipher.init(Cipher.ENCRYPT_MODE, key);  //  3.  Represent the Plaintext   byte[] plaintext =   "Eye for an Eye makes the Whole world blind".getBytes();  // 4. Encrypt the Plaintext       byte[] myciphertext = myCipher.doFinal(plaintext);  // 5. Return the cipher text as String       return getString( myciphertext ); } catch( Exception e ) {       e.printStackTrace();     } . . . //  Decryption using DES, ECB Mode and PKCS5Padding Scheme try { . . .   // 1. Create the cipher using DES algorithm   //    ECB Mode and PKCS5Padding scheme       Cipher myCipher =          Cipher.getInstance("DES/ECB/PKCS5Padding");   // 2. Get the ciphertext       byte[] ciphertext = getBytes( myciphertext );   // 3. Initialize the cipher for decryption       myCipher.init(Cipher.DECRYPT_MODE, key);   // 4. Decrypt the ciphertext       byte[] plaintext = myCipher.doFinal(ciphertext);   // 5. Return the plaintext as string       return new String( plaintext );     }     catch( Exception ex ) {       ex.printStackTrace();     } 

Using Stream Ciphers

Stream ciphers are composed of I/O streams and ciphers. They provide the convenience of reading and writing from underlying InputStream and OutputStream additionally processed by the ciphers. For example, if the cipher is initialized for encryption, the CipherOutputStream will attempt to encrypt data before writing out the encrypted data, and if the cipher is initialized for decryption, the CipherInputStream will attempt to read in data and decrypt them, before returning the decrypted data.

Example 4-9 is a code fragment showing reading a text file myTextFile, encrypting. the text using a stream cipher, and then writing it using CipherOutputStream to the file CipherTextFile.

Example 4-9. Using stream ciphers to encrypt a file
    FileInputStream inputFile                     = new FileInputStream(myTextFile);     FileOutputStream outputFile                  = new FileOutputStream(cipherTextFile);     CipherOutputStream cipherOutputStream         = new CipherOutputStream(outputFile, myCipher);     int i = 0;         while (i=inputFile.read() != -1) {                 cipherOutputStream.write(i);         }    cipherOutputStream.close();    outputFile.close();    inputFile.close(); 

Sealed Object

JCE introduced the notion of creating sealed objects. A Sealed object is all about encrypting a serializable object using a cipher. Sealed objects provide confidentiality and helps preventing unauthorized viewing of contents of the object by restricting de-serialization.

From a programming standpoint, the sealed object creates a copy of given object by serializing the object to an embedded byte array, and then encrypt them using a cipher. To retrieve the original object, the object can be unsealed using the cipher that had been used for sealing the object. Example 4-10 shows how to create a sealed object.

Example 4-10. Creating a sealed object
//  Creating a Sealed Object ObjectOutputStream oos         = new ObjectOutputStream(mySocket.getOutputStream()); Cipher myCipher          = Cipher.getInstance("DES/ECB/PKCS5Padding"); myCipher.init(Cipher.ENCRYPT_MODE, mykey); SealedObject mySealedObject          = new SealedObject(myObject, myCipher); oos.writeObject(mySealedObject); . . . // To deserialize a Sealed object and retrieve its contents ObjectInputStream ois         = new ObjectInputStream(mySocket.getInputStream()); SealedObject mso = (SealedObject)ois.readObject(); Cipher mc          = Cipher.getInstance("DES/ECB/PKCS5Padding"); mc.init(Cipher.DECRYPT_MODE, mykey); Object myObject = mso.getObject(mc); 

Password-Based Encryption (PBE)

Password-Based Encryption (PBE) is a technique that derives an encryption key from a password, which helps in combating dictionary attacks by hackers and other related vulnerabilities. To use PBE, we have to use a salt (a very large random number also referred to as seed) and an iteration count, which will be specified as parameters with PBEParameterSpec. The salt and iteration count used for encryption must be the same as the ones used for decryption.

Example 4-11 is a code fragment that reads a user password from a prompt, stores it in a char array, and then converts it into a SecretKey object using PBEKeySpec and SecretKeyFactory. The PBEKeySpec parameters are specified with the salt and iteration count using PBEParameterSpec. To create the PBE cipher for encryption, we use the PBEWithMD5AndDES algorithm and initialize it with the PBEKey and PBEParameterSpec.

Example 4-11. Password-based encryption using PBEWithMD5AndDES algorithm
    PBEKeySpec pbeKeySpec;     PBEParameterSpec pbeParamSpec;     SecretKeyFactory keyFac;    //Encryption password is obtained    //via prompt ex: args[0]     char[] password = args[0].toCharArray();     // 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);     // Collect user password as char array, and convert     // it into a SecretKey object, using a PBE key     // factory.     pbeKeySpec = new PBEKeySpec(password);     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);     // Text to encrypt     String textForEncryption                        = "This is a test message";     byte[] myText = textForEncryption.getBytes();     // Encrypt the text using PBE Cipher     byte[] ciphertext = pbeCipher.doFinal(myText); 

Advanced Encryption Standard (AES)

AES is a new cryptographic algorithm that can be used to protect electronic data. More specifically, AES is a symmetric-key block cipher that can use keys of 128, 192, and 256 bits, and encrypts and decrypts data in blocks of 128 bits (16 bytes).

AES has been approved by NIST as a standard to replace the DES algorithms. The AES algorithm is based on the Rijndael algorithm (Developed by Vincent Rijmen and Joan Daemen). AES can also encrypt data much faster than Triple-DES, and it is getting wider acceptance for encrypting data used in business applications, telecommunications, and private and federal government information. As part of the Java platform (J2SE 1.4.2 and later), the JCE provider (SunJCE) implementation provides support for the AES algorithm. The AES algorithm can be used like any other cipher such as DES or Blowfish. The programming model and steps involved are also same as those for other ciphers.

Example 4-12 is a full code example showing encryption and decryption using the AES algorithm.

Example 4-12. Encryption and decryption using AES algorithm
package com.csp.ch4; import java.security.*; import javax.crypto.*; public class EncryptDecryptWithAES {  public static void main (String[] args)                            throws Exception   {  if (args.length != 1) {  System.err.println("Usage: java                  EncryptDecryptWithAES <Enter text> ");  System.exit(1);  }    String testData = args[0];    System.out.println("Generating a AES based key...");    // Create a key using "AES"    KeyGenerator myKeyGenerator               = KeyGenerator.getInstance("AES");    keyGenerator.init(128);   // specifying keysize as 128    SecretKey myKey = myKeyGenerator.generateKey();    byte[] encodeKey = myKey.getEncoded();    SecretKeySpec myKeySpec                   = new SecretKeySpec(encodeKey, "AES");    System.out.println("Key generation Done.");   // Create a cipher using the key    Cipher myCipher = Cipher.getInstance("AES");    myCipher.init(Cipher.ENCRYPT_MODE, myKeySpec);    byte[] testBytes = testData.getBytes();   // Perform  encryption      byte[] encryptedText = cipher.doFinal(testBytes);   // Printing out the encrypted data      System.out.println("Encryption Done:"                          + new String(encryptedText));  // Initialize the cipher for DECRYPTION mode      cipher.init(Cipher.DECRYPT_MODE, myKeySpec);  // Performing decryption    byte[] decryptedText = cipher.doFinal(encryptedText);    // Printing out the decrypted data    System.out.println("Decryption Done:"                          + new String(decryptedText));    } } 

Computing Message Authentication Code (MAC) objects

Message Authentication Code (MAC) is generally used for checking the integrity and validity of the information based on a secret key. MAC uses a secret key to generate the hash code for a sequence of specific bytes arrays.

Example 4-13 is a code fragment that shows computing a MAC object using the HMAC-MD5 algorithm.

Example 4-13. Computing a MAC object using HMAC-MD5 algorithm
import java.security.*; import javax.crypto.*; import javax.crypto.spec.*; import java.util.*; // This is for BASE64 encoding and decoding import sun.misc.*;    //...     try {         // Generate a key using HMAC-MD5         KeyGenerator keyGen                    = KeyGenerator.getInstance("HmacMD5");         SecretKey mySecretkey = keyGen.generateKey();         // Create a MAC object and initialize         Mac mac = Mac.getInstance(key.getAlgorithm());         mac.init(mySecretkey);         String testString              = "This is a test message for MAC digest";       // Encode the string into bytes and digest it         byte[] testBytes = testString.getBytes();         byte[] macDigest = mac.doFinal(testBytes);      // convert the digest into a string         String digestB64          =  new        sun.misc.BASE64Encoder().encode(macDigest);       System.out.println("Printing MAC Digest as String:"                    + digestB64);     } catch (InvalidKeyException e) {     } catch (NoSuchAlgorithmException e) {     } 

Using Key Agreement Protocols

A key agreement protocol is a process that allows carrying out an encrypted communication between two or more parties by securely exchanging a secret key over a network. The Diffie-Hellman (DH) key agreement protocol allows two users to exchange a secret key over an insecure medium without any prior secrets. JCE provides support for the Diffie-Hellman key agreement protocol.

To create a Diffie-Hellman KeyAgreement object, instantiate a KeyAgreement object using the getInstance("DH") and then initialize it using the init() method.

   KeyAgreement keyAgreement                      = KeyAgreement.getInstance("DH"); 

If two or more parties are involved in a key agreement, all corresponding parties must create and initialize a KeyAgreement object. After creating and initializing the KeyAgreement object, the corresponding parties execute the different phases specific to the KeyAgreement protocol. The DHParameterSpec constructs a parameter set for Diffie-Hellman, using a prime modulus p, a base generator g, and the size in bits l, of the random exponent (private value).

Example 4-14 is a code fragment showing the steps involved in using the Diffie-Hellman KeyAgreement protocol.

Example 4-14. Using Diffie-Hellman Keyagreement protocol
 try {         //1. Use the values to generate a key pair         KeyPairGenerator keyGen                   = KeyPairGenerator.getInstance("DH");         DHParameterSpec dhSpec                   = new DHParameterSpec(p, g, l);         keyGen.initialize(dhSpec);         KeyPair keypair = keyGen.generateKeyPair();         //2. Get the generated public and private keys         PrivateKey privateKey = keypair.getPrivate();         PublicKey publicKey = keypair.getPublic();         //3. Send the public key bytes to the         // other party...         byte[] publicKeyBytes = publicKey.getEncoded();         //4. Retrieve the public key bytes         // of the other party         publicKeyBytes = ...;         //5. Convert the public key bytes         // into a X.509 PublicKey object         X509EncodedKeySpec x509KeySpec            = new X509EncodedKeySpec(publicKeyBytes);         KeyFactory keyFact            = KeyFactory.getInstance("DH");         publicKey = keyFact.generatePublic(x509KeySpec);         //6. Prepare to generate the secret key          // with the private key and          // public key of the other party         KeyAgreement ka = KeyAgreement.getInstance("DH");         ka.init(privateKey);         ka.doPhase(publicKey, true);         //7. Specify the type of key to generate;         String algorithm = "DES";         //8. Generate the secret key         SecretKey secretKey                    =  ka.generateSecret(algorithm);         //9. Use the secret key to encrypt/decrypt data;         /...     } catch (java.security.InvalidKeyException e) { } catch(java.security.spec.InvalidKeySpecException e) {     } catch (java.security.InvalidAlgorithmParameterException e) {     } catch (java.security.NoSuchAlgorithmException e) {     } 

JCE Hardware Acceleration and Smart Card Support

With the release of J2SE 5.0, JCE provides support for the PKCS#11 standard that allows the following:

  • Using hardware cryptographic accelerators for enhancing performance of cryptographic operations.

  • Using smart cards as key stores for key and trust management.

To use these services, it is necessary to install a PKCS#11 implementation provided by the hardware accelerator and smart card vendors. As part of the J2SE 5.0 bundle, Sun facilitates a SunPKCS#11 provider.

Installing PKCS#11

To install the PKCS#11 provider statically, edit the Java security properties file located at <JAVA_HOME>/jre/lib/security/java.security. For example, to install the Sun PKCS#11 provider with the configuration file /opt/hwcryptocfg/pkcs11.cfg, add the following in the Java security properties file:

  security.provider.7=sun.security.pkcs11.SunPKCS11 \                             /opt/hwcryptocfg/pkcs11.cfg 

To install the provider dynamically (see Example 4-15), create an instance of the provider with the appropriate configuration filename and then install it.

Example 4-15. Programmatically installing a PKCS#11 provider
   String configName ="/opt/hwcryptocfg/pkcs11.cfg";    Provider provider = new             sun.security.pkcs11.SunPKCS11(configName);    Security.addProvider(provider); 

Using Smart Cards as Java Key Stores

To use a smart card as a keystore or trust store, set the javax.net.ssl.keyStoreType and javax.net.ssl.trustStoreType system properties to "pkcs11", and set the javax.net.ssl.keyStore and javax.net.ssl.trustStore system properties to NONE. To specify the use of a vendor smart-card provider, use the javax.net.ssl.keyStoreProvider and javax.net.ssl.trustStoreProvider system properties to identify them. (For example: "SunPKCS11-smart card"). By setting these properties, you can configure an application to use a smart-card keystore with no changes to the application that previously accessed a file-based keystore.

Configuring a Smart card as a Java Keystore

The following example shows how to configure OpenSC supported smart card as a Java keystore and list the certificates using the keytool utility. The OpenSC framework can be downloaded from http://www.opensc.org.

1.

Add the OpenSC PKCS#11 module as the keystore provider in java.security file located at $JAVA_HOME/jre/lib/security/java.security.

    security.provider.8=sun.security.pkcs11.SunPKCS11 \                     /opt/openSC/openscpkcs11-solaris.cfg 

2.

Create the OpenSC PKCS#11 configuration file. For example, the openscpkcs11-solaris.cfg looks like as follows:

name = OpenSC-PKCS11 description = SunPKCS11 w/ OpenSC Smart card Framework library = /usr/lib/pkcs11/opensc-pkcs11.so 

With the above settings, it is possible to use the smart card as a keystore and retrieve information about the certificates. For example (see Example 4-16). Using keytool to list the certificate will look like as follows.

Example 4-16. Using keytool to list certificate entries from a smart card
$ keytool -keystore NONE -storetype PKCS11 \           -providerName SunPKCS11-OpenSC -list -v Enter keystore password: <PIN> Keystore type: PKCS11 Keystore provider: SunPKCS11-OpenSC Your keystore contains 4 entries Alias name: Signature Entry type: keyEntry Certificate chain length: 1 Certificate[1]: Owner: SERIALNUMBER=79797900036, GIVENNAME=Nagappan Expir?e1779, SURNAME=R, CN=Nagappan (Signature), C=US Issuer: CN=Nagappan OpenSSL CA, C=BE Serial number: 1000000000102fdf39941 Valid from: Fri Apr 01 15:29:22 EST 2005 until: Wed Jun 01 15:29:22 EST 2005 Certificate fingerprints:          MD5:  12:20:AC:2F:F2:F5:5E:91:0A:53:7A:4B:8A:F7:39:4F          SHA1: 77:76:48:DA:EC:5E:9C:26:A2:63:A9:EC:A0:14:42:BF:90:53:0F:BC Alias name: Root Entry type: trustedCertEntry Owner: CN=Nagappan OpenSSL Root CA, C=US Issuer: CN=Nagappan OpenSSL Root CA, C=US Serial number: 11111111111111111111111111111112 Valid from: Wed Aug 13 11:00:00 EST 2003 until: Mon Jan 27 00:00:00 EST 2014 Certificate fingerprints:          MD5:  5A:0F:FD:DB:4F:FC:37:D4:CD:95:17:D5:04:01:6E:73          SHA1: 6A:5F:FD:25:7E:85:DC:60:81:82:8D:D1:69:AA:30:4E:7E:37:DD:3B Alias name: Authentication Entry type: keyEntry Certificate chain length: 1 Certificate[1]: Owner: SERIALNUMBER=79797900036, GIVENNAME=Nagappan Expir?e1779, SURNAME=R, CN=NAGAPPAN, C=US Issuer: CN=Nagappan OpenSSL CA, C=US Serial number: 1000000000102fd10d2d9 Valid from: Fri Apr 01 11:21:40 EST 2005 until: Wed Jun 01 11:21:40 EST 2005 Certificate fingerprints:          MD5:  29:7E:8A:5C:91:34:9B:05:52:21:4E:49:5B:45:F8:C4          SHA1: 15:B7:EA:27:E1:0E:9D:94:4E:7B:3B:79:00:48:A2:31:7E:9D:72:1A 

Using Keytool and Jarsigner with Smart Card Tokens

If the Sun PKCS#11 provider (for using a smart card) has been configured in the java.security security properties file, then keytool and jarsigner can be used to operate on the PKCS#11 token by specifying the following options.

  • -keystore NONE

  • -storetype PKCS11

Here is an example of a command to list the contents of the configured PKCS#11 on a smart-card token.

keytool -keystore NONE -storetype PKCS11 list 

The smart-card token PIN can be specified using the -storepass option. If it is not specified, then the keytool and jarsigner tool will prompt the user for the PIN. If the token has a protected authentication path (such as a dedicated PIN-pad or a biometric reader), then the -protected option must be specified, and no password options can be specified. For more information about installing PKCS#11 providers, refer to the JCE PKCS#11 documentation available at http://java.sun.com/j2se/1.5.0/docs/guide/security/p11guide.html.

Strong versus Unlimited Strength Cryptography

By default, JCA allows the use of strong cryptography (128-bit key size). To use 192- and 256-bit key sizes, you are required to use unlimited strength cryptography policy files, which are available as part of a separate download of JCE. U.S. export laws restrict the export and use of JCE with unlimited strength cryptography. Those living in eligible countries may download the unlimited strength version and replace the strong cryptography jar files with the unlimited strength files. Using JCE with unlimited strength cryptography is also subject to the import control restrictions of certain countries. For more information on U.S. export laws related to cryptography, refer to The Bureau of Industry and Security's Web site (U.S. Department of Commerce) at http://www.bxa.doc.gov and the Java Cryptography Extension (JCE) Web site at http://java.sun.com/products/jce/.

To summarize, the JCE implementation and API framework feature an enhancement to JCA that provides a full range of cryptographic services, including support for encryption and decryption and key agreement protocols. It also maintains interoperability with other cryptographic provider implementations. In the next section, we will explore the Java CertPath API, which defines an API framework for creating, building, and validating digital certification paths.




Core Security Patterns. Best Practices and Strategies for J2EE, Web Services, and Identity Management
Core Security Patterns: Best Practices and Strategies for J2EE, Web Services, and Identity Management
ISBN: 0131463071
EAN: 2147483647
Year: 2005
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net