b[1] = byte hash 16; b[2] = byte hash 8;
b[3] = byte hash 0; engineReset ;
return b; }
}
The implementation of this class is simple, which isnt surprising given the fact that the algorithm itself is too simple to be considered an effective digest algorithm. The major points to observe are:
The name of the class XYZMessageDigest
and the name of the algorithm that it implements XYZ must match one of the strings in the provider package for this class to be found. Hence, in our
provider class in Chapter 8, we included this property:
putMessageDigest.XYZ, XYZMessageDigest;
•
Our constructor must be public and take no arguments. It must call the superclass constructor passing the name of the message digest algorithm it implements.
• In order for the
getDigestLength method to function, we chose to implement the
Cloneable interface instead of overriding the
engine−GetDigestLength method. Since
there are no embedded objects in this class, we do not need to override the clone
method. The default implementation of that method a shallow copy is sufficient for this class.
•
The engineUpdate
methods accumulate bytes of data until an integer has been accumulated, at which point that integer can be XOR−ed into the saved state held in the
hash instance variable.
• The
engineDigest method converts the
hash instance variable into a byte array and returns
that to the programmer. Note that the engineDigest
method is responsible for resetting the internal state of the algorithm. In addition, the
engineDigest method is responsible for
padding the data so that it is a multiple of four bytes the size of a Java integer. This type of data padding is a common feature of message digest calculation.
•
The engineReset
method initializes the algorithm to its initial state. •
Once we have an implementation of a message digest, we must install it into the security provider architecture. If we use the
XYZProvider class from Chapter 8, we can change our
Send class above to use
our new digest algorithm:
package javasec.samples.ch11; import java.io.;
import java.security.; import javasec.samples.ch08.XYZProvider;
public class SendXYZ { public static void mainString args[] {
try { Security.addProvidernew XYZProvider ;
FileOutputStream fos = new FileOutputStreamtest.xyz; MessageDigest md = MessageDigest.getInstanceXYZ;
ObjectOutputStream oos = new ObjectOutputStreamfos; 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.;
byte buf[] = data.getBytes ; md.updatebuf;
oos.writeObjectdata; oos.writeObjectmd.digest ;
} catch Exception e { System.out.printlne;
} }
}
Similar changes to the Receive
class will allow us to accept the message that weve saved to the file test.xyz.
11.4.1 The MacSpi Class
Implementing a MAC is similar, except that you extend the MacSpi
class javax.crypto.MacSpi
. The method names within that class follow the method names of the
Mac class: there is an
engineDoFinal method instead of an
engineDigest method, and so on. The key to the implementation of the
engineDoFinal method is that it should use the key it received in the
engineInit method to
calculate a secure message digest perhaps using the technique we outlined above when we used a simple passphrase.
Remember that the Mac
class is a JCE engine, so the constructor of your MAC implementation must verify the JCE installation.
11.5 Comparison with Previous Releases
In Java 1.1, there is no MessageDigestSpi
class, and the MessageDigest
class simply extends Object
. If you want to implement your own message digest in 1.1, then you extend the MessageDigest
class directly. This does not cause any implementation differences. The
getDigestLength method does not exist in 1.1 nor does the
digest method with a
signature that accepts an array, offset, and length.
11.6 Summary
In this chapter, weve explored the message digest. The facility to calculate a message digest is straightforward and easy to use; the facility to write our own message digest class is equally straightforward.
The message digest by itself gives us some comfort about the state of the data it represents, but it does not give us a completely secure system. If we have a shared passphrase or secret key, we can construct a secure
message digest that is, a Message Authentication Code. A secure message digest is very similar to a digital signature, which well explore in the next chapter.
Chapter 12. Digital Signatures
In this chapter, we explore the mechanisms of the digital signature. The use and verification of digital signatures is another standard engine that is included in the security provider architecture. Like the other
engines weve examined, the classes that implement this engine have both a public interface and an SPI for implementors of the engine.
Well start by looking at the interface of the digital signature engine and see how you can create digitally signed objects that you can send between programs. Well continue by looking into the details of digitally
signed classes, including the jarsigner
tool that creates those classes and how you can deal with those classes programatically. Well conclude by looking at the details of the engine algorithm and how you can
implement your own digital signature algorithms.
12.1 The Signature Class
When you handle digital signatures programatically, you perform two operations on them. You create them by taking a piece of data, creating a message digest of the data, and signing the message digest with a private
key. The digitally signed data is then transmitted to someone else, who must verify the digital signature by creating a message digest of the data and verifying the signed digest using a public key. All of these
operations are embodied within the
Signature class
java.security.Signature :
public abstract class Signature extends SignatureSpi Provide an engine to create and verify digital signatures.
The Sun security providers include implementations of this class that generate signatures based on the DSA and RSA algorithms.
12.1.1 Using the Signature Class
As with all engine classes, instances of the Signature
class are obtained by calling one of these methods: public static Signature getInstanceString algorithm
public static Signature getInstanceString algorithm, String provider Generate a signature object that implements the given algorithm, optionally using the named provider.
If an implementation of the given algorithm is not found, a NoSuchAlgorithmException
is thrown. If the named security provider cannot be found, a
NoSuchProviderException is
thrown. If the algorithm string is DSA, the string SHADSA is substituted for it. Hence, implementors of
this class that provide support for DSA signing must register themselves appropriately that is, with the message digest algorithm name in the security provider.
Once a signature object is obtained, the following methods can be invoked on it: public void final initVerifyPublicKey publicKey
Initialize the signature object, preparing it to verify a signature. A signature object must be initialized before it can be used. If the key is not of the correct type for the algorithm or is otherwise invalid, an
InvalidKeyException is thrown.