public class DigestedDataStream extends java.lang.Object implements ContentStream, EncodeListener, EOFListener
DigestedData type.
Each CMS 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 Cryptographic Message Syntax
(CMS, RFC 2630) 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:
DigestedData ::= SEQUENCE {
version Version,
digestAlgorithm DigestAlgorithmIdentifier,
encapContentInfo EncapsulatedContentInfo,
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
encapContentInfo 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.
When creating a DigestedDataStream object for the content to be
digested by using the DigestedDataStream(InputStream data_is, AlgorithmID digestAlgorithm, int mode)
constructor, additionally the transimission mode has to be specified. If the mode is
set to DigestedDataStream.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 DigestedDataStream.EXPLICIT.
However, in both cases the raw data has to be supplied when creating the
DigestedDataStream object, because it is needed for the digest
computation:
InputSrteam data_stream = ...; // the raw data supplying input stream AlgorithmID digestAlg = ...; DigestedDataStream digested_data = new DigestedDataStream(data_stream, digestAlg, DigestedDataStream.IMPLICIT);respectively
DigestedDataStream digested_data = new DigestedDataStream(data_stream, digestAlg, DigestedDataStream.EXPLICIT);In contrast to the non-stream-variant of the CMS DigestedData type (implemented by the
DigestedData class),
where explicit and implicit mode can be handled in the same way when creating
a DigestedData object, they require a different proceeding for the stream-supporting
DigestedDataStream class.
In this way, the steps for creating a DigestedDataStream object and
preparing it for transmission can be summarized in the following way:
DigestedDataStream object thereby supplying the raw data
to be digested as input stream and specifying digest algorithm and transmission mode
to be used (either DigestedDataStream.IMPLICIT or DigestedDataStream.EXPLICIT):
InputStream data_stream = ...;
int mode = ...;
AlgorithmID digestAlg = ...;
DigestedDataStream digested_data = new DigestedDataStream(data_stream, digestAlg, mode);
if (mode == DigestedDataStream.EXPLICIT) {
InputStream data_is = digested_data.getInputStream();
byte[] buf = new byte[1024];
int r;
while ((r = data_is.read(buf)) > 0) {
// do something useful
}
}
When using the implicit mode, do not explicitly read data from the input
stream at all! This will be done automatically during the last step when performing
the encoding.
writeTo method for BER encoding the
the DigestedDataStream object and writing it to an output stream. You optionally
may specify a particular block size for splitting the data encoding:
int blockSize = ...;
digested_data.writeTo(output_stream, blockSize);
respectively
digested_data.writeTo(output_stream);
It is recommended only to use the writeTo method where a particular
block size can be specified, because it is the intended purpose of this stream-supporting
DigestedData implementation to handle large amounts of data. When no block size is
specified whole the raw data is encoded as one primitive definite octet string, which
advantageously may be done when using the non-stream supporting
DigestedData implementation.
When a positve block size is specified for encoding the DigestedData to a stream,
the raw data is BER encoded as indefinite constructed octet string being composed
of a series of definite primitive encoded octet strings of blockSize length,
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.
Again, it has to be distinguished between IMPLICIT and EXPLICIT mode when using the
DigestedDataStream implementation for 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 DigestedDataStream object from the BER encoded
DigestedData object by calling the DigestedDataStream(InputStream is) constructor. On the other side, when
the raw data has been transmitted outside the DigestedData message (EXPLICIT mode), the
DigestedDataStream(InputStream data_is, AlgorithmID digestAlgorithm) constructor
has to be used for initializing the new DigestedDataStream 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 preparing the digest computation on the raw data for the
specified digest algorithm. Later, during digest verification the
digest value computaion is finished and the result is compared against the hash value
sent within the final digest field.
The individual steps necessary for parsing a received DigestedData message and verifying the
digest may be summarized as follows:
DigestedDataStream(InputStream is)
constructor for creating a DigestedDataStream object and implicitly performing the
decoding:
DigestedDataStream digestedData = new DigestedDataStream(encoded_stream);
On the other hand, if the BER encoding represents an
explicit DigestedData object, use the
DigestedDataStream(InputStream data_is, AlgorithmID digestAlgorithm)
constructor for initializing a new DigestedDataStream object with raw data and
digest algorithm for hash computation (assuming that the hash algorithm is SHA-1):
AlgorithmID algID = AlgorithmID.sha1;
DigestedDataStream digestedData = new DigestedDataStream(data_is, algID);
InputStream dataIs = digestedDdata.getInputStream();
byte[] buf = new byte[1024];
int r;
while ((r = dataIs.read(buf)) > 0) {
// do something useful
}
decode method:
digestedData.decode(encoded_stream);
verify method for comparing the
computed digest against the value sent in the digest field:
if (digestedData.verify())
System.out.println("Hash o.k!");
else
System.out.println("hash verification failed!");
| Modifier and Type | Field and Description |
|---|---|
protected int |
blockSize_
The block size for block oriented stream encoding.
|
protected ObjectID |
contentType_
The content type.
|
protected AlgorithmID |
digestAlgorithm_
The digest algorithm to use.
|
protected EncapsulatedContentInfoStream |
encapContentInfo_
The inherent EncapsualtedContentInfo.
|
static int |
EXPLICIT
Denotes a mode where the data to be digested is not included.
|
static int |
IMPLICIT
Denotes a mode where the data to be digested is included.
|
protected java.io.InputStream |
inputStream_
An InputStream holding the data.
|
protected int |
mode_
The mode specifying if the data shall be included
(IMPLICIT), or if is not included (EXPLICIT).
|
protected int |
version_
The CMS version number.
|
| Modifier | Constructor and Description |
|---|---|
protected |
DigestedDataStream()
Default constructor for dynamic object creation in ContentInfoStream.
|
|
DigestedDataStream(java.io.InputStream is)
Creates a DigestedDataStream object from an InputStream.
|
|
DigestedDataStream(java.io.InputStream data_is,
AlgorithmID digestAlgorithm)
Creates a new DigestedDataStream from an InputStream holding the content that
has been transmitted by other means, and the hash algorithm to be used for digesting.
|
|
DigestedDataStream(java.io.InputStream data_is,
AlgorithmID digestAlgorithm,
int mode)
Creates a new
DigestedDataStream object from given content and
and digest algorithm. |
|
DigestedDataStream(ObjectID contentType,
AlgorithmID digestAlgorithm,
byte[] digest)
Creates a new
DigestedDataStream object without content. |
|
DigestedDataStream(ObjectID contentType,
java.io.InputStream data_is,
AlgorithmID digestAlgorithm,
int mode)
Creates a new
DigestedDataStream object from given content and
and digest algorithm. |
| Modifier and Type | Method and Description |
|---|---|
void |
decode(java.io.InputStream is)
Reads and decodes a BER encoded DigestedData from an input stream.
|
void |
encodeCalled(ASN1Object o,
int id)
This method implements the EncodeListener interface.
|
int |
getBlockSize()
Gets the block size defining the length of each definite primitive
encoded octet string component.
|
ObjectID |
getContentType()
Returns the content type this class implements.
|
byte[] |
getDigest()
Returns the message-digest computed on the content value.
|
AlgorithmID |
getDigestAlgorithm()
Returns the message-digest algorithm used for computing the digest.
|
ObjectID |
getEncapsulatedContentType()
Returns the content type the inherent EncapsulatetContentInfo represents.
|
java.io.InputStream |
getInputStream()
Returns an input stream with the raw data.
|
int |
getVersion()
Returns the version syntax number.
|
void |
notifyEOF()
This method implements the EOFListener interface for performing the final decoding.
|
void |
setBlockSize(int blockSize)
Sets the block size for defining the length of each definite primitive
encoded octet string component.
|
void |
setDigest(byte[] digest)
Sets the message-digest value.
|
ASN1Object |
toASN1Object()
Returns this DigestedDataStream as ASN1Object.
|
protected ASN1Object |
toASN1Object(int blockSize)
Returns this DigestedData as ASN1Object where a constructed
OCTET STRING is used for encoding the content.
|
java.lang.String |
toString()
Returns a string giving some information about this
DigestedData object. |
java.lang.String |
toString(boolean detailed)
Returns a string giving some - if requested - detailed information
about this
DigestedData object. |
boolean |
verify()
Verifies the digest.
|
void |
writeTo(java.io.OutputStream os)
Writes this DigestedData DER encoded to the supplied output stream.
|
void |
writeTo(java.io.OutputStream os,
int blockSize)
Writes this object to the supplied output stream where a constructed
OCTET STRING is used for encoding the content.
|
public static final int IMPLICIT
public static final int EXPLICIT
protected int version_
protected AlgorithmID digestAlgorithm_
protected ObjectID contentType_
protected int blockSize_
protected EncapsulatedContentInfoStream encapContentInfo_
protected java.io.InputStream inputStream_
protected int mode_
protected DigestedDataStream()
public DigestedDataStream(java.io.InputStream data_is,
AlgorithmID digestAlgorithm,
int mode)
throws CMSException
DigestedDataStream object from given content and
and digest algorithm.
The data to be digested is supplied as input stream. 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 CMS Data.data_is - the data to be digested supplied from an input streamdigestAlgorithm - the message-digest algorithm to be used for creating the digestmode - either DigestedDataStream.IMPLICIT for including the data, or
DigestedDataStream.EXPLICIT for not including itCMSException - if the supplied paramteres to not satisfy the requirements ot there is no
implementation for the requested hash algorithmpublic DigestedDataStream(ObjectID contentType, java.io.InputStream data_is, AlgorithmID digestAlgorithm, int mode) throws CMSException
DigestedDataStream object from given content and
and digest algorithm.
The data to be digested is supplied as input stream. The mode parameter
specifies whether to include the data (mode = DigestedDataStream.IMPLICIT) or
not include it (mode = DigestedDataStream.EXPLICIT).contentType - the content type of the data to be digesteddata_is - the data to be digested supplied from an input streamdigestAlgorithm - the message-digest algorithm to be used for creating the digestmode - either DigestedDataStream.IMPLICIT for including the data, or
DigestedDataStream.EXPLICIT for not including itCMSException - if the supplied paramteres to not satisfy the requirements ot there is no
implementation for the requested hash algorithmpublic DigestedDataStream(ObjectID contentType, AlgorithmID digestAlgorithm, byte[] digest)
DigestedDataStream object without content.
For instance:
byte[] message = "Test data to be digested".getBytes();
MessageDigest md = MessageDigest.getInstance("SHA", "IAIK");
md.update(message);
byte[] digest = md.digest();
DigestedDataStream digested_data = new DigestedDataStream(ObjectID.cms_data, AlgorithmID.sha, digest);
The content must be transfered 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 already calculated digest valuepublic DigestedDataStream(java.io.InputStream is)
throws java.io.IOException,
CMSParsingException
The given input stream supplies the BER encoding of an already
existing CMS DigestedData object. This constructor shall be used
for parsing a implict DigestedData object where the content is included.
To initialize a DigestedDataStream object for parsing an explicit
DigestedData message where the raw data is not included, use the
DigestedDataStream(InputStream data_is, AlgorithmID hashAlgorithm)
constructor, and perform the decoding explicitly by calling the
decode method.
A sender shall use the DigestedDataStream(InputStream data_is, AlgorithmID digestAlgorithm, int mode)
constructor for supplying the content to be digested when creating a
DigestedDataStream object.
is - the InputStream holding the BER encoded CMS DigestedData objectjava.io.IOException - if an error occurs when reasding from the streamCMSParsingException - if the object can not be parsedpublic DigestedDataStream(java.io.InputStream data_is,
AlgorithmID digestAlgorithm)
throws java.io.IOException
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. The initialization is done by wrapping a digest
stream around the supplied raw data stream for the specified hash algorithm.
Subsequently the hash value will be updated when reading the stream thereby
piping the data through the digest stream.
Later, during digest verification the digest computaion is finished and the result
is compared with the hash values derived parsed from the encoding.
For an explicit message the actual decoding has to be performed by calling
the decode method just after reading the
data:
// initialize for hash computation:
DigestedDataStream digestedData = new DigestedDataStream(data_is, hashAlgorithm);
//read the stream thereby updating the hash values:
InputStream dataIs = digestedData.getInputStream();
byte[] buf = new byte[1024];
int r;
while ((r = dataIs.read(buf)) > 0) {
// do something useful
}
// explicitly perform the decoding
digestedData.decode(encoded_stream);
A sender shall use the DigestedDataStream(InputStream data_is, AlgorithmID digestAlgorithm, int mode)
constructor for supplying the content to be digested when creating a
DigestedDataStream object.
For decoding an implicit DigestedDataStream message, use the
DigestedDataStream(InputStream is) constructor.
data_is - the InputStream supplying the raw data which has been transmitted by other meansdigestAlgorithm - the hash algorithm used by for digesting the content datajava.io.IOException - if there is no implementation for the specified hash algorithmpublic void decode(java.io.InputStream is)
throws java.io.IOException,
CMSParsingException
decode in interface ContentStreamis - the InputStream holding a BER encoded CMS DigestedData objectjava.io.IOException - if an I/O error occurs during reading from the InputStreamCMSParsingException - if an error occurs while parsing the objectpublic ObjectID getContentType()
getContentType in interface ContentStreamObjectID.cms_digestedDatapublic ObjectID getEncapsulatedContentType()
public int getVersion()
public AlgorithmID getDigestAlgorithm()
public byte[] getDigest()
public void setDigest(byte[] digest)
digest - the digest value as byte arraypublic void setBlockSize(int blockSize)
blockSize is smaller or equal to zero the
whole data is encoded as definite primitive octet string.
This method may be used for enforcing block encoding when wrapping the
DigestedData into a ContentInfo.setBlockSize in interface ContentStreamblockSize - for defining the encoding scheme and setting the octet
string component length, if positivepublic int getBlockSize()
blockSize is smaller or equal to zero the
whole data is encoded as definite primitive octet string.getBlockSize in interface ContentStreampublic java.io.InputStream getInputStream()
public ASN1Object toASN1Object() throws CMSException
toASN1Object in interface ContentStreamCMSException - if the ASN1Object could not be createdprotected ASN1Object toASN1Object(int blockSize) throws CMSException
blockSize - the block size defining the encoding scheme - and specifying the
length of each primitive encoded octet string component, if positiveCMSException - if the ASN1Object could not be createdpublic void encodeCalled(ASN1Object o, int id) throws CodingException
EncodeListener
utility. The toASN1Object() method of this DigestedDataStream
class instantiates an empty OCTET_STRING for the digest
field, and registers itself as EncodeListener for this empty OCTET_STRING.
Now, during the encoding process, when the content stream entirely has
been read, this encodeCalled method is called for
performing digest computation. The supplied ASN1Object
is the empty OCTET_STRING to be "filled" with the result of the
digest-computation.encodeCalled in interface EncodeListenero - an OCTET_STRING for being supplied with the message digest valueid - the id identifying the particular octet string to be processedCodingException - if an error occurs when computing/encrypting
the message digestpublic void notifyEOF()
throws java.io.IOException
notifyEOF method for finishing the decoding by parsing the
final digest field.
notifyEOF in interface EOFListenerjava.io.IOException - if an error occurs while parsing the streampublic boolean verify()
throws CMSException
CMSException - if an error occurs during verification processpublic void writeTo(java.io.OutputStream os)
throws java.io.IOException
os - the output stream to which this DigestedData shall be writtenjava.io.IOException - if an IOException occurs while writing to the streampublic void writeTo(java.io.OutputStream os,
int blockSize)
throws java.io.IOException
0x24 0x80
0x04 <blocksize> <data>
0x04 <blocksize> <data>
0x04 <blocksize> <data>
...
0x00 0x00
If the block size is not positive, whole the inherent data is encoded as one
single primitive definite octet string:
0x04 <length> <data>
os - the output stream to which this DigestedData shall be writtenblockSize - the block size defining the encoding scheme - and specifying the
length of each primitive encoded octet string component, if positivejava.io.IOException - if an error occurs during writing the objectpublic java.lang.String toString()
DigestedData object.toString in class java.lang.Objectpublic java.lang.String toString(boolean detailed)
DigestedData object.toString in interface ContentStreamdetailed - - whether or not to give detailed information