iaik.cms
Class EnvelopedDataStream

java.lang.Object
  extended by iaik.cms.EnvelopedDataStream
All Implemented Interfaces:
ContentStream, EOFListener, java.util.EventListener
Direct Known Subclasses:
EnvelopedData, SMimeEncrypted

public class EnvelopedDataStream
extends java.lang.Object
implements ContentStream, EOFListener

This class represents the stream-supporting implementation of the CMS content type EnvelopedData.

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 EnvelopedData content type is defined as:

envelopedData OBJECT IDENTIFIER ::= { pkcs-7 3 }

which corresponds to the OID string "1.2.840.113549.1.7.3".

The Cryptographic Message Syntax (CMS) (RFC 5652) specifies the EnvelopedData content type for providing a syntax for building digital envelopes. Content of any type may be enveloped for any number of recipients in parallel. For each recipient, a commonly at random generated content-encryption key is encrypted with the particular recipient key and - together with recipient-specific information - collected into a RecipientInfo value. The content is encrypted with the content-encryption key giving a EncryptedContent value, which - in combination with a recipient-specific encrypted content-encryption key - forms the digital envelope for each particular recipient. All RecipientInfo values are collected together with the encrypted content into an EnvelopedData value to be sent to each intended recipient.

This class implements the EnvelopedData structure resulting from the last step described above. The EnvelopedData type is defined as ASN.1 SEQUENCE type containing the following components (see RFC 5652):

 EnvelopedData ::= SEQUENCE {
   version                CMSVersion,
   originatorInfo     [0] IMPLICIT OriginatorInfo OPTIONAL,
   recipientInfos         RecipientInfos,
   encryptedContentInfo   EncryptedContentInfo 
   unprotectedAttrs   [1] IMPLICIT UnptotectedAttributes OPTIONAL }
 
