public class DigestedData extends DigestedDataStream implements Content
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 transmission 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 0x00instead of:
0x04 0x05 0x01 0xAB 0x23 0x7F 0xCAfor encoding the five data bytes
0x01 0xAB 0x23 0x7F 0xCA
. The indefinite
constructed 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:
ASN1Object obj = DerCoder.decode(received_message);
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);
if (digestedData.verify()) { System.out.println("Hash ok!"); else System.out.println("Message corrupted!");
byte[] data = digestedData.getContent();
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 transmission 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.
ContentInfo
block_size, content_type, EXPLICIT, IMPLICIT, input_stream, mode, this_object
Modifier | Constructor and Description |
---|---|
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(java.io.InputStream is)
Creates a PKCS#7 DigestedData from an InputStream.
|
|
DigestedData(ObjectID contentType,
AlgorithmID digestAlgorithm,
byte[] digest)
Creates a new
DigestedData object without content. |
Modifier and Type | Method and Description |
---|---|
void |
decode(ASN1Object obj)
Decodes the given DigestedData ASN1 object.
|
void |
decode(java.io.InputStream is)
Reads and decodes the DigestedData from a DerInputStream.
|
byte[] |
getContent()
Returns the content.
|
java.lang.Object |
getContentInfo()
Returns the content info included in this
DigestedData
object. |
byte[] |
getEncoded()
Returns the DER encoding of this DigestedData in a byte array.
|
java.io.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. |
java.lang.String |
toString(boolean detailed)
Returns a string giving some - if requested - detailed information
about this
DigestedData object. |
encodeCalled, getBlockSize, getContentType, getDigest, getDigestAlgorithm, getVersion, notifyEOF, setBlockSize, setDigest, toASN1Object, toString, verify, writeTo, writeTo
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
getBlockSize, getContentType, setBlockSize, toASN1Object
protected DigestedData()
public DigestedData(byte[] content, AlgorithmID digestAlgorithm, int mode) throws PKCSException
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.content
- the data to be digested supplied from a byte arraydigestAlgorithm
- the message-digest algorithm to be used for creating the digestmode
- either Digested.IMPLICIT for including the data, or
DigestedData.EXPLICIT for not including itPKCSException
- if the supplied parameters to not satisfy the requirements or there is no
implementation for the requested hash algorithmpublic DigestedData(Content content, AlgorithmID digestAlgorithm, byte[] digest) throws PKCSException
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);
content
- the content as Content descendantdigestAlgorithm
- the message-digest algorithm (and any associated parameters)
used for creating the digestdigest
- the already hashed content valuePKCSException
- if there occurs an error while encoding the contentpublic DigestedData(ObjectID contentType, AlgorithmID digestAlgorithm, byte[] digest)
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.
contentType
- the content type of the digested datadigestAlgorithm
- the message-digest algorithm (and any associated parameters)
used for creating the digestdigest
- the result of the message-digesting processpublic DigestedData(ASN1Object obj) throws PKCSParsingException
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 existing 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.
obj
- the PKCS#7 DigestedData
as ASN1ObjectPKCSParsingException
- if the object can not be parsedpublic DigestedData(java.io.InputStream is) throws java.io.IOException, PKCSParsingException
is
- the InputStream holding the DER encoded PKCS#7 DigestedData objectjava.io.IOException
- if an error occurs when reading from the streamPKCSParsingException
- if the object can not be parsedpublic DigestedData(byte[] content, AlgorithmID digestAlgorithm) throws java.security.NoSuchAlgorithmException
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 computation: 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.
content
- the content transmitted by other meansdigestAlgorithm
- the hash algorithm used for digesting the
content datajava.security.NoSuchAlgorithmException
- if the supplied hash algorithm is not supportedprotected void setupMessageDigest(AlgorithmID digestAlgorithm, boolean parse) throws java.security.NoSuchAlgorithmException
digestAlgorithm
- the digest algorithm to be usedparse
- whether this method id called during the parsing or
creation processjava.security.NoSuchAlgorithmException
- if the digestAlgorithm is not supportedpublic void decode(ASN1Object obj) throws PKCSParsingException
decode
in interface Content
obj
- the ASN1Object representing an already existing DigestedData objectPKCSParsingException
- if an error occurs when parsing the given ASN1Objectpublic void decode(java.io.InputStream is) throws java.io.IOException, PKCSParsingException
DerInputStream
,
internally a DerInputStream is created before parsing the data.decode
in interface ContentStream
decode
in class DigestedDataStream
is
- the InputStream holding a DER encoded PKCS#7 DigestedData objectjava.io.IOException
- if an I/O error occurs during reading from the InputStreamPKCSParsingException
- if an error occurs while parsing the objectpublic java.lang.Object getContentInfo()
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();
DigestedData
object.public java.io.InputStream getInputStream()
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 arbitrarily 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.
getInputStream
in class DigestedDataStream
DigestedData
objectpublic byte[] getContent()
public byte[] getEncoded() throws PKCSException
PKCSException
- if an error occurs during the encoding procedureprotected ASN1Object toASN1Object(int blockSize) throws PKCSException
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.
toASN1Object
in class DigestedDataStream
blockSize
- the block size to be used for block oriented encodingDigestedData
as ASN1Object.PKCSException
- if the ASN1Object could not be createdpublic java.lang.String toString(boolean detailed)
DigestedData
object.toString
in interface ContentStream
toString
in class DigestedDataStream
detailed
- - whether or not to give detailed information