001: package org.bouncycastle.cms;
002:
003: import org.bouncycastle.asn1.ASN1OctetString;
004: import org.bouncycastle.asn1.ASN1OutputStream;
005: import org.bouncycastle.asn1.DERObjectIdentifier;
006: import org.bouncycastle.asn1.cms.IssuerAndSerialNumber;
007: import org.bouncycastle.asn1.cms.KeyTransRecipientInfo;
008: import org.bouncycastle.asn1.cms.RecipientIdentifier;
009: import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
010: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
011:
012: import javax.crypto.BadPaddingException;
013: import javax.crypto.Cipher;
014: import javax.crypto.IllegalBlockSizeException;
015: import javax.crypto.NoSuchPaddingException;
016: import javax.crypto.spec.SecretKeySpec;
017: import java.io.ByteArrayOutputStream;
018: import java.io.IOException;
019: import java.io.InputStream;
020: import java.security.GeneralSecurityException;
021: import java.security.InvalidKeyException;
022: import java.security.Key;
023: import java.security.NoSuchAlgorithmException;
024: import java.security.NoSuchProviderException;
025:
026: /**
027: * the KeyTransRecipientInformation class for a recipient who has been sent a secret
028: * key encrypted using their public key that needs to be used to
029: * extract the message.
030: */
031: public class KeyTransRecipientInformation extends RecipientInformation {
032: private KeyTransRecipientInfo _info;
033: private AlgorithmIdentifier _encAlg;
034:
035: public KeyTransRecipientInformation(KeyTransRecipientInfo info,
036: AlgorithmIdentifier encAlg, InputStream data) {
037: super (encAlg, AlgorithmIdentifier.getInstance(info
038: .getKeyEncryptionAlgorithm()), data);
039:
040: this ._info = info;
041: this ._encAlg = encAlg;
042: this ._rid = new RecipientId();
043:
044: RecipientIdentifier r = info.getRecipientIdentifier();
045:
046: try {
047: if (r.isTagged()) {
048: ASN1OctetString octs = ASN1OctetString.getInstance(r
049: .getId());
050:
051: _rid.setSubjectKeyIdentifier(octs.getOctets());
052: } else {
053: IssuerAndSerialNumber iAnds = IssuerAndSerialNumber
054: .getInstance(r.getId());
055:
056: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
057: ASN1OutputStream aOut = new ASN1OutputStream(bOut);
058:
059: aOut.writeObject(iAnds.getName());
060:
061: _rid.setIssuer(bOut.toByteArray());
062: _rid
063: .setSerialNumber(iAnds.getSerialNumber()
064: .getValue());
065: }
066: } catch (IOException e) {
067: throw new IllegalArgumentException(
068: "invalid rid in KeyTransRecipientInformation");
069: }
070: }
071:
072: private String getExchangeEncryptionAlgorithmName(
073: DERObjectIdentifier oid) {
074: if (PKCSObjectIdentifiers.rsaEncryption.equals(oid)) {
075: return "RSA/ECB/PKCS1Padding";
076: }
077:
078: return oid.getId();
079: }
080:
081: /**
082: * decrypt the content and return it as a byte array.
083: */
084: public CMSTypedStream getContentStream(Key key, String prov)
085: throws CMSException, NoSuchProviderException {
086: byte[] encryptedKey = _info.getEncryptedKey().getOctets();
087: String keyExchangeAlgorithm = getExchangeEncryptionAlgorithmName(_keyEncAlg
088: .getObjectId());
089: String alg = CMSEnvelopedHelper.INSTANCE
090: .getSymmetricCipherName(_encAlg.getObjectId().getId());
091:
092: try {
093: Cipher keyCipher = CMSEnvelopedHelper.INSTANCE
094: .getSymmetricCipher(keyExchangeAlgorithm, prov);
095: Key sKey;
096:
097: try {
098: keyCipher.init(Cipher.UNWRAP_MODE, key);
099:
100: sKey = keyCipher.unwrap(encryptedKey, alg,
101: Cipher.SECRET_KEY);
102: } catch (GeneralSecurityException e) // some providers do not support UNWRAP
103: {
104: keyCipher.init(Cipher.DECRYPT_MODE, key);
105:
106: sKey = new SecretKeySpec(keyCipher
107: .doFinal(encryptedKey), alg);
108: } catch (IllegalStateException e) // some providers do not support UNWRAP
109: {
110: keyCipher.init(Cipher.DECRYPT_MODE, key);
111:
112: sKey = new SecretKeySpec(keyCipher
113: .doFinal(encryptedKey), alg);
114: } catch (UnsupportedOperationException e) // some providers do not support UNWRAP
115: {
116: keyCipher.init(Cipher.DECRYPT_MODE, key);
117:
118: sKey = new SecretKeySpec(keyCipher
119: .doFinal(encryptedKey), alg);
120: }
121:
122: return getContentFromSessionKey(sKey, prov);
123: } catch (NoSuchAlgorithmException e) {
124: throw new CMSException("can't find algorithm.", e);
125: } catch (InvalidKeyException e) {
126: throw new CMSException("key invalid in message.", e);
127: } catch (NoSuchPaddingException e) {
128: throw new CMSException("required padding not supported.", e);
129: } catch (IllegalBlockSizeException e) {
130: throw new CMSException("illegal blocksize in message.", e);
131: } catch (BadPaddingException e) {
132: throw new CMSException("bad padding in message.", e);
133: }
134: }
135: }
|