OriginatorInfo ::= SEQUENCE { certs [0] IMPLICIT CertificateSet OPTIONAL, crls [1] IMPLICIT RevocationInfoChoices OPTIONAL }
RecipientInfos ::= SET OF RecipientInfo
EncryptedContentInfo ::= SEQUENCE { contentType ContentType, contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
EncryptedContent ::= OCTET STRING
UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute

The recipientInfos field is a non-empty collection of per-recipient information. The encryptedContentInfo field specifies the type of the content being enveloped, the content-encryption algorithm (the same for all recipients) used for encrypting the content, and the result of the content encryption. If the encrypted content value is not present in the encryptedContent field, it has to be supplied by other means.
CMS provides five alternatives for encrypting the content depending on the key management algorithm used to protect the content encryption key for a specific recipient:

The optional originatorInfo field may be used to include certificate/crl information about the originator if required by the key managemant protocol. unprotectedAttrs optionally may provide some attributes that are not encrypted.

A recipient, when receiving the EnvelopedData message, decrypts the corresponding encrypted content-encryption key with his/her key according the right key management protocol for subsequently decrypting the encrypted content using the content-encryption key just recovered. The recipient's key is referenced by proper KeyIdentifier included in the corresponding RecipientInfo object.

See RFC 5652 for more information.


When creating a new EnvelopedDataStream object for the data to be enveloped the symmetric algorithm has to be specified to be used for content-encryption. After setting the recipients, the EnvelopedDataStream object may be encoded and written to an output stream by using a proper writeTo method, e.g.:

  1. Create a new EnvelopedDataStream object and specify the content encryption algorithm to be used by means of the EnvelopedDataStream(InputStream is, AlgorithmID contentEA) constructor. Calling this constructor internally will generate the temporary content-encryption key for the specified content-encryption algorithm. If using a content-encryption algorithm allowing keys of different size, you may specify the key length by using the EnvelopedDataStream(InputStream is, AlgorithmID contentEA, int keyLength) constructor.
         //the data to be enveloped supplied from an input stream:
         InputStream dataStream = ...;
         // use AES in CBC mode for encrypting the content
         EnvelopedDataStream enveloped_data = new EnvelopedDataStream(dataStream, (AlgorithmID)AlgorithmID.aes256_CBC.clone());
         
  2. For each intended recipient, create a RecipientInfo object of requested type (KeyTransRecipientInfo, KeyAgreeRecipientInfo, or KEKRecipientInfo), and add all RecipientInfos to the EnvelopedDataStream object by calling method setRecipientInfos, e.g. (assuming to use two recipients, one having an RSA certificate and one having a ECDH certificate):
         RecipientInfo[] recipients = new RecipientInfo[2];
         // create a KeyTransRecipientInfo for recipient with RSA certificate
         X509Certificate rsaRecipientCert = ...;
         recipients[0] = new KeyTransRecipientInfo(rsaRecipientCert, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
         // create a KeyAgreeRecipientInfo for recipient with ECDH certificate
         X509Certificate ecdhRecipientCert = ...;
         // the key encryption (key agreement) algorithm to use:
         AlgorithmID keyEA = (AlgorithmID)CMSAlgorithmID.dhSinglePass_stdDH_sha256kdf_scheme.clone();
         // the key wrap algorithm to use:
         AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone();
         // the length of the key encryption key to be generated:
         int kekLength = 256;
         recipients[1] = new KeyAgreeRecipientInfo(keyEA, keyWrapAlg, kekLength);
         ((KeyAgreeRecipientInfo)recipients[1]).addRecipient(ecdhRecipientCert, CertificateIdentifier.ISSUER_AND_SERIALNUMBER);
         enveloped_data.setRecipientInfos(recipients);
         
  3. Use a proper writeTo method for BER encoding the EnvelopedData object and writing it to an output stream. You optionally may specify a particular block size for splitting the encoding of encrypted content. This step also will perform the encryption of the symmetric content-encryption key for each participated recipient.
         int blockSize = ...;
         OutputStream encoded_stream = ...;
         enveloped_data.writeTo(encoded_stream, blockSize);
         
    respectively
         enveloped_data.writeTo(encoded_stream);
         
    When a positive block size (default 2048) is specified for encoding the EnvelopedData to a stream, the encrypted content is BER encoded as indefinite constructed octet string being composed of a series of definite primitive encoded octet strings of blockSize length:
         0x24 0x80
                   0x04 <blocksize> <first encrypted content block>
                   0x04 <blocksize> <second encrypted content block>
                   0x04 <blocksize> <third encrypted content block>
                       ...
         0x00 0x00
         
    instead of:
         0x04 <length> <encrypted content>
         
A recipient, when receiving a EnvelopedDataStream encoding, uses the EnvelopedDataStream(InputStream is) constructor for parsing the internal structure. Before reading the recovered content by means of the getInputStream method, the cipher has to be initialized for decryption with the particular recipient key by calling one of the following setupCipher methods: Since in our example both recipients use a RecipientInfo of type KeyTransRecipientInfo, we can use any of the setupCipher methods to setup the cipher for decrypting the encrypted content-encryption key and the encrypted content:
  1. Create an EnvelopedDataStream structure from the supplied encoding, decode and parse the internal structure:
         EnvelopedDataStream enveloped_data = new EnvelopedDataStream(encoded_stream);
         
  2. Get information about the inherent EncryptedContentInfo:
         EncryptedContentInfoStream eci = (EncryptedContentInfoStream)enveloped_data.getEncryptedContentInfo();
         System.out.println("Content type: "+eci.getContentType().getName());
         System.out.println("Content encryption algorithm: "+eci.getContentEncryptionAlgorithm().getName());
         
  3. Get information about the included RecipientInfos:
         RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
         System.out.println("Included RecipientInfos:");
         for (int i=0; i < recipients.length; i++) {
            System.out.print("Recipient "+(i+1)+":");
            System.out.println(recipients[i]);
         }
         
  4. Use some recipient specific key to decrypt the inherent encrypted secret key to be used for initializing the cipher for encrypted-content decryption:
         // the private key of recipient 1:
         Key privateKey = ...;
         //setup cipher for recipient 1:
         int recipientInfoIndex = 0;
         enveloped_data.setupCipher(privateKey, recipientInfoIndex);
         
    Unlike the non-stream supporting EnvelopedData class where the encrypted-content decryption already is performed inside the setupCipher method, the cipher will be only initialized for decryption in this class. The encrypted-content decryption actually is done during reading the data obtained by calling the getInputStream method. So do not call getInputStream before setting up the cipher!

  5. Get and read the recovered content:
         InputStream data_is = enveloped_data.getInputStream();
         byte[] buf = new byte[4096];
         int r;
         while ((r = data_is.read(buf)) > 0) {
            // do something useful
         }
         


This class may be also use to create/encrypt or parse/decrypt explicit EnvelopedData messages where the encrypted content is not included in the EnvelopedData/EncryptedContentInfo but transferred by other means outside the EnvelopedData/EncryptedContentInfo.
For creating an EnvelopedDataStream in explicit mode the (to-be-encrypted) content has to be specified as usual when calling the constructor. Subsequently method setMode has to be called to set the mode to EnvelopedDataStream.EXPLICIT. Before finally writing the EnvelopedData encoded to an output stream, method getInputStream() has to be called to read (and thereby) encrypt the content data to be transferred by other means:

 //the data to be enveloped supplied from an input stream:
 InputStream dataStream = ...;
 // use, e.g., AES in CBC mode for encrypting the content
 EnvelopedDataStream envelopedData = new EnvelopedDataStream(dataStream, (AlgorithmID)AlgorithmID.aes256_CBC.clone());
 // the encrypted content shall be transmitted outside the EnvelopedData
 envelopedData.setMode(EnvelopedDataStream.EXPLICIT);
 // create and set the recipient infos
 RecipientInfo[] recipients = ...;
 envelopedData.setRecipientInfos(recipients);
 // read and encrypt the content data to be transmitted outside the EnvelopedData
 InputStream encryptedContentIs = envelopedData.getInputStream();
 byte[] buf = ...;
 int r;
 while ((r = data_is.read(buf)) > 0) {
   // do something useful
 }
 // encode the EnvelopedData
 OutputStream os = ...;
 envelopedData.writeTo(os); 
 
When parsing an explicit EnvelopedData method setInputStream has to be called to specify the encrypted content received by other means:
 // the input stream from which to read the encoded EnvelopedData:
 InputStream encodedStream = ...;
 // create EnvelopedDataStream
 EnvelopedDataStream envelopedData = new EnvelopedDataStream(encodedStream);
   ...
 // set the encrypted content received by other means
 InputStream encryptedContentStream = ...;
 envelopedData.setInputStream(encryptedContentStream);
 // setup cipher and decrypt the message for the, e.g., first recipient
 PrivateKey privateKey = ...;
 int recipientInfoIndex = 0;
 envelopedData.setupCipher(privateKey, 0);
 InputStream decryptedDataIs = envelopedData.getInputStream();
 byte[] buf = new byte[4096];
 int r;
 while ((r = decryptedDataIs.read(buf)) > 0) {
   // do something useful
 }  
 

See Also:
RecipientInfo, KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo, PasswordRecipientInfo, OtherRecipientInfo, EncryptedContentInfoStream

Field Summary
protected  int blockSize_
          The block size for block oriented stream encoding.
protected  EncryptedContentInfoStream encryptedContentInfo_
          The EncryptedContentInfo for the encrypted content.
static int EXPLICIT
          Denotes a mode where the encrypted message is not transported within the EnvelopedData (EncryptedContentInfo).
static int IMPLICIT
          Denotes a mode where the encrypted message is included in the EnvelopedData (EncryptedContentInfo).
protected  boolean keyChanged_
          Whether the content encryption key has changed.
protected  OriginatorInfo originatorInfo_
          The optional OriginatorInfo.
protected  java.util.Vector recipientInfos_
          Repository for the RecipientInfos.
protected  SecurityProvider securityProvider_
          The SecurityProvider providing the required cryptographic engines.
protected  javax.crypto.SecretKey symmetricKey_
          The secret content encryption key.
protected  Attribute[] unprotectedAttrs_
          Optional unprotected attributes.
protected  int version_
          The version number; default 0.
 
Constructor Summary
protected EnvelopedDataStream()
          Default constructor for dynamic object creation in ContentInfoStream.
  EnvelopedDataStream(java.io.InputStream is)
          Creates a new EnvelopedDataStream from a BER encoded EnvelopedData object which is read from the given InputStream.
  EnvelopedDataStream(java.io.InputStream is, AlgorithmID contentEA)
          Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.
  EnvelopedDataStream(java.io.InputStream is, AlgorithmID contentEA, int keyLength)
          Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.
  EnvelopedDataStream(java.io.InputStream is, SecurityProvider securityProvider)
          Creates a new EnvelopedDataStream from a BER encoded EnvelopedData object which is read from the given InputStream.
  EnvelopedDataStream(ObjectID contentType, java.io.InputStream is, AlgorithmID contentEA)
          Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.
  EnvelopedDataStream(ObjectID contentType, java.io.InputStream is, AlgorithmID contentEA, int keyLength)
          Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.
  EnvelopedDataStream(ObjectID contentType, java.io.InputStream is, AlgorithmID contentEA, int keyLength, SecurityProvider securityProvider)
          Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.
  EnvelopedDataStream(RecipientInfo[] recipients, EncryptedContentInfoStream encryptedCI)
          Constructs an EnvelopedDataStream object with an already created EncryptedContentInfoStream.
 
Method Summary
 void addRecipientInfo(RecipientInfo recipient)
          Adds one recipient to the list of recipient infos.
 void decode(java.io.InputStream is)
          Reads and decodes an BER encoded EnvelopedData from a the given input stream.
 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.
 EncryptedContentInfoStream getEncryptedContentInfo()
          Returns the EncryptedContentInfo included in this EnvelopedDataStream object.
 java.io.InputStream getInputStream()
          Returns an InputStream from where the decrypted data can be read.
 int getMode()
          Gets the mode of this EnvelopedDataStream.
 OriginatorInfo getOriginatorInfo()
          Gets the OriginatorInfo, if included.
 RecipientInfo getRecipientInfo(KeyIdentifier recipientIdentifier)
          Returns the RecipientInfo belonging to the recipient identified by the given recipient identifier.
 RecipientInfo getRecipientInfo(X509Certificate recipientCertificate)
          Returns the recipient info matching to the supplied recipient certificate.
 RecipientInfo[] getRecipientInfos()
          Returns all the recipient infos included in this EnvelopedData object.
 RecipientInfo[] getRecipientInfos(int type)
          Returns all the recipient infos included in this EnvelopedData object that have the specified type.
 SecurityProvider getSecurityProvider()
          Gets the SecurityProvider installed for this EncryptedDataStream.
 Attribute getUnprotectedAttribute(ObjectID oid)
          Returns the first unprotected attribute matching to the given ObjectID, if included in this EnvelopedData object.
 Attribute[] getUnprotectedAttributes()
          Gets the unprotected attributes included in this EnvelopedData.
 int getVersion()
          Returns the syntax version 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 setInputStream(java.io.InputStream is)
          Sets the input stream that supplies the content data to be encrypted.
 void setMode(int mode)
          Sets the mode for this EnvelopedDataStream.
 void setOriginatorInfo(OriginatorInfo originatorInfo)
          Sets the optional OriginatorInfo.
 void setRecipientInfos(RecipientInfo[] recipients)
          Sets the recipient infos.
 void setSecurityProvider(SecurityProvider securityProvider)
          Sets the SecurityProvider for this EnvelopedDataStream.
 void setUnprotectedAttributes(Attribute[] attributes)
          Sets a set of (unprotected) attributes.
 void setupCipher(java.security.Key key)
          Uses the given symmetric key to setup the cipher for decrypting the content.
 javax.crypto.SecretKey setupCipher(java.security.Key recipientKey, int recipientInfoIndex)
          Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this EnvelopedDataStream object for the requesting recipient, specified by its recipientInfoIndex.
 javax.crypto.SecretKey setupCipher(java.security.Key recipientKey, KeyIdentifier recipientIdentifier)
          Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this EnvelopedDataStream object for the requesting recipient, specified by the given recipient identifier.
 javax.crypto.SecretKey setupCipher(java.security.Key recipientKey, X509Certificate recipientCertificate)
          Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this EnvelopedDataStream object for the requesting recipient, specified by the given recipient certificate.
 ASN1Object toASN1Object()
          Returns this EnvelopedDataStream as ASN1Object.
protected  ASN1Object toASN1Object(int blockSize)
          Returns this EnvelopedData as ASN1Object.
 java.lang.String toString()
          Returns a string giving some information about this EnvelopedData object.
 java.lang.String toString(boolean detailed)
          Returns a string giving some - if requested - detailed information about this EnvelopedData object.
 void writeTo(java.io.OutputStream os)
          Writes this EnvelopedData BER encoded to the given output stream.
 void writeTo(java.io.OutputStream os, int blockSize)
          Writes this EnvelopedData BER encoded to the given output stream where a constructed OCTET STRING may be used for encoding the content.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

IMPLICIT

public static final int IMPLICIT
Denotes a mode where the encrypted message is included in the EnvelopedData (EncryptedContentInfo).

See Also:
Constant Field Values

EXPLICIT

public static final int EXPLICIT
Denotes a mode where the encrypted message is not transported within the EnvelopedData (EncryptedContentInfo).

See Also:
Constant Field Values

version_

protected int version_
The version number; default 0.


originatorInfo_

protected OriginatorInfo originatorInfo_
The optional OriginatorInfo.


recipientInfos_

protected java.util.Vector recipientInfos_
Repository for the RecipientInfos.


encryptedContentInfo_

protected EncryptedContentInfoStream encryptedContentInfo_
The EncryptedContentInfo for the encrypted content.


symmetricKey_

protected javax.crypto.SecretKey symmetricKey_
The secret content encryption key.


blockSize_

protected int blockSize_
The block size for block oriented stream encoding. (Default: 2048 to enforce indefinite constructed encoding).


unprotectedAttrs_

protected Attribute[] unprotectedAttrs_
Optional unprotected attributes.


securityProvider_

protected SecurityProvider securityProvider_
The SecurityProvider providing the required cryptographic engines.


keyChanged_

protected boolean keyChanged_
Whether the content encryption key has changed.

Constructor Detail

EnvelopedDataStream

protected EnvelopedDataStream()
Default constructor for dynamic object creation in ContentInfoStream. The block size is set to 2048 to enforce indefinite constructed encoding.


EnvelopedDataStream

public EnvelopedDataStream(java.io.InputStream is,
                           AlgorithmID contentEA)
                    throws java.security.NoSuchAlgorithmException
Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.

The content type is set to CMS Data.

When using this constructor, automatically a temporary symmetric key for content encryption is generated. If using a content-encryption algorithm allowing keys of different size, you may specify the key length by using the EnvelopedDataStream(InputStream is, AlgorithmID contentEA, int keyLength) constructor.
Note that the supplied contentEA AlgorithmID internally is cloned.

Parameters:
is - the InputStream supplying the data to be enveloped
contentEA - the content encryption algorithm for encrypting the content
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedDataStream

public EnvelopedDataStream(ObjectID contentType,
                           java.io.InputStream is,
                           AlgorithmID contentEA)
                    throws java.security.NoSuchAlgorithmException
Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.

When using this constructor, automatically a temporary symmetric key for content encryption is generated. If using a content-encryption algorithm allowing keys of different size, you may specify the key length by using the EnvelopedDataStream(ObjectID contentType, InputStream is, AlgorithmID contentEA, int keyLength) constructor.
Note that the supplied contentEA AlgorithmID internally is cloned.

Parameters:
contentType - the content type of the content to be enveloped
is - the InputStream containing the data to envelope
contentEA - the content encryption algorithm for encrypting the content
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedDataStream

public EnvelopedDataStream(java.io.InputStream is,
                           AlgorithmID contentEA,
                           int keyLength)
                    throws java.security.NoSuchAlgorithmException
Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.
The content type is set to CMS Data.

When using this constructor, automatically a symmetric key for content encryption is generated. If the specified content encryption algorithm supports variable key lengths, a particular key length may be set by means of the keyLength parameter. If no length is specified, the defined default key length will be used. If the algorithm only works with keys of fixed-size length, the keyLength parameter may be set to -1 or the EnvelopedDataStream(InputStream is, AlgorithmID contentEA) constructor may be used.
Note that the supplied contentEA AlgorithmID internally is cloned.

Parameters:
is - the InputStream containing the data to envelope
contentEA - the content encryption algorithm for encrypting the content
keyLength - the key length that may be set when using a content encryption algorithm that supports variable key lengths
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedDataStream

public EnvelopedDataStream(ObjectID contentType,
                           java.io.InputStream is,
                           AlgorithmID contentEA,
                           int keyLength)
                    throws java.security.NoSuchAlgorithmException
Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.

When using this constructor, automatically a symmetric key for content encryption is generated. If the specified content encryption algorithm supports variable key lengths, a particular key length may be set by means of the keyLength parameter. If no length is specified, the defined default key length will be used. If the algorithm only works with keys of fixed-size length, the keyLength parameter may be set to -1 or the EnvelopedDataStream(ObjectID contentType, InputStream is, AlgorithmID contentEA) constructor may be used.
Note that the supplied contentEA AlgorithmID internally is cloned.

Parameters:
contentType - the content type of the content to be enveloped
is - the InputStream containing the data to envelope
contentEA - the content encryption algorithm for encrypting the content
keyLength - the key length that may be set when using a content encryption algorithm that supports variable key lengths
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedDataStream

public EnvelopedDataStream(ObjectID contentType,
                           java.io.InputStream is,
                           AlgorithmID contentEA,
                           int keyLength,
                           SecurityProvider securityProvider)
                    throws java.security.NoSuchAlgorithmException
Creates a new EnvelopedDataStream object where the content to be enveloped is read from the supplied InputStream.

When using this constructor, automatically a symmetric key for content encryption is generated. If the specified content encryption algorithm supports variable key lengths, a particular key length may be set by means of the keyLength parameter. If no length is specified, the defined default key length will be used. If the algorithm only works with keys of fixed-size length, the keyLength parameter may be set to -1 or the EnvelopedDataStream(ObjectID contentType, InputStream is, AlgorithmID contentEA) constructor may be used.
Note that the supplied contentEA AlgorithmID internally is cloned.

Parameters:
contentType - the content type of the content to be enveloped
is - the InputStream containing the data to envelope
contentEA - the content encryption algorithm for encrypting the content
keyLength - the key length that may be set when using a content encryption algorithm that supports variable key lengths
securityProvider - the security provider to be used; if null the default system-wide SecurityProvider is used
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedDataStream

public EnvelopedDataStream(RecipientInfo[] recipients,
                           EncryptedContentInfoStream encryptedCI)
Constructs an EnvelopedDataStream object with an already created EncryptedContentInfoStream.

The given array of RecipientInfo specifies a collection of per-recipient information, and the given EncryptedContentInfoStream supplies the already encrypted content.

Parameters:
recipients - information about the recipients
encryptedCI - the encrypted content info

EnvelopedDataStream

public EnvelopedDataStream(java.io.InputStream is)
                    throws CMSParsingException,
                           java.io.IOException
Creates a new EnvelopedDataStream from a BER encoded EnvelopedData object which is read from the given InputStream. The encoded EnvelopedData may (or may not) be wrapped into a ContentInfo.

Parameters:
is - the InputStream supplying a BER encoded CMS EnvelopedData object
Throws:
java.io.IOException - if an I/O error occurs during reading from the InputStream
CMSParsingException - if an error occurs while parsing the object

EnvelopedDataStream

public EnvelopedDataStream(java.io.InputStream is,
                           SecurityProvider securityProvider)
                    throws CMSParsingException,
                           java.io.IOException
Creates a new EnvelopedDataStream from a BER encoded EnvelopedData object which is read from the given InputStream. The encoded EnvelopedData may (or may not) be wrapped into a ContentInfo.

Parameters:
is - the InputStream supplying a BER encoded CMS EnvelopedData object
securityProvider - the security provider to be used; if null the default system-wide SecurityProvider is used
Throws:
java.io.IOException - if an I/O error occurs during reading from the InputStream
CMSParsingException - if an error occurs while parsing the object
Method Detail

setSecurityProvider

public void setSecurityProvider(SecurityProvider securityProvider)
Sets the SecurityProvider for this EnvelopedDataStream.

This method allows to explicitly set a SecurityProvider for this EnvelopedDataStream. If no explicit SecurityProvider is set, the default system wide installed SecurityProvider will be used for the required cryptographic operations.

This class uses the following method(s) of the SecurityProvider, which may be overriden by an application, if required:

An application may supply the SecurityProvider immediately when creating an EnvelopedData object. This may be preferable on the parsing side, and also when creating a new EnvelopedData object where the EncryptedContentInfo and the RecipientInfos have to be created by this class.

Parameters:
securityProvider - the SecurityProvider to be set

getSecurityProvider

public SecurityProvider getSecurityProvider()
Gets the SecurityProvider installed for this EncryptedDataStream.

This class uses the following method(s) of the SecurityProvider, which may be overriden by an application, if required:

If no explicit SecurityProvider has been set for this object, the default system wide installed SecurityProvider will be used for the required cryptographic operations. However, this method will return null if it does not have its own SecurityProvider.

Returns:
the SecurityProvider explicitly installed for this object, or null if this object does not have its own SecurityProvider

setMode

public void setMode(int mode)
Sets the mode for this EnvelopedDataStream.

This method may be only called to set the mode to EXPLICIT for creating a new EnvelopedDataStream in EXPLICIT mode where the encrypted content shall not be included in the EnvelopedData. In this case the encrypted content has to be transmitted by other means. This method may not be called in IMPLICIT mode (default) where the encrypted content is included in the EnvelopedData. This method MUST not be called when parsing an EnvelopedData where the mode is automatically detected and cannot be changed.

Parameters:
mode - the mode, either IMPLICIT (to include the encrypted content (default) or EXPLICIT to not include it)
Throws:
java.lang.IllegalArgumentException - if the mode is not IMPLICIT or EXPLICIT; or if this method is called when parsing an EnvelopedData

getMode

public int getMode()
Gets the mode of this EnvelopedDataStream.

Returns:
the mode, either IMPLICIT (to include the encrypted content (default) or EXPLICIT to not include it)

decode

public void decode(java.io.InputStream is)
            throws java.io.IOException,
                   CMSParsingException
Reads and decodes an BER encoded EnvelopedData from a the given input stream. The encoded EnvelopedData may (or may not) be wrapped into a ContentInfo.

Specified by:
decode in interface ContentStream
Parameters:
is - the InputStream holding a BER encoded EnvelopedData object
Throws:
java.io.IOException - if an I/O error occurs during reading from the InputStream
CMSParsingException - if an error occurs while parsing the object

getContentType

public ObjectID getContentType()
Returns the content type this class implements.

Use getEncryptedContentInfo().getContentType() for getting the type the encrypted content represents.

Specified by:
getContentType in interface ContentStream
Returns:
ObjectID.cms_envelopedData

setOriginatorInfo

public void setOriginatorInfo(OriginatorInfo originatorInfo)
Sets the optional OriginatorInfo.

The originatorInfo may be set for including certificates and/or certificate revocation lists for the originator if required by the key management algorithm used.

Parameters:
originatorInfo - the OriginatorInfo to be set

setRecipientInfos

public void setRecipientInfos(RecipientInfo[] recipients)
Sets the recipient infos.

Any RecipientInfo added supplies recipient-specific information used for identifying the key of the recipient to be used for en/decrypting the content.

Parameters:
recipients - a collection of per-recipient information
See Also:
RecipientInfo, KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo, PasswordRecipientInfo, OtherRecipientInfo

addRecipientInfo

public void addRecipientInfo(RecipientInfo recipient)
Adds one recipient to the list of recipient infos.

Any RecipientInfo added supplies recipient-specific information used for identifying the key of the recipient to be used for en/decrypting the content.

Parameters:
recipient - the RecipientInfo to be added
See Also:
RecipientInfo, KeyTransRecipientInfo, KeyAgreeRecipientInfo, KEKRecipientInfo, PasswordRecipientInfo, OtherRecipientInfo

setUnprotectedAttributes

public void setUnprotectedAttributes(Attribute[] attributes)
Sets a set of (unprotected) attributes.

Parameters:
attributes - the unprotected attributes to be set

setBlockSize

public void setBlockSize(int blockSize)
Sets the block size for defining the length of each definite primitive encoded octet string component. If the value of blockSize is smaller or equal to zero the whole encrypted data is encoded as definite primitive octet string.

Specified by:
setBlockSize in interface ContentStream
Parameters:
blockSize - for defining the encoding scheme and setting the octet string component length, if positive

getBlockSize

public int getBlockSize()
Gets the block size defining the length of each definite primitive encoded octet string component. If the value of blockSize is smaller or equal to zero the whole data is encoded as definite primitive octet string.

Specified by:
getBlockSize in interface ContentStream
Returns:
the block size defining the encoding scheme and setting the octet string component length, if positive

setupCipher

public javax.crypto.SecretKey setupCipher(java.security.Key recipientKey,
                                          int recipientInfoIndex)
                                   throws CMSException,
                                          java.security.NoSuchAlgorithmException,
                                          java.security.InvalidKeyException
Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this EnvelopedDataStream object for the requesting recipient, specified by its recipientInfoIndex.

This method first uses the given key for decrypting the encrypted temporary symmetric key obtained from the corresponding RecipientInfo structure, and subsequently uses this key to initialize a CipherInputStream for decrypting the inherent encrypted content.

Unlike the non-stream supporting EnvelopedData class where the encrypted-content decryption already is performed inside the setupCipher method, the cipher will be only initialized for decrypting in this class. The encrypted-content decryption actually is done during reading the data obtained by calling the getInputStream method. So do not call getInputStream before setting up the cipher!

Note that you have to know the right index into the recipientInfos field when using this method for setting up the cipher for decryption. You may search for the index by using one of the getRecipientInfo methods thereby identifying the recipient by its keyIdentifier or -- if suitable for the key management algorithm used -- certificate.
However, when having some recipient using a key agreement protocol the corresponding RecipientInfo is of type KeyAgreeRecipientInfo which may hold encrypted content-encryption keys for more than only one recipients using the same key agreement algorithm with same domain parameters. Since this setupCipher method only can get the KeyAgreeRecipientInfo with the given index (but not search for the right recipient in the KeyAgreeRecipientInfo), it will step through any recipient included in the KeyAgreeRecipientInfo trying to decrypt the encrypted content-encryption key with the supplied key. This may give some overhead so it might be appropriate to use another setupCipher method allowing to immediately identify the particular recipient in mind by its #setupCipher(Key, KeyIdentifier) keyIdentifier} or certificate.

Parameters:
recipientKey - the key of the recipient to be used for decrypting the encrypted content-encryption key.
recipientInfoIndex - the index into the recipientInfos field
Returns:
the (decrypted) secret content encryption key
Throws:
CMSException - if there occurs an error while decrypting the content-encryption key or setting up the cipher for decrypting the content
java.security.NoSuchAlgorithmException - if there is no implementation of the content-encryption algorithm
java.security.InvalidKeyException - if the specified key is not valid

setupCipher

public javax.crypto.SecretKey setupCipher(java.security.Key recipientKey,
                                          KeyIdentifier recipientIdentifier)
                                   throws CMSException,
                                          java.security.NoSuchAlgorithmException,
                                          java.security.InvalidKeyException
Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this EnvelopedDataStream object for the requesting recipient, specified by the given recipient identifier.

This method first uses the given key for decrypting the encrypted temporary symmetric key obtained from the corresponding RecipientInfo structure, and subsequently uses this key to initialize a CipherInputStream for decrypting the inherent encrypted content.

Unlike the non-stream supporting EnvelopedData class where the encrypted-content decryption already is performed inside the setupCipher method, the cipher will be only initialized for decrypting in this class. The encrypted-content decryption actually is done during reading the data obtained by calling the getInputStream method. So do not call getInputStream before setting up the cipher!

This setupCipher can be used to setup the cipher for decryption for any type of RecipientInfo. The supplied recipient identifier will be used for searching for the right RecipientInfo in the recipientInfos field.

Parameters:
recipientKey - the key of the recipient to be used for decrypting the encrypted content-encryption key.
recipientIdentifier - specifies which RecipientInfo the given key belongs to
Returns:
the (decrypted) secret content encryption key
Throws:
CMSException - if there occurs an error while decrypting the content-encryption key or setting up the cipher for decrypting the content, or no RecipientInfo for the requested recipient is included
java.security.NoSuchAlgorithmException - if there is no implementation of the content-encryption algorithm
java.security.InvalidKeyException - if the specified key is not valid

setupCipher

public javax.crypto.SecretKey setupCipher(java.security.Key recipientKey,
                                          X509Certificate recipientCertificate)
                                   throws CMSException,
                                          java.security.NoSuchAlgorithmException,
                                          java.security.InvalidKeyException
Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this EnvelopedDataStream object for the requesting recipient, specified by the given recipient certificate.

This method first uses the given key for decrypting the encrypted temporary symmetric key obtained from the corresponding RecipientInfo structure, and subsequently uses this key to initialize a CipherInputStream for decrypting the inherent encrypted content.

Unlike the non-stream supporting EnvelopedData class where the encrypted-content decryption already is performed inside the setupCipher method, the cipher will be only initialized for decrypting in this class. The encrypted-content decryption actually is done during reading the data obtained by calling the getInputStream method. So do not call getInputStream before setting up the cipher!

Note that this method only can be used for decrypting the encrypted content if the recipient in mind has a RecipientInfo of type KeyTransRecipientInfo or KeyAgreeRecipientInfo using a public key from a certificate for its key management protocol.

Parameters:
recipientKey - the private key of the recipient to be used for decrypting the encrypted content-encryption key.
recipientCertificate - the certificate of the recipient specifying which RecipientInfo the recipient private key belongs to
Returns:
the (decrypted) secret content encryption key
Throws:
CMSException - if there occurs an error while decrypting the content-encryption key or setting up the cipher for decrypting the content, or no RecipientInfo for the requested recipient is included
java.security.NoSuchAlgorithmException - if there is no implementation of the content-encryption algorithm
java.security.InvalidKeyException - if the specified private key is not valid

setupCipher

public void setupCipher(java.security.Key key)
                 throws CMSException,
                        java.security.NoSuchAlgorithmException,
                        java.security.InvalidKeyException
Uses the given symmetric key to setup the cipher for decrypting the content.

The secret key supplied to this method has to be the already decrypted content encryption key.

Unlike the non-stream supporting EnvelopedData class where the encrypted-content decryption already is performed inside the setupCipher method, the cipher will be only initialized for decrypting in this class. The encrypted-content decryption actually is done during reading the data obtained by calling the getInputStream method. So do not call getInputStream before setting up the cipher!

Parameters:
key - the temporary symmetric key that has been used to encrypt the content, and now is used for decrypting it again
Throws:
CMSException - if there occurs an error while setting up the cipher for decrypting the content
java.security.NoSuchAlgorithmException - if there is no implementation for the content-encryption algorithm
java.security.InvalidKeyException - if the specified key is not valid

getInputStream

public java.io.InputStream getInputStream()
Returns an InputStream from where the decrypted data can be read.

Attention! The stream only may be read once.

When having created a new (implcit) EnvelopedDataStream object to be encoded to a stream, this method should not be called at all, since the stream automatically will be read during performing the encoding (which is done when calling a writeTo method). However, when not using the EnvelopedDataStream in explicit mode, this getInputStream method may be called to get and read the encrypted content to be transferred by other means:

 //the data to be enveloped supplied from an input stream:
 InputStream dataStream = ...;
 // use, e.g., AES in CBC mode for encrypting the content
 EnvelopedDataStream envelopedData = new EnvelopedDataStream(dataStream, (AlgorithmID)AlgorithmID.aes256_CBC.clone());
 
 // if we want to transmit the encrypted content by other means we use the explicit mode
 envelopedData.setMode(EnvelopedDataStream.EXPLICIT);
 
 // create and set the recipient infos
 RecipientInfo[] recipients = ...;
 envelopedData.setRecipientInfos(recipients);
 
 // if we use explicit mode we read and encrypt the content data to be transmitted 
 // outside the EnvelopedData
 InputStream encryptedContentIs = envelopedData.getInputStream();
 byte[] buf = ...;
 int r;
 while ((r = data_is.read(buf)) > 0) {
   // do something useful
 }
 
 // encode the EnvelopedData
 OutputStream os = ...;
 envelopedData.writeTo(os); 
 

When having decoded and parsed a received EnvelopedDataStream object comimg from some stream, this method may be used for obtaining the raw (decrypted) data after having setup the cipher for decrypting the content.

Returns:
an InputStream for reading the decrypted data

setInputStream

public void setInputStream(java.io.InputStream is)
Sets the input stream that supplies the content data to be encrypted.

Parameters:
is - the input stream holding the content data to encrypt

getVersion

public int getVersion()
Returns the syntax version number.

Returns:
the syntax version number

getOriginatorInfo

public OriginatorInfo getOriginatorInfo()
Gets the OriginatorInfo, if included.

The originatorInfo may be set for including certificates and/or certificate revocation lists if required by the key management algorithm used.

Returns:
the originatorInfo, if included; otherwise null

getRecipientInfos

public RecipientInfo[] getRecipientInfos()
Returns all the recipient infos included in this EnvelopedData object.

Returns:
an array containing all the RecipientInfo objects included into this EnvelopedData

getRecipientInfos

public RecipientInfo[] getRecipientInfos(int type)
Returns all the recipient infos included in this EnvelopedData object that have the specified type.

Returns:
an array containing all the RecipientInfo objects included into this EnvelopedData that have the specified type (e.g. all KeyTransRecipientInfos); the array may be empty if no RecipientInfo with the requested type is included

getRecipientInfo

public RecipientInfo getRecipientInfo(X509Certificate recipientCertificate)
Returns the recipient info matching to the supplied recipient certificate.

This method may be used by a recipient for quering for the recipient info that holds the content encryption key encrypted with the public key of the given certificate.
Note that this method only can be used for searching for RecipientInfos of type KeyTransRecipientInfo or KeyAgreeRecipientInfo, but NOT for a RecipientInfo of type KEKRecipientInfo which does use a certificate.

Returns:
the RecipientInfo matching to the supplied recipient certificate, or null if no recipient info belonging to the given certificate can be found

getRecipientInfo

public RecipientInfo getRecipientInfo(KeyIdentifier recipientIdentifier)
Returns the RecipientInfo belonging to the recipient identified by the given recipient identifier.

Parameters:
recipientIdentifier - the recipient identifier identifying the recipient in mind
Returns:
the RecipientInfo matching to the supplied recipient identifier, or null if no recipient info belonging to the given recipient identifier can be found

getEncryptedContentInfo

public EncryptedContentInfoStream getEncryptedContentInfo()
Returns the EncryptedContentInfo included in this EnvelopedDataStream object.

Returns:
the inherent EncryptedContentInfo

getUnprotectedAttributes

public Attribute[] getUnprotectedAttributes()
Gets the unprotected attributes included in this EnvelopedData.

Returns:
the unprotected attributes; if included

getUnprotectedAttribute

public Attribute getUnprotectedAttribute(ObjectID oid)
Returns the first unprotected attribute matching to the given ObjectID, if included in this EnvelopedData object.

Returns:
the first unprotected attribute belonging to the given ObjectID or null if there is no attribute for the given OID.

toASN1Object

public ASN1Object toASN1Object()
                        throws CMSException
Returns this EnvelopedDataStream as ASN1Object.

Specified by:
toASN1Object in interface ContentStream
Returns:
this EnvelopedDataStream as ASN1Object.
Throws:
CMSException - if the ASN1Object could not be created

toASN1Object

protected ASN1Object toASN1Object(int blockSize)
                           throws CMSException
Returns this EnvelopedData as ASN1Object.

If is positive a constructed OCTET STRING is used for encoding the encrypted content. This method actually will perform the encryption of the symmetric content-encryption key for each participated recipient.

Parameters:
blockSize - the block size defining the encoding scheme - and specifying the length of each primitive encoded octet string component, if positive
Returns:
this EnvelopedData as ASN1Object
Throws:
CMSException - if the ASN1Object could not be created

writeTo

public void writeTo(java.io.OutputStream os)
             throws java.io.IOException
Writes this EnvelopedData BER encoded to the given output stream.

Parameters:
os - the output stream to which this EnvelopedData shall be written
Throws:
java.io.IOException

writeTo

public void writeTo(java.io.OutputStream os,
                    int blockSize)
             throws java.io.IOException
Writes this EnvelopedData BER encoded to the given output stream where a constructed OCTET STRING may be used for encoding the content.

When encoding the content data to the given stream it is piped through a cipher stream thereby performing the content encryption.

If the a positive blockSize value is specified, the encrypted content is encoded as indefinite constructed octet string being composed of a certain number of definite primitive encoded octet strings of blockSize length:

 0x24 0x80
           0x04 <blocksize> <first encrypted content block>
           0x04 <blocksize> <second encrypted content block>
           0x04 <blocksize> <third encrypted content block>
                ...
 0x00 0x00
 
Otherwise, whole the encrypted content is encoded as definite primitive octet string:
  0x04 <length> <encrypted content>
 

Parameters:
os - the output stream to which this SignedData shall be written
blockSize - the block size defining the encoding scheme - and specifying the length of each primitive encoded octet string component, if positive
Throws:
java.io.IOException - if an error occurs during writing the object

notifyEOF

public void notifyEOF()
               throws java.io.IOException
This method implements the EOFListener interface for performing the final decoding. Since unprotected attributes, if present, are located at the end of an EnvelopedData structure, they only can be accessed after reading/decrypting the data included in the EncryptedContentInfo located before the unprotected attributes. For that reason, when starting the parsing of an EnvelopedData message only version, (originatorInfo), recipientInfos, and EncryptedContentInfo fields can be parsed before reading/decrypting the data. Since the data is supplied from an input stream, a iaik.utils.NotifyEOFInputStream is wrapped around this content data stream for indicating that the parsing procedure is to be notified when the stream actually has been read. At that point, the programm exceuting automatically jumps to the notifyEOF method for finishing the decoding by parsing the remaining unprotected attributes, if present.
An application shall not call this method! This method only is qualified as public method since it implements the IAIK-JCE iaik.utils.EOFListener interface.

Specified by:
notifyEOF in interface EOFListener
Throws:
java.io.IOException - if an error occurs while parsing the stream

toString

public java.lang.String toString()
Returns a string giving some information about this EnvelopedData object.

Overrides:
toString in class java.lang.Object
Returns:
the string representation

toString

public java.lang.String toString(boolean detailed)
Returns a string giving some - if requested - detailed information about this EnvelopedData object.

Specified by:
toString in interface ContentStream
Parameters:
detailed - - whether or not to give detailed information
Returns:
the string representation

This Javadoc may contain text parts from text parts from IETF Internet Standard specifications (see copyright note).

IAIK-CMS 6.0, (c) 2002 IAIK, (c) 2003, 2023 SIC