Java tutorial
package org.bouncycastle.cms; import java.io.ByteArrayInputStream; import java.io.IOException; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.util.io.Streams; public abstract class RecipientInformation { protected RecipientId rid; protected AlgorithmIdentifier keyEncAlg; protected AlgorithmIdentifier messageAlgorithm; protected CMSSecureReadable secureReadable; private AuthAttributesProvider additionalData; private byte[] resultMac; private RecipientOperator operator; RecipientInformation(AlgorithmIdentifier keyEncAlg, AlgorithmIdentifier messageAlgorithm, CMSSecureReadable secureReadable, AuthAttributesProvider additionalData) { this.keyEncAlg = keyEncAlg; this.messageAlgorithm = messageAlgorithm; this.secureReadable = secureReadable; this.additionalData = additionalData; } public RecipientId getRID() { return rid; } private byte[] encodeObj(ASN1Encodable obj) throws IOException { if (obj != null) { return obj.toASN1Primitive().getEncoded(); } return null; } /** * Return the key encryption algorithm details for the key in this recipient. * * @return AlgorithmIdentifier representing the key encryption algorithm. */ public AlgorithmIdentifier getKeyEncryptionAlgorithm() { return keyEncAlg; } /** * return the object identifier for the key encryption algorithm. * * @return OID for key encryption algorithm. */ public String getKeyEncryptionAlgOID() { return keyEncAlg.getAlgorithm().getId(); } /** * return the ASN.1 encoded key encryption algorithm parameters, or null if * there aren't any. * * @return ASN.1 encoding of key encryption algorithm parameters. */ public byte[] getKeyEncryptionAlgParams() { try { return encodeObj(keyEncAlg.getParameters()); } catch (Exception e) { throw new RuntimeException("exception getting encryption parameters " + e); } } /** * Return the content digest calculated during the read of the content if one has been generated. This will * only happen if we are dealing with authenticated data and authenticated attributes are present. * * @return byte array containing the digest. */ public byte[] getContentDigest() { if (secureReadable instanceof CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable) { return ((CMSEnvelopedHelper.CMSDigestAuthenticatedSecureReadable) secureReadable).getDigest(); } return null; } /** * Return the MAC calculated for the recipient. Note: this call is only meaningful once all * the content has been read. * * @return byte array containing the mac. */ public byte[] getMac() { if (resultMac == null) { if (operator.isMacBased()) { if (additionalData != null) { try { Streams.drain(operator.getInputStream(new ByteArrayInputStream( additionalData.getAuthAttributes().getEncoded(ASN1Encoding.DER)))); } catch (IOException e) { throw new IllegalStateException("unable to drain input: " + e.getMessage()); } } resultMac = operator.getMac(); } } return resultMac; } /** * Return the decrypted/encapsulated content in the EnvelopedData after recovering the content * encryption/MAC key using the passed in Recipient. * * @param recipient recipient object to use to recover content encryption key * @return the content inside the EnvelopedData this RecipientInformation is associated with. * @throws CMSException if the content-encryption/MAC key cannot be recovered. */ public byte[] getContent(Recipient recipient) throws CMSException { try { return CMSUtils.streamToByteArray(getContentStream(recipient).getContentStream()); } catch (IOException e) { throw new CMSException("unable to parse internal stream: " + e.getMessage(), e); } } /** * Return a CMSTypedStream representing the content in the EnvelopedData after recovering the content * encryption/MAC key using the passed in Recipient. * * @param recipient recipient object to use to recover content encryption key * @return the content inside the EnvelopedData this RecipientInformation is associated with. * @throws CMSException if the content-encryption/MAC key cannot be recovered. */ public CMSTypedStream getContentStream(Recipient recipient) throws CMSException, IOException { operator = getRecipientOperator(recipient); if (additionalData != null) { if (additionalData.isAead()) { // TODO: this needs to be done after reading the encrypted data operator.getAADStream().write(additionalData.getAuthAttributes().getEncoded(ASN1Encoding.DER)); return new CMSTypedStream(operator.getInputStream(secureReadable.getInputStream())); } else { return new CMSTypedStream(secureReadable.getInputStream()); } } return new CMSTypedStream(operator.getInputStream(secureReadable.getInputStream())); } protected abstract RecipientOperator getRecipientOperator(Recipient recipient) throws CMSException, IOException; }