I want to encrypt / decrypt file using Java and GNUPG utility. I am trying to encrypt the file in Java using bouncycastle library and later on want to decrypt using GNUPG to make sure encryption / decryption process works fine.
Using gnupg, I have created the public and private keys using RSA 2048.
The encryption works fine and I am able to decrypt it but when I am signing (with my private key) and encrypting it(with recipient public key) and later on tries to decrypt using GNUPG utility, I am getting the following error
gpg: old style (PGP 2.x) signature
gpg: can't handle this ambiguous signature data
Is there a version mismatch using bounty castle library and GNUPG and is there any alternative in Java to sign/encrypt using GNUPG ?
public void encrypt(OutputStream encryptOut, InputStream clearIn, long length, InputStream publicKeyIn)
throws IOException, PGPException {
String signingPrivateKeyPassword = "password";
PGPCompressedDataGenerator compressedDataGenerator =
new PGPCompressedDataGenerator(compressionAlgorithm);
PGPEncryptedDataGenerator pgpEncryptedDataGenerator = new PGPEncryptedDataGenerator(
// This bit here configures the encrypted data generator
new JcePGPDataEncryptorBuilder(symmetricKeyAlgorithm)
.setWithIntegrityPacket(withIntegrityCheck)
.setSecureRandom(new SecureRandom())
.setProvider(BouncyCastleProvider.PROVIDER_NAME)
);
// Adding public key
pgpEncryptedDataGenerator.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(CommonUtils.getPublicKey(publicKeyIn)));
if (armor) {
encryptOut = new ArmoredOutputStream(encryptOut);
}
OutputStream cipherOutStream = pgpEncryptedDataGenerator.open(encryptOut, new byte[bufferSize]);
InputStream keyInputStream = Files.newInputStream(new File("path to private key").toPath());
PGPSecretKey secretKey = CommonUtils.findSecretKey(keyInputStream);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
.setProvider(BouncyCastleProvider.PROVIDER_NAME).build(signingPrivateKeyPassword.toCharArray());
PGPPrivateKey privateKey = secretKey.extractPrivateKey(keyDecryptor);
int algorithm = secretKey.getPublicKey().getAlgorithm();
PGPSignatureGenerator sigGen = new PGPSignatureGenerator(
new JcaPGPContentSignerBuilder(algorithm, PGPUtil.SHA512).setProvider(BouncyCastleProvider.PROVIDER_NAME));
sigGen.init(PGPSignature.BINARY_DOCUMENT, privateKey);
Iterator it = secretKey.getPublicKey().getUserIDs();
if (it.hasNext()) {
PGPSignatureSubpacketGenerator ssg = new PGPSignatureSubpacketGenerator();
ssg.setSignerUserID(false, (String) it.next());
sigGen.setHashedSubpackets(ssg.generate());
}
/* Output the standard header */
sigGen.generateOnePassVersion(false).encode(cipherOutStream);
OutputStream compressedOutStream = compressedDataGenerator.open(cipherOutStream);
byte[] data = CommonUtils.copyAsLiteralData(compressedOutStream, clearIn, length, bufferSize);
// Closing all output streams in sequence
/* Calculate signature and output it */
sigGen.update(data);
sigGen.generate().encode(compressedOutStream);
compressedDataGenerator.close();
cipherOutStream.close();
encryptOut.close();
}
public byte[] encrypt(byte[] clearData, InputStream pubicKeyIn) throws PGPException, IOException {
ByteArrayInputStream inputStream = new ByteArrayInputStream(clearData);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
encrypt(outputStream, inputStream, clearData.length, pubicKeyIn);
return outputStream.toByteArray();
}
static PGPPublicKey getPublicKey(InputStream keyInputStream) throws IOException, PGPException {
PGPPublicKeyRingCollection pgpPublicKeyRings = new PGPPublicKeyRingCollection(
PGPUtil.getDecoderStream(keyInputStream), new JcaKeyFingerprintCalculator());
Iterator<PGPPublicKeyRing> keyRingIterator = pgpPublicKeyRings.getKeyRings();
while (keyRingIterator.hasNext()) {
PGPPublicKeyRing pgpPublicKeyRing = keyRingIterator.next();
Optional<PGPPublicKey> pgpPublicKey = extractPGPKeyFromRing(pgpPublicKeyRing);
if (pgpPublicKey.isPresent()) {
return pgpPublicKey.get();
}
}
throw new PGPException("Invalid public key");
}
private static Optional<PGPPublicKey> extractPGPKeyFromRing(PGPPublicKeyRing pgpPublicKeyRing) {
for (PGPPublicKey publicKey : pgpPublicKeyRing) {
if (publicKey.isEncryptionKey()) {
return Optional.of(publicKey);
}
}
return Optional.empty();
}
public static PGPSecretKey findSecretKey(InputStream in) throws IOException, PGPException {
in = PGPUtil.getDecoderStream(in);
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(in),
new JcaKeyFingerprintCalculator());
Iterator<PGPSecretKeyRing> keyRingIterator = pgpSec.getKeyRings();
while (keyRingIterator.hasNext()) {
PGPSecretKeyRing pgpSecretKeyRing = keyRingIterator.next();
Optional<PGPSecretKey> pgpSecretKey = extractPGPSecretKeyFromRing(pgpSecretKeyRing);
if (pgpSecretKey.isPresent()) {
return pgpSecretKey.get();
}
}
throw new PGPException("Invalid Secret key");
}
private static Optional<PGPSecretKey> extractPGPSecretKeyFromRing(PGPSecretKeyRing pgpSecretKeyRing) {
for (PGPSecretKey secretKey : pgpSecretKeyRing) {
if (secretKey.isSigningKey()) {
return Optional.of(secretKey);
}
}
return Optional.empty();
}
Calling the program with below code
BCPGPUtils pgpEncryptionUtil = BCPGPUtils.builder()
.armor(true)
.compressionAlgorithm(CompressionAlgorithmTags.ZIP)
.symmetricKeyAlgorithm(SymmetricKeyAlgorithmTags.AES_256)
.withIntegrityCheck(true)
.build();
File initialFile = new File("public_key.txt");
InputStream targetStream = new FileInputStream(initialFile);
String str = "test string";
byte[] output = pgpEncryptionUtil.encrypt(str.getBytes(), targetStream);
File file = new File("encrypted_file.txt");
OutputStream os = new FileOutputStream(file);
// Starting writing the bytes in it
os.write(output);
os.close();