How to use pgpainless-core

Document https://pgpainless.readthedocs.io/en/latest/quickstart.html Setup // If you use Gradle ... dependencies { ... implementation "org.pgpainless:pgpainless-core:1.7.2" ... } // If you use Maven ... ... org.pgpainless pgpainless-core 1.7.2 ... What's ASCII Armor ASCII armor is a layer of radix64 encoding that can be used to wrap binary OpenPGP data in order to make it save to transport via text-based channels (e.g. email bodies). The way in which ASCII armor can be applied depends on the type of data that you want to protect. The easies way to ASCII armor an OpenPGP key or certificate is by using PGPainless’ asciiArmor() method: PGPPublicKey certificate = ...; String asciiArmored = PGPainless.asciiArmor(certificate); How to Setup the ProducerOptions when Encrypt Suppose you have a FileInputStream or ByteArrayInputStream. Then also you need to have a OutputStream, like OutputStream outputStream = Files.newOutputStream(outputFileLocation, StandardOpenOption.CREATE_NEW); Before you call the Painless.encryptAndOrSign(), you need to build up the ProducerOptions. It will be like /** The secret key ring used for decrypting and signing. */ private final PGPSecretKeyRing secretKeyRing = ...; /** The public key ring used for encrypting. */ private final PGPPublicKeyRing publicKeyRing = ...; /** Stores the password securely, required to access the secret key. */ private final SecretKeyRingProtector secretKeyRingProtector = ...; SigningOptions signOptions = SigningOptions.get().addInlineSignature(secretKeyRingProtector, secretKeyRing); when you try to build your secretKeyRing and secretKeyRingProtector, you probably will get it from your properties like this.secretKeyRing = armorStringKeyringLoader.load(properties.getSecretKey(), PGPSecretKeyRing.class) this.publicKeyRing = armorStringKeyringLoader.load(properties.getPublicKey(), PGPPublicKeyRing.class) In order to load the key, all you need to do is to get the BufferedInputStream, then protected T readKeyRing(BufferedInputStream keyInputStream, Class clazz) throws IOException, KeyRingLoaderException { if (clazz.isAssignableFrom(PGPSecretKeyRing.class)) { return clazz.cast(PGPainless.readKeyRing().secretKeyRing(keyInputStream)); } else if (clazz.isAssignableFrom(PGPPublicKeyRing.class)) { return clazz.cast(PGPainless.readKeyRing().publicKeyRing(keyInputStream)); } throw new KeyRingLoaderException( String.format("Unsupported key ring type [class=%s]", clazz.getSimpleName())); } } Create that BufferedInputStream from string can be like public BufferedInputStream getBufferedInputStreamForKey(String armorKey) throws Exception { // return a new BufferedInputStream with the key as the content. ByteSource byteSource = ByteSource.wrap(armorKey.getBytes()); return new BufferedInputStream(byteSource.openStream()); } Or create that BufferedInputStream from file can be like public BufferedInputStream getBufferedInputStreamForKey(String armorKeyfileLocation) throws IOException { // Loads the ascii armor key file from the file system. return (BufferedInputStream) Files.asByteSource(new File(armorKeyfileLocation)).openBufferedStream(); } Now lets build the encryptionOptions. You only need to add the recipient's public key as the PGPPublicKey certificate = ...; EncryptionOptions encOptions = EncryptionOptions.get().addRecipient(certificate); Same philosophy to load the PGPPublicKey via PGPainless.readKeyRing().publicKeyRing(keyInputStream). So now we can put both of them into the ProducerOptions options like ProducerOptions options = ProducerOptions.signAndEncrypt(signingOptions, encryptionOptions); If you want to ASCII armor ciphertext, you can enable ASCII armoring during encrypting/signing by requesting PGPainless to armor the result: producerOptions.setAsciiArmor(true); // enable armoring File Association: When you encrypt data, you might want to include the original file name so that the recipient knows what the encrypted content represents. The setFileName method allows you to set this file name. Metadata: Including the file name as metadata can help the recipient understand the context of the encrypted data, especially if multiple files are being encrypted and sent together. So you can do like: producerOptions.setFileName(outputFileLocation.toString()). Encrypt with the OutputStream EncryptionStream encryptionStream = PGPainless.encryptAndOrSign() .onOutputStream(outputStream) .withOptions(producerOptions); Encrypt the file data If you already have an existing file, you can encrypt it to another file location like InputStream plaintext = ...; // The data that will be encrypted and/or signed ByteArrayInputSt

Mar 9, 2025 - 02:51
 0
How to use pgpainless-core

Document

https://pgpainless.readthedocs.io/en/latest/quickstart.html

Setup

// If you use Gradle
...
dependencies {
    ...
    implementation "org.pgpainless:pgpainless-core:1.7.2"
    ...
}

// If you use Maven
...

    ...
    
        org.pgpainless
        pgpainless-core
        1.7.2
    
    ...

What's ASCII Armor

ASCII armor is a layer of radix64 encoding that can be used to wrap binary OpenPGP data in order to make it save to transport via text-based channels (e.g. email bodies).

