Example usage for org.bouncycastle.openpgp PGPPublicKeyEncryptedData getSymmetricAlgorithm

List of usage examples for org.bouncycastle.openpgp PGPPublicKeyEncryptedData getSymmetricAlgorithm

Introduction

In this page you can find the example usage for org.bouncycastle.openpgp PGPPublicKeyEncryptedData getSymmetricAlgorithm.

Prototype

public int getSymmetricAlgorithm(PublicKeyDataDecryptorFactory dataDecryptorFactory) throws PGPException 

Source Link

Document

Return the symmetric key algorithm required to decrypt the data protected by this object.

Usage

From source file:org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation.java

License:Open Source License

private EncryptStreamResult handleEncryptedPacket(PgpDecryptVerifyInputParcel input,
        CryptoInputParcel cryptoInput, PGPEncryptedDataList enc, OperationLog log, int indent,
        boolean useBackupCode) throws PGPException {

    EncryptStreamResult result = new EncryptStreamResult();

    boolean asymmetricPacketFound = false;
    boolean symmetricPacketFound = false;
    boolean anyPacketFound = false;
    boolean decryptedSessionKeyAvailable = false;

    PGPPublicKeyEncryptedData encryptedDataAsymmetric = null;
    PGPPBEEncryptedData encryptedDataSymmetric = null;
    CanonicalizedSecretKey decryptionKey = null;
    CachingDataDecryptorFactory cachedKeyDecryptorFactory = new CachingDataDecryptorFactory(
            Constants.BOUNCY_CASTLE_PROVIDER_NAME, cryptoInput.getCryptoData());
    ;/* w w w  .ja  va  2 s.c o  m*/

    Passphrase passphrase = null;

    Iterator<?> it = enc.getEncryptedDataObjects();

    // go through all objects and find one we can decrypt
    while (it.hasNext()) {
        Object obj = it.next();
        if (obj instanceof PGPPublicKeyEncryptedData) {
            anyPacketFound = true;

            PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
            long subKeyId = encData.getKeyID();

            log.add(LogType.MSG_DC_ASYM, indent, KeyFormattingUtils.convertKeyIdToHex(subKeyId));

            decryptedSessionKeyAvailable = cachedKeyDecryptorFactory.hasCachedSessionData(encData);
            if (decryptedSessionKeyAvailable) {
                asymmetricPacketFound = true;
                encryptedDataAsymmetric = encData;
                break;
            }

            CachedPublicKeyRing cachedPublicKeyRing;
            try {
                // get actual keyring object based on master key id
                cachedPublicKeyRing = mProviderHelper
                        .getCachedPublicKeyRing(KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(subKeyId));
                long masterKeyId = cachedPublicKeyRing.getMasterKeyId();

                // allow only specific keys for decryption?
                if (input.getAllowedKeyIds() != null) {
                    Log.d(Constants.TAG, "encData.getKeyID(): " + subKeyId);
                    Log.d(Constants.TAG, "mAllowedKeyIds: " + input.getAllowedKeyIds());
                    Log.d(Constants.TAG, "masterKeyId: " + masterKeyId);

                    if (!input.getAllowedKeyIds().contains(masterKeyId)) {
                        // this key is in our db, but NOT allowed!
                        // continue with the next packet in the while loop
                        result.skippedDisallowedKey = true;
                        log.add(LogType.MSG_DC_ASKIP_NOT_ALLOWED, indent + 1);
                        continue;
                    }
                }

                SecretKeyType secretKeyType = cachedPublicKeyRing.getSecretKeyType(subKeyId);
                if (!secretKeyType.isUsable()) {
                    decryptionKey = null;
                    log.add(LogType.MSG_DC_ASKIP_UNAVAILABLE, indent + 1);
                    continue;
                }

                // get actual subkey which has been used for this encryption packet
                CanonicalizedSecretKeyRing canonicalizedSecretKeyRing = mProviderHelper
                        .getCanonicalizedSecretKeyRing(masterKeyId);
                CanonicalizedSecretKey candidateDecryptionKey = canonicalizedSecretKeyRing
                        .getSecretKey(subKeyId);

                if (!candidateDecryptionKey.canEncrypt()) {
                    log.add(LogType.MSG_DC_ASKIP_BAD_FLAGS, indent + 1);
                    continue;
                }

                if (secretKeyType == SecretKeyType.DIVERT_TO_CARD) {
                    passphrase = null;
                } else if (secretKeyType == SecretKeyType.PASSPHRASE_EMPTY) {
                    passphrase = new Passphrase("");
                } else if (cryptoInput.hasPassphrase()) {
                    passphrase = cryptoInput.getPassphrase();
                } else {
                    // if no passphrase was explicitly set try to get it from the cache service
                    try {
                        // returns "" if key has no passphrase
                        passphrase = getCachedPassphrase(subKeyId);
                        log.add(LogType.MSG_DC_PASS_CACHED, indent + 1);
                    } catch (PassphraseCacheInterface.NoSecretKeyException e) {
                        log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1);
                        return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
                    }

                    // if passphrase was not cached, return here indicating that a passphrase is missing!
                    if (passphrase == null) {
                        log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
                        return result.with(new DecryptVerifyResult(log,
                                RequiredInputParcel.createRequiredDecryptPassphrase(masterKeyId, subKeyId),
                                cryptoInput));
                    }
                }

                // check for insecure encryption key
                if (!PgpSecurityConstants.isSecureKey(candidateDecryptionKey)) {
                    log.add(LogType.MSG_DC_INSECURE_KEY, indent + 1);
                    result.insecureEncryptionKey = true;
                }

                // we're good, write down the data for later
                asymmetricPacketFound = true;
                encryptedDataAsymmetric = encData;
                decryptionKey = candidateDecryptionKey;

            } catch (PgpKeyNotFoundException | ProviderHelper.NotFoundException e) {
                // continue with the next packet in the while loop
                log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1);
                continue;
            }

            // break out of while, only decrypt the first packet where we have a key
            break;

        } else if (obj instanceof PGPPBEEncryptedData) {
            anyPacketFound = true;

            log.add(LogType.MSG_DC_SYM, indent);

            if (!input.isAllowSymmetricDecryption()) {
                log.add(LogType.MSG_DC_SYM_SKIP, indent + 1);
                continue;
            }

            /*
             * When mAllowSymmetricDecryption == true and we find a data packet here,
             * we do not search for other available asymmetric packets!
             */
            symmetricPacketFound = true;

            encryptedDataSymmetric = (PGPPBEEncryptedData) obj;

            // if no passphrase is given, return here
            // indicating that a passphrase is missing!
            if (!cryptoInput.hasPassphrase()) {

                try {
                    passphrase = getCachedPassphrase(key.symmetric);
                    log.add(LogType.MSG_DC_PASS_CACHED, indent + 1);
                } catch (PassphraseCacheInterface.NoSecretKeyException e) {
                    // nvm
                }

                if (passphrase == null) {
                    log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1);
                    RequiredInputParcel requiredInputParcel = useBackupCode
                            ? RequiredInputParcel.createRequiredBackupCode()
                            : RequiredInputParcel.createRequiredSymmetricPassphrase();
                    return result.with(new DecryptVerifyResult(log, requiredInputParcel, cryptoInput));
                }

            } else {
                passphrase = cryptoInput.getPassphrase();
            }

            // break out of while, only decrypt the first packet
            break;
        }
    }

    // More data, just acknowledge and ignore.
    while (it.hasNext()) {
        Object obj = it.next();
        if (obj instanceof PGPPublicKeyEncryptedData) {
            PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj;
            long subKeyId = encData.getKeyID();
            log.add(LogType.MSG_DC_TRAIL_ASYM, indent, KeyFormattingUtils.convertKeyIdToHex(subKeyId));
        } else if (obj instanceof PGPPBEEncryptedData) {
            log.add(LogType.MSG_DC_TRAIL_SYM, indent);
        } else {
            log.add(LogType.MSG_DC_TRAIL_UNKNOWN, indent);
        }
    }

    // we made sure above one of these two would be true
    if (symmetricPacketFound) {
        PGPDigestCalculatorProvider digestCalcProvider = new JcaPGPDigestCalculatorProviderBuilder()
                .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build();
        PBEDataDecryptorFactory decryptorFactory = new JcePBEDataDecryptorFactoryBuilder(digestCalcProvider)
                .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.getCharArray());

        try {
            result.cleartextStream = encryptedDataSymmetric.getDataStream(decryptorFactory);
        } catch (PGPDataValidationException e) {
            log.add(LogType.MSG_DC_ERROR_SYM_PASSPHRASE, indent + 1);
            RequiredInputParcel requiredInputParcel = useBackupCode
                    ? RequiredInputParcel.createRequiredBackupCode()
                    : RequiredInputParcel.createRequiredSymmetricPassphrase();
            return result.with(new DecryptVerifyResult(log, requiredInputParcel, cryptoInput));
        }

        result.encryptedData = encryptedDataSymmetric;

        result.symmetricEncryptionAlgo = encryptedDataSymmetric.getSymmetricAlgorithm(decryptorFactory);
    } else if (asymmetricPacketFound) {
        CachingDataDecryptorFactory decryptorFactory;
        if (decryptedSessionKeyAvailable) {
            decryptorFactory = cachedKeyDecryptorFactory;
        } else {
            try {
                log.add(LogType.MSG_DC_UNLOCKING, indent + 1);
                if (!decryptionKey.unlock(passphrase)) {
                    log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent + 1);
                    return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
                }
            } catch (PgpGeneralException e) {
                log.add(LogType.MSG_DC_ERROR_EXTRACT_KEY, indent + 1);
                return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
            }

            decryptorFactory = decryptionKey.getCachingDecryptorFactory(cryptoInput);

            // special case: if the decryptor does not have a session key cached for this encrypted
            // data, and can't actually decrypt on its own, return a pending intent
            if (!decryptorFactory.canDecrypt()
                    && !decryptorFactory.hasCachedSessionData(encryptedDataAsymmetric)) {

                log.add(LogType.MSG_DC_PENDING_NFC, indent + 1);
                return result.with(new DecryptVerifyResult(log,
                        RequiredInputParcel.createSecurityTokenDecryptOperation(
                                decryptionKey.getRing().getMasterKeyId(), decryptionKey.getKeyId(),
                                encryptedDataAsymmetric.getSessionKey()[0]),
                        cryptoInput));
            }
        }

        try {
            result.cleartextStream = encryptedDataAsymmetric.getDataStream(decryptorFactory);
        } catch (PGPKeyValidationException | ArrayIndexOutOfBoundsException e) {
            log.add(LogType.MSG_DC_ERROR_CORRUPT_DATA, indent + 1);
            return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
        }

        result.symmetricEncryptionAlgo = encryptedDataAsymmetric.getSymmetricAlgorithm(decryptorFactory);
        result.encryptedData = encryptedDataAsymmetric;

        Map<ByteBuffer, byte[]> cachedSessionKeys = decryptorFactory.getCachedSessionKeys();
        cryptoInput.addCryptoData(cachedSessionKeys);
        if (cachedSessionKeys.size() >= 1) {
            Entry<ByteBuffer, byte[]> entry = cachedSessionKeys.entrySet().iterator().next();
            result.sessionKey = entry.getKey().array();
            result.decryptedSessionKey = entry.getValue();
        }
    } else {
        // there wasn't even any useful data
        if (!anyPacketFound) {
            log.add(LogType.MSG_DC_ERROR_NO_DATA, indent + 1);
            return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_NO_DATA, log));
        }
        // there was data but key wasn't allowed
        if (result.skippedDisallowedKey) {
            log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1);
            return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_KEY_DISALLOWED, log));
        }
        // no packet has been found where we have the corresponding secret key in our db
        log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1);
        return result.with(new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log));
    }

    return result;

}