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
...
<dependencies>
...
<dependency>
<groupId>org.pgpainless</groupId>
<artifactId>pgpainless-core</artifactId>
<version>1.7.2</version>
</dependency>
...
</dependencies>
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
orByteArrayInputStream
. Then also you need to have aOutputStream
, like
OutputStream outputStream =
Files.newOutputStream(outputFileLocation, StandardOpenOption.CREATE_NEW);
- Before you call the
Painless.encryptAndOrSign()
, you need to build up theProducerOptions
. 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
andsecretKeyRingProtector
, 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 extends PGPKeyRing> T readKeyRing(BufferedInputStream keyInputStream, Class<T> 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.
How to Setup the ConsumerOptions when Decrypt
new ConsumerOptions()
.addDecryptionKey(SecretKeyRing, SecretKeyRingProtector)
.addVerificationCert(PublicKeyRing)
Build the DecryptionStream
// this is the file we are going to decrypt
InputStream inputStream = Files.newInputStream(inputFileLocation, StandardOpenOption.CREATE_NEW);
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
.onInputStream(inputStream)
.withOptions(ConsumerOptions)
Reuse this DecryptionStream in Spring batch reader
new InputStreamWriter(decryptionStream, StandardCharsets.UTF_8);
Decrypt the file
if you have an existing encrypted file, and you want to decrypt it to another file location. You can initialize the ByteArrayOutputStream which will receive the decrypted data.
ByteArrayOutputStream decryptedContentOutput;
Streams.pipeAll(decryptionStream, decryptedContentOutput);
// must close before we can get the metadata.
decryptionStream.close();
MessageMetadata messageMetadata = decryptionStream.getMetadata();
logCompleted(messageMetadata, inputFileLocation);
Top comments (0)