Получение GPG-расшифровки для работы на Java (Bouncy Castle)
Позвольте мне начать с того, что я очень новичок в этом. Я пытаюсь использовать gpg изнутри Java, чтобы расшифровать зашифрованный файл.
Что я сделал успешно:
-
Если бы коллега зашифровал файл с использованием моего открытого ключа и его закрытого ключа и успешно расшифровал его.
-
Пошел другим способом
-
Если бы другой коллега попытался расшифровать файл, который не был для него: сбой (как ожидалось)
Мой ключ был сгенерирован следующим образом:
(gpg --version говорит мне, что я использую 1.4.5, и я использую Bouncy Castle 1.47)
gpg --gen-ley
Выберите опцию "DSA и Elgamal (по умолчанию)"
Заполните другие поля и сгенерируйте ключ.
Файл был зашифрован с использованием моего открытого ключа и другого секретного ключа. Я хочу расшифровать его. Для этого я написал следующий код Java. Я использую несколько устаревших методов, но я не могу понять, как правильно внедрять методы factory, необходимые для использования устаревших версий, поэтому, если у кого-то есть идея о реализации тех, которые я должен использовать, быть хорошим бонусом.
Security.addProvider(new BouncyCastleProvider());
PGPSecretKeyRingCollection secretKeyRing = new PGPSecretKeyRingCollection(new FileInputStream(new File("test-files/secring.gpg")));
PGPSecretKeyRing pgpSecretKeyRing = (PGPSecretKeyRing) secretKeyRing.getKeyRings().next();
PGPSecretKey secretKey = pgpSecretKeyRing.getSecretKey();
PGPPrivateKey privateKey = secretKey.extractPrivateKey("mypassword".toCharArray(), "BC");
System.out.println(privateKey.getKey().getAlgorithm());
System.out.println(privateKey.getKey().getFormat());
PGPObjectFactory pgpF = new PGPObjectFactory(
new FileInputStream(new File("test-files/test-file.txt.gpg")));
Object pgpObj = pgpF.nextObject();
PGPEncryptedDataList encryptedDataList = (PGPEncryptedDataList) pgpObj;
Iterator objectsIterator = encryptedDataList.getEncryptedDataObjects();
PGPPublicKeyEncryptedData publicKeyEncryptedData = (PGPPublicKeyEncryptedData) objectsIterator.next();
InputStream inputStream = publicKeyEncryptedData.getDataStream(privateKey, "BC");
Поэтому, когда я запускаю этот код, я узнаю, что мой алгоритм и формат для моего секретного ключа следующие:
Алгоритм: DSA
Формат: PKCS # 8
И затем он разбивается на последнюю строку:
Exception in thread "main" org.bouncycastle.openpgp.PGPException: error setting asymmetric cipher
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder.decryptSessionData(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder.access$000(Unknown Source)
at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder$2.recoverSessionData(Unknown Source)
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
at org.bouncycastle.openpgp.PGPPublicKeyEncryptedData.getDataStream(Unknown Source)
at TestBouncyCastle.main(TestBouncyCastle.java:74)
Вызвано: java.security.InvalidKeyException: неизвестный тип ключа, переданный ElGamal at org.bouncycastle.jcajce.provider.asymmetric.elgamal.CipherSpi.engineInit(Неизвестный источник) at org.bouncycastle.jcajce.provider.asymmetric.elgamal.CipherSpi.engineInit(Неизвестный источник) на javax.crypto.Cipher.init(DashoA13 *..) на javax.crypto.Cipher.init(DashoA13 *..) ... еще 8
Я открыт для многих предложений здесь: "не используйте gpg, используйте x вместо", чтобы "не использовать bouncy castle, используйте x вместо", чтобы что-либо между ними. Спасибо!
Ответы
Ответ 1
Я решил пойти с совершенно другим подходом, который заключается в том, чтобы отказаться от использования надувного замка вообще и просто использовать процесс выполнения. Для меня это решение работает и полностью устраняет сложность окружающего оживленного замка:
String[] gpgCommands = new String[] {
"gpg",
"--passphrase",
"password",
"--decrypt",
"test-files/accounts.txt.gpg"
};
Process gpgProcess = Runtime.getRuntime().exec(gpgCommands);
BufferedReader gpgOutput = new BufferedReader(new InputStreamReader(gpgProcess.getInputStream()));
BufferedReader gpgError = new BufferedReader(new InputStreamReader(gpgProcess.getErrorStream()));
После этого вам нужно помнить, что нужно слить поток ввода, поскольку ваш процесс выполняется, или ваша программа, вероятно, зависает в зависимости от того, сколько вы выводите. См. Мой ответ в этой теме (а также о Камероне Скиннере и Мэтью Уилсоне, который нашел меня на правильном пути) для немного большего контекста: Вызов GnuPG на Java через процесс выполнения для шифрования и расшифровать файлы - Расшифровка всегда зависает
Ответ 2
Если кому-то интересно узнать, как зашифровать и дешифровать файлы gpg с помощью библиотеки openPGP с помощью bouncy, проверьте приведенный ниже код java:
Ниже приведены 4 метода, которые вам понадобятся:
Ниже приведен метод чтения и импорта секретного ключа из файла .asc:
public static PGPSecretKey readSecretKeyFromCol(InputStream in, long keyId) throws IOException, PGPException {
in = PGPUtil.getDecoderStream(in);
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(in, new BcKeyFingerprintCalculator());
PGPSecretKey key = pgpSec.getSecretKey(keyId);
if (key == null) {
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
return key;
}
Ниже приведен метод чтения и импорта открытого ключа из файла .asc:
@SuppressWarnings("rawtypes")
public static PGPPublicKey readPublicKeyFromCol(InputStream in) throws IOException, PGPException {
in = PGPUtil.getDecoderStream(in);
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(in, new BcKeyFingerprintCalculator());
PGPPublicKey key = null;
Iterator rIt = pgpPub.getKeyRings();
while (key == null && rIt.hasNext()) {
PGPPublicKeyRing kRing = (PGPPublicKeyRing) rIt.next();
Iterator kIt = kRing.getPublicKeys();
while (key == null && kIt.hasNext()) {
PGPPublicKey k = (PGPPublicKey) kIt.next();
if (k.isEncryptionKey()) {
key = k;
}
}
}
if (key == null) {
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
return key;
}
Ниже приведены два способа дешифрования и шифрования файлов gpg:
public void decryptFile(InputStream in, InputStream secKeyIn, InputStream pubKeyIn, char[] pass) throws IOException, PGPException, InvalidCipherTextException {
Security.addProvider(new BouncyCastleProvider());
PGPPublicKey pubKey = readPublicKeyFromCol(pubKeyIn);
PGPSecretKey secKey = readSecretKeyFromCol(secKeyIn, pubKey.getKeyID());
in = PGPUtil.getDecoderStream(in);
JcaPGPObjectFactory pgpFact;
PGPObjectFactory pgpF = new PGPObjectFactory(in, new BcKeyFingerprintCalculator());
Object o = pgpF.nextObject();
PGPEncryptedDataList encList;
if (o instanceof PGPEncryptedDataList) {
encList = (PGPEncryptedDataList) o;
} else {
encList = (PGPEncryptedDataList) pgpF.nextObject();
}
Iterator<PGPPublicKeyEncryptedData> itt = encList.getEncryptedDataObjects();
PGPPrivateKey sKey = null;
PGPPublicKeyEncryptedData encP = null;
while (sKey == null && itt.hasNext()) {
encP = itt.next();
secKey = readSecretKeyFromCol(new FileInputStream("PrivateKey.asc"), encP.getKeyID());
sKey = secKey.extractPrivateKey(new BcPBESecretKeyDecryptorBuilder(new BcPGPDigestCalculatorProvider()).build(pass));
}
if (sKey == null) {
throw new IllegalArgumentException("Secret key for message not found.");
}
InputStream clear = encP.getDataStream(new BcPublicKeyDataDecryptorFactory(sKey));
pgpFact = new JcaPGPObjectFactory(clear);
PGPCompressedData c1 = (PGPCompressedData) pgpFact.nextObject();
pgpFact = new JcaPGPObjectFactory(c1.getDataStream());
PGPLiteralData ld = (PGPLiteralData) pgpFact.nextObject();
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
InputStream inLd = ld.getDataStream();
int ch;
while ((ch = inLd.read()) >= 0) {
bOut.write(ch);
}
//System.out.println(bOut.toString());
bOut.writeTo(new FileOutputStream(ld.getFileName()));
//return bOut;
}
public static void encryptFile(OutputStream out, String fileName, PGPPublicKey encKey) throws IOException, NoSuchProviderException, PGPException {
Security.addProvider(new BouncyCastleProvider());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP);
PGPUtil.writeFileToLiteralData(comData.open(bOut), PGPLiteralData.BINARY, new File(fileName));
comData.close();
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(new BcPGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.TRIPLE_DES).setSecureRandom(new SecureRandom()));
cPk.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(encKey));
byte[] bytes = bOut.toByteArray();
OutputStream cOut = cPk.open(out, bytes.length);
cOut.write(bytes);
cOut.close();
out.close();
}
Теперь вот как вызвать/запустить выше:
try {
decryptFile(new FileInputStream("encryptedFile.gpg"), new FileInputStream("PrivateKey.asc"), new FileInputStream("PublicKey.asc"), "yourKeyPassword".toCharArray());
PGPPublicKey pubKey = readPublicKeyFromCol(new FileInputStream("PublicKey.asc"));
encryptFile(new FileOutputStream("encryptedFileOutput.gpg"), "fileToEncrypt.txt", pubKey);
} catch (PGPException e) {
fail("exception: " + e.getMessage(), e.getUnderlyingException());
}
Ответ 3
Первый Google результат this. Похоже, вы пытаетесь расшифровать данные ElGamal, но вы не передаете ключ ElGamal.
Есть две простые возможности:
- В вашей коллекции ключей есть несколько ключей.
- В вашей клавиатуре есть подразделы.
Вы выбрали DSA с шифрованием ElGamal, поэтому я подозреваю, что, по крайней мере, последнее: подключи подписываются главным ключом; ElGamal не является алгоритмом подписи (я не знаю, может ли DSA и ElGamal использовать один и тот же ключ, но обычно рекомендуется использовать разные ключи для разных целей).
Я думаю, вам нужно что-то вроде этого (также, secretKeyRing
следует переименовать в secretKeyRingCollection
):
PGPSecretKey secretKey = secretKeyRing.getSecretKey(publicKeyEncryptedData.getKeyID());
Ответ 4
Для любого, кто ищет альтернативное решение, см. fooobar.com/info/539225/...
final InputStream plaintextStream = BouncyGPG
.decryptAndVerifyStream()
.withConfig(keyringConfig)
.andRequireSignatureFromAllKeys("[email protected]")
.fromEncryptedInputStream(cipherTextStream)
Короче говоря: Bouncycastle - это программирование, часто много грузовое культовое программирование, и я написал библиотеку, чтобы изменить это.