Example usage for org.bouncycastle.openpgp PGPLiteralData getFileName

List of usage examples for org.bouncycastle.openpgp PGPLiteralData getFileName

Introduction

In this page you can find the example usage for org.bouncycastle.openpgp PGPLiteralData getFileName.

Prototype

public String getFileName() 

Source Link

Document

Return the file name associated with the data packet.

Usage

From source file:com.geekcommune.identity.EncryptionUtil.java

License:Open Source License

/**
 * Decrypt the specified (PBE) input file
 *///  w w w .  j  a v  a  2 s  .c o m
public void decryptPBEBasedFile(String outputFilename, InputStream in, char[] passPhrase, boolean mdcRequired)
        throws PGPException {
    try {
        //
        // we need to be able to reset the stream if we try a
        // wrong passphrase, we'll assume that all the mechanisms
        // appear in the first 10k for the moment...
        //
        int READ_LIMIT = 10 * 1024;

        in.mark(READ_LIMIT);

        PGPPBEEncryptedData pbe;
        InputStream clear;
        int count = 0;

        for (;;) {
            InputStream dIn = PGPUtil.getDecoderStream(in);

            PGPObjectFactory pgpF = new PGPObjectFactory(dIn);
            PGPEncryptedDataList enc;
            Object o = pgpF.nextObject();

            //
            // the first object might be a PGP marker packet.
            //
            if (o instanceof PGPEncryptedDataList) {
                enc = (PGPEncryptedDataList) o;
            } else {
                enc = (PGPEncryptedDataList) pgpF.nextObject();
            }

            while (count < enc.size()) {
                if (enc.get(count) instanceof PGPPBEEncryptedData) {
                    break;
                }

                count++;
            }

            if (count >= enc.size()) {
                throw new PGPException("Passphrase invalid");
            }

            pbe = (PGPPBEEncryptedData) enc.get(count);

            try {
                clear = pbe.getDataStream(passPhrase, "BC");
            } catch (PGPKeyValidationException e) {
                in.reset();
                continue;
            }

            break;
        }

        PGPObjectFactory pgpFact = new PGPObjectFactory(clear);

        PGPCompressedData cData = (PGPCompressedData) pgpFact.nextObject();

        pgpFact = new PGPObjectFactory(cData.getDataStream());

        PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();

        if (outputFilename == null) {
            outputFilename = ld.getFileName();
        }

        FileOutputStream fOut = new FileOutputStream(outputFilename);

        InputStream unc = ld.getInputStream();

        int ch;
        while ((ch = unc.read()) >= 0) {
            fOut.write(ch);
        }

        if (pbe.isIntegrityProtected()) {
            if (!pbe.verify()) {
                throw new PGPException("Message failed integrity check");
            }
            if (_verbose) {
                System.out.println("Message integrity check passed");
            }
        } else {
            if (_verbose) {
                System.out.println("No message integrity check");
            }

            if (mdcRequired) {
                throw new PGPException("Missing required message integrity check");
            }
        }
    } catch (PGPException e) {
        throw e;
    } catch (Exception e) {
        throw new PGPException("Error in decryption", e);
    }
}

From source file:com.google.e2e.bcdriver.Decryptor.java

License:Apache License

