< Day Day Up > |
The JCE framework and implementations for encryption, key generation, key agreement, and MAC algorithms supplement the message digest and digital-signature interfaces and implementations provided in the JCA. Support for encryption includes symmetric, asymmetric, block, and stream ciphers. The software also supports secure streams and sealed ”encrypted ”objects. JCE was previously shipped as a standard extension to the Java 2 SDK V1.2 and 1.3 but has now been integrated into the Java 2 SDK V1.4. JCE is based on the same design principles found elsewhere in the JCA: implementation independence and interoperability, and algorithm independence and extensibility (see Section 11.1.2 on page 379). Additionally, the JCE uses the same provider architecture (see Section 11.1.3 on page 382). Providers signed by a trusted entity can be plugged into the JCE framework, and new algorithms can be added seamlessly. The JCE includes two software components :
The JCE API covers
The JCE provider consists of the main package javax.crypto and its two subpackages javax.crypto.spec and javax.crypto.interfaces .
11.3.1 The javax.crypto.Cipher ClassThe javax.crypto.Cipher engine class forms the core of the JCE framework. This class provides the functionality of a cryptographic cipher used for encryption and decryption. Like other engine classes, the Cipher class is instantiated using its getInstance() static factory method. This method takes as argument a String object that represents a transformation. A transformation is a string that describes the operation or set of operations to be performed on the given input to produce some output. A transformation always includes the name of a cryptographic algorithm, which may be followed by a mode and padding scheme. Therefore, a transformation is of the form algorithm / mode / padding or just algorithm . For example, the following is a valid way to create a Cipher object: Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding"); This Cipher object will be used for encryption or decryption using the DES algorithm with CBC mode of operation. Algorithms usually operate on blocks having a predefined size. Plaintext packets whose length is not a multiple of that size must be padded according to a specified padding scheme prior to encryption. The Cipher c above uses a padding scheme known as PKCS5Padding (see Section 12.1.2 on page 435). If mode and padding are not specified, provider-specific default values are used. Optionally, getInstance() can accept, as a second argument, the name of the provider after the transformation parameter. A Cipher object obtained from getInstance() must be initialized for encryption, decryption, wrap , or unwrap mode . These modes are defined as final int constants in the Cipher class. These four modes can be referenced by their symbolic names : ENCRYPT_MODE , DECRYPT_MODE , WRAP_MODE , and UNWRAP_MODE , respectively. The Cipher will perform a different function, based on its initialized mode.
A Cipher object is initialized by calling the init() method. When this happens, the object loses all previously acquired states. In other words, initializing a Cipher is equivalent to creating a new instance of that Cipher and initializing it. Data can be encrypted or decrypted in one step ( single-part operation) or in multiple steps ( multiple-part operation). This depends on whether you call the doFinal() or the update() method, respectively. A multiple-part operation is useful if the exact length of the data is not known in advance or if the data is too long to be stored in memory all at once. 11.3.2 The CipherInputStream and CipherOutputStream Classes in the javax.crypto PackageThe JCE introduces the concept of secure streams, which combine a java.io.InputStream or a java.io.OutputStream with a Cipher object. Secure streams are provided by the CipherInputStream and CipherOutputStream classes.
The code fragment in Listing 11.12 shows how to
The code makes use of the CipherInputStream class to encrypt and decrypt data passing through a FileInputStream . Listing 11.12. How to Use the CipherInputStream APIimport java.io.FileInputStream; import java.io.FileOutputStream; import java.security.Key; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.CipherInputStream; // Other code goes here... // Generate Cipher objects for encryption and decryption. Cipher cipher1 = Cipher.getInstance("DES"); Cipher cipher2 = Cipher.getInstance("DES"); // Generate a KeyGenerator object. KeyGenerator kg = KeyGenerator.getInstance("DES"); // Generate a DES key. Key desKey = kg.generateKey(); // Initialize the Cipher objects. cipher1.init(Cipher.ENCRYPT_MODE, desKey); cipher2.init(Cipher.DECRYPT_MODE, desKey); // Create the encrypting CipherInputStream. FileInputStream fis = new FileInputStream(inputFile); CipherInputStream cis1 = new CipherInputStream(fis, cipher1); // Create the decrypting CipherInputStream. CipherInputStream cis2 = new CipherInputStream (cis1, cipher2); // Write the decrypted data to output file. FileOutputStream fos = new FileOutputStream(outputFile); byte[] b2 = new byte[1024]; int i2 = cis2.read(b2); while (i2 != -1) { fos.write(b2, 0, i2); i2 = cis2.read(b2); } // Close the streams. fos.close(); cis1.close(); cis2.close(); // Other code goes here... 11.3.3 The javax.crypto.SecretKey InterfaceThe JCE offers a set of classes and interfaces to manage secret keys. At the root of the hierarchy is the javax.crypto.SecretKey interface, which contains no methods or constants. Its only purpose is to group and provide type safety for secret, or symmetric, keys. Provider implementations of this interface must overwrite the equals() and hashCode() methods inherited from java.lang.Object , so that secret keys are compared on the basis of their underlying key material, not on reference. Because it extends the Key interface (see Section 11.2.2 on page 393), this interface is an opaque representation of a symmetric key. 11.3.4 The javax.crypto.spec.SecretKeySpec ClassThe javax.crypto.spec.SecretKeySpec class specifies a secret key in a provider-independent fashion. The class can be used to construct a SecretKey from a byte array, without the need to go through a provider-based SecretKeyFactory . This class is useful only for raw secret keys that have been pregenerated, can be represented as a byte array, and have no key parameters associated with them: for example, DES or Triple-DES keys. This class is a transparent representation of a symmetric key. 11.3.5 The javax.crypto.KeyGenerator ClassAs we saw in Section 11.2.6 on page 394, the KeyPairGenerator class is used to generate a pair of public and private keys. The JCE provides for a KeyGenerator engine class, which is used to generate secret keys for symmetric algorithms. KeyGenerator objects are created using the getInstance() factory method of the KeyGenerator class. Note that a factory method is by definition static. The getInstance() method takes as its argument the name of a symmetric algorithm for which a secret key is to be generated. Optionally, a package provider name may be specified. If only an algorithm name is specified, the system will determine whether an implementation of the requested key-generator algorithm is available in the environment; if there is more than one, the preferred one will be selected. If both an algorithm name and a package provider are specified, the system will determine whether an implementation of the requested key-generator algorithm is in the package requested and throw a NoSuchAlgorithmException if there is not. A KeyGenerator for a particular symmetric-key algorithm creates a symmetric key that can be used with that algorithm and associates algorithm-specific parameters, if any, with the generated key. 11.3.6 The javax.crypto.SecretKeyFactory ClassThe javax.crypto.SecretKeyFactory class represents a factory for secret keys. A KeyFactory (see Section 11.2.4 on page 394) is bidirectional, which means that it allows building an opaque Key object from a given key specification ”key material ”or retrieving the underlying key material of a Key object in a suitable format. In general, a KeyFactory is used to convert keys ”opaque cryptographic keys of type Key ”into key specifications ”transparent representations of the underlying key material ”and vice versa. In particular, SecretKeyFactory operates only on secret, or symmetric, keys, whereas a KeyFactory object processes both the public- and the private-key components of a key pair. Objects of type java.security.Key ”an interface of which PublicKey , PrivateKey (see Section 11.2.3 on page 393) and SecretKey (see Section 11.3.3 on page 421) are subinterfaces ”are opaque key objects; you cannot tell how they are implemented. The underlying implementation is provider dependent and may be software or hardware based. KeyFactory allows providers to supply their own implementations of cryptographic keys. For example, suppose that you have a key specification for a DH public key, consisting of the public value y , the prime modulus q , and the base generator a (see Section 10.3.1.2 on page 362). If you feed the same specification to DH KeyFactory objects from various providers, the resulting PublicKey objects will most likely have different underlying implementations. A provider should document the key specifications supported by its SecretKeyFactory .
11.3.7 The javax.crypto.SealedObject ClassThis class enables a programmer to create a Serializable Object and protect its confidentiality with a cryptographic algorithm. This provides a way of storing Serializable Object s safely. Given any Object whose class implements the java.io.Serializable interface, one can create a SealedObject that encapsulates the original Object , in serialized format ”a deep copy of the Object ”and seals, or encrypts, its serialized contents, using a cryptographic algorithm, such as DES, to protect the Object 's confidentiality. The encrypted content can later be decrypted and deserialized, yielding the original Object . This class provides a variety of options for decrypting a SealedObject and recovering it in its original form. The original Object can be recovered by either passing the same Cipher object appropriately initialized with the same key and algorithm parameters as used for encryption or by passing only the decryption key; in this case, the appropriate Cipher object is automatically created with the decryption key and the same algorithm parameters that were stored in the sealed object. The code fragment in Listing 11.13, which could be embedded in any J2EE application, illustrates the use of the SealedObject class. Listing 11.13. How to Use the SealedObject Classimport java.security.Key; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SealedObject; // Other code goes here... // Generate Cipher objects for encoding and decoding. Cipher cipher1 = Cipher.getInstance("DES"); Cipher cipher2 = Cipher.getInstance("DES"); // Generate a KeyGenerator object. KeyGenerator kg = KeyGenerator.getInstance("DES"); // generate a DES key. Key desKey = kg.generateKey(); // Initialize the Ciphers for encryption and decryption. cipher1.init(Cipher.ENCRYPT_MODE, mykey); cipher2.init(Cipher.DECRYPT_MODE, mykey); // Seal a String object. SealedObject s = new SealedObject ("SSN 123-456-7890", cipher1); // Recover the sealed String object String s1 = (String) s.getObject(cipher2); System.out.println ("The sealed object is: " + s1); // Other code goes here... 11.3.8 The javax.crypto.KeyAgreement ClassWhenever two or more parties decide to initiate a secure conversation over a nonsecure communication channel using secret-key encryption, they need to use the same secret key ”which is called the session key ”without transmitting it in the clear over the channel. To achieve this result, public-key encryption can be used to transmit the session key securely. An alternative is to use a key agreement , a protocol that allows two or more parties to calculate the same secret value without exchanging it directly. Therefore, the parties share the same secret key and can encrypt the communication using symmetric encryption. The most famous of these protocols is the DH algorithm (see Section 10.3.1.2 on page 362). The javax.crypto.KeyAgreement class provides the functionality of a key-agreement protocol. The keys involved in establishing a shared secret key are created by KeyPairGenerator or KeyGenerator , a KeyFactory , or as a result from an intermediate phase of the key-agreement protocol. Each party involved in the key agreement has to create a KeyAgreement object. This can be done using the getInstance() factory method of the KeyAgreement engine class. This method accepts as its argument a String representing a key-agreement algorithm as parameter. Optionally, you can specify a provider as the second argument.
If the DH algorithm is used, a DH private key is used to initialize the KeyAgreement object. Additional initialization information may contain a source of randomness and/or a set of algorithm parameters. Every key-agreement protocol consists of a number of phases that need to be executed by each party involved in the key agreement. The doPhase() method is used to execute the next phase in the key agreement. This method takes two arguments: a Key and a boolean .
After each party has executed all the required key-agreement phases, the key agreement can compute the shared secret by calling the generateSecret() method. 11.3.9 The javax.crypto.Mac ClassThe Mac class provides the functionality of a MAC (see Section 10.2.2.4 on page 356). As with all other engine classes in the API, Mac objects are created using the getInstance() factory methods of the Mac class. A factory method is a static method that returns an instance of a class; in this case, an instance of Mac that provides the requested MAC algorithm. The getInstance() method takes as its argument the name of a MAC algorithm. Optionally, a package provider name may be specified.
|
< Day Day Up > |