The Mac Class Secure Message Digests

We can use this class to simplify the example we used earlier: package javasec.samples.ch11; import java.io.; import java.security.; public class SendStream { public static void mainString args[] { try { FileOutputStream fos = new FileOutputStreamtest; MessageDigest md = MessageDigest.getInstanceSHA; DigestOutputStream dos = new DigestOutputStreamfos, md; ObjectOutputStream oos = new ObjectOutputStreamdos; String data = This have I thought good to deliver thee, + that thou mightst not lose the dues of rejoicing + by being ignorant of what greatness is promised thee.; oos.writeObjectdata; dos.onfalse; oos.writeObjectmd.digest ; } catch Exception e { System.out.printlne; } } } The big change is in constructing the object output stream −− we now want to wrap it around the digest output stream so that as each object is written to the file, the message digest will include those bytes. We also want to make sure that we turn off the message digest calculation before we send the digest itself to the file. Turning off the digest isnt strictly necessary in this case since we dont use the digest object once weve calculated a single digest in this example, but its good practice to keep the digest on only when strictly required. Note that there is a subtle difference between the digest produced in this example and our first example. In the first example, the digest was calculated over just the bytes of the string that we saved to the file. In the second example, the digest was calculated over the serialized string object itself −− which includes some information regarding the class definition in addition to the bytes of the string.

11.3.2 The DigestInputStream Class

The symmetric operation to the digest output stream is the DigestInputStream class java.security.DigestInputStream : public class DigestInputStream extends FilterInputStream Create an input stream that is associated with a message digest. When data is read from the input stream, it is also sent to the update method of the streams associated message digest. The digest input stream has essentially the same interface as the digest output stream with writing replaced by reading. There is a single constructor for the class: public DigestInputStreamInputStream is, MessageDigest md Construct a digest input stream that associates the given input stream with the given message digest. Data that is read from the stream will also automatically be passed to the update method of the message digest. The interface provided by the digest input stream is symmetric to the digest output stream: 214 public MessageDigest getMessageDigest Return the message digest that is associated with this output stream. public void setMessageDigestMessageDigest md Associate the given message digest with this output stream. The internal reference to the original message digest is lost, but the original message digest is otherwise unaffected e.g., you can still calculate the digest of the data that had been written to the stream while that digest was in place. public void readint b public void readbyte b[], int off, int len Read one or more bytes from the underlying output stream, and also update the internal message digest with the given data if the digest stream is marked as on. These methods may throw an IOException from the underlying stream. public void onboolean on Turn the message digest stream on or off. When data is read from a stream that is off, the message digest will not be updated. Heres how we can use this class to read the file we created with the digest output stream: package javasec.samples.ch11; import java.io.; import java.security.; public class ReceiveStream { public static void mainString args[] { try { FileInputStream fis = new FileInputStreamtest; MessageDigest md = MessageDigest.getInstanceSHA; DigestInputStream dis = new DigestInputStreamfis, md; ObjectInputStream ois = new ObjectInputStreamdis; Object o = ois.readObject ; if o instanceof String { System.out.printlnUnexpected data in file; System.exit−1; } String data = String o; System.out.printlnGot message + data; dis.onfalse; o = ois.readObject ; if o instanceof byte[] { System.out.printlnUnexpected data in file; System.exit−1; } byte origDigest[] = byte [] o; if MessageDigest.isEqualmd.digest , origDigest System.out.printlnMessage is valid; else System.out.printlnMessage was corrupted; } catch Exception e { System.out.printlne; } } } Once again, constructing the input stream is a matter of providing a message digest. In this example, weve again turned off the digest input stream after reading the string object in the file. Turning off the stream is strictly required in this case. We want to make sure that the digest we calculate is computed only over the string object and not the stored byte array that is, the stored message digest.

11.4 Implementing a MessageDigest Class

If you want to write your own security provider, you have the option of creating your own message digest engine. Typically, youd do this because you want to ensure that a particular algorithm like SHA is available regardless of who the default security provider is; if you have a mathematics background, its conceivable that you might want to implement your own algorithm. In order to implement a message digest algorithm, you must provide a concrete subclass of the MessageDigestSpi class. That means providing a body for each of the following methods: protected abstract void engineUpdatebyte input protected abstract void engineUpdatebyte[] input, int offset, int len Add the given bytes to the data over which the digest will be calculated. Note that there is no method in this list that accepts simply an array of bytes; the updatebyte[] b method in the base class simply uses an offset of and a length equal to the entire array. protected abstract byte[] engineDigest Calculate the digest over the accumulated data, resetting the internal state of the object afterwards. Note that there is no corresponding method that accepts an array of bytes as an argument; the digest method in the base class simply calls the engineUpdate method if needed before calling the engineDigest method. protected int engineDigestbyte buf[], int offset, int len Calculate the digest, placing the output into the buf array starting at the given offset and proceeding for len bytes and returning the length of the calculated digest. The default implementation of this method simply calls the engineDigest method and then copies the result into buf . The buffer passed to this method always has sufficient length to hold the digest since if the buffer had been too short the digest method itself would have thrown an exception. protected abstract void engineReset Reset the internal state of the engine, discarding all accumulated data and resetting the algorithm to an initial condition. protected int engineGetDigestLength Return the digest length that is supported by this implementation. Unlike most of the protected methods in this class, this method is not abstract; it does not need to be overridden. However, the default implementation simply returns 0. If is returned by this method, the getDigestLength method attempts to create a clone of the digest object, calculate its digest, and return the length of the calculated digest. If a digest implementation does not override this method and does not implement the Cloneable interface, the getDigestLength method will not operate correctly. Each of these methods corresponds to a public method of the MessageDigest class, with the name of the public method preceded by the word engine. The public methods that do not have a corresponding method