The way in which ASCII armor can be applied depends on the type of data that you want to protect. The easies way to ASCII armor an OpenPGP key or certificate is by using PGPainless’ asciiArmor() method:

PGPPublicKey certificate = ...;
String asciiArmored = PGPainless.asciiArmor(certificate);

How to Setup the ProducerOptions when Encrypt

  • Suppose you have a FileInputStream or ByteArrayInputStream. Then also you need to have a OutputStream, like
OutputStream outputStream =
                        Files.newOutputStream(outputFileLocation, StandardOpenOption.CREATE_NEW);
  • Before you call the Painless.encryptAndOrSign(), you need to build up the ProducerOptions. It will be like
/** The secret key ring used for decrypting and signing. */
private final PGPSecretKeyRing secretKeyRing = ...;

/** The public key ring used for encrypting. */
private final PGPPublicKeyRing publicKeyRing = ...;

/** Stores the password securely, required to access the secret key. */
private final SecretKeyRingProtector secretKeyRingProtector = ...;

SigningOptions signOptions = SigningOptions.get().addInlineSignature(secretKeyRingProtector, secretKeyRing);
  • when you try to build your secretKeyRing and secretKeyRingProtector, you probably will get it from your properties like
this.secretKeyRing = armorStringKeyringLoader.load(properties.getSecretKey(), PGPSecretKeyRing.class)
this.publicKeyRing = armorStringKeyringLoader.load(properties.getPublicKey(), PGPPublicKeyRing.class)

In order to load the key, all you need to do is to get the BufferedInputStream, then

protected  T readKeyRing(BufferedInputStream keyInputStream, Class clazz) throws IOException, KeyRingLoaderException {
    if (clazz.isAssignableFrom(PGPSecretKeyRing.class)) {
        return clazz.cast(PGPainless.readKeyRing().secretKeyRing(keyInputStream));
    } else if (clazz.isAssignableFrom(PGPPublicKeyRing.class)) {
        return clazz.cast(PGPainless.readKeyRing().publicKeyRing(keyInputStream));
    } throw new KeyRingLoaderException(
        String.format("Unsupported key ring type [class=%s]", clazz.getSimpleName()));
    }
}

Create that BufferedInputStream from string can be like

public BufferedInputStream getBufferedInputStreamForKey(String armorKey) throws Exception {
        // return a new BufferedInputStream with the key as the content.
        ByteSource byteSource = ByteSource.wrap(armorKey.getBytes());
        return new BufferedInputStream(byteSource.openStream());
    }

Or create that BufferedInputStream from file can be like

public BufferedInputStream getBufferedInputStreamForKey(String armorKeyfileLocation) throws IOException {
    // Loads the ascii armor key file from the file system.
    return (BufferedInputStream) Files.asByteSource(new File(armorKeyfileLocation)).openBufferedStream();
}
  • Now lets build the encryptionOptions. You only need to add the recipient's public key as the
PGPPublicKey certificate = ...;
EncryptionOptions encOptions = EncryptionOptions.get().addRecipient(certificate);

Same philosophy to load the PGPPublicKey via PGPainless.readKeyRing().publicKeyRing(keyInputStream).

  • So now we can put both of them into the ProducerOptions options like
ProducerOptions options = ProducerOptions.signAndEncrypt(signingOptions, encryptionOptions);

If you want to ASCII armor ciphertext, you can enable ASCII armoring during encrypting/signing by requesting PGPainless to armor the result:

producerOptions.setAsciiArmor(true); // enable armoring

File Association: When you encrypt data, you might want to include the original file name so that the recipient knows what the encrypted content represents. The setFileName method allows you to set this file name.
Metadata: Including the file name as metadata can help the recipient understand the context of the encrypted data, especially if multiple files are being encrypted and sent together. So you can do like:
producerOptions.setFileName(outputFileLocation.toString()).

Encrypt with the OutputStream

EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
        .onOutputStream(outputStream)
        .withOptions(producerOptions);

Encrypt the file data

If you already have an existing file, you can encrypt it to another file location like

InputStream plaintext = ...; // The data that will be encrypted and/or signed
ByteArrayInputStream contentToEncrypt = ...; // can also be the ByteArrayInputStream 
OutputStream ciphertext = Files.newOutputStream(Path outputFileLocation, StandardOpenOption.CREATE_NEW); // Destination for the ciphertext

EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
        .onOutputStream(ciphertext)
        .withOptions(producerOptions); // pass in the options object

Streams.pipeAll(plaintext, encryptionStream); // pipe the data through
encryptionStream.close(); // important! Close the stream to finish encryption/signing

EncryptionResult result = encryptionStream.getResult(); // metadata

Use the EncryptionStream in Spring batch OutputStreamWriter.

As EncryptionStream is also a sub-class of OutputStream, so we can wrap it into the Spring batch writer like

new OutputStreamWriter(EncryptionStream, StandardCharsets.UTF_8);

So now we will get a Encrypted output stream, we can write the encrypted data into the output stream in Spring batch.