iaik.cms
Class EnvelopedData

java.lang.Object
  extended by iaik.cms.EnvelopedDataStream
      extended by iaik.cms.EnvelopedData
All Implemented Interfaces:
Content, ContentStream, EOFListener, java.util.EventListener

public class EnvelopedData
extends EnvelopedDataStream
implements Content

This class represents the non-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 three 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 EnvelopedData 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 EnvelopedData object may be prepared for transmission by transforming it into an ASN1Object or immediately encoding it, e.g.:

  1. Create a new EnvelopedData object and specify the content encryption algorithm to be used by means of the EnvelopedData(byte[] content, 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 EnvelopedData(byte[] content, AlgorithmID contentEA, int keyLength) constructor.
         //the data to be enveloped:
         byte[] data = ...;
         // use AES in CBC mode for encrypting the content
         EnvelopedData enveloped_data = new EnvelopedData(data, (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 EnvelopedData 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. Prepare the EnvelopedData object for transmission by transforming it into an ASN1Object or immediately encoding it. This step also will perform the encryption of the symmetric content-encryption key for each participated recipient.
         ASN1Object obj = enveloped_data.toASN1Object();
         
    respectively
         byte[] encoding = enveloped_data.getEncoding();
         
    For forcing a constructed, blocksize oriented encoding, alternatively you may use the corresponding writeTo method of the parent EnvelopedDataStream class.
A recipient uses the EnvelopedData(ASN1Object obj) or EnvelopedData(InputStream is) constructor for parsing the EnvelopedData supplied as ASN1Object oder BER encoding. Before getting the recovered content by means of the getContent 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 have a certificate, we can use a certificate bases setupCipher methods to setup the cipher for decrypting the encrypted content-encryption key and the encrypted content:
  1. Create an EnvelopedData from its BER encoding:
         ByteArrayInputStream bais = new ByteArrayInputStream(encoding);
         EnvelopedData enveloped_data = new EnvelopedData(is);
         
  2. Get information about the inherent EncryptedContentInfo:
         EncryptedContentInfo eci = (EncryptedContentInfo)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.pritnln("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 subsequently performing encrypted-content decryption:
         // private key and certificate of the recipient:
         Key recipientKey = ...;
         X509Certificate recipientCertificate = ...;
         //setup cipher for recipient:
         enveloped_data.setupCipher(privateKey, recipientCertificate);
         
    Unlike the stream supporting EnvelopedDataStream class where the setupCipher method only initializes the cipher for decryption, whole the encrypted-content decryption already is performed inside the setupCipher method of this class.

  5. Get the recovered content:
         byte[] content = enveloped_data.getContent();
         


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 EnvelopedData 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 EnvelopedData.EXPLICIT. Before finally encoding the EnvelopedData, method getContent() maybe be called to get the encrypted content data that shall be transferred by other means:

 //the data to be enveloped supplied from an input stream:
 byte[] data = ...;
 //use, e.g., AES in CBC mode for encrypting the content
 EnvelopedData envelopedData = new EnvelopedData(data, (AlgorithmID)AlgorithmID.aes256_CBC.clone());
 // the encrypted content shall be transmitted outside the EnvelopedData
 envelopedData.setMode(EnvelopedData.EXPLICIT);
 // create and set the recipient infos
 RecipientInfo[] recipients = ...;
 envelopedData.setRecipientInfos(recipients);
 // get the encrypted content data to be transmitted outside the EnvelopedData
 byte[] encryptedContent = envelopedData.getContent();
 // encode the EnvelopedData
 byte[] encodedEnvelopedData = envelopedData.getEncoded(); 
 
When parsing an explicit EnvelopedData method setContent has to be called to specify the encrypted content received by other means:
 // the encoded EnvelopedData:
 InputStream encodedStream = ...;
 // create EnvelopedDataStream
 EnvelopedData envelopedData = new EnvelopedData(encodedStream);
   ...
 // set the encrypted content received by other means
 byte[] encryptedContent = ...;
 envelopedData.setContent(encryptedContent);
 // setup cipher and decrypt the message for the, e.g., first recipient
 PrivateKey privateKey = ...;
 int recipientInfoIndex = 0;
 envelopedData.setupCipher(privateKey, 0);
 byte[] content = envelopedData.getContent();  
 

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

Field Summary
 
Fields inherited from class iaik.cms.EnvelopedDataStream
blockSize_, encryptedContentInfo_, EXPLICIT, IMPLICIT, keyChanged_, originatorInfo_, recipientInfos_, securityProvider_, symmetricKey_, unprotectedAttrs_, version_
 
Constructor Summary
protected EnvelopedData()
          Default constructor for dynamic object creation in ContentInfo.
  EnvelopedData(ASN1Object obj)
          Creates a CMS EnvelopedData from an ASN1Object.
  EnvelopedData(ASN1Object obj, SecurityProvider securityProvider)
          Creates a CMS EnvelopedData from an ASN1Object.
  EnvelopedData(byte[] content, AlgorithmID contentEA)
          Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(byte[] content, AlgorithmID contentEA, int keyLength)
          Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(java.io.InputStream is)
          Creates a new EnvelopedDataStream from a BER encoded EnvelopedData object which is read from the given InputStream.
  EnvelopedData(java.io.InputStream is, SecurityProvider securityProvider)
          Creates a new EnvelopedData from a BER encoded EnvelopedData object which is read from the given InputStream.
  EnvelopedData(ObjectID contentType, byte[] content, AlgorithmID contentEA)
          Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(ObjectID contentType, byte[] content, AlgorithmID contentEA, int keyLength)
          Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(ObjectID contentType, byte[] content, AlgorithmID contentEA, int keyLength, SecurityProvider securityProvider)
          Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(RecipientInfo[] recipients, EncryptedContentInfo encryptedCI)
          Constructs a CMS EnvelopedData type with an already created EncryptedContentInfo.
 
Method Summary
 void decode(ASN1Object obj)
          Decodes the given EnvelopedData ASN1 object.
 void decode(java.io.InputStream is)
          Reads and decodes a BER encoded EnvelopedData from the given input stream.
 byte[] getContent()
          Returns the content as byte array.
 byte[] getEncoded()
          Returns the BER encoding of this EnvelopedData in a byte array.
 void setContent(byte[] content)
          Sets the content data to be en/decrypted.
 void setInputStream(java.io.InputStream is)
          Sets the input stream that supplies the content data to be en/decrypted.
protected  ASN1Object toASN1Object(int blockSize)
          Returns this EnvelopedData as ASN1Object.
 
Methods inherited from class iaik.cms.EnvelopedDataStream
addRecipientInfo, getBlockSize, getContentType, getEncryptedContentInfo, getInputStream, getMode, getOriginatorInfo, getRecipientInfo, getRecipientInfo, getRecipientInfos, getRecipientInfos, getSecurityProvider, getUnprotectedAttribute, getUnprotectedAttributes, getVersion, notifyEOF, setBlockSize, setMode, setOriginatorInfo, setRecipientInfos, setSecurityProvider, setUnprotectedAttributes, setupCipher, setupCipher, setupCipher, setupCipher, toASN1Object, toString, toString, writeTo, writeTo
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface iaik.cms.ContentStream
getBlockSize, getContentType, setBlockSize, toASN1Object, toString
 

Constructor Detail

EnvelopedData

protected EnvelopedData()
Default constructor for dynamic object creation in ContentInfo. The block size is set to -1 to enforce definite primitive encoding.


EnvelopedData

public EnvelopedData(byte[] content,
                     AlgorithmID contentEA)
              throws java.security.NoSuchAlgorithmException
Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.
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 EnvelopedData(byte[] content, AlgorithmID contentEA, int keyLength) constructor.
Note that the supplied contentEA AlgorithmID internally is cloned.

Parameters:
content - the byte array 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

EnvelopedData

public EnvelopedData(ObjectID contentType,
                     byte[] content,
                     AlgorithmID contentEA)
              throws java.security.NoSuchAlgorithmException
Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.

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 EnvelopedData(ObjectID contentType, byte[] content, 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
content - the byte array 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

EnvelopedData

public EnvelopedData(byte[] content,
                     AlgorithmID contentEA,
                     int keyLength)
              throws java.security.NoSuchAlgorithmException
Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.
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 EnvelopedData(byte[] content, AlgorithmID contentEA) constructor may be used.
Note that the supplied contentEA AlgorithmID internally is cloned.

Parameters:
content - the byte array 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

EnvelopedData

public EnvelopedData(ObjectID contentType,
                     byte[] content,
                     AlgorithmID contentEA,
                     int keyLength)
              throws java.security.NoSuchAlgorithmException
Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.

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 EnvelopedData(ObjectID contentType, byte[] content, 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
content - the byte array 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

EnvelopedData

public EnvelopedData(ObjectID contentType,
                     byte[] content,
                     AlgorithmID contentEA,
                     int keyLength,
                     SecurityProvider securityProvider)
              throws java.security.NoSuchAlgorithmException
Creates a new CMS EnvelopedData object where the raw data is supplied as byte array.

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 EnvelopedData(ObjectID contentType, byte[] content, 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
content - the byte array 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

EnvelopedData

public EnvelopedData(RecipientInfo[] recipients,
                     EncryptedContentInfo encryptedCI)
Constructs a CMS EnvelopedData type with an already created EncryptedContentInfo. The given array of RecipientInfo specifies a collection of per-recipient information, and the given EncryptedContentInfo supplies the already encrypted content.

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

EnvelopedData

public EnvelopedData(ASN1Object obj)
              throws CMSParsingException
Creates a CMS EnvelopedData from an ASN1Object. The ASN.1 EnvelopedData may (or may not) be wrapped into a ContentInfo. The ASN1Object supplied to this constructor represents an already exisiting EnvelopedData object that may have been created by calling toASN1Object.

Use the EnvelopedData(byte[] content, AlgorithmID contentEA) constructor for supplying the content to be enveloped when creating an EnvelopedData object.

Parameters:
obj - the EnvelopedData as ASN1Object
Throws:
CMSParsingException - if the object can not be parsed

EnvelopedData

public EnvelopedData(ASN1Object obj,
                     SecurityProvider securityProvider)
              throws CMSParsingException
Creates a CMS EnvelopedData from an ASN1Object. The ASN.1 EnvelopedData may (or may not) be wrapped into a ContentInfo. The ASN1Object supplied to this constructor represents an already exisiting EnvelopedData object that may have been created by calling toASN1Object.

Use the EnvelopedData(byte[] content, AlgorithmID contentEA) constructor for supplying the content to be enveloped when creating an EnvelopedData object.

Parameters:
obj - the EnvelopedData as ASN1Object
securityProvider - the security provider to be used; if null the default system-wide SecurityProvider is used
Throws:
CMSParsingException - if the object can not be parsed

EnvelopedData

public EnvelopedData(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 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

EnvelopedData

public EnvelopedData(java.io.InputStream is,
                     SecurityProvider securityProvider)
              throws CMSParsingException,
                     java.io.IOException
Creates a new EnvelopedData 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 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

decode

public void decode(ASN1Object obj)
            throws CMSParsingException
Decodes the given EnvelopedData ASN1 object. The ASN.1 EnvelopedData may (or may not) be wrapped into a ContentInfo.

Specified by:
decode in interface Content
Parameters:
obj - the ASN1Object representing an already exisiting EnvelopedData object
Throws:
CMSParsingException - if an error occurs when parsing the given ASN1Object

decode

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

Specified by:
decode in interface ContentStream
Overrides:
decode in class EnvelopedDataStream
Parameters:
is - the InputStream holding 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

getContent

public byte[] getContent()
Returns the content as byte array.

The returned content depends on whether creating a new EnvelopedData or parsing an existing one:

Returns:
a byte array holding the content

setInputStream

public void setInputStream(java.io.InputStream is)
Sets the input stream that supplies the content data to be en/decrypted. This method reads the data from the stream.

Overrides:
setInputStream in class EnvelopedDataStream
Parameters:
is - the input stream holding the content data to en/decrypt

setContent

public void setContent(byte[] content)
Sets the content data to be en/decrypted.

Parameters:
content - the content data to en/decrypt

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 also will perform the encryption of the symmetric content-encryption key for each participated recipient.

Overrides:
toASN1Object in class EnvelopedDataStream
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

getEncoded

public byte[] getEncoded()
                  throws CMSException
Returns the BER encoding of this EnvelopedData in a byte array.

Returns:
a byte array holding the BER encoding of this EnvelopedData
Throws:
CMSException

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