private static final Result verifySignedContent(InputStream inp, KeyChecker.PKR verify)
        throws IOException, PGPException, SignatureException {
    PGPObjectFactory plainFact = new PGPObjectFactory(inp, new BcKeyFingerprintCalculator());

    Object msg = plainFact.nextObject();

    // swap in uncompressed data if necessary
    if (msg instanceof PGPCompressedData) {
        PGPCompressedData cData = (PGPCompressedData) msg;
        plainFact = new PGPObjectFactory(cData.getDataStream(), new BcKeyFingerprintCalculator());
        msg = plainFact.nextObject();/*  w ww.j  a v  a 2  s  .  com*/
    }

    PGPOnePassSignatureList onePassSigList;
    PGPLiteralData lData;
    if (msg instanceof PGPOnePassSignatureList) {
        onePassSigList = (PGPOnePassSignatureList) msg;
        lData = (PGPLiteralData) plainFact.nextObject();
    } else {
        onePassSigList = null;
        lData = (PGPLiteralData) msg;
    }

    if ((verify != null) && (onePassSigList == null)) {
        throw new IOException("Message is unsigned");
    }

    PGPOnePassSignature onePassSig = null;
    int onePassStartIndex = -1;
    PGPPublicKey verifyKey = null;
    if (verify != null) {
        for (int i = 0; i < onePassSigList.size(); i++) {
            List<PGPPublicKey> candidates = verify.getSigningKeysByKeyID(onePassSigList.get(i).getKeyID());
            if (candidates.size() == 1) {
                onePassSig = onePassSigList.get(i);
                onePassStartIndex = i;
                verifyKey = candidates.get(0);
                break;
            }
        }
    }

    if ((verify != null) && (onePassSig == null)) {
        throw new IOException("Failed to find a signature from verifying key");
    }

    if (onePassSig != null) {
        onePassSig.init(new BcPGPContentVerifierBuilderProvider(), verifyKey);
    }
    ByteArrayOutputStream baout = new ByteArrayOutputStream();
    InputStream lin = lData.getInputStream();
    byte buf[] = new byte[8192];
    int nread;
    while ((nread = lin.read(buf)) > 0) {
        baout.write(buf, 0, nread);
        if (onePassSig != null) {
            onePassSig.update(buf, 0, nread);
        }
    }
    baout.close();
    if (onePassSig != null) {
        PGPSignatureList sigList = (PGPSignatureList) plainFact.nextObject();
        // One pass signature trailers occur in LIFO order compared to their
        // location in the header.
        PGPSignature sig = sigList.get(sigList.size() - 1 - onePassStartIndex);
        if (!onePassSig.verify(sig)) {
            throw new IOException("Invalid signature in message");
        }
    }
    return new Result(baout.toByteArray(), lData.getFileName());
}

From source file:crypttools.PGPCryptoBC.java

License:Open Source License

public boolean validateData(String data, String publicKey) throws Exception {
    Security.addProvider(new BouncyCastleProvider());
    File fileToVerify = File.createTempFile("temp", ".privateScrap");
    FileUtils.writeStringToFile(fileToVerify, data);

    File publicKeyFile = File.createTempFile("temp", ".publicScrap");
    // Creates an exception
    //        System.out.println(this.armoredPublicKey);
    //        String armoredKeyString = getPublicKey();
    //        System.out.println(armoredKeyString);
    FileUtils.writeStringToFile(publicKeyFile, publicKey);
    //FileUtils.writeStringToFile(publicKeyFile, new String(this.armoredPublicKey, "UTF-8"));

    try {/*from  w w  w.j  a v  a2 s . c o m*/
        InputStream in = PGPUtil.getDecoderStream(new FileInputStream(fileToVerify));

        PGPObjectFactory pgpObjFactory = new PGPObjectFactory(in);
        PGPCompressedData compressedData = (PGPCompressedData) pgpObjFactory.nextObject();

        //Get the signature from the file

        pgpObjFactory = new PGPObjectFactory(compressedData.getDataStream());
        PGPOnePassSignatureList onePassSignatureList = (PGPOnePassSignatureList) pgpObjFactory.nextObject();
        PGPOnePassSignature onePassSignature = onePassSignatureList.get(0);

        //Get the literal data from the file

        PGPLiteralData pgpLiteralData = (PGPLiteralData) pgpObjFactory.nextObject();
        InputStream literalDataStream = pgpLiteralData.getInputStream();

        InputStream keyIn = new FileInputStream(publicKeyFile);
        PGPPublicKeyRingCollection pgpRing = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(keyIn));
        PGPPublicKey key = pgpRing.getPublicKey(onePassSignature.getKeyID());

        FileOutputStream literalDataOutputStream = new FileOutputStream(pgpLiteralData.getFileName());
        onePassSignature.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), key);

        int ch;
        while ((ch = literalDataStream.read()) >= 0) {
            onePassSignature.update((byte) ch);
            literalDataOutputStream.write(ch);
        }

        literalDataOutputStream.close();

        //Get the signature from the written out file

        PGPSignatureList p3 = (PGPSignatureList) pgpObjFactory.nextObject();
        PGPSignature signature = p3.get(0);

        //Verify the two signatures
        boolean valid = onePassSignature.verify(signature);
        return valid;
    } catch (Exception e) {
        System.out.println("Got an Exception: " + e.getMessage());
        return false;
        //do something clever with the exception
    } finally {
        fileToVerify.delete();
        publicKeyFile.delete();
    }
}

