使用 bouncycastle 解密文件时出现额外字符

问题描述 投票:0回答:1

我需要在java中创建一个类来加密和解密文件。 我使用 bouncy castle 库,因为它看起来是 Java 最常用的库。

我能够加密和解密该文件。但解密后的文件末尾有一些额外的字符。元数据类型,因为原始文件名以十六进制字符嵌入其中。

正常吗? 如何跳过?

由于我对 pgp 和此类东西一无所知,所以我要求 chatpgt tu 生成一些代码。经过几次迭代后工作,但我得到了这些额外的字符......

我的代码

package myPackage;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;

import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;


public class PGPHelper {

    public static void encryptFile(String inputFilePath, String publicKeyFilePath, String outputFilePath, boolean armor, boolean withIntegrityCheck) {
        Security.addProvider(new BouncyCastleProvider());

        try (InputStream publicKeyInputStream = new BufferedInputStream(new FileInputStream(publicKeyFilePath));
             OutputStream encryptedFileOutputStream = new BufferedOutputStream(new FileOutputStream(outputFilePath))) {

            PGPPublicKeyRingCollection publicKeyRingCollection = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(publicKeyInputStream),
                    new JcaKeyFingerprintCalculator());

            // Sélectionnez la clé publique du destinataire (vous pouvez ajuster cette logique selon vos besoins)
            PGPPublicKey recipientPublicKey = selectRecipientPublicKey(publicKeyRingCollection);

            // Initialiser le chiffrement PGP
            PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(
                    new JcePGPDataEncryptorBuilder(PGPEncryptedData.AES_256)
                            .setWithIntegrityPacket(withIntegrityCheck)
                            .setSecureRandom(new SecureRandom())
                            .setProvider("BC")
            );

            encryptedDataGenerator.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(recipientPublicKey).setProvider("BC"));

            try (OutputStream encryptedOutputStream = encryptedDataGenerator.open(encryptedFileOutputStream, new byte[4096])) {
                PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.UNCOMPRESSED);
                OutputStream compressedOutputStream = compressedDataGenerator.open(encryptedOutputStream);

                PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator();
                OutputStream literalOutputStream = literalDataGenerator.open(compressedOutputStream, PGPLiteralData.BINARY, new File(inputFilePath));

                try (InputStream inputFileStream = new BufferedInputStream(new FileInputStream(inputFilePath))) {
                    byte[] buffer = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = inputFileStream.read(buffer)) != -1) {
                        literalOutputStream.write(buffer, 0, bytesRead);
                    }
                } finally {
                    // Fermez explicitement les ressources PGPLiteralDataGenerator et PGPCompressedDataGenerator ici
                    literalOutputStream.close();
                    literalDataGenerator.close();
                    compressedOutputStream.close();
                    compressedDataGenerator.close();
                }
            } catch (IOException | PGPException e) {
                e.printStackTrace();
            }


        } catch (IOException | PGPException e) {
            e.printStackTrace();
        }
    }
    
    
    private static PGPPublicKey selectRecipientPublicKey(PGPPublicKeyRingCollection publicKeyRingCollection) {
        // Dans un cas réel, vous devrez implémenter la logique pour sélectionner la clé publique du destinataire
        // Dans cet exemple, je prends simplement la première clé publique disponible
        return publicKeyRingCollection.getKeyRings().next().getPublicKeys().next();
    }
    
   
    
/**********************************
 * 
 */
    public static void decryptFile(String encryptedFilePath, String privateKeyFilePath, String privateKeyPassword, String outputFilePath) {
        Security.addProvider(new BouncyCastleProvider());

        try (InputStream encryptedFileInputStream = new BufferedInputStream(new FileInputStream(encryptedFilePath));
             InputStream privateKeyInputStream = new BufferedInputStream(new FileInputStream(privateKeyFilePath));
             OutputStream outputFileOutputStream = new BufferedOutputStream(new FileOutputStream(outputFilePath))) {

            PGPObjectFactory pgpObjectFactory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(encryptedFileInputStream));
            PGPEncryptedDataList encryptedDataList = (PGPEncryptedDataList) pgpObjectFactory.nextObject();

            PGPPublicKeyEncryptedData encryptedData = (PGPPublicKeyEncryptedData) encryptedDataList.get(0);

            try (InputStream privateKeyStream = PGPUtil.getDecoderStream(privateKeyInputStream)) {
                PGPSecretKeyRingCollection secretKeys = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateKeyStream),
                        new JcaKeyFingerprintCalculator());

                PGPSecretKey secretKey = secretKeys.getSecretKey(encryptedData.getKeyID());
                
                PGPPrivateKey privateKey = secretKey.extractPrivateKey(
                        new org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(privateKeyPassword.toCharArray())
                );
                
                try (InputStream decryptedInputStream = encryptedData.getDataStream(
                        new JcePublicKeyDataDecryptorFactoryBuilder()
                        .setProvider("BC")
                        .build(privateKey));
                        
                        Reader reader = new InputStreamReader(decryptedInputStream, StandardCharsets.UTF_8);
                        Writer writer = new FileWriter(outputFilePath))
                {

                       char[] buffer = new char[4096];
                       int charsRead;
                       while ((charsRead = reader.read(buffer)) != -1) {
                           writer.write(buffer, 0, charsRead);
                       }
                   } catch (IOException | PGPException e) {
                       e.printStackTrace();
                   }
            }

        } catch (IOException | PGPException e) {
            e.printStackTrace();
        }
    }

 
}

