public class EnvelopedData extends EnvelopedDataStream implements Content
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.:
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);
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);
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.
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:
ASN1Object obj = DerCoder.decode(encoding);
EnvelopedData enveloped_data = new EnvelopedData(obj);
EncryptedContentInfo eci = (EncryptedContentInfo) enveloped_data .getEncryptedContentInfo(); System.out.println("Content type: " + eci.getContentType().getName()); System.out.println("Content encryption algorithm: " + eci.getContentEncryptionAlgorithm().getName());
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()); }
// 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.
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.RecipientInfo
,
EncryptedContentInfo
block_size, recipient_infos, symmetric_key, version
Modifier | Constructor and Description |
---|---|
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(java.io.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.
|
Modifier and Type | Method and Description |
---|---|
void |
decode(ASN1Object obj)
Decodes the given EnvelopedData ASN1 object.
|
void |
decode(java.io.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.
|
java.lang.Object |
getEncryptedContentInfo()
Returns the encrypted content info included in this
EnvelopedData object. |
java.io.InputStream |
getInputStream()
Returns an InputStream for reading the content.
|
void |
setupCipher(java.security.Key key)
Uses the given symmetric key to setup the cipher for decrypting the
content.
|
void |
setupCipher(java.security.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.
|
java.lang.String |
toString(boolean detailed)
Returns a string giving some - if requested - detailed information about
this
EnvelopedData object. |
addRecipientInfo, getBlockSize, getContentType, getRecipientInfo, getRecipientInfos, getVersion, setBlockSize, setRecipientInfos, toASN1Object, toString, writeTo, writeTo
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
getBlockSize, getContentType, setBlockSize, toASN1Object
protected EnvelopedData()
public EnvelopedData(byte[] content, AlgorithmID contentEA) throws java.security.NoSuchAlgorithmException
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 RecipientInfos and
EncryptedContentInfo. Consult the
EncryptedContentInfo(Stream)
class documentation for more information
about special key/parameter handling.
content
- the byte array containing the data to envelopecontentEA
- the content encryption algorithm for encrypting the contentjava.security.NoSuchAlgorithmException
- if there is no implementation for the specified algorithmpublic EnvelopedData(byte[] content, AlgorithmID contentEA, int keyLength) throws java.security.NoSuchAlgorithmException
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 RecipientInfos
and EncryptedContentInfo. Consult the
EncryptedContentInfo(Stream)
class documentation for more information
about special key/parameter handling.
content
- the byte array containing the data to envelopecontentEA
- the content encryption algorithm for encrypting the contentkeyLength
- the key length that may be set when using a content encryption
algorithm that supports variable key lengthsjava.security.NoSuchAlgorithmException
- if there is no implementation for the specified algorithmpublic EnvelopedData(byte[] content, AlgorithmID contentEA, int keyLength, int version) throws java.security.NoSuchAlgorithmException
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 RecipientInfos
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.
content
- the byte array containing the data to envelopecontentEA
- the content encryption algorithm for encrypting the contentkeyLength
- the key length that may be set when using a content encryption
algorithm that supports variable key lengthsversion
- either 0 (indicating a PKCS#7v1.5 EnvelopedData) or 1 (indicating
a PKCS#71.6 EnvelopedData); default is 0.java.security.NoSuchAlgorithmException
- if there is no implementation for the specified algorithmpublic EnvelopedData(RecipientInfo[] recipients, EncryptedContentInfo encryptedCI)
RecipientInfo
specifies a collection of
per-recipient information, and the given EncryptedContentInfo
supplies the already encrypted content.recipients
- information about the recipientsencryptedCI
- the encrypted content infopublic EnvelopedData(RecipientInfo[] recipients, EncryptedContentInfo encryptedCI, int version)
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.
recipients
- information about the recipientsencryptedCI
- the encrypted content infoversion
- either 0 (indicating a PKCS#7v1.5 EnvelopedData) or 1 (indicating
a PKCS#71.6 EnvelopedData); default is 0.public EnvelopedData(ASN1Object obj) throws PKCSParsingException
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.
obj
- the PKCS#7 EnvelopedData
as ASN1ObjectPKCSParsingException
- if the object can not be parsedpublic EnvelopedData(java.io.InputStream is) throws PKCSParsingException, java.io.IOException
is
- the InputStream holding a DER encoded PKCS#7 EnvelopedData objectjava.io.IOException
- if an I/O error occurs during reading from the InputStreamPKCSParsingException
- if an error occurs while parsing the objectpublic void decode(ASN1Object obj) throws PKCSParsingException
decode
in interface Content
obj
- the ASN1Object representing an already existing EnvelopedData
objectPKCSParsingException
- if an error occurs when parsing the given ASN1Objectpublic void decode(java.io.InputStream is) throws java.io.IOException, PKCSParsingException
DerInputStream
, internally a DerInputStream is created before parsing the
data.decode
in interface ContentStream
decode
in class EnvelopedDataStream
is
- the InputStream holding a DER encoded PKCS#7 EnvelopedData objectjava.io.IOException
- if an I/O error occurs during reading from the InputStreamPKCSParsingException
- if an error occurs while parsing the objectpublic void setupCipher(java.security.PrivateKey recipientPrivateKey, int recipientInfoIndex) throws PKCSException, java.security.NoSuchAlgorithmException, java.security.InvalidKeyException
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 separately, 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 and params eci.setupCipher(secretKey, ivSpec); //get the recovered raw data: byte[] data = EncryptedContentInfo.getContent();
setupCipher
in class EnvelopedDataStream
recipientPrivateKey
- the private key of one recipient specified in a RecipientInfo
objectrecipientInfoIndex
- specifies which RecipientInfo the private key belongs toPKCSException
- if there occurs an error while decrypting the datajava.security.NoSuchAlgorithmException
- if there is no implementation of the content-encryption
algorithmjava.security.InvalidKeyException
- if the specified private key is not validpublic void setupCipher(java.security.Key key) throws PKCSException, java.security.NoSuchAlgorithmException, java.security.InvalidKeyException
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 separately, 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 and params eci.setupCipher(secretKey, ivSpec); // get the recovered raw data: byte[] data = EncryptedContentInfo.getContent();
setupCipher
in class EnvelopedDataStream
key
- the temporary symmetric key that has been used to encrypt the
content, and now is used for decrypting it againPKCSException
- if there occurs an error while decrypting the datajava.security.NoSuchAlgorithmException
- if there is no implementation for the content-encryption
algorithmjava.security.InvalidKeyException
- if the specified private key is not validpublic java.io.InputStream getInputStream()
The returned content depends on whether creating a new EnvelopedData or parsing an existing one:
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
arbitrarily often; it only returns a ByteArrayInputStream that is
initialized with the content bytes.getInputStream
in class EnvelopedDataStream
public byte[] getContent()
The returned content depends on whether creating a new EnvelopedData or parsing an existing one:
public java.lang.Object getEncryptedContentInfo()
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();
getEncryptedContentInfo
in class EnvelopedDataStream
protected ASN1Object toASN1Object(int blockSize) throws PKCSException
toASN1Object
in class EnvelopedDataStream
blockSize
- the block size defining the encoding scheme - and specifying the
length of each primitive encoded octet string component, if
positiveEnvelopedData
as ASN1ObjectPKCSException
- if the ASN1Object could not be createdpublic byte[] getEncoded() throws PKCSException
PKCSException
public java.lang.String toString(boolean detailed)
EnvelopedData
object.toString
in interface ContentStream
toString
in class EnvelopedDataStream
detailed
- - whether or not to give detailed information