From source file:google.registry.rde.Ghostryde.java

License:Open Source License

/**
 * Opens a new {@link Input} for reading the original contents (Reading Step 3/3)
 *
 * <p>This is the final step in reading a ghostryde file. After calling this method, you should
 * call the read methods on the returned {@link InputStream}.
 *
 * @param input is the value returned by {@link #openDecompressor}.
 * @throws IOException/*w  w  w. ja  v  a  2s . c om*/
 * @throws PGPException
 */
@CheckReturnValue
public Input openInput(@WillNotClose Decompressor input) throws IOException, PGPException {
    PGPObjectFactory fact = new BcPGPObjectFactory(checkNotNull(input, "input"));
    PGPLiteralData literal = pgpCast(fact.nextObject(), PGPLiteralData.class);
    DateTime modified = new DateTime(literal.getModificationTime(), UTC);
    return new Input(literal.getDataStream(), literal.getFileName(), modified);
}

From source file:gr.abiss.calipso.util.PgpUtils.java

License:Open Source License

/**
 * decrypt the passed in message stream// ww w  .  j a v  a  2  s . c  o m
 */
private static void decryptFile(InputStream in, InputStream keyIn, char[] passwd, String defaultFileName)
        throws IOException, NoSuchProviderException {
    in = PGPUtil.getDecoderStream(in);

    try {
        PGPObjectFactory pgpF = new PGPObjectFactory(in);
        PGPEncryptedDataList enc;

        Object o = pgpF.nextObject();
        //
        // the first object might be a PGP marker packet.
        //
        if (o instanceof PGPEncryptedDataList) {
            enc = (PGPEncryptedDataList) o;
        } else {
            enc = (PGPEncryptedDataList) pgpF.nextObject();
        }

        //
        // find the secret key
        //
        Iterator it = enc.getEncryptedDataObjects();
        PGPPrivateKey sKey = null;
        PGPPublicKeyEncryptedData pbe = null;
        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn));

        while (sKey == null && it.hasNext()) {
            pbe = (PGPPublicKeyEncryptedData) it.next();

            sKey = findSecretKey(pgpSec, pbe.getKeyID(), passwd);
        }

        if (sKey == null) {
            throw new IllegalArgumentException("secret key for message not found.");
        }

        InputStream clear = pbe.getDataStream(sKey, "BC");

        PGPObjectFactory plainFact = new PGPObjectFactory(clear);

        Object message = plainFact.nextObject();

        if (message instanceof PGPCompressedData) {
            PGPCompressedData cData = (PGPCompressedData) message;
            PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream());

            message = pgpFact.nextObject();
        }

        if (message instanceof PGPLiteralData) {
            PGPLiteralData ld = (PGPLiteralData) message;

            String outFileName = ld.getFileName();
            if (outFileName.length() == 0) {
                outFileName = defaultFileName;
            }

            InputStream unc = ld.getInputStream();
            OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));

            Streams.pipeAll(unc, fOut);

            fOut.close();
        } else if (message instanceof PGPOnePassSignatureList) {
            throw new PGPException("encrypted message contains a signed message - not literal data.");
        } else {
            throw new PGPException("message is not a simple encrypted file - type unknown.");
        }

        if (pbe.isIntegrityProtected()) {
            if (!pbe.verify()) {
                System.err.println("message failed integrity check");
            } else {
                System.err.println("message integrity check passed");
            }
        } else {
            System.err.println("no message integrity check");
        }
    } catch (PGPException e) {
        System.err.println(e);
        if (e.getUnderlyingException() != null) {
            e.getUnderlyingException().printStackTrace();
        }
    }
}

