| ## Java 1.1 Unleashed # - 16 - The Security Package by Qusay H. Mahmoud IN THIS CHAPTER An Introduction to Cryptography Java Security Mechanisms in JDK 1.0 Overview of the Java Security API The Java Security API Core Classes The javakey Tool Certificates The introduction of worldwide computer networks has led to issues related to communication channels protection. Communication channels are accessible to eavesdroppers, and the only way to enforce protection for those communication channels is to apply cryptography. Cryptography is used to protect information to which illegal access is possible. Cryptography is defined as "the science of secret writing." ## An Introduction to Cryptography The Java Security API is based on cryptography. A quick review of some of the concepts of cryptography will help you better understand how the security package works. In cryptography, the main operation is encryption. Encryption is a special computation that converts messages into representations that are meaningless to all parties except the intended receiver. Because there are many encryption algorithms, you have a choice to make--and your choice depends on the sensitivity of the data you want to encrypt. There are two types of encryption: conventional encryption and public-key encryption. ### Conventional Encryption Conventional encryption is also known as symmetric encryption, or single-key encryption, or private-key encryption. Conventional encryption was the only type available before the development of public-key encryption. In conventional encryption, the process of encryption consists of an algorithm and a key. The key is shared between the sender of the message and the intended receiver. The original message, referred to as plain text, is converted into scrambled text known as cipher text. The output of the algorithm used depends on the key; different keys return different output. Once the message has been encrypted, it can be transmitted. After it is received, it can be converted back to plain text by using a decryption algorithm with the same key used to encrypt the message. Note that the key must be kept secret. An example of conventional encryption is DES (Data Encryption Standard). ### Public-Key Encryption Public-key encryption is also known as asymmetric encryption. One of the main reasons that led to the development of this type of encryption was the problem of distributing the keys (key management) in conventional encryption. In public-key encryption, there are two keys (rather than the one key used in conventional encryption): One is public (can be seen by anyone), and one is private (must be kept secret and only its owner should know it). An example of public-key encryption is RSA (Rivest-Shamir-Adleman). ### Digital Signatures In the real world, it is easy to differentiate between originals and copies. In the digital world, the task of differentiating between originals and copies is almost impossible because all information is represented as bits. Therefore, in the digital world, we need a mechanism by which one party can send a "signed" message to another party so that: The receiver can verify the claimed identity of the sender. The sender cannot duplicate the message at a later time. A digital signature therefore establishes sender authenticity. It is analogous to an ordinary written signature in that: It must be able to verify the author, data, and time of the signature. It must be verifiable by third parties to resolve disputes. For digital signatures to be of practical use, they must have the following properties: They must be easy to produce. They must be easy to recognize and verify. It must be computationally infeasible to forge a digital signature, either by constructing a new message for an existing digital signature or by constructing a fraudulent digital signature for a given message. Public-key cryptosystems provide a simple scheme for implementing digital signatures. However, note that conventional cryptosystems, such as DES, do not in themselves provide sender authenticity because the sender and receiver share the same key. An example of digital signature is DSA (Digital Signature Algorithm), which is supported by the security API in JDK 1.1. ### Certification One of the limitations of public-key encryption is its inability to verify that a public key belongs to the individual you believe it does. It is possible that a hostile individual can send you a message signed with a secret key, claiming to be from another party. The attacker then advertises a public key; you retrieve that key and decrypt the signature. Believing that you have verified the author, you now trust information written by that hostile source. Thus, there is a need for a certificate and a certification authority. A certificate is a block of data that identifies a user and is signed by a third party, the certification authority. The most common certificate format is the X.509. The X.509 certificate contains standard information about the user name, organization, e-mail address, and so on, along with the user's public key. Certification Authorities (CA) have four primary functions: to issue new certificates and key pairs to users, to store a copy of each user's private key, to answer queries for users' certificates, and to keep an updated list of revoked and invalid certificates. ## Java Security Mechanisms in JDK 1.0 Until now, applets have been one of the most exciting uses of the Java platform. However, the use of applets adds security vulnerabilities to your programming tasks. The automatic distribution and execution of applets makes it likely that software can be obtained from untrusted third parties; because this software is downloaded to the user's machine and run locally, the untrusted software can potentially steal or damage information and files stored on the user's machine. The beta release of JDK 1.0 introduced the `SecurityManager` class. The `SecurityManager` class defines and implements a security policy by centralizing all access-control decisions. Web browsers such as HotJava, Netscape, and Microsoft IE use the `SecurityManager` class to define and implement their own browser security policies when dealing with applets. When executing untrusted code from an applet, the browser installs its own security manager. Java protects its users from the dangers of untrusted code by placing strict limitations on applets: Applets cannot read from or write to the local disk. Applets cannot make network connections to computers other than the one from which they were downloaded. ### How Can Cryptography Help? Encryption can expand the capabilities of applets. If an applet is digitally signed with a public key, you can identify the person who has created the applet. With the Java Security API, you can establish trust relationships. In a trust relationship, applets do not have the restrictions just listed and can do the following: Read from and write to files residing on your computer Make network connections to computers throughout the Internet ## Overview of the Java Security API The `java.security` package lets developers incorporate low-level and high-level security functionality into their Java applications (both applets and standalone applications). The Java Security API provides APIs for digital signatures, message digests, key management, and access control lists. A message digest is a condensed form of the original message, produced using a hash function that maps a variable-length message into a fixed-length value called a hash code. Key management refers to the technique used for the distribution of public keys and the use of public-key encryption for the distribution of private keys. An access control list lists users and their permitted access rights to objects. The JDK 1.1 includes the `javakey` utility for managing keys and certificates and for digitally signing files. The JDK also includes facilities for signing and verifying Java ARchive (JAR) files. The Java Security API introduces the notion of a Security Package Provider (SPP). A provider is a package or a set of packages that provides a particular implementation of a subset of the Java Security API. The Java Security API itself provides mostly interfaces and abstract classes. To put security to work, you need implementations for the interfaces and abstract classes; this is where SPPs come in to play. SPPs are explicitly installed and configured according to the developer's preferences. The JDK 1.1 comes with a default security provider known as the Sun Security Provider, or SUN. The `sun.security.provider` package provides implementations for the following: The digital signature standard The message digests MD5 and SHA (Secure Hash Algorithm) In addition, the SUN provider provides implementations of a simple key system and a trust management mechanism. Note that the `sun.security.provider` classes should not be accessed directly. If the requested security provider is SUN, those classes are instantiated and used by the Java Security API. ## The Java Security API Core Classes The following sections describe the core classes of the Java Security API. ### The Signature Class The `Signature` class is a subclass of `Object`. The `Signature` class provides the functionality of the Digital Signature Algorithm (DSA). Once a `Signature` object has been created, it can be used for two purposes: To sign data To verify that an alleged signature is in fact the authentic signature of the data associated with it A `Signature` object can be in one of three states: `UNINITIALIZED`, `SIGN`, or `VERIFY`. Thus, a `Signature` object can do only one type of operation at a given time. When you first create a `Signature` object, it is in the `UNINITIALIZED` state. Two initialization methods are defined in the `Signature` class: `initSign()` and `initVerify()`. These methods change the state of the `Signature` object to `SIGN` and `VERIFY`, respectively. Once a `Signature` object has been created and initialized, it can be used to sign data or verify a signature. #### Creating a Signature Object Some developers may be interested in implementing other digital signature algorithms (that is, the developer may want to request a particular signature algorithm). If a developer wants to implement a particular signature algorithm, he or she has to provide a Security Provider Package (SPP). Thus, it is possible to call a particular signature algorithm from a particular package. To create a `Signature` object, the programmer has the choice of specifying an algorithm or both an algorithm and a provider using one of the following methods: `public static Signature getInstance(String algorithm) throws NoSuchAlgorithmException` `public static Signature getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException` A call to the first method generates a `Signature` object that implements the specified algo- rithm as the argument to `getInstance()`. If no such algorithm exists, the exception, `NoSuchAlgorithmException`, is thrown. A call to the second method generates a `Signature` object that implements the specified algorithm supplied by the specified provider. If no such algorithm is implemented by the specified provider, the exception, `NoSuchAlgorithmException`, is thrown. If the specified provider does not exist, the exception, `NoSuchProviderException`, is thrown. Once a `Signature` object has been created, it must be initialized. As mentioned earlier, a `Signature` object can be in one of three states: `UNITIALIZED` (when the object is created), `SIGN`, and `VERIFY`. The state to which you initialize a `Signature` object depends on whether the object is going to be used for signing data or verifying a signature. If the `Signature` object is going to be used for signing data, that object must be initialized with the private key of the entity whose signature is going to be generated. You can initialize the `Signature` object to the `SIGN` state by calling this method: `public final void initSign(PrivateKey` priv) throws InvalidKeyException If the key provided is invalid, the exception, `InvalidKeyException`, is thrown. Once this method is called, the state of the `Signature` object becomes `SIGN`. If the `Signature` object is going to be used for verifying a signature, it must be initialized with the public key of the entity whose signature is going to be verified. In this case, you initialize the `Signature` object to the `VERIFY` state by calling this method: `public final void initVerify(PublicKey` pub) throws InvalidKeyException Again, if the key provided is invalid, the exception, `InvalidKeyException`, is thrown. #### Signing Data If a `Signature` object is in the `SIGN` state (that is, it has been initialized for signing with the `initSign()` method), the data to be signed can be supplied to the object by making one or more calls to one of the following `update()` methods: `public final void update(byte` b`) throws SignatureException` Updates the data to be signed by byte. `public final void update(byte` data`[]) throws SignatureException` Updates the data to be signed using the specified array of bytes. `public final void update(byte` data`[], int` off`, int` len`) throws SignatureException` Updates the data to be signed or verified using the specified array of bytes, starting at the specified offset. A `SignatureException` is thrown by any of these methods if the `Signature` object is not initialized properly. To generate the signature, you simply call the `sign()` method: `public final byte[] sign() throws SignatureException` #### Verifying a Signature If a `Signature` object is in the `VERIFY` state (that is, it has been initialized with the `initVerify()` method), the data to be verified can be supplied to the object by making one or more calls to the three `update()` methods just described. Once the updating process is complete, the signature can be verified simply by calling the `verify()` method: `public final boolean verify(byte signature[]) throws SignatureException` Listing 16.1 is an example of how to sign a file by using the private key of a signer defined and generated by the `javakey` tool. The example uses some of the other classes' methods, explained later in this chapter. #### Listing 16.1. Signing a file with a private key defined and generated by the javakey tool.
    // package java.security
    import java.io.*;
    import java.util.*;
    import java.security.*;

    public class SigFile {
    public static void main(String argv[]) {
            IdentityScope ss = IdentityScope.getSystemScope();
            Signer sig = (Signer) ss.getIdentity("alice");
            PrivateKey priv = sig.getPrivateKey();
            PublicKey pub = sig.getPublicKey();
            try {
              Signature signature;
              signature = Signature.getInstance("DSA");
              signature.initSign(priv);
              File file = new File("test.data");
              FileInputStream fis = new FileInputStream(file);
              while (fis.available() != 0) {
                signature.update((byte)fis.read());
              }
              byte[] realSignature = signature.sign();
              System.out.println(realSignature);
              signature.initVerify(pub);
              File f = new File("test.data");
              FileInputStream fx = new FileInputStream(f);
              while (fx.available() != 0) {
                signature.update((byte)fx.read());
              }
              if (signature.verify(realSignature)) {
                System.out.println("Signature checks out");
              } else {
                System.out.println("Signature does not check out");
              }
            }catch(Exception e) {
               System.err.println(e);
            }
        }
    }
