iaik.pkcs.pkcs7
Class EnvelopedData

java.lang.Object
  |
  +--iaik.pkcs.pkcs7.EnvelopedDataStream
        |
        +--iaik.pkcs.pkcs7.EnvelopedData
All Implemented Interfaces:
Content, ContentStream

public class EnvelopedData
extends EnvelopedDataStream
implements Content

This class represents the non-stream supporting implementation of the PKCS#7 content type EnvelopedData.

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

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

which corresponds to the OID string "1.2.840.1.113549.1.7.3".

The PKCS#7 Cryptographic Message Standard 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īs public 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 PKCS#7 specification, Version 1.5):

 EnvelopedData ::= SEQUENCE {
   version                Version,
   recipientInfos         RecipientInfos,
   encryptedContentInfo   EncryptedContentInfo }
 
RecipientInfos ::= SET OF RecipientInfo
EncryptedContentInfo ::= SEQUENCE { contentType ContentType, contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
EncryptedContent ::= OCTET STRING

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.

A recipient, when receiving the EnvelopedData message, decrypts the corresponding encrypted content-encryption key with his/her private key for subsequently decrypting the encrypted content using the content-encryption key just recovered. The recipient's private key is referenced by an issuer distinguished name and an issuer-specific serial number that uniquely identify the certificate for the corresponding public key.

For more information consult the RSA PKCS#7 specification.


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:
         //the data to be enveloped:
         byte[] data = ...;
         //use TripleDES in CBC mode for encrypting the content
         EnvelopedData enveloped_data = new EnvelopedData(data, AlgorithmID.des_EDE3_CBC);
         
  2. For each intended recipient, create a RecipientInfo object, and add all RecipientInfos to the EnvelopedData structure by calling the setRecipientInfos method, e.g. (assuming to add two recipients with corresponding certificates cert1 and cert2; currently only the PKCS#1 rsaEncryption is supported as key- encryption algorithm):
         RecipientInfo[] recipients = new RecipientInfo[2];
         recipients[0] = new RecipientInfo(cert1, AlgorithmID.rsaEncryption);
         recipients[1] = new RecipientInfo(cert2, AlgorithmID.rsaEncryption);
         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, when receiving an ASN1Object representing an EnvelopedData structure, uses the EnvelopedData(ASN1Object obj) constructor for parsing the internal structure. Before getting the recovered content by means of the getContent method, the cipher has to be initialized for decryption with the particular recipientīs private key by calling the setupCipher method:
  1. If the EnvelopedData is supplied as DER encoding, first decode it to an ASN1Object:
         ASN1Object obj = DerCoder.decode(encoding);
         
  2. Create an EnvelopedData structure from the supplied ASN.1 object, and parse the internal structure:
         EnvelopedData enveloped_data = new EnvelopedData(obj);
         
  3. 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());
         
  4. 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].getIssuerAndSerialNumber());
         }
         
  5. Use some recipientīs specific private key to decrypt the inherent encrypted secret key to be used for subsequently performing encrypted-content decryption:
         //setup cipher for recipient 1:
         int recipientInfoIndex = 0;
         enveloped_data.setupCipher(privateKey, recipientInfoIndex);
         
    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.

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

PKCS#7v1.6 Support:
===================

This class also may be used for creating/parsing EnvelopedData objects of version 1.6 as used by the SET protocol. Main differences between v1.5 and v1.6 are the content encryption (v1.6 encrypts the whole content encoding and therefore may be unsuitable for handling large amounts of data) and the encoding of SET OF structures which is replaced by SEQUENCE OF in PKCS#7v1.6. For creating a v1.6 EnvelopedData object you only have to set the version number (1 for indicating PKCS#7v1.6) when creating an EnvelopedData object:

 byte[] content = ...;
 AlgorithmID contentEA = ...;
 int keyLength = ...;
 // version number 1 indicates PKCS#7v1.6
 int version = 1;
 EnvelopedData envelopedData = new EnvelopedData(content, contentEA, keyLength, version);
 ...
 
On the receiving end you can use this class in the same way as described above for parsing and decrypting the content of a PKCS#7v1.5 or v1.6 EnvelopedData object. Since PKCS#7v1.6 is unsuitable for stream handling, the stream based class EnvelopedDataStream does not support PKCS#7v1.6.

Version:
File Revision 40
See Also:
RecipientInfo, EncryptedContentInfo

Fields inherited from class iaik.pkcs.pkcs7.EnvelopedDataStream
block_size, encrypted_content_info, recipient_infos, symmetric_key, version
 
