Bouncy Castle PGP sign and encrypt - ambiguous signature data

48 Views Asked by At

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();
0

There are 0 best solutions below