iaik.pkcs.pkcs7
Class DigestedData

java.lang.Object
  |
  +--iaik.pkcs.pkcs7.DigestedDataStream
        |
        +--iaik.pkcs.pkcs7.DigestedData
All Implemented Interfaces:
Content, ContentStream, EncodeListener, EOFListener, EventListener

public class DigestedData
extends DigestedDataStream
implements Content

This class represents the non-stream supporting implementation of the PKCS#7 DigestedData type.

Each PKCS#7 content type is associated with a specific object identifier, derived from:

 pkcs-7 OBJECT IDENTIFIER ::=
   { iso(1) member-body(2) US(840) rsadsi(113549)
       pkcs(1) 7 }
 

The object identifier for the DigestedData content type is defined as:

digestedData OBJECT IDENTIFIER ::= { pkcs-7 5 }

which corresponds to the OID string "1.2.840.1.113549.1.7.5".

The PKCS#7 Cryptographic Message Standard specifies the DigestedData content type for providing a syntax for building message digests. The digested-data content type consists of content of any type and a message digest of the content (Version 1.5):

 DigestedData ::= SEQUENCE {
    version            Version,
    digestAlgorithm    DigestAlgorithmIdentifier,
    contentInfo        ContentInfo,
    digest             Digest }
 
Digest ::= OCTET STRING

The digestAlgorithm field specifies the digest algorithm to be used for computing the message digest of the content given in the contentInfo field. The result of the digest calculation is stored in the digest field. Verifying a received message digest is done by comparing it with an independently computed message digest.

For more information consult the RSA PKCS#7 specification (section 12.Digested-data content type).


This class may be used in two ways: If the inherent ContentInfo represents a Data object this class may be used like the parent DigestedDataStream class where digest computation and verification is done inside the class. On the other hand you may do all computations outside by yourself.

If you choose the first way proceed as follows:
When creating a DigestedData object for the content to be digested by using the DigestedData(byte[] content, AlgorithmID digestAlgorithm, int mode) constructor, additionally the transimission mode has to be specified. If the mode is set to DigestedData.IMPLICIT the raw data will be included in the DigestedData message to be transmitted, but it will be not included if the mode is set to DigestedData.EXPLICIT. However, in both cases the raw data has to be supplied when creating the DigestedData object, because it is needed for the digest computation:

 byte[] content = ...; // the raw data to be digested
 AlgorithmID digestAlg = ...;
 DigestedData digested_data = new DigestedData(content, digestAlg, DigestedData.IMPLICIT);
 
respectively
 DigestedData digested_data = new DigestedData(content, digestAlg, DigestedData.EXPLICIT);
 
In contrast to the stream-variant of the PKCS#7 DigestedData type (implemented by the DigestedDataStream class), where explicit and implicit mode have to be handled in different way when creating a DigestedData object, they have the same proceeding for this non-stream-supporting DigestedData class. In this way, after having created a DigestedData object the only remaining task is to prepare the DigestedData object for transmission by transforming it into an ASN1Object or immediately DER encoding it. The former is done by calling the toASN1Object method, the latter by using the getEncoded method:
 ASN1Object obj = digested_data.toASN1Object();
 
respectively
 byte[] encoding = digested_data.getEncoded();
 
You alternatively may use a proper writeTo method of the parent DigestedDataStream class for immediately encoding this DigestedData object to an output stream. When using writeTo in implicit mode, you additionally have the possibility of specifying a particular blockSize for forcing an indefinite constructed encoding of the inherent raw data bytes, instead of of the default definite primitive encoding, e.g:
 0x24 0x80
           0x04 0x02 0x01 0xAB
           0x04 0x02 0x23 0x7F
           0x04 0x01 0xCA
 0x00 0x00
 
instead of:
 0x04 0x05 0x01 0xAB 0x23 0x7F 0xCA
 