Constructor Summary
protected EnvelopedData()
          Default constructor for dynamic object creation in ContentInfo.
  EnvelopedData(ASN1Object obj)
          Creates a PKCS#7 EnvelopedData from an ASN1Object.
  EnvelopedData(byte[] content, AlgorithmID contentEA)
          Creates a new PKCS#7 EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(byte[] content, AlgorithmID contentEA, int keyLength)
          Creates a new PKCS#7 EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(byte[] content, AlgorithmID contentEA, int keyLength, int version)
          Creates a new PKCS#7 EnvelopedData object where the raw data is supplied as byte array.
  EnvelopedData(InputStream is)
          Creates a new EnvelopedData where the DER encoded data is read from the given InputStream.
  EnvelopedData(RecipientInfo[] recipients, EncryptedContentInfo encryptedCI)
          Constructs a PKCS#7 EnvelopedData type with an already created EncryptedContentInfo.
  EnvelopedData(RecipientInfo[] recipients, EncryptedContentInfo encryptedCI, int version)
          Constructs a PKCS#7 EnvelopedData type with an already created EncryptedContentInfo.
 
Method Summary
 void decode(ASN1Object obj)
          Decodes the given EnvelopedData ASN1 object.
 void decode(InputStream is)
          Reads and decodes the EnvelopedData from a DerInputStream.
 byte[] getContent()
          Returns the content as byte array.
 byte[] getEncoded()
          Returns the DER encoding of this EnvelopedData in a byte array.
 Object getEncryptedContentInfo()
          Returns the encrypted content info included in this EnvelopedData object.
 InputStream getInputStream()
          Returns an InputStream for reading the content.
 void setupCipher(Key key)
          Uses the given symmetric key to setup the cipher for decrypting the content.
 void setupCipher(PrivateKey recipientPrivateKey, int recipientInfoIndex)
          Uses the specified private key to setup the Cipher for decrypting the content-encryption key and subsequently using it to decrypt the encrypted content of this EnvelopedData object for the requesting recipient, specified by its recipientInfoIndex.
protected  ASN1Object toASN1Object(int blockSize)
          Returns this EnvelopedData as ASN1Object.
 String toString(boolean detailed)
          Returns a string giving some - if requested - detailed information about this EnvelopedData object.
 
Methods inherited from class iaik.pkcs.pkcs7.EnvelopedDataStream
addRecipientInfo, getBlockSize, getContentType, getRecipientInfo, getRecipientInfos, getVersion, setBlockSize, setRecipientInfos, toASN1Object, 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.pkcs.pkcs7.ContentStream
getBlockSize, getContentType, setBlockSize, toASN1Object
 

Constructor Detail

EnvelopedData

protected EnvelopedData()
Default constructor for dynamic object creation in ContentInfo. The block size is set to -1 meaning that the data will be encoded a one simple octet string by deafult.

EnvelopedData

public EnvelopedData(byte[] content,
                     AlgorithmID contentEA)
              throws NoSuchAlgorithmException
Creates a new PKCS#7 EnvelopedData object where the raw data is supplied as byte array. The content type is set to PKCS#7 Data.

When using this constructor, automatically a symmetric key for content encryption is generated. For that reason this constructor shall not be used in situations where the desired content encryption algorithm requires a specific key/parameter handling. In such cases the EnvelopedData(RecipientInfo[], EncryptedContentInfo) constructor shall be used to be supplied with precomputed RcipientInfos and EncryptedContentInfo. Consult the EncryptedContentInfo(Stream) class documentation for more information about special key/parameter handling.

Parameters:
content - the byte array containing the data to envelope
contentEA - the content encryption algorithm for encrypting the content
Throws:
NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedData

public EnvelopedData(byte[] content,
                     AlgorithmID contentEA,
                     int keyLength)
              throws NoSuchAlgorithmException
Creates a new PKCS#7 EnvelopedData object where the raw data is supplied as byte array. The content type is set to PKCS#7 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.

This constructor shall not be used in situations where the desired content encryption algorithm requires a specific key/parameter handling. In such cases the EnvelopedData(RecipientInfo[], EncryptedContentInfo) constructor shall be used to be supplied with precomputed RcipientInfos and EncryptedContentInfo. Consult the EncryptedContentInfo(Stream) class documentation for more information about special key/parameter handling.

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:
NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedData

public EnvelopedData(byte[] content,
                     AlgorithmID contentEA,
                     int keyLength,
                     int version)
              throws NoSuchAlgorithmException
Creates a new PKCS#7 EnvelopedData object where the raw data is supplied as byte array. The content type is set to PKCS#7 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.

