Authentication

This section describes mechanisms for signing and verifying operations. It contains the following subsections:

>Digital Signatures

>Object Signing

Digital Signatures

The java.security.Signature class provides the functionality of a digital signature algorithm. Digital signatures are the digital equivalent of the traditional pen-and paper-signature. They can be used to authenticate the originator of a document, as well as to prove that a person signed the document. Generally, digital signatures are based on public-key encryption, which means that, unlike a MAC, anyone that has access to the public key (and the document) can check the validity of the document.

The Signature interface supports generation and verification of signatures. Once a signature instance has been created using the Signature.getInstance() method, it needs to be initialized with the Signature.initSign() method for creation of a signature, or Signature.initVerify() method for verification of a signature.

Once initialized, the document to be processed should be passed to the signature via the Signature.update() methods. Once the entire document has been processed, the Signature.sign() method may be called to generate the signature, or the Signature.verify() method to verify a supplied signature against a previously generated signature.

After a signature has been generated or verified, the Signature instance is reset to the state it was in after it was last initialized, allowing another signature to be generated or verified using the same key.

One such signature algorithm is "MD5 with RSA", defined in PKCS#1. This algorithm specifies that the document to be signed is passed through the MD5 digest algorithm and then an ASN.1 block containing the digest, along with a digest algorithm identifier, is enciphered using RSA.

To create such a signature:

   /*
    * Assume this private key is initialized
    */
   PrivateKey rsaPrivKey;

   /*
    * Create the Signature instance and initialize
    * it for signing with our private key
    */
   Signature rsaSig = Signature.getInstance("MD5withRSA");
   rsaSig.initSign(rsaPrivKey);

   /*
    * Pass in the document data via the update() methods
    */
   byte[] document = "The document".getBytes();
   rsaSig.update(document);

   /*
    * Generate the signature
    */
   byte[] signature = rsaSig.sign();

To verify the generated signature:

   /*
    * Assume this public key is initialized
    */
   PublicKey rsaPubKey;

   /*
    * Create the Signature instance and initialize
    * it for signature verification with the public key
    */
   Signature rsaSig = Signature.getInstance("MD5withRSA");
   rsaSig.initVerify(rsaPubKey);

   /*
    * Pass in the document data via the update() methods
    */
   byte[] document = "The document".getBytes();
   rsaSig.update(document);

   /*
    * Check the generated signature against the supplied
    * signature
    */
   if (rsaSig.verify(signature))
   {
      // signature okay
   }
   else
   {
      // signature fails
   }

Object Signing

The java.security.SignedObject provides a mechanism for ensuring that a Java object can be authenticated and cannot be tampered with without detection. The mechanism used is similar to the SealedObject in that the object to be protected is serialized and then a signature is attached. The SealedObject is serializable, so it may be stored or transmitted via the object streams.

To create a SignedObject, firstly create an instance of the signature algorithm to use via the Signature.getInstance() method, then create the new SignedObject instance by providing the object to be signed, the signing key and the Signature instance. Note that there is no need to initialize the Signature instance; the SignedObject constructor will perform that function.

   Signature signingEngine = Signature.getInstance(
      "MD5withRSA");
   SignedObject so = new SignedObject("hello world",
      privateKey, signingEngine);  

To verify a SignedObject, simply create the Signature instance for the required algorithm and then use the SignedObject.verify() method with the appropriate PublicKey. Again, there is no need to initialize the Signature instance.

   Signature verifyEngine = Signature.getInstance(
      "MD5withRSA");
   if (so.verify(publicKey, verifyEngine))
   {
      // object okay, extract it
      Object obj = so.getObject();
   }
   else
   {
      // object not authenticated
   }

Note that this class only provides a mechanism for authentication and verification, it does not provide confidentiality (i.e. encryption). The SealedObject may be used for this purpose (see SealedObject). The following example combines these two classes to provide a confidential, authenticated, tamper-proof object:

   /*
    * sealedObj will contain the signed, enciphered data
    */
   SignedObject signedObj = new SignedObject(
      "hello world", privateKey, signingEngine);
   SealedObject sealedObj = new SealedObject(
      signedObj, cipher);

   /*
    * to verify and recover the original object
    */
   SignedObject newObj = sealedObject.getObject(cipher);
   if (newObj.verify(publicKey, verificationEngine))
   {
      // object verified tampered
      String str = (String)newObj.getObject();
   }
   else
   {
      // object tampered with!
   }