From source file:hh.learnj.test.license.test.lincense3j.KeyBasedFileProcessor.java

/**
 * decrypt the passed in message stream//from ww w.ja v  a2  s.com
 */
private static void decryptFile(InputStream in, InputStream keyIn, char[] passwd, String defaultFileName)
        throws IOException, NoSuchProviderException {
    in = PGPUtil.getDecoderStream(in);
    try {
        JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in);
        PGPEncryptedDataList enc;

        Object o = pgpF.nextObject();
        //
        // the first object might be a PGP marker packet.
        //
        if (o instanceof PGPEncryptedDataList) {
            enc = (PGPEncryptedDataList) o;
        } else {
            enc = (PGPEncryptedDataList) pgpF.nextObject();
        }
        //
        // find the secret key
        //
        Iterator it = enc.getEncryptedDataObjects();
        PGPPrivateKey sKey = null;
        PGPPublicKeyEncryptedData pbe = null;
        PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(keyIn),
                new JcaKeyFingerprintCalculator());

        while (sKey == null && it.hasNext()) {
            pbe = (PGPPublicKeyEncryptedData) it.next();
            sKey = MyPGPUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd);
        }
        if (sKey == null) {
            throw new IllegalArgumentException("secret key for message not found.");
        }
        InputStream clear = pbe
                .getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").build(sKey));
        JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear);
        Object message = plainFact.nextObject();
        if (message instanceof PGPCompressedData) {
            PGPCompressedData cData = (PGPCompressedData) message;
            JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(cData.getDataStream());
            message = pgpFact.nextObject();
        }
        if (message instanceof PGPLiteralData) {
            PGPLiteralData ld = (PGPLiteralData) message;

            String outFileName = ld.getFileName();
            if (outFileName.length() == 0) {
                outFileName = defaultFileName;
            } else {
                /**
                 * modify 20160520 set fileName ????????
                 */
                String separator = "";
                if (outFileName.contains("/")) {
                    separator = "/";
                } else if (outFileName.contains("\\")) {
                    separator = "\\";

                }
                String fileName = outFileName.substring(outFileName.lastIndexOf(separator) + 1);
                //
                String defseparator = "";
                if (defaultFileName.contains("/")) {
                    defseparator = "/";
                } else if (defaultFileName.contains("\\")) {
                    defseparator = "\\";
                }

                defaultFileName = defaultFileName.substring(0, defaultFileName.lastIndexOf(defseparator));

                outFileName = defaultFileName + File.separator + fileName;

            }

            InputStream unc = ld.getInputStream();
            OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName));

            Streams.pipeAll(unc, fOut);

            fOut.close();
        } else if (message instanceof PGPOnePassSignatureList) {
            throw new PGPException("encrypted message contains a signed message - not literal data.");
        } else {
            throw new PGPException("message is not a simple encrypted file - type unknown.");
        }

        if (pbe.isIntegrityProtected()) {
            if (!pbe.verify()) {
                System.err.println("message failed integrity check");
            } else {
                System.err.println("message integrity check passed");
            }
        } else {
            System.err.println("no message integrity check");
        }
    } catch (PGPException e) {
        System.err.println(e);
        if (e.getUnderlyingException() != null) {
            e.getUnderlyingException().printStackTrace();
        }
    }
}

From source file:org.pgptool.gui.encryption.implpgp.EncryptionServicePgpImpl.java

License:Open Source License

