iaik.smime
Class SMimeAuthEncrypted

java.lang.Object
  extended by iaik.cms.AuthEnvelopedDataStream
      extended by iaik.smime.SMimeAuthEncrypted
All Implemented Interfaces:
EncodeListener, ContentStream, EOFListener, java.util.EventListener

public class SMimeAuthEncrypted
extends AuthEnvelopedDataStream

This class represents the "CMS AuthEnvelopedData object carrying" part of a S/MIME message.

This class extends the AuthEnvelopedDataStream class of the iaik.cms package and may be used for creating and parsing CMS (RFC 5083) AuthEnvelopedData objects that are (to be) wrapped into a ContentInfo structure.

The steps for creating a SMimeAuthEncrypted object and writing it to a stream may be summarized as follows (note that in this example we use AES-GCM as content encryption algorithm and RSA key transport for encrypting the content-encryption key; however, an application may wish to use any other authenticated content encryption algorithm supported by a cryptographic provider installed, and any other key management technique allowed (e.g. ESDH or ECDH key agreement):

  1. Create a new SMimeAuthEncrypted by specifying the data to be authentcated enveloped, the content encryption algorithm, and - if required - the key length, e.g.:
          InputStream dataStream = ...;
          AlgorithmID contentEA = (AlgorithmID)AlgorithmID.aes256_GCM.clone();
          int keyLength = 256;
          SMimeAuthEncrypted sme = new SMimeAuthEncryoted(dataStream, contentEA, keyLength);
          
    This step also will create the symmetric content encryption key.
  2. Add any intended recipient by calling the addRecipient method thereby specifying the particular recipient certificate and the key encryption algorithm to be used for encrypting the symmetric content encryption key with the recipient public key obtained from the supplied certificate, e.g.:
          // the certificate of the recipient
          X509Certificate recipientCert = ...;
          // the sender wants to be able to decrypt the message, too
          X509Certificate senderCert = ...;
          sme.addRecipient(recipientCert, AlgorithmID.rsaEncryption);
          sme.addRecipient(senderCert, AlgorithmID.rsaEncryption);
          
  3. Finally call the writeTo method for wrapping the EnvelopedData object into a ContentInfo and writing it BER encoded to an output stream thereby actually performing the content encryption by piping the data through a cipher stream:
          OutputStrem os = ...;
          sme.writeTo(os);
          
On the receiving side, the recipient first creates a new SMimeAuthEncrypted object from an input stream supplying the BER encoded message, subsequently decrypts the encrypted symmetric content encryption key with her/his (private) key, and finally gets and reads the data holding input stream which is decrypted during the read operation, e.g.:
 InputStream encryptedStream = ...;
 SMimeAuthEncrypted sme = new SMimeAuthEncrypted(encryptedStream);
 //recipient has index 0
 sme.decryptSymmetricKey(privateKey, 0);
 //get and read the data
 InputStream data_stream = sme.getInputStream();
 byte[] buf = new byte[2048];
 int r;
 while ((r = data_is.read(buf)) > 0) {
   // do something useful
 }
 
The decryptSymmetricKey method used in the sample above requires that the recipient knows the index of the RecipientInfo that belongs to her/his key. Alternatively you may use the certificate of the recipient or her/his KeyIdentifier to find the right RecipientInfo and decrypt the symmetric content encryption key.

See Also:
EnvelopedDataStream, RecipientInfo, EncryptedContent

Field Summary
 
Fields inherited from class iaik.cms.AuthEnvelopedDataStream
encryptedContentInfo_, EXPLICIT, IMPLICIT
 
Constructor Summary
SMimeAuthEncrypted(java.io.InputStream is)
          Creates a new SAuthMimeEncrypted object where the BER encoded message is read from the given input stream.
SMimeAuthEncrypted(java.io.InputStream is, AlgorithmID contentEA, int keyLength)
          Creates a new SAuthMimeEncrypted object where the data to be authenticated enveloped is read from the given InputStream.
SMimeAuthEncrypted(java.io.InputStream is, byte[] encodedAuthAttributes, long inputLength)
           
 
Method Summary
 java.security.KeyPair addRecipient(X509Certificate[] originatorCertificates, java.security.PrivateKey originatorPrivateKey, X509Certificate recipientCertificate, AlgorithmID keyEA, AlgorithmID keyWrapAlg, int kekLength)
          Adds one recipient to this S/MIME SMimeAuthEncrypted object.
 void addRecipient(X509Certificate recipientCertificate, AlgorithmID keyEA)
          Adds one recipient to this S/MIME SMimeAuthEncrypted object.
 java.security.KeyPair addRecipient(X509Certificate recipientCertificate, AlgorithmID keyEA, AlgorithmID keyWrapAlg, int kekLength)
          Adds one recipient to this S/MIME SMimeAuthEncrypted object.
 javax.crypto.SecretKey decryptSymmetricKey(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 SAuthMimeEncrypted object for the requesting recipient, specified by its recipientInfoIndex.
 javax.crypto.SecretKey decryptSymmetricKey(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 SAuthMimeEncrypted object for the requesting recipient, specified by the given recipient identifier.
 javax.crypto.SecretKey decryptSymmetricKey(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 SAuthMimeEncrypted object for the requesting recipient, specified by the given recipient certificate.
 AlgorithmID getEncryptionAlgorithm()
          Returns the content-encryption algorithm (including any associated parameters) of this SAuthMimeEncrypted object.
 int getRecipientInfoIndex(X509Certificate recipientCertificate)
          Returns the recipient info index matching to the supplied recipient certificate.
 void setInputStream(java.io.InputStream is)
          Sets the input stream that supplies the content data to be authenticated encrypted.
 ASN1Object toASN1Object(int blockSize)
          Returns the CMS authenticated EnvelopedData object as an ASN1Object wrapped into a ContentInfo.
 void writeTo(java.io.OutputStream os)
          Writes this SAuthMimeEncrypted object to the supplied output stream.
 void writeTo(java.io.OutputStream os, int blockSize)
          Writes this SAuthMimeEncrypted object to the supplied output stream.
 
Methods inherited from class iaik.cms.AuthEnvelopedDataStream
addRecipientInfo, decode, decode, encodeCalled, getAuthenticatedAttribute, getAuthenticatedAttributes, getBlockSize, getContentType, getEncryptedContentInfo, getInputLength, getInputStream, getMac, getMode, getOriginatorInfo, getRecipientInfo, getRecipientInfo, getRecipientInfos, getRecipientInfos, getSecurityProvider, getUnauthenticatedAttribute, getUnauthenticatedAttributes, getVersion, notifyEOF, setAuthenticatedAttributes, setBlockSize, setInputLength, setMac, setMode, setOriginatorInfo, setRecipientInfos, setSecurityProvider, setUnauthenticatedAttributes, setupCipher, setupCipher, setupCipher, setupCipher, toASN1Object, toString, toString
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Constructor Detail

SMimeAuthEncrypted

public SMimeAuthEncrypted(java.io.InputStream is,
                          AlgorithmID contentEA,
                          int keyLength)
                   throws java.security.NoSuchAlgorithmException
Creates a new SAuthMimeEncrypted object where the data to be authenticated enveloped is read from the given InputStream.

This constructor automatically will create the symmetric content encryption key for the specified algorithm.

Parameters:
is - an InputStream holding the data to be enveloped
contentEA - the content encryption algorithm to be used
keyLength - the length of the key; if -1 the default key length for the specified algorithm will be used
Throws:
java.security.NoSuchAlgorithmException - if there is no implementation for the specified algorithm

SMimeAuthEncrypted

public SMimeAuthEncrypted(java.io.InputStream is)
                   throws java.io.IOException
Creates a new SAuthMimeEncrypted object where the BER encoded message is read from the given input stream.

Do not use this constructor for supplying the content data to be enveloped. This constructor may be used by the recipient for parsing an already existing authenticated enveloped message, supplied as BER encoding from an input stream, that may have been created by means of the writeTo method.

Use the SAuthMimeEncrypted(InputStream is, AlgorithmID contentEA, int keyLength) constructor for supplying the content data to be enveloped when creating a SAuthMimeEncrypted object.

Parameters:
is - the input stream where the BER encoded message shall be read from
Throws:
java.io.IOException - if an I/O error occurs

SMimeAuthEncrypted

public SMimeAuthEncrypted(java.io.InputStream is,
                          byte[] encodedAuthAttributes,
                          long inputLength)
                   throws CMSParsingException,
                          java.io.IOException
Throws:
CMSParsingException
java.io.IOException
Method Detail

setInputStream

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

Overrides:
setInputStream in class AuthEnvelopedDataStream
Parameters:
is - the input stream holding the content data to authenticated and encrypt

getRecipientInfoIndex

public int getRecipientInfoIndex(X509Certificate recipientCertificate)
Returns the recipient info index 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.

Parameters:
recipientCertificate - the certificate of the recipient
Returns:
the recipient info index matching to the supplied recipient certificate, or -1 if no recipient info belonging to the given certificate can be found

decryptSymmetricKey

public javax.crypto.SecretKey decryptSymmetricKey(java.security.Key recipientKey,
                                                  int recipientInfoIndex)
                                           throws SMimeException,
                                                  java.security.InvalidKeyException
Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this SAuthMimeEncrypted 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.

Note that 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 decrypting the encrypted content-encryption key!

Note that you have to know the right index into the recipientInfos field when using this method for decrypting the encrypted content-encryption key and setting up the cipher for decryption. You may search for the index by using the getRecipientInfoIndex method.
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 decryptSymmetricKey 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 decryptSymmetricKey method allowing to immediately identify the particular recipient in mind by its 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:
SMIMEException - if there occurs an error while decrypting the content-encryption key or setting up the cipher for decrypting the content
java.security.InvalidKeyException - if the specified recipient key is not valid
SMimeException

decryptSymmetricKey

public javax.crypto.SecretKey decryptSymmetricKey(java.security.Key recipientKey,
                                                  KeyIdentifier recipientIdentifier)
                                           throws SMimeException,
                                                  java.security.InvalidKeyException
Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this SAuthMimeEncrypted 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.

Note that 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 decrypting the encrypted content-encryption key!

This decryptSymmetricKey method can be used to decrypt the encrypted content-encryption key and 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:
SMIMEException - 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.InvalidKeyException - if the specified recipient key is not valid
SMimeException

decryptSymmetricKey

public javax.crypto.SecretKey decryptSymmetricKey(java.security.Key recipientKey,
                                                  X509Certificate recipientCertificate)
                                           throws SMimeException,
                                                  java.security.InvalidKeyException
Uses the specified key for decrypting the content-encryption key to setup the cipher for decrypting the encrypted content of this SAuthMimeEncrypted 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.

Note that 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 decrypting the encrypted content-encryption key!

Note that this method only can be used for decrypting the encrypted content encyrption key and setting up the cipher for content decryption 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. However, this should be no problem since S/MIME generally only uses certificate based RecipientInfos.

Parameters:
recipientKey - the 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:
SMimeException - 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.InvalidKeyException - if the specified recipient key is not valid

addRecipient

public void addRecipient(X509Certificate recipientCertificate,
                         AlgorithmID keyEA)
Adds one recipient to this S/MIME SMimeAuthEncrypted object.

When using this method for adding a Recipient, the corresponding RecipientInfo will be the KeyTransRecipientInfo choice and the recipient certificate will be identified by IssuerAndSerialNumber. So use this method with rsaEncyrption as key transport algorithm to be compatible to S/MIMEv2.

Parameters:
recipientCertificate - the certificate of the recipient
keyEA - the algorithm to use for encrypting the symmetric key (e.g. AlgorithmID.rsaEncryption)

addRecipient

public java.security.KeyPair addRecipient(X509Certificate recipientCertificate,
                                          AlgorithmID keyEA,
                                          AlgorithmID keyWrapAlg,
                                          int kekLength)
                                   throws SMimeException
Adds one recipient to this S/MIME SMimeAuthEncrypted object.

When using this method for adding a Recipient, the corresponding RecipientInfo will be the KeyAgreeRecipientInfo choice and the recipient certificate will be identified by IssuerAndSerialNumber. The KeyAgreeRecipientInfo originator field will be the OriginatorPublicKey choice for using an ephemeral originator key.

This method may be called repeatedly for adding information for each recipient using key agreement as key management protocol. When calling this method the first time (for adding the first "KeyAgree" recipient) and the originator key yet has not been set, this method itself creates a OriginatorPublicKey with domain parameters matching to those of the supplied recipient key. Any further call of this method might add a recipient to an already existing KeyAgreeRecipientInfo (if the recipient to be added has a public key with domain parameters matching to those of an already existing KeyAgreeRecipientInfo originator key) or create a new KeyAgreeRecipientInfo for this recipient.

Parameters:
recipientCertificate - the certificate of the recipient
keyEA - the (key agreement) algorithm to use for creating a shared secret key encryption key for encrypting the symmetric key (e.g. AlgorithmID.esdhKeyAgreement)
keyWrapAlg - the key wrap algorithm to be used for encrypting (wrapping) the content-encryption key with the shared key-encryption created according to the requested key agreement protocol
kekLength - the length of the shared key encryption key to be generated
Returns:
the originator key pair matching to the domain parameters of the recipient key
Throws:
SMimeException - if it was not possible to create a RecipientInfo or encrypt the symmetric key for this recipient

addRecipient

public java.security.KeyPair addRecipient(X509Certificate[] originatorCertificates,
                                          java.security.PrivateKey originatorPrivateKey,
                                          X509Certificate recipientCertificate,
                                          AlgorithmID keyEA,
                                          AlgorithmID keyWrapAlg,
                                          int kekLength)
                                   throws SMimeException
Adds one recipient to this S/MIME SMimeAuthEncrypted object.

When using this method for adding a Recipient, the corresponding RecipientInfo will be the KeyAgreeRecipientInfo choice and the recipient certificate will be identified by IssuerAndSerialNumber. The KeyAgreeRecipientInfo originator field will be build the OriginatorPublicKey choice for using an ephemeral originator key.

This method may be called repeatedly for adding information for each recipient using key agreement as key management protocol. When calling this method the first time (for adding the first "KeyAgree" recipient) and the originator key yet has not been set, this method itself creates a OriginatorPublicKey with domain parameters matching to those of the supplied recipient key. Any further call of this method might add a recipient to an already existing KeyAgreeRecipientInfo (if the recipient to be added has a public key with domain parameters matching to those of an already existing KeyAgreeRecipientInfo originator key) or create a new KeyAgreeRecipientInfo for this recipient.

Parameters:
recipientCertificate - the certificate of the recipient
keyEA - the (key agreement) algorithm to use for creating a shared secret key encryption key for encrypting the symmetric key (e.g. AlgorithmID.esdhKeyAgreement)
keyWrapAlg - the key wrap algorithm to be used for encrypting (wrapping) the content-encryption key with the shared key-encryption created according to the requested key agreement protocol
kekLength - the length of the shared key encryption key to be generated
Returns:
the originator key pair matching to the domain parameters of the recipient key
Throws:
SMimeException - if it was not possible to create a RecipientInfo or encrypt the symmetric key for this recipient

getEncryptionAlgorithm

public AlgorithmID getEncryptionAlgorithm()
Returns the content-encryption algorithm (including any associated parameters) of this SAuthMimeEncrypted object.

Returns:
the content-encryption AlgorithmID

toASN1Object

public ASN1Object toASN1Object(int blockSize)
                        throws CMSException
Returns the CMS authenticated EnvelopedData object as an ASN1Object wrapped into a ContentInfo. Automatically enforces block encoding with a block size of 2048 if a negative blockSize value is supplied.

Overrides:
toASN1Object in class AuthEnvelopedDataStream
Parameters:
blockSize - the block size for using block encoding
Returns:
the S/MIME enveloped message as an ASN1Object
Throws:
CMSException - if an error occurs while building the ASN.1 object

writeTo

public void writeTo(java.io.OutputStream os)
             throws java.io.IOException
Writes this SAuthMimeEncrypted object to the supplied output stream. Automatically enforces block encoding with a block size of 2048.

Overrides:
writeTo in class AuthEnvelopedDataStream
Parameters:
os - the output stream to which this SAuthMimeEncrypted shall be written
Throws:
java.io.IOException - if an I/O error occurs while writing to the stream

writeTo

public void writeTo(java.io.OutputStream os,
                    int blockSize)
             throws java.io.IOException
Writes this SAuthMimeEncrypted object to the supplied output stream. The blockSize parameter indicates the block size to be used for performing block encoding.

Overrides:
writeTo in class AuthEnvelopedDataStream
Parameters:
os - the output stream to which this SAuthMimeEncrypted shall be written
blockSize - the block size for using block encoding
Throws:
java.io.IOException - if an I/O error occurs while writing to the stream

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