title: PGP Encrypt using BouncyCastle in Java
body: <p>I was given a task to build a java method to encrypt data (String or InputStream) using PGP. I have generated a test public key, private key with passphrase following the guide <a href="https://edoceo.com/sys/gpg" rel="nofollow noreferrer">here</a>. I then exported the public key using the command below and copy and pasted it to my java code.</p>
  <pre><code>gpg --armor --output pubkey.txt --export 'Your Name'
  </code></pre>
  <p>I am able to encrypt a file using the command below</p>
  <pre><code>gpg --encrypt --armor -r 'Your Name' plaintext.txt
  </code></pre>
  <p>And I get the below content which is what I'm trying to achieve in my java program. I might need to sign it later as part of the requirement but all I want to do for now is to be able to successfully encrypt it like this.</p>
  <pre><code>-----BEGIN PGP MESSAGE-----
  Version: GnuPG v2.0.22 (GNU/Linux)
  
  hQEMA0PxXau0Q30VAQf/RuWsN3f4L2HW2GJWOZUjetJsw0odXYbDc7Sug1gZULP8
  I0KRrvxnHgiiJgSlBZsws8E8iB1/LDCYJ8oJGj6olicz83iUT8VLdzdJZlc0+96/
  BHAvtSTtEv2PWZlh307nU+Zn9cuGAccaijyekCosS5/0JpDyXSFefsLTexMgphAL
  veXsxtsISyUU6S0xUux6Ac9HgUWTpCrlNaSdqBN1bk7y8YuvbZgbQ5akwY5FEbq1
  f9rxmgXgEgz3N+7f8n5yN2OvWiEyXb+qngVgDLzysD8NTtKDqtw5nViscvVF1h3v
  AebdxYxOKGYnWk6XAWhpIgIZdY0ZXG0yu9NJH5VfLtJSAc3c6d2/Nhb7g+k+f2Mn
  srZW6XzHCeyGQQqSfr5YJfyUVdsW12udmhnc+ErbRkz84oDkMvFaxes6+2AAKrP/
  jdWXsp4fTPl454m+tG5ec/Kn0Q==
  =cZH2
  -----END PGP MESSAGE-----
  </code></pre>
  <p>The java method I need to build accepts a Public Key as a String parameter where I then use the following method to convert it to a PGPPublicKey.</p>
  <pre><code>  private static PGPPublicKey getPublicKey(String keyAscii) throws IOException, PGPException, Exception {
      InputStream encodedKey = new ByteArrayInputStream(keyAscii.getBytes());
      InputStream decodedKey = PGPUtil.getDecoderStream(encodedKey);
  
      JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(decodedKey);
      decodedKey.close();
  
      PGPPublicKey key = null;
      Iterator&lt;PGPPublicKeyRing&gt; rIt = pgpPub.getKeyRings();
      while (key == null &amp;&amp; rIt.hasNext()) {
        PGPPublicKeyRing kRing = rIt.next();
        Iterator&lt;PGPPublicKey&gt; kIt = kRing.getPublicKeys();
  
        while (key == null &amp;&amp; kIt.hasNext()) {
          PGPPublicKey k = kIt.next();
  
          if (k.isEncryptionKey()) {
            key = k;
          }
        }
      }
      if (key == null) {
        throw new Exception(&quot;Can't find key&quot;);
      }
      return key;
    }
  </code></pre>
  <p>However, when I run the java program, I get an error &quot;exception constructing public key&quot; on the following line of code.</p>
  <pre><code>      OutputStream cOut = encGen.open(encOut, new byte[4096]);
  </code></pre>
  <p>Complete error below</p>
  <pre><code>org.bouncycastle.openpgp.PGPException: exception constructing public key
      at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.getPublicKey(Unknown Source)
      at org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator.encryptSessionInfo(Unknown Source)
      at org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator.generate(Unknown Source)
      at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
      at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
      at pgp.PgpImpl.encrypt(PgpImpl.java:84)
      at pgp.PgpImpl.main(PgpImpl.java:216)
  Caused by: java.security.NoSuchProviderException: no such provider: BC
      at sun.security.jca.GetInstance.getService(GetInstance.java:83)
      at sun.security.jca.GetInstance.getInstance(GetInstance.java:206)
      at java.security.KeyFactory.getInstance(KeyFactory.java:211)
      at org.bouncycastle.jcajce.util.NamedJcaJceHelper.createKeyFactory(Unknown Source)
      at org.bouncycastle.openpgp.operator.jcajce.OperatorHelper.createKeyFactory(Unknown Source)
      at org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter.implGeneratePublic(Unknown Source)
      ... 7 more
  </code></pre>
  <p>I followed the sample <a href="https://stackoverflow.com/questions/61826843/java-pgp-encryption-using-bouncy-castle">here</a> but it didn't provide any information on how to construct the publickey coming from a String.</p>
  <p>Here's my code so far.</p>
  <pre><code>package pgp;
  
  import java.io.ByteArrayInputStream;
  import java.io.ByteArrayOutputStream;
  import java.io.IOException;
  
  import java.io.InputStream;
  import java.io.OutputStream;
  
  import java.security.SecureRandom;
  
  import java.util.Date;
  import java.util.Iterator;
  
  import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
  import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
  import org.bouncycastle.openpgp.PGPException;
  import org.bouncycastle.openpgp.PGPLiteralData;
  import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
  import org.bouncycastle.openpgp.PGPPrivateKey;
  import org.bouncycastle.openpgp.PGPPublicKey;
  import org.bouncycastle.openpgp.PGPPublicKeyRing;
  import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
  import org.bouncycastle.openpgp.PGPSecretKey;
  import org.bouncycastle.openpgp.PGPUtil;
  import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
  import org.bouncycastle.openpgp.operator.PGPDataEncryptorBuilder;
  import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
  import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
  import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
  import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
  import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
  
  import org.bouncycastle.jce.provider.BouncyCastleProvider;
  import org.bouncycastle.openpgp.PGPSecretKeyRing;
  import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
  import org.bouncycastle.openpgp.jcajce.JcaPGPPublicKeyRingCollection;
  
  public class PgpImpl {
  
    public PgpImpl() {
    }
  
    private static String encrypt(byte[] data, PGPPublicKey encryptionKey) throws Exception {
      String step = &quot;Step-0&quot;;
      try {
        step = &quot;Step-1&quot;;
        PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
            new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
            .setWithIntegrityPacket(true)
            .setSecureRandom(new SecureRandom())
            .setProvider(&quot;BC&quot;));
        
        step = &quot;Step-2&quot;;
        encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey)
            .setSecureRandom(new SecureRandom()).setProvider(&quot;BC&quot;));
  
        step = &quot;Step-3&quot;;
        ByteArrayOutputStream encOut = new ByteArrayOutputStream();
  
        step = &quot;Step-4&quot;;
        // create an indefinite length encrypted stream
        OutputStream cOut = encGen.open(encOut, new byte[4096]);
        step = &quot;Step-5&quot;;
        // write out the literal data
        PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
        OutputStream pOut = lData.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length,
            new Date());
        pOut.write(data);
        pOut.close();
        // finish the encryption
        cOut.close();
        step = &quot;Step-6&quot;;
        
        return new String(encOut.toByteArray());
      } catch (Exception e) {
        //throw new Exception(String.format(&quot;%s: %s&quot;, e.getMessage(), step));
        e.printStackTrace();
      }
      return new String(step);
    }
  
    private static PGPPublicKey getPublicKey(String keyAscii) throws IOException, PGPException, Exception {
      InputStream encodedKey = new ByteArrayInputStream(keyAscii.getBytes());
      InputStream decodedKey = PGPUtil.getDecoderStream(encodedKey);
  
      JcaPGPPublicKeyRingCollection pgpPub = new JcaPGPPublicKeyRingCollection(decodedKey);
      decodedKey.close();
  
      PGPPublicKey key = null;
      Iterator&lt;PGPPublicKeyRing&gt; rIt = pgpPub.getKeyRings();
      while (key == null &amp;&amp; rIt.hasNext()) {
        PGPPublicKeyRing kRing = rIt.next();
        Iterator&lt;PGPPublicKey&gt; kIt = kRing.getPublicKeys();
  
        while (key == null &amp;&amp; kIt.hasNext()) {
          PGPPublicKey k = kIt.next();
  
          if (k.isEncryptionKey()) {
            key = k;
          }
        }
      }
      if (key == null) {
        throw new Exception(&quot;Can't find key&quot;);
      }
      return key;
    }
  
    public static void main(String[] args) {
      String publicKey = &quot;-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n&quot; + &quot;Version: GnuPG v2.0.22 (GNU/Linux)\r\n&quot;
          + &quot;\r\n&quot; + &quot;mQENBGA1A70BCADK8BnH6GgMbnS1TJSpJvgH+D9VIw0sN8XZWQsUmWWV9WSqhqXt\r\n&quot;
          + &quot;5wNC4XJDcaWtMCapaekQXV5S52T7QCxAz/E5oZzIDe+IUCHQz0WUs37S4Wnw+SZ6\r\n&quot;
          + &quot;QNPXOFaC4nNByRq6gvg0+wtD2Bo/3OJur3f0O0aRSHNiwfd0PdFgG0NU5vGV9PwE\r\n&quot;
          + &quot;xbTMpGssWexIC0MwJaYfJkxzov33CkwLaITvBTCn/J3oeX6JarMkgpurp1FAW0Jk\r\n&quot;
          + &quot;YzgGMOOxwuEVedwP4NtEPce+UtLv2NHHfqsW6xSxjWqsJkMdJ9afzu1jvn9M6e0j\r\n&quot;
          + &quot;MOTmPUCYVCioXK59It8ngN8NLtwaPgfnBwcbABEBAAG0BWFsbGVuiQE5BBMBAgAj\r\n&quot;
          + &quot;BQJgNQO9AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AACgkQxzGJxIrjAlxq\r\n&quot;
          + &quot;aggAgoiO82MZZMHyhZ3uLD4qTQ2vsT6+onhCr83kw0eFNM5AH0r3xlVARXHaViWC\r\n&quot;
          + &quot;SFutpb/34lrCTpJfLfKwdFU2bJP2SI3hAujtTg45UFklswu6GZaqQno6JKkZM4hw\r\n&quot;
          + &quot;ltFIXU1dMpIud7nsJ2QU46TI97n+HeD7DvOSGY/CFPnNot0YFHxXCKtHdPHk8JO3\r\n&quot;
          + &quot;JdOG0X90Yi9XSI1USv8HL/WjOTvhSqo7Qps2MpcUZrfNsa0H9Adk9xVYiz0nKNPY\r\n&quot;
          + &quot;qLQxFAiHb34vdav4e28anJ8th93SfiRn5OFK2G6R3DlhLlvn3h1dSAT6vSOrzx80\r\n&quot;
          + &quot;EylyMg2BIbRfp+JEgwCMf2V8X7kBDQRgNQO9AQgA3qV0wYvdH5M4XBzVwDtuGuIs\r\n&quot;
          + &quot;+GRcSRQqmvnt94e8ZE4Kv2w2Pf/JxPMwnPC92lVRypdOjmTZrT3R0z7g+D8mU5A9\r\n&quot;
          + &quot;o/CPvvSShA8Jh3z69S+hLP0nSaajsVsQlBGrI8ehI1EVJDsNh15PZrl27OK0aBb4\r\n&quot;
          + &quot;Fp0BYm0D2HaLnQPD4/jhTR13i1mt5E5hmBwiZiiWr/Wa1i1g1o/XaT4CApu91zgg\r\n&quot;
          + &quot;cmJBz9DL/C2hYC5lkp/cz5IJYp5BsvfA2lwamca33aHxFj8+Bz3+REWa8zvEqQ9U\r\n&quot;
          + &quot;a26RbPVjkeGChwNWLxNTuj1rNDdqB/KZO6iM02orqW86L45SKTBWYqPcpD7GeQAR\r\n&quot;
          + &quot;AQABiQEfBBgBAgAJBQJgNQO9AhsMAAoJEMcxicSK4wJcOLEIAMevvOk9iZ13T3yA\r\n&quot;
          + &quot;+ZW8mWKKE5aXy93VPKAvplP/WlW2VVGeb+6rEkFFsdN4doYIJPEIr+U7K0GDR6XX\r\n&quot;
          + &quot;TKLyI7BtUZPegOdjgcFWVGFnFogDnkrO+IPY+JUy1VMg8fGStThfa2dYEgd7yqpq\r\n&quot;
          + &quot;fZ97q5RQun1B+wyRdPDgC39roSGEwtXbRCZnuSMVNT7J9a2qnXkenvQRSoPjY7wQ\r\n&quot;
          + &quot;tn1wUfnHyjyS9OzfXTSHDi2A5JDRCh5L/V7Q93/P5Isv/U4QzIWudGM6AjuaoZ6i\r\n&quot;
          + &quot;chksRI9EchNKnSut9ebTyTkIJ80sB7Eyfp8TtORAnz8/Xf8A8aYD73r9rD4poSmo\r\n&quot; + &quot;FV15pP8=\r\n&quot; + &quot;=Yc74\r\n&quot;
          + &quot;-----END PGP PUBLIC KEY BLOCK-----&quot;;
  
      try {
        PGPPublicKey key = getPublicKey(publicKey);
        System.out.println(encrypt(&quot;Test&quot;.getBytes(), key));
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (PGPException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }
  </code></pre>
  <p>Appreciate any help.</p>
  <p>UPDATE #1: After getting the stacktrace, I found out that the error is due to an invalid provider which I then change using</p>
  <pre><code>BouncyCastleProvider provider = new BouncyCastleProvider();
  </code></pre>
  <p>So I had to change all reference to the provider.</p>
  <pre><code>private static String encrypt(byte[] data, PGPPublicKey encryptionKey) {
      BouncyCastleProvider provider = new BouncyCastleProvider();
      String step = &quot;Step-0&quot;;
      try {
          step = &quot;Step-1&quot;;
          PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator(
                  new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256)
                  .setWithIntegrityPacket(true)
                  .setSecureRandom(new SecureRandom())
                  .setProvider(provider));
          
          step = &quot;Step-2&quot;;
          encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encryptionKey)
                  .setSecureRandom(new SecureRandom()).setProvider(provider));
  
          step = &quot;Step-3&quot;;
          ByteArrayOutputStream encOut = new ByteArrayOutputStream();
  
          step = &quot;Step-4&quot;;
          // create an indefinite length encrypted stream
          OutputStream cOut = encGen.open(encOut, new byte[1 &lt;&lt; 16]);
          step = &quot;Step-5&quot;;
          // write out the literal data
          PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator();
          OutputStream pOut = lData.open(cOut, PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, data.length,
                  new Date());
          pOut.write(data);
          pOut.close();
          // finish the encryption
          cOut.close();
          step = &quot;Step-6&quot;;
          
          return new String(encOut.toByteArray());
      } catch (Exception e) {
          //throw new Exception(String.format(&quot;%s: %s&quot;, e.getMessage(), step));
          e.printStackTrace();
      }
      return new String(&quot;&quot;);
  }
  </code></pre>
  <p>But now I'm getting a different error.</p>
  <pre><code>org.bouncycastle.openpgp.PGPException: Exception creating cipher
  
      at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
      at org.bouncycastle.openpgp.PGPEncryptedDataGenerator.open(Unknown Source)
      at pgp.PgpImpl.encrypt(PgpImpl.java:85)
      at pgp.PgpImpl.main(PgpImpl.java:217)
  Caused by: org.bouncycastle.openpgp.PGPException: invalid key: Illegal key size
      at org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder$MyPGPDataEncryptor.&lt;init&gt;(Unknown Source)
      at org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder.build(Unknown Source)
      ... 4 more
  Caused by: java.security.InvalidKeyException: Illegal key size
      at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1034)
      at javax.crypto.Cipher.init(Cipher.java:1367)
      at javax.crypto.Cipher.init(Cipher.java:1301)
      ... 6 more
  </code></pre>
  <p>UPDATE#2: Did a bit of research and came across <a href="https://help.mulesoft.com/s/article/Illegal-key-size-Error-when-using-PGP" rel="nofollow noreferrer">this</a>. Followed the instructions there and got everything working.</p>