private String getInitialFileName(PGPPublicKeyEncryptedData pbe, PGPPrivateKey privateKey) {
    InputStream clear = null;//from   w w  w. java  2 s. co m
    try {
        clear = pbe.getDataStream(new BcPublicKeyDataDecryptorFactory(privateKey));

        BcPGPObjectFactory plainFact = new BcPGPObjectFactory(clear);
        Object message = plainFact.nextObject();
        if (message instanceof PGPMarker) {
            message = plainFact.nextObject();
        }

        BcPGPObjectFactory pgpFactory = null;
        if (message instanceof PGPCompressedData) {
            PGPCompressedData cData = (PGPCompressedData) message;
            pgpFactory = new BcPGPObjectFactory(cData.getDataStream());
            message = pgpFactory.nextObject();
        }

        int watchDog = 0;
        while (message != null) {
            Preconditions.checkState(watchDog++ < 100, "Inifinite loop watch dog just hit");
            if (message instanceof PGPLiteralData) {
                PGPLiteralData ld = (PGPLiteralData) message;
                return ld.getFileName();
            } else if (message instanceof PGPOnePassSignatureList) {
                Preconditions.checkState(pgpFactory != null, "pgpFactory supposed to be not null");
                message = pgpFactory.nextObject();
            } else if (message instanceof PGPSignatureList) {
                Preconditions.checkState(pgpFactory != null, "pgpFactory supposed to be not null");
                message = pgpFactory.nextObject();
            } else {
                throw new PGPException(
                        "Don't know how to decrypt the input file. Encountered unexpected block: " + message);
            }
        }
        throw new IllegalStateException("Unknown file format, cannot determine initial file name");
    } catch (Throwable e) {
        throw new RuntimeException("Failed to get initial file name", e);
    } finally {
        IoStreamUtils.safeClose(clear);
    }
}

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

License:Open Source License