我怎么称呼它

String inputFilePath = "C:/temp/source.txt";
String publicKeyFilePath = "C:/temp/public.key";
String outputFilePath = "C:/temp/source.pgp";
boolean armor = true;
boolean withIntegrityCheck = true;

PGPHelper.encryptFile(inputFilePath, publicKeyFilePath, outputFilePath, armor, withIntegrityCheck);

System.out.println("start decrypt");
String encryptedFilePath = "C:/temp/source.pgp";
String privateKeyFilePath = "C:/temp/secret.key";
String privateKeyPassword = "mypassword";
String outputFilePath = "C:/temp/dest2.txt";
  
PGPHelper.decryptFile(encryptedFilePath, privateKeyFilePath, privateKeyPassword, outputFilePath);
java encryption bouncycastle pgp
1个回答
0
投票

解密过程中缺少一些步骤。

你错过了:

  1. 获取压缩数据流,它没有压缩,但它有一些包装字节说明这一点。
  2. 从中获取文字数据流。

基本上,与您在压缩部分所做的相反。

这里有一些修复它的代码,而不是最终代码,缺少关闭中间流的行,代码还假设对象是其强制转换的类型。

    public static void decryptFile(String encryptedFilePath, String privateKeyFilePath, String privateKeyPassword, String outputFilePath) {
        Security.addProvider(new BouncyCastleProvider());

        try (InputStream encryptedFileInputStream = new BufferedInputStream(new FileInputStream(encryptedFilePath));
             InputStream privateKeyInputStream = new BufferedInputStream(new FileInputStream(privateKeyFilePath));
             OutputStream outputFileOutputStream = new BufferedOutputStream(new FileOutputStream(outputFilePath))) {

            PGPObjectFactory pgpObjectFactory = new JcaPGPObjectFactory(PGPUtil.getDecoderStream(encryptedFileInputStream));
            PGPEncryptedDataList encryptedDataList = (PGPEncryptedDataList) pgpObjectFactory.nextObject();

            PGPPublicKeyEncryptedData encryptedData = (PGPPublicKeyEncryptedData) encryptedDataList.get(0);

            try (InputStream privateKeyStream = PGPUtil.getDecoderStream(privateKeyInputStream)) {
                PGPSecretKeyRingCollection secretKeys = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateKeyStream),
                        new JcaKeyFingerprintCalculator());

                PGPSecretKey secretKey = secretKeys.getSecretKey(encryptedData.getKeyID());
                var a = 
                        new org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder().setProvider("BC").build(privateKeyPassword.toCharArray());
                System.out.println(a);
                System.out.println(secretKey);
                PGPPrivateKey privateKey = secretKey.extractPrivateKey(a);
                InputStream decryptedInputStream = encryptedData.getDataStream(
                        new JcePublicKeyDataDecryptorFactoryBuilder()
                        .setProvider("BC")
                        .build(privateKey));
                        PGPCompressedData pgpCompressedData = (PGPCompressedData) new JcaPGPObjectFactory(decryptedInputStream).nextObject();
                        InputStream compressedDataStream = new BufferedInputStream(pgpCompressedData.getDataStream());
                        JcaPGPObjectFactory pgpCompObjFac = new JcaPGPObjectFactory(compressedDataStream);
                
                try (   InputStream is = ((PGPLiteralData)pgpCompObjFac.nextObject()).getInputStream();
                        Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8);
                        Writer writer = new FileWriter(outputFilePath))
                {

                       char[] buffer = new char[4096];
                       int charsRead;
                       while ((charsRead = reader.read(buffer)) != -1) {
                           writer.write(buffer, 0, charsRead);
                       }
                   } catch (IOException e) {
                       e.printStackTrace();
                   }
            }

        } catch (IOException | PGPException e) {
            e.printStackTrace();
        }
    }

© www.soinside.com 2019 - 2024. All rights reserved.