BouncyCastle PGP-Verschlüsselung / Entschlüsselung: Verursacht durch: java.io.EOFException: vorzeitige Ende des Stroms in PartialInputStream

Beim Versuch, verschlüsseln, entschlüsseln Sie eine Datei, die ich mit der folgenden Ausnahme:

com.example.common.crypto.CipherException: org.bouncycastle.openpgp.PGPException: Exception starting decryption
    at com.example.common.crypto.PGPFileCipher.decrypt(PGPFileCipher.java:151)
    at com.example.common.crypto.PGPFileCipherTest.testEncryptDecryptFile(PGPFileCipherTest.java:41)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:43)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
    at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
    at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
    at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
    at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)
Caused by: org.bouncycastle.openpgp.PGPException: Exception starting decryption
    at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
    at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
    at com.example.common.crypto.PGPFileCipher.decrypt(PGPFileCipher.java:128)
    ... 28 more
Caused by: java.io.EOFException: premature end of stream in PartialInputStream
    at org.bouncycastle.bcpg.BCPGInputStream$PartialInputStream.read(Unknown Source)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    at java.io.InputStream.read(InputStream.java:82)
    at javax.crypto.CipherInputStream.a(DashoA13*..)
    at javax.crypto.CipherInputStream.read(DashoA13*..)
    at org.bouncycastle.bcpg.BCPGInputStream.read(Unknown Source)
    ... 31 more

Meine PGPFileCipher Klasse:

package com.example.common.crypto;

public class PGPFileCipher implements FileCipher {

    private static final Logger logger = LoggerFactory.getLogger(PGPFileCipher.class);

    public File encryptFile(File inputFile, String encryptedFilePath, String publicKeyPath) throws CipherException {
        FileInputStream publicKeyStream = null;
        FileOutputStream encryptedFileOutputStream = null;
        try {
            publicKeyStream = new FileInputStream(new File(publicKeyPath));
            File encryptedFile = new File(encryptedFilePath);
            encryptedFileOutputStream = new FileOutputStream(encryptedFile);
            encryptedFileOutputStream.write(encrypt(getBytesFromFile(inputFile), publicKeyStream, ""));
            encryptedFileOutputStream.flush();
            return encryptedFile;
        } catch (Exception e) {
            throw new CipherException(e);
        } finally {
            IOUtils.closeQuietly(encryptedFileOutputStream);
            IOUtils.closeQuietly(publicKeyStream);
        }
    }

    private PGPPrivateKey findSecretKey(PGPSecretKeyRingCollection pgpSec, long keyID, char[] pass) throws CipherException {
        try {
            PGPSecretKey pgpSecKey = pgpSec.getSecretKey(keyID);
            if (pgpSecKey == null) {
                return null;
            }
            return pgpSecKey.extractPrivateKey(pass, new BouncyCastleProvider());
        } catch (Exception e) {
            throw new CipherException(e);
        }
    }

    /**
     * decrypt the passed in message stream
     *
     * @param encrypted
     *            The message to be decrypted.
     * @param keyIn
     *            InputStream of the key
     *
     * @return Clear text as a byte array. I18N considerations are not handled
     *         by this routine
     * @exception CipherException
     */
    public byte[] decrypt(byte[] encrypted, InputStream keyIn, char[] password) throws CipherException {
        ByteArrayOutputStream out = null;
        InputStream clear = null;
        InputStream in = null;
        InputStream unc = null;
        try {
            in = new ByteArrayInputStream(encrypted);

            in = PGPUtil.getDecoderStream(in);

            PGPObjectFactory pgpF = new PGPObjectFactory(in);
            PGPEncryptedDataList enc = null;
            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(), password);
            }

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

            clear = pbe.getDataStream(sKey, new BouncyCastleProvider());

            PGPObjectFactory pgpFact = new PGPObjectFactory(clear);

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

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

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

            unc = ld.getInputStream();

            out = new ByteArrayOutputStream();
            int ch;

