public class DigestedDataStream extends java.lang.Object implements ContentStream, EncodeListener, EOFListener
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:
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).
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 transmission 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 PKCS#7 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 positive 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 0x00instead of:
0x04 0x05 0x01 0xAB 0x23 0x7F 0xCAfor 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 DER 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 computation 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):
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 |
block_size
The block size for block oriented stream encoding.
|
protected ObjectID |
content_type
The content type.
|
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 |
input_stream
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 DerInputStream |
this_object
An InputStream from which a DER encoded DigestedData object is read.
|
Modifier | Constructor and Description |
---|---|
protected |
DigestedDataStream()
Default constructor for dynamic object creation in ContentInfo.
|
|
DigestedDataStream(java.io.InputStream is)
Creates a PKCS#7 DigestedData 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. |
Modifier and Type | Method and Description |
---|---|
void |
decode(java.io.InputStream is)
Reads and decodes the DigestedDataStream from a DerInputStream.
|
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.
|
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 ObjectID content_type
protected DerInputStream this_object
protected int block_size
protected java.io.InputStream input_stream
protected int mode
protected DigestedDataStream()
public DigestedDataStream(java.io.InputStream data_is, AlgorithmID digestAlgorithm, int mode) throws PKCSException
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 PKCS#7 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 itPKCSException
- if the supplied parameters to not satisfy the requirements or
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"); md.update(message); byte[] digest = md.digest(); DigestedDataStream digested_data = new DigestedDataStream(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 already calculated digest valuepublic DigestedDataStream(java.io.InputStream is) throws java.io.IOException, PKCSParsingException
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 DER encoded PKCS#7 DigestedData objectjava.io.IOException
- if an error occurs when reading from the streamPKCSParsingException
- 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
DigestedDataStream 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 computation 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, PKCSParsingException
DerInputStream
, internally a
DerInputStream is created before parsing the data.decode
in interface ContentStream
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 ObjectID getContentType()
getContentType
in interface ContentStream
ObjectID.pkcs7_digestedData
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 ContentStream
blockSize
- for defining the encoding scheme and setting the octet string
component length, if positiveOCTET_STRING
public int getBlockSize()
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 EncryptedData into a ContentInfo.getBlockSize
in interface ContentStream
OCTET_STRING
public java.io.InputStream getInputStream()
public ASN1Object toASN1Object() throws PKCSException
toASN1Object
in interface ContentStream
PKCSException
- if the ASN1Object could not be createdprotected ASN1Object toASN1Object(int blockSize) throws PKCSException
blockSize
- the block size defining the encoding scheme - and specifying the
length of each primitive encoded octet string component, if
positivePKCSException
- 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-encryption.encodeCalled
in interface EncodeListener
o
- 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
iaik.utils.NotifyEOFInputStream
is
wrapped around this raw data stream for indicating that the parsing
procedure is to be notified when the stream actually has been read. At that
point, the program executing automatically jumps to the actual
notifyEOF
method for finishing the decoding by parsing the
final digest field. iaik.utils.EOFListener
interface.notifyEOF
in interface EOFListener
java.io.IOException
- if an error occurs while parsing the streamEOFListener
,
NotifyEOFInputStream
public boolean verify() throws PKCSException
PKCSException
- 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 0x00If 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.Object
public java.lang.String toString(boolean detailed)
DigestedData
object.toString
in interface ContentStream
detailed
- - whether or not to give detailed information