To run the program in Listing 16.1, you must first create a file called `test.data`. Put anything you like in that file. Note that a signer with the user name `alice` must exist in the database managed by `javakey`. When you run the program, you should see something like this:
    % java SigFile
    [B@1dc62277
    Signature checks out
The first line of the output of the program is the signature used for signing the file; the second line tells us that `alice`'s signature has been verified. ### The java.security.Key Interface The `Key` interface is the base interface for all keys. The `Key` interface defines the characteristics shared by all `Key` objects. These characteristics are listed here: An algorithm: This is the algorithm for that particular key. It is an encryption algorithm such as RSA or DSA. The name of the algorithm of a key can be obtained using this method: `public abstract String getAlgorithm()` This method returns the name of the algorithm for that key. A `null` value is returned if the algorithm for this key is unknown. An encoded form: This is an external encoded form for the key used when a representation of the key is required outside the Java virtual machine. The key is encoded according to a standard format: X.509. The encoded key can be obtained by calling this method: `public abstract byte[] getEncoded()` A `null` value is returned if the key does not support encoding. A format: This is the name of the format of the encoded key, which can be obtained by a call to this method: `public abstract String getFormat()` A `null` value is returned if the key does not support encoding. In addition to the `Key` interface, you should be aware of two other key interfaces that are part of the Security API. The `PrivateKey` interface provides neither methods nor constants. It groups all private-key interfaces. Specialized private-key interfaces such as `DSAPrivateKey` extend this interface. The `PublicKey` interface provides neither methods nor constants. It groups all public-key interfaces. Specialized public-key interfaces such as `DSAPublicKey` extend this interface. NOTE: Interfaces are useful for designing reusable object-oriented software libraries and frameworks. The `PublicKey` and `PrivateKey` interfaces are methodless and are used mainly for type safety and type identification purposes. ### The KeyPair Class The `KeyPair` class extends the `Object` class. This class is a holder for a key pair--a public key and a private key. This class has two methods: `public PublicKey getPublic()` returns the public key, and `public PrivateKey getPrivate()` returns the private key. ### The KeyPairGenerator Class The `KeyPairGenerator` class is used to generate a pair of keys: a public key and a private key. You can generate keys using `KeyPairGenerator` in two ways: by using algorithm-independent or algorithm-specific methods. The only difference between the two approaches is the initialization of the object. You must initialize a `KeyPairGenerator` before you can use it to generate keys. Note that algorithm-independent initialization is sufficient for most cases; however, if you want more control over the parameter of the algorithm, you can use a particular algorithm initialization approach. To generate a pair of keys, follow these steps: 1. Create a `KeyPairGenerator` object for generating keys. This line of Java code creates an instance object of `KeyPairGenerator` to generate keys for the DSA algorithm: `KeyPairGenerator keys = KeyPairGenerator.getInstance("DSA");` 2. Initialize the `KeyPairGenerator`. Before you initialize the `KeyPairGenerator`, you must decide whether you want to generate keys using an algorithm-independent or algorithm-specific approach. For demonstration purposes, let's do it both ways: Algorithm-independent initialization: Initialization can be done using `KeyPairGenerator`'s method, `initialize()`: `public abstract void initialize(int` strength, SecureRandom random) The strength argument refers to the strength of the key; the random argument refers to the source of randomness--which can be obtained from the `SecureRandom` class, described later in this chapter. If you want to generate your keys with a modulus length of `1024` and an automatically seeded random number, you can use the following code: `keys.initialize(1024, new SecureRandom());` Algorithm-specific initialization: As you can see in the preceding line of code, we have accepted the default parameters supplied by the SUN provider. However, if you want to have control over those parameters, you may use algorithm-specific initialization. In this approach, you must set the DSA-specific parameters: `p`, `q`, and `g`. `q` is a 160-bit prime number. `p` is a prime number with a length between 512 and 1,024 bits such that `q` divides `(p-1)`; `g` is a number of the form `h((p-1)/q) mod p` where `h` is an integer between `1` and `(p-1)`. If you don't want to accept the default values for these parameters, set them yourself. You can do this with the following code: `D` `SAParams params = new DSAParams(p, q, g); DSAKeyPairGenerator dsaKeys = (DSAKeyPairGenerator)keys; dsaKeys.initialize(params, new SecureRandom());``` In this example, we cast the `KeyPairGenerator` object created with `KeyPairGenerator.getInstance()` to a specific algorithm--DSA in this case, because that is what we want to use. The DSA algorithm implements the `DSAKeyPairGenerator`. 3. Generate the key pair using this code: `KeyPair pair = keys.generateKeyPair();` This statement generates a pair of keys: a public key and a private key. If you want to extract the public key from the pair, use the `getPublic()` method of `KeyPair`: `pair.getPublic();` `` To extract the private key, use the `getPrivate()` method of `KeyPair`: `pair.getPrivate();` Listing 16.2 shows the complete program for using an algorithm-independent initialization. #### Listing 16.2. Key pairs generation using an algorithm-independent initialization.
    import java.security.*;

    class Ks {
        public static void main(String argv[]) {
            KeyPairGenerator keys = null;
            try {
              keys = KeyPairGenerator.getInstance("DSA");
            } catch(NoSuchAlgorithmException e) {
              System.err.println(e);
            }
            keys.initialize(1024, new SecureRandom());
            KeyPair pair = keys.generateKeyPair();

           System.out.println(pair.getPublic().toString());  // public key
           System.out.println(pair.getPrivate().toString()); // private key
        }
    }
If you compile the code in Listing 16.2 and run it, you generate a pair of keys using algorithm-independent initialization. You should see something similar to the following. In this output, the `y` value refers to the public key, and the `x` value refers to the private key.
    % java Ks        # the % is my csh prompt under unix
    Sun DSA Public Key
    parameters:
    p: fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f
    5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a61
    50f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7

    q: 9760508f15230bccb292b982a2eb840bf0581cf5
    g: f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b4
    49167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243
    bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a

    y: 47006b52c5c2b766f6e6864758f4a79fd4f069317de66a13093f42ac32176217f23d174899dc02ffca009c21f78f77c
    4c258bdfa8069fd493148b78da6d5860216793a1b51faa9a7800867bcba912ca762847d30a57f87e4676dff91bbeb0d35c
    a2591d4c4293b910435fc552a346fc2bfef921f6b398d1a9531a486fbc28ff0

    Sun DSA Private Key
    parameters:
    p: fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f
    6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d
    3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7

    q: 9760508f15230bccb292b982a2eb840bf0581cf5
    g: f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b44916
    7123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1b
    ea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a
    x: 3669898a02adf49267ac1f07fd49952132c133b4
### The SecureRandom Class This `SecureRandom` class extends `Random` and provides a platform-independent, cryptographically strong random-number generator. You can create an instance of `SecureRandom` in two ways: by using the default (automatically generated) seed or by providing the seed yourself. Not surprisingly, then, there are two constructors of `SecureRandom`:
    SecureRandom()
    SecureRandom(byte[] seed)
The `SecureRandom` class provides five methods for using and reseeding a `SecureRandom` object: `public synchronized void setSeed(byte seed[])` This method reseeds the `SecureRandom` object, where the given seed supplements (rather than replaces) the existing seed. Repeated calls never reduce randomness. `public void setSeed(long seed)` This method reseeds a `SecureRandom` object using the eight bytes in the given `long` argument. As with the preceding method, the given seed supplements the existing one. `public synchronized void nextBytes(byte bytes[])` This method generates a user-specified number of random bytes. The array given as argument is filled with random bytes. `protected final int next(int` `numBits``)` This method generates an integer containing the user-specified number of random bits. `public static byte[] getSeed(int numBytes)` This method returns the given number of seed bytes,. You have already seen how to use methods from this class in the example in Listing 16.2. ### The Identity Class The `Identity` class is one of the key-management classes and is the basic key-management entity. This class represents real-world objects such as people, organizations, and so on whose identities can be authenticated using their public keys. An `Identity` object has a name and a public key. An `Identity` object may also have a scope, as described in the following section. An `Identity` object also has a set of certificates that certify its public key. The `Identity` class can be inherited so that you can add your e-mail address, an image of your face, and so on. The `Identity` class has a handful of methods. However, the most important ones are those that return the object's name, public key, and scope:
    public final String getName()
    public final IdentityScope getScope()
    public PublicKey getPublicKey()
Note that the methods `getName()` and `getScope()` are `final`, thus the name and scope of the `Identity` object are immutable. ### The IdentityScope Class The `IdentityScope` class is a subclass of the `Identity` class. This class merely serves as an abstraction for repositories of `Identity` objects. These repositories can be used, for example, to assign permission and verify classes being loaded. They can also be used by signing tools to retrieve private keys and generate digital signatures. An `IdentityScope` object is an `Identity` object itself. Thus, an `IdentityScope` object has a name, a public key, and a scope. Note that no two objects in the same scope can have the same public key. Some of the important methods in the `IdentityScope` class are listed here: `public abstract void addIdentity(Identity identity) throws KeyManagementException` This method adds an identity to this `IdentityScope`. An exception is thrown if the identity is not valid, if there is a name conflict, or if another identity has the same public key. p`ublic abstract Identity getIdentity(String name) public abstract Identity getIdentity(PublicKey` key`)` With these two methods, you can retrieve an identity, given either its name or its public key. `public abstract void removeIdentity(Identity identity)throwsKeyManagementException` This method removes an identity from this `IdentityScope`. An exception is thrown if the identity is missing. `public abstract Enumeration identities()`With this method, you can get an enumeration of all identities in this identity scope. Listings 16.3 through 16.5 show some examples of how to retrieve identities. #### Listing 16.3. Retrieving an identity, given its name.
    import java.security.*;

    // retrieve an identity given its name
    class ID {
        public static void main(String argv[]) {
            IdentityScope id = IdentityScope.getSystemScope();
            // please see javakey tool below to see how we created the identity "alice".
            Identity d  = id.getIdentity("alice");
            System.out.println(d.toString());
       }
    }
Compiling and running this program gives an output similar to the following. Note that if an identity with the user name `alice` has not been created, the program returns an error.
    % java ID
    [Signer]alice[identitydb.obj][trusted]
#### Listing 16.4. Retrieving an identity, given its public key.
    import java.util.*;
    import java.security.*;

    // retrieve all the identities in the system scope
    class Ids {
        public static void main(String argv[]) {
            IdentityScope id = IdentityScope.getSystemScope();
            Enumeration e = id.identities();
            while (e.hasMoreElements()) {
               System.out.println(e.nextElement());
            }
        }
    }
Compiling and running this code gives the following output:
    % java ID2
    [Signer]alice[identitydb.obj][trusted]
#### Listing 16.5. Retrieving all identities in the system scope.
    import java.util.*;
    import java.security.*;

    // retrieve all the identities in the system scope
    class Ids {
        public static void main(String argv[]) {
            IdentityScope id = IdentityScope.getSystemScope();
            Enumeration e = id.identities();
            while (e.hasMoreElements()) {
               System.out.println(e.nextElement());
            }
        }
    }
Compiling and running this program gives the following output. Note that your output will differ depending on how many identities have you created.
    % java Ids
    [Signer]duke[identitydb.obj][trusted]
    jane[identitydb.obj][not trusted]
    [Signer]alice[identitydb.obj][trusted]
### The Signer Class The `Signer` class extends the `Identity` class. The `Signer` class can be used to represent an entity that can sign data. Such an entity must have a public and a private key. There are two main methods in the `Signer` class: `public PrivateKey getPrivateKey()` This method returns the signer's private key. `public final void setKeyPair(KeyPair` pair`) throws InvalidParameterException, KeyException` This method is used to set the key pair for the signer. An exception is thrown if the key pair is not properly initialized. An example of how to use this class was shown in Listing 16.4, which retrieved an identity given its public key. ### The Provider Class The `Provider` class represents a Security Package Provider (SPP, but provider for short). A provider is a package or a set of packages that implements some or all parts of Java security, including algorithms (such as DSA, RSA, MD5, and so on) and key-generation and key- management facilities. Each provider has a name and a version number. JDK 1.1 comes with a default provider with the name SUN. The main methods in the `Provider` class are listed here: `public String getName()` This method returns the name of the provider `public double getVersion`() This method returns the version number of the provider. `public String getInfo()` This method returns information about the provider such as a description of the provider and its services. Listing 16.6 shows an example of the usage of this class. #### Listing 16.6. Using the SUN provider and the Provider class methods.
    import java.security.*;

    class Supp {
        public static void main(String argv[]) {
            Provider p = Security.getProvider("SUN");  // please see the Security class below
            System.out.println(p.getName());           // name of the security package provider (SPP)
            System.out.println(p.getVersion());        // the version number
            System.out.println(p.getInfo());           // information about the SPP
        }
    }
Compile and run this code to see the following output:
    % java Supp
    SUN
    1.0
    SUN Security Provider v1.0, DSA signing and key generation, SHA-1 and MD5 message digests.
### The Security Class The `Security` class is a subclass of `Object`. The `Security` class has two main purposes: To manage security properties To manage Security Package Providers (SPPs) The `Security` class provides only `static` methods and is never instantiated. Thus, the methods in this class can be called only from a trusted program. Here, a trusted program refers to either a local application or a trusted applet. One of the main purposes of the `Security` class is to manage providers. Thus, this class provides methods to do just that: `public static int addProvider(Provider provider)` This method adds a provider to the next position available. The method returns either the position in which the provider was added or `-1` if the provider was not added for some reason (for example, it is already installed). `public static void removeProvider(String name)` This method removes the provider with the specified name. Nothing is returned if the provider is not installed. `public static Provider[] getProviders()`This method returns an array of all providers currently installed. The small program in Listing 16.7 shows how to get a list of currently installed providers. #### Listing 16.7. Getting a list of currently installed providers.
    import java.security.*;

    class Supps {
        public static void main(String argv[]) {
            Provider p[] = Security.getProviders();
            for (int i=0; i<p.length; i++) {
               System.out.println(p[i].toString());
            }
        }
    }
Compiling and running this program gives the following output:
    % java Supps
    SUN version 1.0
### The MessageDigest Class The `MessageDigest` class is an engine that provides a cryptographically secure message digest such as SHA-1 (Secure Hashing Algorithm) or MD5. Message digests, or digital fingerprints, are used to produce unique identifiers of data. A digest has the following properties: It should be computationally infeasible to find another input string that generates the same digest. The digest does not reveal anything about the input string that was used to generate it. There are three steps to follow in computing a message digest: 1. Create a `MessageDigest` object by calling this method: `public static MessageDigest getInstance(String` algorithm) If you want to specify a particular provider, call this method: `public static MessageDigest getInstance(String` algorithm, String provider) 2. Update the `MessageDigest` object by making one or more calls to one of the `update()` methods: `public void update(byte input)` `public void update(byte[] input)` `public void update(byte[] input, int offset, int len)` 3. Compute the digest (hash) by calling one of the `digest()` methods: `public byte[] digest()` `public byte[] digest(byte[] input)` Listing 16.8 is an example that shows how to compute a digest. #### Listing 16.8. Computing a digest.
    import java.util.*;
    import java.security.*;

    // message digest
    class Med {
        public static void main(String argv[]) {
            MessageDigest md = null;
            try {
              md = MessageDigest.getInstance("SHA");
            } catch(NoSuchAlgorithmException nsa) {
               System.err.println("Error: "+nsa);
            }
            String alg = md.getAlgorithm();  // what algorithm are we using? obviously SHA
            System.out.println(alg);

            byte b[] = new byte[100];
            for (int i=0; i<100; i++) {
               b[i] = (byte) i;
            }
            md.update(b);
            byte[] hash = md.digest();
            System.out.println(hash.toString());

        }
    }
Compile and run this program to see the following output. The first line of output is the algorithm used (SHA), and the second line is the hash code generated.
    % java Med
    SHA
    [B@1dc607a2
> ## The javakey Tool The `javakey` tool manages a database of entities, their key pairs (public key and private key), and certificates. The tool is also used to generate and verify signatures for Java ARchive (JAR) files. The `javakey` tool always generates signatures using the Digital Signature Algorithm (DSA). In its current implementation, there is one database per user. The `javakey` tool manages two kinds of entities: identities and signers. Identities are real-world objects, such as people and organizations that have a public key associated with them; signers have private keys in addition to public keys associated with them. Note that you can sign files only with private keys--you cannot use public keys to sign files. Also note that before signing files, you must generate a public and private key pair. Using `javakey`, you can either import existing keys or generate new ones for entities and signers. Entities (identities and signers) have a user name in the database managed by `javakey`. The user name is local to the database, so it does not have to be the same user name as your login ID on a UNIX machine, for example. User names can be specified when you add entities to the database. The `javakey` tool has many options you can specify on the command line, as shown in the following examples: Create a trusted signer called `alice`:
>     % javakey -cs alice true
>     Created identity [Signer]alice[identitydb.obj][trusted]
> Create a trusted entity called `bob`:
>     % javakey -c bob true
>     Created identity bob[identitydb.obj][trusted]
Generate a key pair for `alice` using `512` as the key size and writing a copy of the public key to the file `/tmp/pk`: `% javakey -gk alice DSA 512 /tmp/pk Generated DSA keys for [Signer]alice[identitydb.obj][trusted] (strength:512). Saved public key to /tmp/pk.` Get detailed information about the signer `alice`: `% javakey -li alice Identity: alice [Signer]alice[identitydb.obj][trusted] public and private keys initialized certificates: No further information available.` ## Certificates A certificate is a digitally signed statement from one signer that says the public key of some other entity (the identity of a signer) has a particular value. If you trust the entity that signed the certificate, then you trust that the association between the specified public key and another entity is authentic. ### Generating a Certificate You must first generate a directive file before generating a certificate. In the directive file, you must supply the following information: Information about the signer of the certificate Information about the entity whose public key is being authenticated Information about the certificate itself The name of a file in which to save a copy of the certificate (this is optional) Listing 16.9 shows an example of a directive file. Note that lines starting with a pound sign (#) are comments. Note that the serial number must be unique to distinguish this certificate from other certificates signed by the issuer. Also note that in the example in Listing 16.9, the `signature.algorithm` field is missing. This means that we are using the DSA algorithm. If you want to use another algorithm, you must use the `signature.algorithm` field to specify the algorithm you want to use. #### Listing 16.9. A sample directive file.
    # Filename: directivefile
    # Information about the signer
    issuer.name=alice
    issuer.real.name=Alice Johnson
    issuer.org.unit=Management
    issuer.org=Sekurity Inc
    issuer.country=SomeCountry

    # Information about the entity whose public key is being authenticated
    subject.name=alice
    subject.real.name=Alice Johnson
    subject.org.unit=Management
    subject.org=Sekurity Inc
    subject.country=SomeCountry

    # Information about the certificate
    state.date=1 March 1997
    end.date=1 March 1997
    serial.number=1002

    # Name of a file in which to save a copy of the certificate
    out.file=certif
To generate a certificate, issue the following command:
    % javakey -gc directivefile
    Generated certificate from directive file directivefile.
To display information about the certificate, issue this command:
    % javakey -dc certif

    [
    X.509v1 certificate,
    Subject is CN=Alice Johnson, OU=Management, O=Sekurity Inc, C=SomeCountry
    Key:  Sun DSA Public Key
    parameters:
    p:
    fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bc d132acd50d99151bdc43ee737592e17

    q: 962eddcc369cba8ebb260ee6b6a126d9346e38c5
    g:
    678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1 c2062354d0da20a6c416e50be794ca4
    y:
    2bfe2d23d60ce90554965bbb065b910c9fa874fa3b771a21850fd28222706c93409119b42f7d555ff86c267dae7241a93e 97c8a202dbe9f885e642e29bcad441
    Validity <Fri Feb 28 16:00:00 PST 1997> until <Fri Feb 28 16:00:00 PST
    1997>
    Issuer is CN=Alice Johnson, OU=Management, O=Sekurity Inc, C=SomeCountry
    Issuer signature used [SHA1withDSA]
    Serial number =     03ea
    ]
Table 16.1 lists the options you can use with the `javakey` tool. NOTE: The hyphen before each option is not necessary; however, you are encouraged to use it. Note that only one of the following options can be specified for each `javakey` command. #### Table 16.1. The javakey tool options.
Option | Description
`-c` identity`{true | false}` | Creates a new identity in the database with the user name identity. The optional `true` or `false` specifies whether or not an identity is to be considered trusted. The default is `false`.
`-cs` signer`{true | false}` | Creates a new signer in the database with the user name signer. The optional `true` or `false` specifies whether or not an identity is to be considered trusted. The default is `false`.
`-t` identityOrSigner`{true | false}` | This option sets or resets the trust level for the specified identity or signer.
`-l` | Lists all the user names in the database.
`-ld` | Lists the user names in the database with detailed information about them.
`-li` identityOrSigner | Gives detailed information about the specified identity or signer.
`-r` identityOrSigner | Deletes the specified identity or signer from the database.
`-ik` identity`` keyfile | Imports the public key in the file keyfile and associates it with the specified identity.
`-ikp` signer pubfile privfile | Imports the public key in the file pubfile, and the private key in the file privfile, and associates them with the signer.
`-ic` identityOrSigner certificateFile | Imports the public key certificate in the file certificateFile and associates it with the specified identity or signer. If a public key is associated with the identity or signer in the database, `javakey` makes sure that the public key is the same as the one in the file certificateFile.
`-ii` identityOrSigner | Sets information for the specified identity or signer. When using this option, you can type as many lines of information as you want; when you are finished, type a period on a line by itself to exit.
`-gk` signer algorithm keysize Generates a key pair for the specified algorithm | `{`pubfile`} {`privfile`}` signer using the specified with the keysize (strength). The key size has to be between `512` and `1024` bits. Optionally, you can specify a public key file and/or a private key file. If those options are specified, the generated keys are also written in those files. When you use this option to generate keys, you must type some random characters and end with a period on a line by itself. These random characters are used to generate the random number to be used by DSA.
`-g` signer algorithm keysize | This option is a shortcut for the `-gk` option to `{`pubfile`} {`privfile`}`generate a key pair for the specified signer.
`-gc` directivefile | Generates a certificate according to the information provided in the file directivefile.
`-dc` certfile | Shows the certificate stored in the file certfile.
`-gs` directivefile jarfile | Signs the jarfile according to information supplied in the directivefile.
## Summary After reading this chapter, you should be familiar with the Java Security API. This chapter introduced you to the important classes from the Java Security API that you can incorporate into your Java-based applications. Although some of the examples given in this chapter are not full-fledged applications, they do demonstrate how to use the Java Security API. You can find more information about Java security issues in Chapter 34, "Java Security."
| ©Copyright, Macmillan Computer Publishing. All rights reserved.