/** Decrypt and/or verify binary or ascii armored pgp data. */
@NonNull//from  w  ww .j  a  v  a2s .c o  m
private DecryptVerifyResult decryptVerify(PgpDecryptVerifyInputParcel input, CryptoInputParcel cryptoInput,
        InputData inputData, InputStream in, OutputStream out, int indent) throws IOException, PGPException {

    OperationLog log = new OperationLog();

    log.add(LogType.MSG_DC, indent);
    indent += 1;

    updateProgress(R.string.progress_reading_data, 0, 100);

    // parse ASCII Armor headers
    ArmorHeaders armorHeaders = parseArmorHeaders(in, log, indent);
    String charset = armorHeaders.charset;
    boolean useBackupCode = false;
    if (armorHeaders.backupVersion != null && armorHeaders.backupVersion == 2) {
        useBackupCode = true;
    }

    OpenPgpDecryptionResultBuilder decryptionResultBuilder = new OpenPgpDecryptionResultBuilder();

    JcaSkipMarkerPGPObjectFactory plainFact;
    Object dataChunk;
    EncryptStreamResult esResult = null;
    { // resolve encrypted (symmetric and asymmetric) packets
        JcaSkipMarkerPGPObjectFactory pgpF = new JcaSkipMarkerPGPObjectFactory(in);
        Object obj = pgpF.nextObject();

        if (obj instanceof PGPEncryptedDataList) {
            esResult = handleEncryptedPacket(input, cryptoInput, (PGPEncryptedDataList) obj, log, indent,
                    useBackupCode);

            // if there is an error, nothing left to do here
            if (esResult.errorResult != null) {
                return esResult.errorResult;
            }

            // if this worked out so far, the data is encrypted
            decryptionResultBuilder.setEncrypted(true);
            if (esResult.sessionKey != null && esResult.decryptedSessionKey != null) {
                decryptionResultBuilder.setSessionKey(esResult.sessionKey, esResult.decryptedSessionKey);
            }

            if (esResult.insecureEncryptionKey) {
                log.add(LogType.MSG_DC_INSECURE_SYMMETRIC_ENCRYPTION_ALGO, indent + 1);
                decryptionResultBuilder.setInsecure(true);
            }

            // Check for insecure encryption algorithms!
            if (!PgpSecurityConstants.isSecureSymmetricAlgorithm(esResult.symmetricEncryptionAlgo)) {
                log.add(LogType.MSG_DC_INSECURE_SYMMETRIC_ENCRYPTION_ALGO, indent + 1);
                decryptionResultBuilder.setInsecure(true);
            }

            plainFact = new JcaSkipMarkerPGPObjectFactory(esResult.cleartextStream);
            dataChunk = plainFact.nextObject();

        } else {
            decryptionResultBuilder.setEncrypted(false);

            plainFact = pgpF;
            dataChunk = obj;
        }

    }

    log.add(LogType.MSG_DC_PREP_STREAMS, indent);

    log.add(LogType.MSG_DC_CLEAR, indent);
    indent += 1;

    // resolve compressed data
    if (dataChunk instanceof PGPCompressedData) {
        log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent + 1);

        PGPCompressedData compressedData = (PGPCompressedData) dataChunk;

        JcaSkipMarkerPGPObjectFactory fact = new JcaSkipMarkerPGPObjectFactory(compressedData.getDataStream());
        dataChunk = fact.nextObject();
        plainFact = fact;
    }

    PgpSignatureChecker signatureChecker = new PgpSignatureChecker(mProviderHelper, input.getSenderAddress());
    if (signatureChecker.initializeOnePassSignature(dataChunk, log, indent + 1)) {
        dataChunk = plainFact.nextObject();
    }

    if (dataChunk instanceof PGPSignatureList) {
        // skip
        dataChunk = plainFact.nextObject();
    }

    OpenPgpMetadata metadata;

    if (!(dataChunk instanceof PGPLiteralData)) {

        log.add(LogType.MSG_DC_ERROR_INVALID_DATA, indent);
        return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);

    }

    log.add(LogType.MSG_DC_CLEAR_DATA, indent + 1);
    indent += 2;

    PGPLiteralData literalData = (PGPLiteralData) dataChunk;

    String originalFilename = literalData.getFileName();
    // reject filenames with slashes completely (path traversal issue)
    if (originalFilename.contains("/")) {
        originalFilename = "";
    }
    String mimeType = null;
    if (literalData.getFormat() == PGPLiteralData.TEXT || literalData.getFormat() == PGPLiteralData.UTF8) {
        mimeType = "text/plain";
    } else {
        // try to guess from file ending
        String extension = MimeTypeMap.getFileExtensionFromUrl(originalFilename);
        if (extension != null) {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            mimeType = mime.getMimeTypeFromExtension(extension);
        }
    }
    if (mimeType == null) {
        mimeType = "application/octet-stream";
    }

    if (!"".equals(originalFilename)) {
        log.add(LogType.MSG_DC_CLEAR_META_FILE, indent + 1, originalFilename);
    }
    log.add(LogType.MSG_DC_CLEAR_META_TIME, indent + 1,
            new Date(literalData.getModificationTime().getTime()).toString());

    // return here if we want to decrypt the metadata only
    if (input.isDecryptMetadataOnly()) {

        log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, mimeType);

        // this operation skips the entire stream to find the data length!
        Long originalSize = literalData.findDataLength();

        if (originalSize != null) {
            log.add(LogType.MSG_DC_CLEAR_META_SIZE, indent + 1, Long.toString(originalSize));
        } else {
            log.add(LogType.MSG_DC_CLEAR_META_SIZE_UNKNOWN, indent + 1);
        }

        metadata = new OpenPgpMetadata(originalFilename, mimeType, literalData.getModificationTime().getTime(),
                originalSize == null ? 0 : originalSize, charset);

        log.add(LogType.MSG_DC_OK_META_ONLY, indent);
        DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);
        result.setDecryptionMetadata(metadata);
        return result;
    }

    InputStream dataIn = literalData.getInputStream();

    long opTime, startTime = System.currentTimeMillis();

    long alreadyWritten = 0;
    long wholeSize = inputData.getSize() - inputData.getStreamPosition();
    boolean sizeIsKnown = inputData.getSize() != InputData.UNKNOWN_FILESIZE && wholeSize > 0;
    int length;
    byte[] buffer = new byte[8192];
    byte[] firstBytes = new byte[48];
    CharsetVerifier charsetVerifier = new CharsetVerifier(buffer, mimeType, charset);

    updateProgress(R.string.progress_decrypting, 1, 100);

    long nextProgressTime = 0L;
    int lastReportedProgress = 1;
    while ((length = dataIn.read(buffer)) > 0) {
        // Log.d(Constants.TAG, "read bytes: " + length);
        if (out != null) {
            out.write(buffer, 0, length);
        }

        // update signature buffer if signature is also present
        signatureChecker.updateSignatureData(buffer, 0, length);

        charsetVerifier.readBytesFromBuffer(0, length);

        // note down first couple of bytes for "magic bytes" file type detection
        if (alreadyWritten == 0) {
            System.arraycopy(buffer, 0, firstBytes, 0, length > firstBytes.length ? firstBytes.length : length);
        }

        alreadyWritten += length;
        if (sizeIsKnown && nextProgressTime < System.currentTimeMillis()) {
            long progress = 100 * inputData.getStreamPosition() / wholeSize;
            // stop at 100% for wrong file sizes...
            if (progress > 100) {
                progress = 100;
            }
            if (progress > lastReportedProgress) {
                updateProgress((int) progress, 100);
                lastReportedProgress = (int) progress;
                nextProgressTime = System.currentTimeMillis() + PROGRESS_STRIDE_MILLISECONDS;
            }
        }
    }

    if (signatureChecker.isInitialized()) {

        Object o = plainFact.nextObject();
        boolean signatureCheckOk = signatureChecker.verifySignatureOnePass(o, log, indent + 1);

        if (!signatureCheckOk) {
            return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
        }

    }

    opTime = System.currentTimeMillis() - startTime;
    Log.d(Constants.TAG, "decrypt time taken: " + String.format("%.2f", opTime / 1000.0) + "s, for "
            + alreadyWritten + " bytes");

    // special treatment to detect pgp mime types
    // TODO move into CharsetVerifier? seems like that would be a plausible place for this logic
    if (matchesPrefix(firstBytes, "-----BEGIN PGP PUBLIC KEY BLOCK-----")
            || matchesPrefix(firstBytes, "-----BEGIN PGP PRIVATE KEY BLOCK-----")) {
        mimeType = Constants.MIME_TYPE_KEYS;
    } else if (matchesPrefix(firstBytes, "-----BEGIN PGP MESSAGE-----")) {
        // this is NOT application/pgp-encrypted, see RFC 3156!
        mimeType = Constants.MIME_TYPE_ENCRYPTED_ALTERNATE;
    } else {
        mimeType = charsetVerifier.getGuessedMimeType();
    }
    metadata = new OpenPgpMetadata(originalFilename, mimeType, literalData.getModificationTime().getTime(),
            alreadyWritten, charsetVerifier.getCharset());

    log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, mimeType);
    Log.d(Constants.TAG, metadata.toString());

    indent -= 1;

    if (esResult != null) {
        if (esResult.encryptedData.isIntegrityProtected()) {
            if (esResult.encryptedData.verify()) {
                log.add(LogType.MSG_DC_INTEGRITY_CHECK_OK, indent);
            } else {
                log.add(LogType.MSG_DC_ERROR_INTEGRITY_CHECK, indent);
                return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log);
            }
        } else if (!signatureChecker.isInitialized()) {
            // If no signature is present, we *require* an MDC!
            // Handle missing integrity protection like failed integrity protection!
            // The MDC packet can be stripped by an attacker!
            log.add(LogType.MSG_DC_INSECURE_MDC_MISSING, indent);
            decryptionResultBuilder.setInsecure(true);
        }
    }

    updateProgress(R.string.progress_done, 100, 100);

    log.add(LogType.MSG_DC_OK, indent);

    // Return a positive result, with metadata and verification info
    DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log);

    result.setCachedCryptoInputParcel(cryptoInput);
    result.setSignatureResult(signatureChecker.getSignatureResult());
    result.setDecryptionResult(decryptionResultBuilder.build());
    result.setDecryptionMetadata(metadata);
    result.mOperationTime = opTime;

    return result;

}