Skip to main content
FJATP
Silver ⭐️⭐️
March 8, 2022
Question

building a encrypt Content-like script for NiFi with PGP Encryption

I need to encrypt some content with PGP, but i can't use the processor Encrypt Content because we require that the "Keyring file route" and the "passphrase" must be entered through attributes (We must use an old version of NiFi). I make this script using the repo of NiFi and modifying the things that i need and using a single script file considering how the processor works. My problem is that the result can't be decrypted backwards.
I'm using Nifi 1.13.2
With Groovy as language
and Bouncy Castle (bcpg-jdk15on-1.70 and bcprov-jdk15on-1.70)
And my code is:

 

import org.bouncycastle.bcpg.ArmoredOutputStream
import org.bouncycastle.openpgp.PGPCompressedData
import org.bouncycastle.openpgp.PGPCompressedDataGenerator
import org.bouncycastle.openpgp.PGPEncryptedData
import org.bouncycastle.openpgp.PGPEncryptedDataGenerator
import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPLiteralData
import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPLiteralDataGenerator
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator
import org.bouncycastle.jce.provider.BouncyCastleProvider

import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.security.SecureRandom
import java.util.Date
import java.util.zip.Deflater

FlowFile flowFile = session.get()

if (!flowFile) {
return
}

final int BUFFER_SIZE = 65536;
final int BLOCK_SIZE = 4096;

try {
flowFile = session.write(flowFile, { inputStream, outputStream ->
output = new ArmoredOutputStream(outputStream)
int cipher = PGPEncryptedData.AES_256
String provider = "BC"
filename = "encrypted.txt"
publicKeyUserId = flowFile.getAttribute('PublicKeyUserId')
publicKeyringFile = flowFile.getAttribute('publicKeyRoute')
publicKey = getPublicKey(publicKeyUserId, publicKeyringFile)

try {
PGPEncryptedDataGenerator encryptedDataGenerator = new PGPEncryptedDataGenerator(
new JcePGPDataEncryptorBuilder(cipher).setWithIntegrityPacket(true).setSecureRandom(new SecureRandom()).setProvider(provider))

encryptedDataGenerator.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(publicKey).setProvider(provider))

OutputStream encryptedOut = encryptedDataGenerator.open(output, new byte[BUFFER_SIZE])

PGPCompressedDataGenerator compressedDataGenerator = new PGPCompressedDataGenerator(PGPCompressedData.ZIP, Deflater.BEST_SPEED)

OutputStream compressedOut = compressedDataGenerator.open(encryptedOut, new byte[BUFFER_SIZE])
PGPLiteralDataGenerator literalDataGenerator = new PGPLiteralDataGenerator()

OutputStream literalOut = literalDataGenerator.open(compressedOut, PGPLiteralData.BINARY, filename, new Date(), new byte[BUFFER_SIZE])

final byte[] buffer = new byte[BLOCK_SIZE];
int len;
while ((len = inputStream.read(buffer)) >= 0) {
literalOut.write(buffer, 0, len);
}
} finally {
output.close();
}

} as StreamCallback)

session.transfer(flowFile, REL_SUCCESS)
} catch (Exception e) {
log.error("There was an error encrypting the attributes: ${e.getMessage()}")
session.transfer(flowFile, REL_FAILURE)
}

static PGPPublicKey getPublicKey(String userId, String publicKeyringFile){
FileInputStream keyInputStream = new FileInputStream(publicKeyringFile)
// Form the PublicKeyRing collection (1.53 way with fingerprint calculator)
PGPPublicKeyRingCollection pgpPublicKeyRingCollection = new PGPPublicKeyRingCollection(keyInputStream, new BcKeyFingerprintCalculator());
// Iterate over all public keyrings
Iterator<PGPPublicKeyRing> iter = pgpPublicKeyRingCollection.getKeyRings();
PGPPublicKeyRing keyRing;
while (iter.hasNext()) {
keyRing = iter.next();

// Iterate over each public key in this keyring
Iterator<PGPPublicKey> keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext()) {
PGPPublicKey publicKey = keyIter.next();

// Iterate over each userId attached to the public key
Iterator userIdIterator = publicKey.getUserIDs();
while (userIdIterator.hasNext()) {
String id = (String) userIdIterator.next();
if (userId.equalsIgnoreCase(id)) {
return publicKey;
}
}
}
}
}

 


 Can anyone help me making this work?
Thank you!

6 replies

araujo
Platinum ⭐️⭐️⭐️
Platinum ⭐️⭐️⭐️
March 8, 2022

@FJATP 

 

Please have a look at this.  It doesn't use PGP but it's a similar encryption implementation using Groovy:

 

https://community.cloudera.com/t5/Support-Questions/How-to-encrypt-a-column-using-nifi/m-p/336023/highlight/true#M232103

 

In that case I used parameters but you can replace them with variables/attributes.

 

Let me know if that helps.

 

André

--

Was your question answered? Make sure to mark the answer as the accepted solution.
If you find a reply useful, say thanks by clicking on the thumbs up button.

 

Translate
-- Was your question answered? Please take some time to click on "Accept as Solution" below this post. If you find a reply useful, say thanks by clicking on the thumbs up button.
FJATP
FJATPAuthor
Silver ⭐️⭐️
March 8, 2022

Thanks, but i must use PGP, with the public and private keys and all that. 

Translate
araujo
Platinum ⭐️⭐️⭐️
Platinum ⭐️⭐️⭐️
March 8, 2022

What's the error you're getting?

 

André

Translate
-- Was your question answered? Please take some time to click on "Accept as Solution" below this post. If you find a reply useful, say thanks by clicking on the thumbs up button.