我需要在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);
解密过程中缺少一些步骤。
你错过了:
基本上,与您在压缩部分所做的相反。
这里有一些修复它的代码,而不是最终代码,缺少关闭中间流的行,代码还假设对象是其强制转换的类型。
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();
}
}