for encoding the five data bytes 0x01 0xAB 0x23 0x7F 0xCA. The indefinte constrcuted encoding scheme may be preferable when intending to be compatible to the encoding practice of some particular application (for instance some versions of Netscape Navigator).

Unlike the procedure of newly creating a DigestedData object to be transmitted, even when using this non-stream implementation of the DigestedData content type, it has to be distinguished between IMPLICIT and EXPLICIT mode when parsing a received DigestedData message. When operating in IMPLICIT mode, the raw data is included in the received DigestedData object, and so the parsing immediately may be performed when creating a DigestedData object from the DigestedData ASN1Object by calling the DigestedData(ASN1Object obj) constructor. On the other side, when the raw data has been transmitted outside the DigestedData message (EXPLICIT mode), the DigestedData(byte[] content, AlgorithmID digestAlgorithm) constructor has be to used for initializing the new DigestedData object with raw data and hash algorithm to be used for digest computation; and the decoding has to be performed explicitly by calling the decode method. The initialization is necessary for computing the digest on the raw data for the supplied digest algorithm. Later, during digest verification this digest value has to be compared against the hash value sent within the digest field.
All further steps are the same for implicit and explicit mode, and so the proceeding necessary for parsing a received DigestedData message and verifying the digest may be summarized as follows:

  1. If nessecary, first decode the received DER encoded mesage to obtain an ASN1Object:
         ASN1Object obj = DerCoder.decode(received_message);
         
  2. If the ASN1Object resulting from step 1 above represents an implicit DigestedData object, use the DigestedData(ASN1Object obj) constructor for creating a DigestedData object and implicitly parsing the the supplied ASN.1 structure:
         DigestedData digestedData = new DigestedData(obj);
         
    On the other hand, if the ASN1Object resulting from step 1 above represents an explicit DigestedData object, use the DigestedData(byte[] content, AlgorithmID digestAlgorithm) constructor for initializing a new DigestedData object with raw data and digest algorithm for hash computation, and subsequently explicitly perform the decoding by means of the decode method (assuming that the SHA-1 hash algorithm is used):
         AlgorithmID algIDs =  AlgorithmID.sha1;
         DigestedData digestedData = new DigestedData(raw_data, algID);
         digestedData.decode(obj);
         
  3. Now verify the digest:
         if (digestedData.verify()) {
            System.out.println("Hash ok!");
         else
            System.out.println("Message corrupted!");
         
  4. In implicit mode, get the raw data from the DigestedData object:
         byte[] data = digestedData.getContent();
         
Attention! This way only shall be used for inherent ContentInfos of type Data!

If you choose the second way doing all computations by yourself you may proceed as followed:

 //the message to be hashed:
 byte[] message = "Test data to be digested".getBytes();
 //compute the message digest:
 MessageDigest md = MessageDigest.getInstance("SHA");
 md.update(message);
 byte[] digest = md.digest();
 //create a DigestedData object and supply content and message digest:
 DigestedData digested_data = new DigestedData(new Data(message), AlgorithmID.sha, digest);
 //prepare the DigestedData structure just created for transmition by transforming it
 //into an ASN1Object or immediately DER encoding it:
 ASN1Object obj = digested_data.toASN1Object();
 //respectively: byte[] encoding = digested_data.getEncoded();
 
The receiver verifies the message digest by comparing it with an independently computed digest of the original message:

 //if the DigestedData is supplied as DER encoding, first decode it to an ASN1Object
 ASN1Object obj = DerCoder.decode(encoding);
 //create a DigestedData from the received ASN1Object:
 DigestedData digested_data = new DigestedData(obj);
 //get the content and the inherent message:
 ContentInfo ci = (ContentInfo)digested_data.getContentInfo();
 Data data = (Data)ci.getContent();
 byte[] message = data.getData();
 //compute the digest from the obtained message:
 MessageDigest md = MessageDigest.getInstance(digested_data.getDigestAlgorithm().getName());
 md.update(message);
 byte[] message_digest = md.digest();
 //get the digest from the received DigestedData and compare it against the
 //message digest just computed:
 byte[] digest = digested_data.getDigest();
 if (CryptoUtils.equalsBlock(digest, message_digest)) {
    System.out.println("Digest verification successfully completed!");
 }
 

Use the stream supporting DigestedDataStream parent class for handling structures with large amounts of data.

Version:
File Revision 31
See Also:
ContentInfo

Fields inherited from class iaik.pkcs.pkcs7.DigestedDataStream
block_size, content_type, EXPLICIT, IMPLICIT, input_stream, mode, this_object
 
Constructor Summary
protected DigestedData()
          Default constructor for dynamic object creation in ContentInfo.
  DigestedData(ASN1Object obj)
          Creates a PKCS#7 DigestedData from an ASN1Object.
  DigestedData(byte[] content, AlgorithmID digestAlgorithm)
          Creates a new DigestedData from a byte array holding the content that has been transmitted by other means, and the hash algorithms to be used for digesting.
  DigestedData(byte[] content, AlgorithmID digestAlgorithm, int mode)
          Creates a new DigestedData object from given content and and digest algorithm.
  DigestedData(Content content, AlgorithmID digestAlgorithm, byte[] digest)
          Creates a new DigestedData object from given content and already hashed content value.
  DigestedData(InputStream is)
          Creates a PKCS#7 DigestedData from an InputStream.
  DigestedData(ObjectID contentType, AlgorithmID digestAlgorithm, byte[] digest)
          Creates a new DigestedData object without content.
 
Method Summary
 void decode(ASN1Object obj)
          Decodes the given DigestedData ASN1 object.
 void decode(InputStream is)
          Reads and decodes the DigestedData from a DerInputStream.
 byte[] getContent()
          Returns the content.
 Object getContentInfo()
          Returns the content info included in this DigestedData object.
 byte[] getEncoded()
          Returns the DER encoding of this DigestedData in a byte array.
 InputStream getInputStream()
          Returns an InputStream from which the contents of this object can be read.
protected  void setupMessageDigest(AlgorithmID digestAlgorithm, boolean parse)
          Calculates the digest.
protected  ASN1Object toASN1Object(int blockSize)
          Returns this DigestedData as ASN1Object.
 String toString(boolean detailed)
          Returns a string giving some - if requested - detailed information about this DigestedData object.
 
Methods inherited from class iaik.pkcs.pkcs7.DigestedDataStream
encodeCalled, getBlockSize, getContentType, getDigest, getDigestAlgorithm, getVersion, notifyEOF, setBlockSize, setDigest, toASN1Object, toString, verify, writeTo, writeTo
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface iaik.pkcs.pkcs7.ContentStream
getBlockSize, getContentType, setBlockSize, toASN1Object
 

Constructor Detail

DigestedData

protected DigestedData()
Default constructor for dynamic object creation in ContentInfo. The block size is set to -1 meaning that the data will be encoded a one simple octet string by deafult.

DigestedData

public DigestedData(byte[] content,
                    AlgorithmID digestAlgorithm,
                    int mode)
             throws PKCSException
Creates a new DigestedData object from given content and and digest algorithm. The data to be digested is supplied as byte array. The mode parameter specifies whether to include the data (mode = DigestedDataStream.IMPLICIT) or not include it (mode = DigestedDataStream.EXPLICIT). The content type of the inherent ContentInfo automatically is set to PKCS#7 Data.
Parameters:
content - the data to be digested supplied from a byte array
digestAlgorithm - the message-digest algorithm to be used for creating the digest
mode - either Digested.IMPLICIT for including the data, or DigestedData.EXPLICIT for not including it
Throws:
PKCSException - if the supplied paramteres to not satisfy the requirements ot there is no implementation for the requested hash algorithm

DigestedData

public DigestedData(Content content,
                    AlgorithmID digestAlgorithm,
                    byte[] digest)
             throws PKCSException
Creates a new DigestedData object from given content and already hashed content value.

For instance:

 byte[] message = "Test data to be digested".getBytes();
 MessageDigest md = MessageDigest.getInstance("SHA");
 md.update(message);
 byte[] digest = md.digest();
 DigestedData digested_data = new DigestedData(new Data(message), AlgorithmID.sha, digest);
 

Parameters:
content - the content as Content descendant
digestAlgorithm - the message-digest algorithm (and any associated parameters) used for creating the digest
digest - the already hashed content value
Throws:
PKCSException - if there occurs an error while encoding the content

DigestedData

public DigestedData(ObjectID contentType,
                    AlgorithmID digestAlgorithm,
                    byte[] digest)
Creates a new DigestedData object without content.

For instance:

 byte[] message = "Test data to be digested".getBytes();
 MessageDigest md = MessageDigest.getInstance("SHA");
 md.update(message);
 byte[] digest = md.digest();
 DigestedData digested_data = new DigestedData(ObjectID.pkcs7_data, AlgorithmID.sha, digest);
 

The content must be supplied by other means.

Parameters:
contentType - the content type of the digested data
digestAlgorithm - the message-digest algorithm (and any associated parameters) used for creating the digest
digest - the result of the message-digesting process

DigestedData

public DigestedData(ASN1Object obj)
             throws PKCSParsingException
Creates a PKCS#7 DigestedData from an ASN1Object.

Do not use this constructor for supplying content and hashed content value. This constructor may be used by the recipient for parsing an already exisiting DigestedData object, supplied as ASN1Object that may have been created by calling toASN1Object.

Use the DigestedData(Content content, AlgorithmID digestAlgorithm, byte[] digest) constructor for supplying content and hashed content value when creating a DigestedData object.

Parameters:
obj - the PKCS#7 DigestedData as ASN1Object
Throws:
PKCSParsingException - if the object can not be parsed

DigestedData

public DigestedData(InputStream is)
             throws IOException,
                    PKCSParsingException
Creates a PKCS#7 DigestedData from an InputStream. The given input stream supplies the DER encoding of an already existing DigestedData object.
Parameters:
is - the InputStream holding the DER encoded PKCS#7 DigestedData object
Throws:
IOException - if an error occurs when reasding from the stream
PKCSParsingException - if the object can not be parsed

DigestedData

public DigestedData(byte[] content,
                    AlgorithmID digestAlgorithm)
             throws NoSuchAlgorithmException
Creates a new DigestedData from a byte array holding the content that has been transmitted by other means, and the hash algorithms to be used for digesting.

Do not use this constructor for supplying the content value to be digested. This constructor may be used by the recipient for initializing the digest computation for an already existing explicit DigestedData message where the raw data is not included. In contrast to the equivalent constructor of the parent DigestedDataStream class, this constructor not only initializes the digest computation, but also already computes the digest for the given digest algorithm. Later, during digest verification these digest value have to be compared against the hash value sent in the digest field.
For subsequently performing the decoding of the received explicit DigestedData object, use the decode method:

 // the received explicit DigestedData structure as ASN1Object:
 ASN1Object = DerCoder.decode(received_message);
 //initialize - and perform - digest computaion:
 DigestedData digestedData = new DigestedData(raw_data, hashAlgorithm);
 //parse the received DigestedData ASN1Object
 digestedData.decode(obj);
 

A sender shall use the DigestedData(byte[] content, AlgorithmID digestAlgorithm, int mode) constructor for supplying the content value to be digested when creating a DigestedData object.

For parsing an implicit DigestedData message, use the DigestedData(ASN1Object obj) constructor.

Parameters:
content - the content transmitted by other means
digestAlgorithm - the hash algorithm used for digesting the content data
Throws:
NoSuchAlgorithmException - if the supplied hash algorithm is not supported
Method Detail

setupMessageDigest

protected void setupMessageDigest(AlgorithmID digestAlgorithm,
                                  boolean parse)
                           throws NoSuchAlgorithmException
Calculates the digest.
Parameters:
digestAlgorithm - the digest algorithm to be used
Throws:
NoSuchAlgorithmException - if the digestAlgorithm is not supported

decode

public void decode(ASN1Object obj)
            throws PKCSParsingException
Decodes the given DigestedData ASN1 object.
Specified by:
decode in interface Content
Parameters:
obj - the ASN1Object representing an already exisiting DigestedData object
Throws:
PKCSParsingException - if an error occurs when parsing the given ASN1Object

decode

public void decode(InputStream is)
            throws IOException,
                   PKCSParsingException
Reads and decodes the DigestedData from a DerInputStream. If the supplied InputStream actually is not an instance of DerInputStream, internally a DerInputStream is created before parsing the data.
Specified by:
decode in interface ContentStream
Overrides:
decode in class DigestedDataStream
Parameters:
is - the InputStream holding a DER encoded PKCS#7 DigestedData object
Throws:
IOException - if an I/O error occurs during reading from the InputStream
PKCSParsingException - if an error occurs while parsing the object

getContentInfo

public Object getContentInfo()
Returns the content info included in this DigestedData object. When calling this method for obtaining the inherent ContentInfo an explicit cast to ContentInfo has to be made:
 ContentInfo ci = (ContentInfo)digested_data.getContentInfo();
 
Returns:
the ContentInfo included in this DigestedData object.

getInputStream

public InputStream getInputStream()
Returns an InputStream from which the contents of this object can be read.

This method only overrides the corresponding getInputStream method of the parent DigestedDataStream class for returning the content of this DigestedData object. There should be no real necessity for using this method since the raw data bytes immediately can be obtained by the getContent method. However, in contrast to the equivalent getInputStream method of the parent DigesetdDataStream class, this method may be called arbitrarly often; it only returns a ByteArrayInputStream that is initialized with the raw content bytes.

This method only can be used if the type of the inherent ContentInfo is PKCS#7 data.

Overrides:
getInputStream in class DigestedDataStream
Returns:
an InputStream with the contents of this DigestedData object

getContent

public byte[] getContent()
Returns the content. Only to be used if the type of the inherent ContentInfo is PKCS#7 data.
Returns:
the content as byte array

getEncoded

public byte[] getEncoded()
                  throws PKCSException
Returns the DER encoding of this DigestedData in a byte array. If for the inherent content structure a positive blocksize has been specified, the content is encoded as indefinite constructed octet string.
Returns:
a byte array holding the DER encoding of this DigestedData
Throws:
PKCSException - if an error occurs durin gthe encoding procedure

toASN1Object

protected ASN1Object toASN1Object(int blockSize)
                           throws PKCSException
Returns this DigestedData as ASN1Object.

The ASN1Object returned by this method may be used as parameter value when creating a DigestedData object using the DigestedData(ASN1Object obj) constructor.

Overrides:
toASN1Object in class DigestedDataStream
Parameters:
the - blockSize to be used for block oriented encoding
Returns:
this DigestedData as ASN1Object.
Throws:
PKCSException - if the ASN1Object could not be created

toString

public String toString(boolean detailed)
Returns a string giving some - if requested - detailed information about this DigestedData object.
Specified by:
toString in interface ContentStream
Overrides:
toString in class DigestedDataStream
Parameters:
detailed - - whether or not to give detailed information
Returns:
the string representation

This Javadoc may contain text parts from Internet Standard specifications (RFC 2459, 3280, 3039, 2560, 1521, 821, 822, 2253, 1319, 1321, ,2630, 2631, 2268, 3058, 2984, 2104, 2144, 2040, 2311, 2279, see copyright note) and RSA Data Security Public-Key Cryptography Standards (PKCS#1,3,5,7,8,9,10,12, see copyright note).

IAIK-JCE 3.1 with IAIK-JCE CC Core 3.1, (c) 1997-2004 IAIK