            while ((ch = unc.read()) >= 0) {
                out.write(ch);

            }
            out.flush();
            byte[] returnBytes = out.toByteArray();
            return returnBytes;
        } catch (Exception e) {
            e.printStackTrace();
            throw new CipherException(e);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(in);
            IOUtils.closeQuietly(clear);
            IOUtils.closeQuietly(unc);
        }
    }

    /**
     * Simple PGP encryptor between byte[].
     *
     * @param clearData
     *            The test to be encrypted
     * @param keyInputStream
     *            Input stream of the key
     * @param fileName
     *            File name. This is used in the Literal Data Packet (tag 11)
     *            which is really inly important if the data is to be related to
     *            a file to be recovered later. Because this routine does not
     *            know the source of the information, the caller can set
     *            something here for file name use that will be carried. If this
     *            routine is being used to encrypt SOAP MIME bodies, for
     *            example, use the file name from the MIME type, if applicable.
     *            Or anything else appropriate.
     *
     * @return encrypted data.
     * @exception CipherException
     */
    public byte[] encrypt(byte[] clearData, InputStream keyInputStream, String fileName)
            throws CipherException {
        OutputStream out = null;
        OutputStream cOut = null;
        PGPCompressedDataGenerator comData = null;
        PGPLiteralDataGenerator lData = null;
        ByteArrayOutputStream encOut = null;
        ByteArrayOutputStream bOut = null;
        OutputStream cos = null;
        OutputStream pOut = null;
        try {
            PGPPublicKey encKey = readPublicKey(keyInputStream);
            if (fileName == null || fileName.trim().length() < 1) {
                fileName = PGPLiteralData.CONSOLE;
            }

            encOut = new ByteArrayOutputStream();

            out = encOut;

            bOut = new ByteArrayOutputStream();

            comData = new PGPCompressedDataGenerator(
                    PGPCompressedDataGenerator.ZIP);
            cos = comData.open(bOut); //open it with the final
            //destination
            lData = new PGPLiteralDataGenerator();

            //we want to generate compressed data. This might be a user option
            //later,
            //in which case we would pass in bOut.
            pOut = lData.open(cos, //the compressed output stream
                    PGPLiteralData.BINARY, fileName, //"filename" to store
                    clearData.length, //length of clear data
                    new Date() //current time
            );
            pOut.write(clearData);
            pOut.flush();
            PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(
                    PGPEncryptedData.CAST5, false, new SecureRandom(),
                    new BouncyCastleProvider());

            cPk.addMethod(encKey);

            byte[] bytes = bOut.toByteArray();

            cOut = cPk.open(out, bytes.length);

            cOut.write(bytes); //obtain the actual bytes from the compressed stream
            cOut.flush();
            encOut.flush();
            return encOut.toByteArray();
        } catch (Exception e) {
            throw new CipherException(e);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(cOut);
            IOUtils.closeQuietly(encOut);
            IOUtils.closeQuietly(bOut);
            IOUtils.closeQuietly(cos);
            IOUtils.closeQuietly(pOut);
            try {
                if (lData != null) {
                    lData.close();
                }
                if (comData != null) {
                    comData.close();
                }
            } catch (IOException ignored) {}
        }
    }

    private PGPPublicKey readPublicKey(InputStream in)
            throws CipherException {
        try {
            in = PGPUtil.getDecoderStream(in);

            PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in);

            //
            //we just loop through the collection till we find a key suitable for
            //encryption, in the real
            //world you would probably want to be a bit smarter about this.
            //

            //
            //iterate through the key rings.
            //
            Iterator rIt = pgpPub.getKeyRings();

            while (rIt.hasNext()) {
                PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
                Iterator kIt = kRing.getPublicKeys();

                while (kIt.hasNext()) {
                    PGPPublicKey k = (PGPPublicKey) kIt.next();

                    if (k.isEncryptionKey()) {
                        return k;
                    }
                }
            }
            throw new IllegalArgumentException("Can't find encryption key in key ring.");
        } catch (Exception e) {
            throw new CipherException(e);
        }
    }

    private byte[] getBytesFromFile(File file) throws CipherException {
        InputStream is = null;
        try {
            is = new FileInputStream(file);
            //Get the size of the file
            long length = file.length();

            if (length > Integer.MAX_VALUE) {
                throw new CipherException("File is too large: " + file.getName());
            }

            return IOUtils.toByteArray(is);
        } catch (IOException e) {
            throw new CipherException(e);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }
}

Und den test-ich bin versucht zu laufen, ist:

package com.example.common.crypto;

public class PGPFileCipherTest {

    private static final Logger logger = LoggerFactory.getLogger(PGPFileCipherTest.class);

    @Rule
    public TemporaryFolder folder = new TemporaryFolder();

    @Test
    public void testEncryptDecryptFile() throws IOException, CipherException {
        FileOutputStream decryptedFileOutputStream = null;
        InputStream privateKeyStream = null;
        try {
            PGPFileCipher fileCipher = new PGPFileCipher();
            Resource inputFile = new ClassPathResource("testInputFile.txt");
            Resource publicKey = new ClassPathResource("PUBLIC.asc");
            Resource privateKey = new ClassPathResource("PRIVATE.asc");
            //Encrypt file
            File encryptedFile = fileCipher.encryptFile(inputFile.getFile(), folder.newFile("testInputFile_enc.txt").getPath(), publicKey.getFile().getPath());
            //Now decrypt the file
            File decryptedFile = folder.newFile("testInputFile_dec.txt");
            decryptedFileOutputStream = new FileOutputStream(decryptedFile);
            privateKeyStream = new FileInputStream(privateKey.getFile());
            decryptedFileOutputStream.write(fileCipher.decrypt(FileUtils.readFileToByteArray(encryptedFile), privateKeyStream, "".toCharArray()));
            decryptedFileOutputStream.flush();
        } finally {
            IOUtils.closeQuietly(decryptedFileOutputStream);
            IOUtils.closeQuietly(privateKeyStream);
        }
    }
}

Leider bin ich nicht allzu vertraut mit der BouncyCastle-und es würde scheinen, als ob ein stream ist nicht richtig geschlossen /geleert, aber ich kann nicht scheinen, um es aufzuspüren. Dies ist eine modifizierte version von einem der BouncyCastle Beispiele FYI. Vielen Dank im Voraus für Eure Hilfe.

Schreibe einen Kommentar