This constructor shall not be used in situations where the desired content encryption algorithm requires a specific key/parameter handling. In such cases the EnvelopedData(RecipientInfo[], EncryptedContentInfo) constructor shall be used to be supplied with precomputed RcipientInfos and EncryptedContentInfo. Consult the EncryptedContentInfo(Stream) class documentation for more information about special key/parameter handling.

This constructor may be used for creating an v1.6 EnvelopedData message, where the version number (1) has to be supplied for indicating to encrypt the content encoding.

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
version - either 0 (indicating a PKCS#7v1.5 EnvelopedData) or 1 (indicating a PKCS#71.6 EnvelopedData); default is 0.
Throws:
NoSuchAlgorithmException - if there is no implementation for the specified algorithm

EnvelopedData

public EnvelopedData(RecipientInfo[] recipients,
                     EncryptedContentInfo encryptedCI)
Constructs a PKCS#7 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(RecipientInfo[] recipients,
                     EncryptedContentInfo encryptedCI,
                     int version)
Constructs a PKCS#7 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.

This constructor may be used for creating an v1.6 EnvelopedData message, where the version number (1) has to be supplied for indicating that supplied EncryptedContentInfo has encrypted the content encoding.

Parameters:
recipients - information about the recipients
encryptedCI - the encrypted content info
version - either 0 (indicating a PKCS#7v1.5 EnvelopedData) or 1 (indicating a PKCS#71.6 EnvelopedData); default is 0.

EnvelopedData

public EnvelopedData(ASN1Object obj)
              throws PKCSParsingException
Creates a PKCS#7 EnvelopedData from an ASN1Object. 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 PKCS#7 EnvelopedData as ASN1Object
Throws:
PKCSParsingException - if the object can not be parsed

EnvelopedData

public EnvelopedData(InputStream is)
              throws PKCSParsingException,
                     IOException
Creates a new EnvelopedData where the DER encoded data is read from the given InputStream.
Parameters:
is - the InputStream holding a DER encoded PKCS#7 EnvelopedData object
Throws:
IOException - if an I/O error occurs during reading from the InputStream
PKCSParsingException - if an error occurs while parsing the object
Method Detail

decode

public void decode(ASN1Object obj)
            throws PKCSParsingException
Decodes the given EnvelopedData ASN1 object.
Specified by:
decode in interface Content
Parameters:
obj - the ASN1Object representing an already exisiting EnvelopedData object
Throws:
PKCSParsingException - if an error occurs when parsing the given ASN1Object

decode

public void decode(InputStream is)
            throws IOException,
                   PKCSParsingException
Reads and decodes the EnvelopedData from a DerInputStream. If the supplied InputStream actually is not an instance of DerInputStream, internally a DerInputStream is created before parsing the data.
Specified by:
decode in interface ContentStream
Overrides:
decode in class EnvelopedDataStream
Parameters:
is - the InputStream holding a DER encoded PKCS#7 EnvelopedData object
Throws:
IOException - if an I/O error occurs during reading from the InputStream
PKCSParsingException - if an error occurs while parsing the object

setupCipher

public void setupCipher(PrivateKey recipientPrivateKey,
                        int recipientInfoIndex)
                 throws PKCSException,
                        NoSuchAlgorithmException,
                        InvalidKeyException
Uses the specified private key to setup the Cipher for decrypting the content-encryption key and subsequently using it to decrypt the encrypted content of this EnvelopedData object for the requesting recipient, specified by its recipientInfoIndex.

This method first uses the given private key for decrypting the encrypted temporary symmetric key obtained from the corresponding RecipientInfo structure, and subsequently uses this key for decrypting the encrypted content.

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.

Attention! This method only can be used when the content encryption AlgorithmID contains IV parameters encoded as an OCTET_STRING. When the algorithmID contains parameters of other type (e.g. S/MIME RC2-CBC parameters) they have to be decoded separatly, and the setupCipher(Key key, AlgorithmParameterSpec) method of the EncryptedContentInfo class has to be used to setup the cipher for content decryption, e.g.:

 //get the ECI from the enveloped data:
 EncryptedContentInfo eci =
      (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
 // get the recipient infos
 RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
 // use the specific recipientīs private key for decrypting the required
 // symmetric content encryption key, e.g.:
 SecretKey secretKey =
   recipient_infos[0].decryptKey(recipientPrivateKey)
 //get the content encryption algorithm:
 AlgorithmID contentEA = eci.getContentEncryptionAlgorithm();
 // get the parameters as SEQUENCE
 SEQUENCE seq = (SEQUENCE)contentEA.getParameter();
 // the iv is the second component
 OCTET_STRING oct = (OCTET_STRING)seq.getComponentAt(1);
 // create an IvParameterSpec:
 IvParameterSpec ivSpec = new IvParameterSpec(oct.getValue());
 //now setup the cipher with previously decrypted recipient key amd params
 eci.setupCipher(secretKey, ivSpec);
 //get the recovered raw data:
 byte[] data = EncryptedContentInfo.getContent();
 

Overrides:
setupCipher in class EnvelopedDataStream
Parameters:
recipientPrivateKey - the private key of one recipient specified in a RecipientInfo object
recipientInfoIndex - specifies which RecipientInfo the private key belongs to
Throws:
PKCSException - if there occurs an error while decrypting the data
NoSuchAlgorithmException - if there is no implementation of the content-encryption algorithm
InvalidKeyException - if the specified private key is not valid

setupCipher

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

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.

Attention! This method only can be used when the content encryption AlgorithmID contains IV parameters encoded as an OCTET_STRING. When the algorithmID contains parameters of other type (e.g. S/MIME RC2-CBC parameters) they have to be decoded separatly, and the setupCipher(Key key, AlgorithmParameterSpec) method of the EncryptedContentInfo class has to be used to setup the cipher for content decryption, e.g.:

 //get the ECI from the enveloped data:
 EncryptedContentInfo eci =
      (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
 //get the content encryption algorithm:
 AlgorithmID contentEA = eci.getContentEncryptionAlgorithm();
 // get the parameters as SEQUENCE
 SEQUENCE seq = (SEQUENCE)contentEA.getParameter();
 // the iv is the second component
 OCTET_STRING oct = (OCTET_STRING)seq.getComponentAt(1);
 // create an IvParameterSpec:
 IvParameterSpec ivSpec = new IvParameterSpec(oct.getValue());
 //now setup the cipher with previously decrypted recipient key amd params
 eci.setupCipher(secretKey, ivSpec);
 //get the recovered raw data:
 byte[] data = EncryptedContentInfo.getContent();
 
Overrides:
setupCipher in class EnvelopedDataStream
Parameters:
key - the temporary symmetric key that has been used to encrypt the content, and now is used for decrypting it again
Throws:
PKCSException - if there occurs an error while decrypting the data
NoSuchAlgorithmException - if there is no implementation for the content-encryption algorithm
InvalidKeyException - if the specified private key is not valid

getInputStream

public InputStream getInputStream()
Returns an InputStream for reading the content.

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

This method only overrides the corresponding getInputStream method of the parent EnvelopedDataStream class for returning the content of this EnvelopedData object. There should be no real necessity for using this method since the content bytes immediately can be obtained by the getContent method. However, in contrast to the equivalent getInputStream method of the parent EnvelopedDataStream class, this method may be called arbitrarly often; it only returns a ByteArrayInputStream that is initialized with the content bytes.
Overrides:
getInputStream in class EnvelopedDataStream
Returns:
an InputStream holding the content

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

getEncryptedContentInfo

public Object getEncryptedContentInfo()
Returns the encrypted content info included in this EnvelopedData object. When calling this method for obtaining the inherent EncryptedContentInfo an explicit cast to EncryptedContentInfo has to be made:
 EncryptedContentInfo eci = (EncryptedContentInfo)enveloped_data.getEncryptedContentInfo();
 
Overrides:
getEncryptedContentInfo in class EnvelopedDataStream
Returns:
the encrypted content info

toASN1Object

protected ASN1Object toASN1Object(int blockSize)
                           throws PKCSException
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 PKCS#7 EnvelopedData as ASN1Object
Throws:
PKCSException - if the ASN1Object could not be created

getEncoded

public byte[] getEncoded()
                  throws PKCSException
Returns the DER encoding of this EnvelopedData in a byte array.
Returns:
a byte array holding the DER encoding of this EnvelopedData

toString

public String toString(boolean detailed)
Returns a string giving some - if requested - detailed information about this EnvelopedData object.
Specified by:
toString in interface ContentStream
Overrides:
toString in class EnvelopedDataStream
Parameters:
detailed - - whether or not to give detailed information
Returns:
the string representation

This Javadoc may contain text parts from Internet Standard specifications (RFC 2459, 3280, 3039, 2560, 1521, 821, 822, 2253, 1319, 1321, ,2630, 2631, 2268, 3058, 2984, 2104, 2144, 2040, 2311, 2279, see copyright note) and RSA Data Security Public-Key Cryptography Standards (PKCS#1,3,5,7,8,9,10,12, see copyright note).

IAIK-JCE 3.1 with IAIK-JCE CC Core 3.1, (c) 1997-2004 IAIK