This is an automated email from the ASF dual-hosted git repository.
pvillard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 665b1696ef NIFI-11268 Removed deprecated OpenPGP support from
EncryptContent
665b1696ef is described below
commit 665b1696efb40f5793344a0bc9da4788e17b79b8
Author: exceptionfactory <[email protected]>
AuthorDate: Fri Mar 10 10:30:15 2023 -0600
NIFI-11268 Removed deprecated OpenPGP support from EncryptContent
Signed-off-by: Pierre Villard <[email protected]>
This closes #7030.
---
.../nifi/encrypt/PropertyEncryptorFactoryTest.java | 2 +-
.../nifi/security/util/EncryptionMethod.java | 2 -
.../nifi-standard-processors/pom.xml | 4 -
.../nifi/processors/standard/EncryptContent.java | 213 +----------
.../nifi/processors/standard/util/PGPUtil.java | 94 -----
.../util/crypto/OpenPGPKeyBasedEncryptor.java | 388 ---------------------
.../util/crypto/OpenPGPPasswordBasedEncryptor.java | 166 ---------
.../additionalDetails.html | 30 --
.../processors/standard/TestEncryptContent.java | 381 +-------------------
.../util/crypto/OpenPGPKeyBasedEncryptorTest.java | 66 ----
.../crypto/OpenPGPPasswordBasedEncryptorTest.java | 59 ----
.../test/resources/TestEncryptContent/pubring.gpg | Bin 1250 -> 0 bytes
.../test/resources/TestEncryptContent/secring.gpg | Bin 2628 -> 0 bytes
.../test/resources/TestEncryptContent/text.txt.asc | 33 --
.../test/resources/TestEncryptContent/text.txt.gpg | Bin 1481 -> 0 bytes
.../TestEncryptContent/text.txt.unsigned.gpg | Bin 824 -> 0 bytes
16 files changed, 13 insertions(+), 1425 deletions(-)
diff --git
a/nifi-commons/nifi-property-encryptor/src/test/java/org/apache/nifi/encrypt/PropertyEncryptorFactoryTest.java
b/nifi-commons/nifi-property-encryptor/src/test/java/org/apache/nifi/encrypt/PropertyEncryptorFactoryTest.java
index a711cc23b7..032dd9283c 100644
---
a/nifi-commons/nifi-property-encryptor/src/test/java/org/apache/nifi/encrypt/PropertyEncryptorFactoryTest.java
+++
b/nifi-commons/nifi-property-encryptor/src/test/java/org/apache/nifi/encrypt/PropertyEncryptorFactoryTest.java
@@ -33,7 +33,7 @@ public class PropertyEncryptorFactoryTest {
@Test
public void testGetPropertyEncryptorUnsupportedEncryptionMethod() {
final Properties properties = new Properties();
- properties.setProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM,
EncryptionMethod.PGP.getAlgorithm());
+ properties.setProperty(NiFiProperties.SENSITIVE_PROPS_ALGORITHM,
EncryptionMethod.AES_CBC_NO_PADDING.getAlgorithm());
properties.setProperty(NiFiProperties.SENSITIVE_PROPS_KEY,
String.class.getName());
final NiFiProperties niFiProperties =
NiFiProperties.createBasicNiFiProperties(null, properties);
diff --git
a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/EncryptionMethod.java
b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/EncryptionMethod.java
index 0ba3d59a03..ac481f1508 100644
---
a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/EncryptionMethod.java
+++
b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/EncryptionMethod.java
@@ -47,8 +47,6 @@ public enum EncryptionMethod {
SHA_2KEYTRIPLEDES("PBEWITHSHAAND2-KEYTRIPLEDES-CBC", "BC", false, false),
SHA_3KEYTRIPLEDES("PBEWITHSHAAND3-KEYTRIPLEDES-CBC", "BC", false, false),
SHA_TWOFISH("PBEWITHSHAANDTWOFISH-CBC", "BC", false, false),
- PGP("PGP", "BC", false, false),
- PGP_ASCII_ARMOR("PGP-ASCII-ARMOR", "BC", false, false),
// AES/CBC/NoPadding supported for decryption
AES_CBC_NO_PADDING("AES/CBC/NoPadding", "BC", false, true),
AES_CBC("AES/CBC/PKCS7Padding", "BC", false, true),
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml
index 12ef990880..d77a08e91f 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml
@@ -149,10 +149,6 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
</dependency>
- <dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcpg-jdk18on</artifactId>
- </dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
index 7fc901b8ff..38c5a90fd4 100644
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncryptContent.java
@@ -48,11 +48,7 @@ import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
-import org.apache.nifi.deprecation.log.DeprecationLogger;
-import org.apache.nifi.deprecation.log.DeprecationLoggerFactory;
-import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.flowfile.FlowFile;
-import org.apache.nifi.flowfile.attributes.CoreAttributes;
import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
@@ -66,12 +62,9 @@ import org.apache.nifi.security.util.EncryptionMethod;
import org.apache.nifi.security.util.KeyDerivationFunction;
import org.apache.nifi.security.util.crypto.CipherUtility;
import org.apache.nifi.security.util.crypto.KeyedEncryptor;
-import org.apache.nifi.security.util.crypto.OpenPGPKeyBasedEncryptor;
-import org.apache.nifi.security.util.crypto.OpenPGPPasswordBasedEncryptor;
import org.apache.nifi.security.util.crypto.PasswordBasedEncryptor;
import org.apache.nifi.util.StopWatch;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openpgp.PGPEncryptedData;
@EventDriven
@SideEffectFree
@@ -152,47 +145,6 @@ public class EncryptContent extends AbstractProcessor {
.addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
.sensitive(true)
.build();
- public static final PropertyDescriptor PUBLIC_KEYRING = new
PropertyDescriptor.Builder()
- .name("public-keyring-file")
- .displayName("Public Keyring File")
- .description("In a PGP encrypt mode, this keyring contains the
public key of the recipient")
- .required(false)
- .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
- .build();
- public static final PropertyDescriptor PUBLIC_KEY_USERID = new
PropertyDescriptor.Builder()
- .name("public-key-user-id")
- .displayName("Public Key User Id")
- .description("In a PGP encrypt mode, this user id of the
recipient")
- .required(false)
- .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
- .build();
- public static final PropertyDescriptor PRIVATE_KEYRING = new
PropertyDescriptor.Builder()
- .name("private-keyring-file")
- .displayName("Private Keyring File")
- .description("In a PGP decrypt mode, this keyring contains the
private key of the recipient")
- .required(false)
- .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
- .build();
- public static final PropertyDescriptor PRIVATE_KEYRING_PASSPHRASE = new
PropertyDescriptor.Builder()
- .name("private-keyring-passphrase")
- .displayName("Private Keyring Passphrase")
- .description("In a PGP decrypt mode, this is the private keyring
passphrase")
- .required(false)
- .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
-
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
- .sensitive(true)
- .build();
-
- public static final PropertyDescriptor PGP_SYMMETRIC_ENCRYPTION_CIPHER =
new PropertyDescriptor.Builder()
- .name("pgp-symmetric-cipher")
- .displayName("PGP Symmetric Cipher")
- .description("When using PGP encryption, this is the symmetric
cipher to be used. This property is ignored if "
- + "Encryption Algorithm is not PGP or
PGP-ASCII-ARMOR\nNote that the provided cipher is only used during"
- + "the encryption phase, while it is inferred from the
ciphertext in the decryption phase")
- .required(false)
- .allowableValues(buildPGPSymmetricCipherAllowableValues())
- .defaultValue(String.valueOf(PGPEncryptedData.AES_128))
- .build();
public static final PropertyDescriptor RAW_KEY_HEX = new
PropertyDescriptor.Builder()
.name("raw-key-hex")
@@ -217,8 +169,6 @@ public class EncryptContent extends AbstractProcessor {
public static final Relationship REL_FAILURE = new
Relationship.Builder().name("failure")
.description("Any FlowFile that cannot be encrypted or decrypted
will be routed to failure").build();
- private static final DeprecationLogger deprecationLogger =
DeprecationLoggerFactory.getLogger(EncryptContent.class);
-
private List<PropertyDescriptor> properties;
private Set<Relationship> relationships;
@@ -261,23 +211,6 @@ public class EncryptContent extends AbstractProcessor {
"if unsafe combinations of encryption algorithms and passwords
are provided on a JVM with limited strength crypto. To fix this, see the Admin
Guide.");
}
- private static AllowableValue[] buildPGPSymmetricCipherAllowableValues() {
- // Allowed values are inferred from SymmetricKeyAlgorithmTags. Note
that NULL and SAFER cipher are not supported and therefore not listed
- return new AllowableValue[]{
- new AllowableValue("1", "IDEA"),
- new AllowableValue("2", "TRIPLE_DES"),
- new AllowableValue("3", "CAST5"),
- new AllowableValue("4", "BLOWFISH"),
- new AllowableValue("6", "DES"),
- new AllowableValue("7", "AES_128"),
- new AllowableValue("8", "AES_192"),
- new AllowableValue("9", "AES_256"),
- new AllowableValue("10", "TWOFISH"),
- new AllowableValue("11", "CAMELLIA_128"),
- new AllowableValue("12", "CAMELLIA_192"),
- new AllowableValue("13", "CAMELLIA_256")};
- }
-
@Override
protected void init(final ProcessorInitializationContext context) {
final List<PropertyDescriptor> properties = new ArrayList<>();
@@ -287,11 +220,6 @@ public class EncryptContent extends AbstractProcessor {
properties.add(ALLOW_WEAK_CRYPTO);
properties.add(PASSWORD);
properties.add(RAW_KEY_HEX);
- properties.add(PUBLIC_KEYRING);
- properties.add(PUBLIC_KEY_USERID);
- properties.add(PRIVATE_KEYRING);
- properties.add(PRIVATE_KEYRING_PASSPHRASE);
- properties.add(PGP_SYMMETRIC_ENCRYPTION_CIPHER);
this.properties = Collections.unmodifiableList(properties);
final Set<Relationship> relationships = new HashSet<>();
@@ -310,124 +238,24 @@ public class EncryptContent extends AbstractProcessor {
return properties;
}
- public static boolean isPGPAlgorithm(final String algorithm) {
- return algorithm.startsWith("PGP");
- }
-
- public static boolean isPGPArmoredAlgorithm(final String algorithm) {
- return isPGPAlgorithm(algorithm) && algorithm.endsWith("ASCII-ARMOR");
- }
-
@Override
protected Collection<ValidationResult> customValidate(final
ValidationContext context) {
final List<ValidationResult> validationResults = new
ArrayList<>(super.customValidate(context));
final String methodValue =
context.getProperty(ENCRYPTION_ALGORITHM).getValue();
final EncryptionMethod encryptionMethod =
EncryptionMethod.valueOf(methodValue);
- final String algorithm = encryptionMethod.getAlgorithm();
final String password = context.getProperty(PASSWORD).getValue();
final KeyDerivationFunction kdf =
KeyDerivationFunction.valueOf(context.getProperty(KEY_DERIVATION_FUNCTION).getValue());
final String keyHex = context.getProperty(RAW_KEY_HEX).getValue();
final boolean encrypt =
context.getProperty(MODE).getValue().equalsIgnoreCase(ENCRYPT_MODE);
- if (isPGPAlgorithm(algorithm)) {
- deprecationLogger.warn("{}[id={}] OpenPGP support is deprecated:
see EncryptContentPGP and DecryptContentPGP",
- getClass().getSimpleName(),
- getIdentifier()
- );
-
- final String publicKeyring =
context.getProperty(PUBLIC_KEYRING).getValue();
- final String publicUserId =
context.getProperty(PUBLIC_KEY_USERID).getValue();
- final String privateKeyring =
context.getProperty(PRIVATE_KEYRING).getValue();
- final String privateKeyringPassphrase =
context.getProperty(PRIVATE_KEYRING_PASSPHRASE).evaluateAttributeExpressions().getValue();
- final Integer cipher =
context.getProperty(PGP_SYMMETRIC_ENCRYPTION_CIPHER).asInteger();
- validationResults.addAll(validatePGP(encryptionMethod, password,
encrypt, publicKeyring, publicUserId,
- privateKeyring, privateKeyringPassphrase, cipher));
- } else { // Not PGP
- boolean allowWeakCrypto =
context.getProperty(ALLOW_WEAK_CRYPTO).getValue().equalsIgnoreCase(WEAK_CRYPTO_ALLOWED_NAME);
- if (encryptionMethod.isKeyedCipher()) { // Raw key or derived key
from password
- validationResults.addAll(validateKeyed(encryptionMethod, kdf,
keyHex, password, allowWeakCrypto, encrypt));
- } else { // PBE
- validationResults.addAll(validatePBE(encryptionMethod, kdf,
password, allowWeakCrypto));
- }
+ boolean allowWeakCrypto =
context.getProperty(ALLOW_WEAK_CRYPTO).getValue().equalsIgnoreCase(WEAK_CRYPTO_ALLOWED_NAME);
+ if (encryptionMethod.isKeyedCipher()) { // Raw key or derived key from
password
+ validationResults.addAll(validateKeyed(encryptionMethod, kdf,
keyHex, password, allowWeakCrypto, encrypt));
+ } else { // PBE
+ validationResults.addAll(validatePBE(encryptionMethod, kdf,
password, allowWeakCrypto));
}
return validationResults;
}
- /**
- * Returns true if the integer value provided maps to a valid {@code
cipher} as contained in the {@code PGP_SYMMETRIC_ENCRYPTION_CIPHER}.
- *
- * @param cipher an integer indicating a particular cipher
- * @return true if the cipher is supported
- */
- private static boolean isValidCipher(int cipher) {
- return
PGP_SYMMETRIC_ENCRYPTION_CIPHER.getAllowableValues().stream().anyMatch(av ->
av.getValue().equals(String.valueOf(cipher)));
- }
-
- private List<ValidationResult> validatePGP(EncryptionMethod
encryptionMethod, String password, boolean encrypt,
- String publicKeyring, String
publicUserId, String privateKeyring,
- String
privateKeyringPassphrase, int cipher) {
- List<ValidationResult> validationResults = new ArrayList<>();
-
- if (encrypt && password != null && !isValidCipher(cipher)) {
- validationResults.add(new
ValidationResult.Builder().subject(PGP_SYMMETRIC_ENCRYPTION_CIPHER.getDisplayName())
- .explanation("When performing an encryption with " +
encryptionMethod.getAlgorithm() + " and a symmetric " +
- PASSWORD.getDisplayName() + ", a" +
PGP_SYMMETRIC_ENCRYPTION_CIPHER.getDisplayName() + " is required")
- .build());
- }
-
- if (password == null) {
- if (encrypt) {
- // If encrypting without a password, require both
public-keyring-file and public-key-user-id
- if (publicKeyring == null || publicUserId == null) {
- validationResults.add(new
ValidationResult.Builder().subject(PUBLIC_KEYRING.getDisplayName())
- .explanation(encryptionMethod.getAlgorithm() + "
encryption without a " + PASSWORD.getDisplayName() + " requires both "
- + PUBLIC_KEYRING.getDisplayName() + " and
" + PUBLIC_KEY_USERID.getDisplayName())
- .build());
- } else {
- // Verify the public keyring contains the user id
- try {
- if
(OpenPGPKeyBasedEncryptor.getPublicKey(publicUserId, publicKeyring) == null) {
- validationResults.add(new
ValidationResult.Builder().subject(PUBLIC_KEYRING.getDisplayName())
-
.explanation(PUBLIC_KEYRING.getDisplayName() + " " + publicKeyring
- + " does not contain user id " +
publicUserId)
- .build());
- }
- } catch (final Exception e) {
- validationResults.add(new
ValidationResult.Builder().subject(PUBLIC_KEYRING.getDisplayName())
- .explanation("Invalid " +
PUBLIC_KEYRING.getDisplayName() + " " + publicKeyring
- + " because " + e.toString())
- .build());
- }
- }
- } else { // Decrypt
- // Require both private-keyring-file and
private-keyring-passphrase
- if (privateKeyring == null || privateKeyringPassphrase ==
null) {
- validationResults.add(new
ValidationResult.Builder().subject(PRIVATE_KEYRING.getName())
- .explanation(encryptionMethod.getAlgorithm() + "
decryption without a " + PASSWORD.getDisplayName() + " requires both "
- + PRIVATE_KEYRING.getDisplayName() + " and
" + PRIVATE_KEYRING_PASSPHRASE.getDisplayName())
- .build());
- } else {
- final String providerName = encryptionMethod.getProvider();
- // Verify the passphrase works on the private keyring
- try {
- if
(!OpenPGPKeyBasedEncryptor.validateKeyring(providerName, privateKeyring,
privateKeyringPassphrase.toCharArray())) {
- validationResults.add(new
ValidationResult.Builder().subject(PRIVATE_KEYRING.getDisplayName())
-
.explanation(PRIVATE_KEYRING.getDisplayName() + " " + privateKeyring
- + " could not be opened with the
provided " + PRIVATE_KEYRING_PASSPHRASE.getDisplayName())
- .build());
- }
- } catch (final Exception e) {
- validationResults.add(new
ValidationResult.Builder().subject(PRIVATE_KEYRING.getDisplayName())
- .explanation("Invalid " +
PRIVATE_KEYRING.getDisplayName() + " " + privateKeyring
- + " because " + e.toString())
- .build());
- }
- }
- }
- }
-
- return validationResults;
- }
-
private List<ValidationResult> validatePBE(EncryptionMethod
encryptionMethod, KeyDerivationFunction kdf, String password, boolean
allowWeakCrypto) {
// Start by validating the password specifically
List<ValidationResult> validationResults =
validatePassword(encryptionMethod, kdf, password, allowWeakCrypto);
@@ -571,9 +399,6 @@ public class EncryptContent extends AbstractProcessor {
final ComponentLog logger = getLogger();
final String method =
context.getProperty(ENCRYPTION_ALGORITHM).getValue();
final EncryptionMethod encryptionMethod =
EncryptionMethod.valueOf(method);
- final String providerName = encryptionMethod.getProvider();
- final String algorithm = encryptionMethod.getAlgorithm();
- final Integer pgpCipher =
context.getProperty(PGP_SYMMETRIC_ENCRYPTION_CIPHER).asInteger();
final String password = context.getProperty(PASSWORD).getValue();
final KeyDerivationFunction kdf =
KeyDerivationFunction.valueOf(context.getProperty(KEY_DERIVATION_FUNCTION).getValue());
final boolean encrypt =
context.getProperty(MODE).getValue().equalsIgnoreCase(ENCRYPT_MODE);
@@ -581,9 +406,7 @@ public class EncryptContent extends AbstractProcessor {
Encryptor encryptor;
StreamCallback callback;
try {
- if (isPGPAlgorithm(algorithm)) {
- encryptor = createPGPEncryptor(context, flowFile,
providerName, algorithm, pgpCipher, password, encrypt);
- } else if (kdf.equals(KeyDerivationFunction.NONE)) { // Raw key
+ if (kdf.equals(KeyDerivationFunction.NONE)) { // Raw key
encryptor = createKeyedEncryptor(context, encryptionMethod);
} else { // PBE
encryptor = createPBEEncryptor(encryptionMethod, password,
kdf);
@@ -596,7 +419,7 @@ public class EncryptContent extends AbstractProcessor {
}
} catch (final Exception e) {
- logger.error("Failed to initialize {}cryption algorithm because -
", new Object[]{encrypt ? "en" : "de", e});
+ logger.error("Failed to initialize {}cryption algorithm because -
", encrypt ? "en" : "de", e);
session.rollback();
context.yield();
return;
@@ -611,33 +434,15 @@ public class EncryptContent extends AbstractProcessor {
encryptor.updateAttributes(clonedAttributes);
flowFile = session.putAllAttributes(flowFile, clonedAttributes);
- logger.info("successfully {}crypted {}", new Object[]{encrypt ?
"en" : "de", flowFile});
+ logger.info("successfully {}crypted {}", encrypt ? "en" : "de",
flowFile);
session.getProvenanceReporter().modifyContent(flowFile,
stopWatch.getElapsed(TimeUnit.MILLISECONDS));
session.transfer(flowFile, REL_SUCCESS);
} catch (final ProcessException e) {
- logger.error("Cannot {}crypt {} - ", new Object[]{encrypt ? "en" :
"de", flowFile, e});
+ logger.error("Cannot {}crypt {} - ", encrypt ? "en" : "de",
flowFile, e);
session.transfer(flowFile, REL_FAILURE);
}
}
- private Encryptor createPGPEncryptor(ProcessContext context, FlowFile
flowFile, String providerName, String algorithm, Integer pgpCipher, String
password, boolean encrypt) {
- Encryptor encryptor;
- final String filename =
flowFile.getAttribute(CoreAttributes.FILENAME.key());
- final String publicKeyring =
context.getProperty(PUBLIC_KEYRING).getValue();
- final String privateKeyring =
context.getProperty(PRIVATE_KEYRING).getValue();
- if (encrypt && publicKeyring != null) {
- final String publicUserId =
context.getProperty(PUBLIC_KEY_USERID).getValue();
- encryptor = new OpenPGPKeyBasedEncryptor(algorithm, pgpCipher,
providerName, publicKeyring, publicUserId, null, filename);
- } else if (!encrypt && privateKeyring != null) {
- final char[] keyringPassphrase =
context.getProperty(PRIVATE_KEYRING_PASSPHRASE).evaluateAttributeExpressions().getValue().toCharArray();
- encryptor = new OpenPGPKeyBasedEncryptor(algorithm, pgpCipher,
providerName, privateKeyring, null, keyringPassphrase, filename);
- } else {
- final char[] passphrase = Normalizer.normalize(password,
Normalizer.Form.NFC).toCharArray();
- encryptor = new OpenPGPPasswordBasedEncryptor(algorithm,
pgpCipher, providerName, passphrase, filename);
- }
- return encryptor;
- }
-
private Encryptor createKeyedEncryptor(ProcessContext context,
EncryptionMethod encryptionMethod) throws DecoderException {
Encryptor encryptor;
final String keyHex = context.getProperty(RAW_KEY_HEX).getValue();
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/PGPUtil.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/PGPUtil.java
deleted file mode 100644
index 8f6646195b..0000000000
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/PGPUtil.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.processors.standard.util;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.nifi.processors.standard.EncryptContent;
-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.PGPLiteralDataGenerator;
-import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
-import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-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;
-
-/**
- * This class contains static utility methods to assist with common PGP
operations.
- */
-public class PGPUtil {
- private static final Logger logger =
LoggerFactory.getLogger(PGPUtil.class);
-
- public static final int BUFFER_SIZE = 65536;
- public static final int BLOCK_SIZE = 4096;
-
- public static void encrypt(InputStream in, OutputStream out, String
algorithm, String provider, int cipher, String filename,
PGPKeyEncryptionMethodGenerator encryptionMethodGenerator) throws
- IOException, PGPException {
- if (StringUtils.isEmpty(algorithm)) {
- throw new IllegalArgumentException("The algorithm must be
specified");
- }
- final boolean isArmored =
EncryptContent.isPGPArmoredAlgorithm(algorithm);
- OutputStream output = out;
- if (isArmored) {
- output = new ArmoredOutputStream(out);
- }
-
- // Default value, do not allow null encryption
- if (cipher == PGPEncryptedData.NULL) {
- logger.warn("Null encryption not allowed; defaulting to AES-128");
- cipher = PGPEncryptedData.AES_128;
- }
-
- try {
- // TODO: Can probably hard-code provider to BC and remove one
method parameter
- PGPEncryptedDataGenerator encryptedDataGenerator = new
PGPEncryptedDataGenerator(
- new
JcePGPDataEncryptorBuilder(cipher).setWithIntegrityPacket(true).setSecureRandom(new
SecureRandom()).setProvider(provider));
-
- encryptedDataGenerator.addMethod(encryptionMethodGenerator);
-
- try (OutputStream encryptedOut =
encryptedDataGenerator.open(output, new byte[BUFFER_SIZE])) {
- PGPCompressedDataGenerator compressedDataGenerator = new
PGPCompressedDataGenerator(PGPCompressedData.ZIP, Deflater.BEST_SPEED);
- try (OutputStream compressedOut =
compressedDataGenerator.open(encryptedOut, new byte[BUFFER_SIZE])) {
- PGPLiteralDataGenerator literalDataGenerator = new
PGPLiteralDataGenerator();
- try (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 = in.read(buffer)) > -1) {
- literalOut.write(buffer, 0, len);
- }
- }
- }
- }
- } finally {
- if (isArmored) {
- output.close();
- }
- }
- }
-}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/OpenPGPKeyBasedEncryptor.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/OpenPGPKeyBasedEncryptor.java
deleted file mode 100644
index a50f9ba058..0000000000
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/OpenPGPKeyBasedEncryptor.java
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.security.util.crypto;
-
-import static org.apache.nifi.processors.standard.util.PGPUtil.BLOCK_SIZE;
-import static org.apache.nifi.processors.standard.util.PGPUtil.BUFFER_SIZE;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.NoSuchProviderException;
-import java.security.SecureRandom;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.zip.Deflater;
-import org.apache.nifi.processor.exception.ProcessException;
-import org.apache.nifi.processor.io.StreamCallback;
-import org.apache.nifi.processors.standard.EncryptContent;
-import org.apache.nifi.processors.standard.EncryptContent.Encryptor;
-import org.bouncycastle.bcpg.ArmoredOutputStream;
-import org.bouncycastle.openpgp.PGPCompressedData;
-import org.bouncycastle.openpgp.PGPCompressedDataGenerator;
-import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
-import org.bouncycastle.openpgp.PGPEncryptedDataList;
-import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPLiteralData;
-import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
-import org.bouncycastle.openpgp.PGPObjectFactory;
-import org.bouncycastle.openpgp.PGPOnePassSignatureList;
-import org.bouncycastle.openpgp.PGPPrivateKey;
-import org.bouncycastle.openpgp.PGPPublicKey;
-import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
-import org.bouncycastle.openpgp.PGPPublicKeyRing;
-import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
-import org.bouncycastle.openpgp.PGPSecretKey;
-import org.bouncycastle.openpgp.PGPSecretKeyRing;
-import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
-import org.bouncycastle.openpgp.PGPUtil;
-import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
-import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
-import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
-import
org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
-import
org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
-import
org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class OpenPGPKeyBasedEncryptor implements Encryptor {
- private static final Logger logger =
LoggerFactory.getLogger(OpenPGPPasswordBasedEncryptor.class);
-
- private String algorithm;
- private Integer cipher;
- private String provider;
- // TODO: This can hold either the secret or public keyring path
- private String keyring;
- private String userId;
- private char[] passphrase;
- private String filename;
-
- public OpenPGPKeyBasedEncryptor(final String algorithm, final Integer
cipher, final String provider, final String keyring,
- final String userId, final char[]
passphrase, final String filename) {
- this.algorithm = algorithm;
- this.cipher = cipher;
- this.provider = provider;
- this.keyring = keyring;
- this.userId = userId;
- this.passphrase = passphrase;
- this.filename = filename;
- }
-
- @Override
- public void updateAttributes(Map<String, String> attributes) throws
ProcessException {
- // TODO: Implement
- }
-
- @Override
- public StreamCallback getEncryptionCallback() throws Exception {
- return new OpenPGPEncryptCallback(algorithm, cipher, provider,
keyring, userId, filename);
- }
-
- @Override
- public StreamCallback getDecryptionCallback() throws Exception {
- return new OpenPGPDecryptCallback(provider, keyring, passphrase);
- }
-
- /**
- * Returns true if the passphrase is valid.
- * <p>
- * This is used in the EncryptContent custom validation to check if the
passphrase can extract a private key from the secret key ring. After BC was
upgraded from 1.46 to 1.53, the API changed
- * so this is performed differently but the functionality is equivalent.
- *
- * @param provider the provider name
- * @param secretKeyringFile the file path to the keyring
- * @param passphrase the passphrase
- * @return true if the passphrase can successfully extract any private key
- * @throws IOException if there is a problem reading the
keyring file
- * @throws PGPException if there is a problem
parsing/extracting the private key
- * @throws NoSuchProviderException if the provider is not available
- */
- public static boolean validateKeyring(String provider, String
secretKeyringFile, char[] passphrase) throws IOException, PGPException,
NoSuchProviderException {
- try {
- getDecryptedPrivateKey(provider, secretKeyringFile, passphrase);
- return true;
- } catch (Exception e) {
- // If this point is reached, no private key could be extracted
with the given passphrase
- return false;
- }
- }
-
- private static PGPPrivateKey getDecryptedPrivateKey(String provider,
String secretKeyringFile, char[] passphrase) throws IOException, PGPException {
- // TODO: Verify that key IDs cannot be 0
- return getDecryptedPrivateKey(provider, secretKeyringFile, 0L,
passphrase);
- }
-
- private static PGPPrivateKey getDecryptedPrivateKey(String provider,
String secretKeyringFile, long keyId, char[] passphrase) throws IOException,
PGPException {
- // TODO: Reevaluate the mechanism for executing this task as
performance can suffer here and only a specific key needs to be validated
-
- // Read in from the secret keyring file
- try (FileInputStream keyInputStream = new
FileInputStream(secretKeyringFile)) {
-
- // Form the SecretKeyRing collection (1.53 way with fingerprint
calculator)
- PGPSecretKeyRingCollection pgpSecretKeyRingCollection = new
PGPSecretKeyRingCollection(keyInputStream, new BcKeyFingerprintCalculator());
-
- // The decryptor is identical for all keys
- final PBESecretKeyDecryptor decryptor = new
JcePBESecretKeyDecryptorBuilder().setProvider(provider).build(passphrase);
-
- // Iterate over all secret keyrings
- Iterator<PGPSecretKeyRing> keyringIterator =
pgpSecretKeyRingCollection.getKeyRings();
- PGPSecretKeyRing keyRing;
- PGPSecretKey secretKey;
-
- while (keyringIterator.hasNext()) {
- keyRing = keyringIterator.next();
-
- // If keyId exists, get a specific secret key; else, iterate
over all
- if (keyId != 0) {
- secretKey = keyRing.getSecretKey(keyId);
- try {
- return secretKey.extractPrivateKey(decryptor);
- } catch (Exception e) {
- throw new PGPException("No private key available using
passphrase", e);
- }
- } else {
- Iterator<PGPSecretKey> keyIterator =
keyRing.getSecretKeys();
-
- while (keyIterator.hasNext()) {
- secretKey = keyIterator.next();
- try {
- return secretKey.extractPrivateKey(decryptor);
- } catch (Exception e) {
- // TODO: Log (expected) failures?
- }
- }
- }
- }
- }
-
- // If this point is reached, no private key could be extracted with
the given passphrase
- throw new PGPException("No private key available using passphrase");
- }
-
- /*
- * Get the public key for a specific user id from a keyring.
- */
- @SuppressWarnings("rawtypes")
- public static PGPPublicKey getPublicKey(String userId, String
publicKeyringFile) throws IOException, PGPException {
- // TODO: Reevaluate the mechanism for executing this task as
performance can suffer here and only a specific key needs to be validated
-
- // Read in from the public keyring file
- try (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;
- }
- }
- }
- }
- }
-
- // If this point is reached, no public key could be extracted with the
given userId
- throw new PGPException("Could not find a public key with the given
userId");
- }
-
- private static class OpenPGPDecryptCallback implements StreamCallback {
-
- private String provider;
- private String secretKeyringFile;
- private char[] passphrase;
-
- OpenPGPDecryptCallback(final String provider, final String
secretKeyringFile, final char[] passphrase) {
- this.provider = provider;
- this.secretKeyringFile = secretKeyringFile;
- this.passphrase = passphrase;
- }
-
- @Override
- public void process(InputStream in, OutputStream out) throws
IOException {
- try (InputStream pgpin = PGPUtil.getDecoderStream(in)) {
- PGPObjectFactory pgpFactory = new PGPObjectFactory(pgpin, new
BcKeyFingerprintCalculator());
-
- Object obj = pgpFactory.nextObject();
- if (!(obj instanceof PGPEncryptedDataList)) {
- obj = pgpFactory.nextObject();
- if (!(obj instanceof PGPEncryptedDataList)) {
- throw new ProcessException("Invalid OpenPGP data");
- }
- }
- PGPEncryptedDataList encList = (PGPEncryptedDataList) obj;
-
- try {
- PGPPrivateKey privateKey = null;
- PGPPublicKeyEncryptedData encData = null;
-
- // Find the secret key in the encrypted data
- Iterator it = encList.getEncryptedDataObjects();
- while (privateKey == null && it.hasNext()) {
- obj = it.next();
- if (!(obj instanceof PGPPublicKeyEncryptedData)) {
- throw new ProcessException("Invalid OpenPGP data");
- }
- encData = (PGPPublicKeyEncryptedData) obj;
-
- // Check each encrypted data object to see if it
contains the key ID for the secret key -> private key
- try {
- privateKey = getDecryptedPrivateKey(provider,
secretKeyringFile, encData.getKeyID(), passphrase);
- } catch (PGPException e) {
- // TODO: Log (expected) exception?
- }
- }
- if (privateKey == null) {
- throw new ProcessException("Secret keyring does not
contain the key required to decrypt");
- }
-
- // Read in the encrypted data stream and decrypt it
- final PublicKeyDataDecryptorFactory dataDecryptor = new
JcePublicKeyDataDecryptorFactoryBuilder().setProvider(provider).build(privateKey);
- try (InputStream clear =
encData.getDataStream(dataDecryptor)) {
- // Create a plain object factory
- JcaPGPObjectFactory plainFact = new
JcaPGPObjectFactory(clear);
-
- Object message = plainFact.nextObject();
-
- // Check the message type and act accordingly
-
- // If compressed, decompress
- if (message instanceof PGPCompressedData) {
- PGPCompressedData cData = (PGPCompressedData)
message;
- JcaPGPObjectFactory pgpFact = new
JcaPGPObjectFactory(cData.getDataStream());
-
- message = pgpFact.nextObject();
- }
-
- // If the message is literal data, read it and process
to the out stream
- if (message instanceof PGPLiteralData) {
- PGPLiteralData literalData = (PGPLiteralData)
message;
-
- try (InputStream lis =
literalData.getInputStream()) {
- final byte[] buffer = new byte[BLOCK_SIZE];
- int len;
- while ((len = lis.read(buffer)) >= 0) {
- out.write(buffer, 0, len);
- }
- }
- } else if (message instanceof PGPOnePassSignatureList)
{
- // TODO: This is legacy code but should verify
signature list here
- throw new PGPException("encrypted message contains
a signed message - not literal data.");
- } else {
- throw new PGPException("message is not a simple
encrypted file - type unknown.");
- }
-
- if (encData.isIntegrityProtected()) {
- if (!encData.verify()) {
- throw new PGPException("Failed message
integrity check");
- }
- } else {
- logger.warn("No message integrity check");
- }
- }
- } catch (Exception e) {
- throw new ProcessException(e.getMessage());
- }
- }
- }
-
- }
-
- private static class OpenPGPEncryptCallback implements StreamCallback {
-
- private String algorithm;
- private Integer cipher;
- private String provider;
- private String publicKeyring;
- private String userId;
- private String filename;
-
- OpenPGPEncryptCallback(final String algorithm, final Integer cipher,
final String provider, final String keyring, final String userId, final String
filename) {
- this.algorithm = algorithm;
- this.cipher = cipher;
- this.provider = provider;
- this.publicKeyring = keyring;
- this.userId = userId;
- this.filename = filename;
- }
-
- @Override
- public void process(InputStream in, OutputStream out) throws
IOException {
- PGPPublicKey publicKey;
- final boolean isArmored =
EncryptContent.isPGPArmoredAlgorithm(algorithm);
-
- try {
- publicKey = getPublicKey(userId, publicKeyring);
- } catch (Exception e) {
- throw new ProcessException("Invalid public keyring - " +
e.getMessage());
- }
-
- try {
- OutputStream output = out;
- if (isArmored) {
- output = new ArmoredOutputStream(out);
- }
-
- try {
- PGPEncryptedDataGenerator encryptedDataGenerator = new
PGPEncryptedDataGenerator(
- new
JcePGPDataEncryptorBuilder(cipher).setWithIntegrityPacket(true).setSecureRandom(new
SecureRandom()).setProvider(provider));
-
- encryptedDataGenerator.addMethod(new
JcePublicKeyKeyEncryptionMethodGenerator(publicKey).setProvider(provider));
-
- // TODO: Refactor shared encryption code to utility
- try (OutputStream encryptedOut =
encryptedDataGenerator.open(output, new byte[BUFFER_SIZE])) {
- PGPCompressedDataGenerator compressedDataGenerator =
new PGPCompressedDataGenerator(PGPCompressedData.ZIP, Deflater.BEST_SPEED);
- try (OutputStream compressedOut =
compressedDataGenerator.open(encryptedOut, new byte[BUFFER_SIZE])) {
- PGPLiteralDataGenerator literalDataGenerator = new
PGPLiteralDataGenerator();
- try (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 = in.read(buffer)) >= 0) {
- literalOut.write(buffer, 0, len);
- }
- }
- }
- }
- } finally {
- if (isArmored) {
- output.close();
- }
- }
- } catch (Exception e) {
- throw new ProcessException(e.getMessage());
- }
- }
- }
-}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/OpenPGPPasswordBasedEncryptor.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/OpenPGPPasswordBasedEncryptor.java
deleted file mode 100644
index 524f839868..0000000000
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/security/util/crypto/OpenPGPPasswordBasedEncryptor.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.security.util.crypto;
-
-import static org.bouncycastle.openpgp.PGPUtil.getDecoderStream;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Map;
-import org.apache.nifi.processor.exception.ProcessException;
-import org.apache.nifi.processor.io.StreamCallback;
-import org.apache.nifi.processors.standard.EncryptContent.Encryptor;
-import org.bouncycastle.openpgp.PGPCompressedData;
-import org.bouncycastle.openpgp.PGPEncryptedDataList;
-import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPLiteralData;
-import org.bouncycastle.openpgp.PGPPBEEncryptedData;
-import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
-import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory;
-import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
-import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator;
-import
org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
-import
org.bouncycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
-import
org.bouncycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class OpenPGPPasswordBasedEncryptor implements Encryptor {
- private static final Logger logger =
LoggerFactory.getLogger(OpenPGPPasswordBasedEncryptor.class);
-
- private String algorithm;
- private String provider;
- private char[] password;
- private String filename;
- private Integer cipher;
-
- public OpenPGPPasswordBasedEncryptor(final String algorithm, final Integer
cipher, final String provider, final char[] passphrase, final String filename) {
- this.algorithm = algorithm;
- this.provider = provider;
- this.password = passphrase;
- this.filename = filename;
- this.cipher = cipher;
- }
-
- @Override
- public StreamCallback getEncryptionCallback() throws Exception {
- return new OpenPGPEncryptCallback(algorithm, cipher, provider,
password, filename);
- }
-
- @Override
- public StreamCallback getDecryptionCallback() throws Exception {
- return new OpenPGPDecryptCallback(provider, password);
- }
-
- @Override
- public void updateAttributes(Map<String, String> attributes) throws
ProcessException {
- // TODO: Implement
- }
-
- private static class OpenPGPDecryptCallback implements StreamCallback {
-
- private String provider;
- private char[] password;
-
- OpenPGPDecryptCallback(final String provider, final char[] password) {
- this.provider = provider;
- this.password = password;
- }
-
- @Override
- public void process(InputStream in, OutputStream out) throws
IOException {
- InputStream pgpin = getDecoderStream(in);
- JcaPGPObjectFactory pgpFactory = new JcaPGPObjectFactory(pgpin);
-
- Object obj = pgpFactory.nextObject();
- if (!(obj instanceof PGPEncryptedDataList)) {
- obj = pgpFactory.nextObject();
- if (!(obj instanceof PGPEncryptedDataList)) {
- throw new ProcessException("Invalid OpenPGP data");
- }
- }
- PGPEncryptedDataList encList = (PGPEncryptedDataList) obj;
-
- obj = encList.get(0);
- if (!(obj instanceof PGPPBEEncryptedData)) {
- throw new ProcessException("Invalid OpenPGP data");
- }
- PGPPBEEncryptedData encryptedData = (PGPPBEEncryptedData) obj;
-
- try {
- final PGPDigestCalculatorProvider digestCalculatorProvider =
new JcaPGPDigestCalculatorProviderBuilder().setProvider(provider).build();
- final PBEDataDecryptorFactory decryptorFactory = new
JcePBEDataDecryptorFactoryBuilder(digestCalculatorProvider).setProvider(provider).build(password);
- InputStream clear =
encryptedData.getDataStream(decryptorFactory);
-
- JcaPGPObjectFactory pgpObjectFactory = new
JcaPGPObjectFactory(clear);
-
- obj = pgpObjectFactory.nextObject();
- if (obj instanceof PGPCompressedData) {
- PGPCompressedData compressedData = (PGPCompressedData) obj;
- pgpObjectFactory = new
JcaPGPObjectFactory(compressedData.getDataStream());
- obj = pgpObjectFactory.nextObject();
- }
-
- PGPLiteralData literalData = (PGPLiteralData) obj;
- InputStream plainIn = literalData.getInputStream();
- final byte[] buffer = new
byte[org.apache.nifi.processors.standard.util.PGPUtil.BLOCK_SIZE];
- int len;
- while ((len = plainIn.read(buffer)) >= 0) {
- out.write(buffer, 0, len);
- }
-
- if (encryptedData.isIntegrityProtected()) {
- if (!encryptedData.verify()) {
- throw new PGPException("Integrity check failed");
- }
- } else {
- logger.warn("No message integrity check");
- }
- } catch (Exception e) {
- throw new ProcessException(e.getMessage());
- }
- }
- }
-
- private static class OpenPGPEncryptCallback implements StreamCallback {
-
- private String algorithm;
- private String provider;
- private char[] password;
- private String filename;
- private Integer cipher;
-
- OpenPGPEncryptCallback(final String algorithm, final Integer cipher,
final String provider, final char[] password, final String filename) {
- this.algorithm = algorithm;
- this.provider = provider;
- this.password = password;
- this.filename = filename;
- this.cipher = cipher;
- }
-
- @Override
- public void process(InputStream in, OutputStream out) throws
IOException {
- try {
- PGPKeyEncryptionMethodGenerator encryptionMethodGenerator =
new JcePBEKeyEncryptionMethodGenerator(password).setProvider(provider);
- org.apache.nifi.processors.standard.util.PGPUtil.encrypt(in,
out, algorithm, provider, cipher, filename, encryptionMethodGenerator);
- } catch (Exception e) {
- throw new ProcessException(e.getMessage());
- }
- }
- }
-}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/resources/docs/org.apache.nifi.processors.standard.EncryptContent/additionalDetails.html
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/resources/docs/org.apache.nifi.processors.standard.EncryptContent/additionalDetails.html
deleted file mode 100644
index 7dab982fb1..0000000000
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/resources/docs/org.apache.nifi.processors.standard.EncryptContent/additionalDetails.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
- <!--
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- -->
- <head>
- <meta charset="utf-8"/>
- <title>EncryptContent</title>
- <link rel="stylesheet" href="../../../../../css/component-usage.css"
type="text/css"/>
- </head>
-
- <body>
- <!-- Processor Documentation
================================================== -->
- <p>
- <strong>Note:</strong> This processor supports OpenPGP algorithms
that are compatible with third party programs.
- However, it currently cannot add a digital signature to an
encrypted FlowFile.
- </p>
- </body>
-</html>
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncryptContent.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncryptContent.java
index 6968cb057c..6ec4cda785 100644
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncryptContent.java
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncryptContent.java
@@ -20,7 +20,6 @@ import groovy.time.TimeCategory;
import groovy.time.TimeDuration;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
-import org.apache.nifi.components.AllowableValue;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.security.util.EncryptionMethod;
import org.apache.nifi.security.util.KeyDerivationFunction;
@@ -35,8 +34,6 @@ import org.apache.nifi.util.MockProcessContext;
import org.apache.nifi.util.StringUtils;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
-import org.bouncycastle.bcpg.BCPGInputStream;
-import org.bouncycastle.bcpg.SymmetricKeyEncSessionPacket;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -46,42 +43,25 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.security.Security;
import java.text.ParseException;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
-import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
-import static org.bouncycastle.openpgp.PGPUtil.getDecoderStream;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
public class TestEncryptContent {
- private static AllowableValue[] getPGPCipherList() {
- try{
- Method method =
EncryptContent.class.getDeclaredMethod("buildPGPSymmetricCipherAllowableValues");
- method.setAccessible(true);
- return ((AllowableValue[]) method.invoke(null));
- } catch (Exception e){
- fail("Cannot access buildPGPSymmetricCipherAllowableValues");
- }
- return null;
- }
-
private static final List<EncryptionMethod>
SUPPORTED_KEYED_ENCRYPTION_METHODS = Arrays
.stream(EncryptionMethod.values())
.filter(method -> method.isKeyedCipher() && method !=
EncryptionMethod.AES_CBC_NO_PADDING)
@@ -164,85 +144,6 @@ public class TestEncryptContent {
}
}
-
- @Test
- public void testPGPCiphersRoundTrip() {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncryptContent());
- testRunner.setProperty(EncryptContent.PASSWORD, "passwordpassword");
// a >=16 characters password
- testRunner.setProperty(EncryptContent.KEY_DERIVATION_FUNCTION,
KeyDerivationFunction.NONE.name());
-
- List<String> pgpAlgorithms = new ArrayList<>();
- pgpAlgorithms.add("PGP");
- pgpAlgorithms.add("PGP_ASCII_ARMOR");
-
- for (String algorithm : pgpAlgorithms) {
- testRunner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
algorithm);
- for (AllowableValue cipher :
Objects.requireNonNull(getPGPCipherList())) {
-
testRunner.setProperty(EncryptContent.PGP_SYMMETRIC_ENCRYPTION_CIPHER,
cipher.getValue());
- testRunner.setProperty(EncryptContent.MODE,
EncryptContent.ENCRYPT_MODE);
-
- testRunner.enqueue("A cool plaintext!");
- testRunner.clearTransferState();
- testRunner.run();
-
-
testRunner.assertAllFlowFilesTransferred(EncryptContent.REL_SUCCESS, 1);
-
- MockFlowFile flowFile =
testRunner.getFlowFilesForRelationship(EncryptContent.REL_SUCCESS).get(0);
- testRunner.assertQueueEmpty();
-
- testRunner.setProperty(EncryptContent.MODE,
EncryptContent.DECRYPT_MODE);
- // Encryption cipher is inferred from ciphertext, this
property deliberately set a fixed cipher to prove
- // the output will still be correct
-
testRunner.setProperty(EncryptContent.PGP_SYMMETRIC_ENCRYPTION_CIPHER, "1");
-
- testRunner.enqueue(flowFile);
- testRunner.clearTransferState();
- testRunner.run();
-
testRunner.assertAllFlowFilesTransferred(EncryptContent.REL_SUCCESS, 1);
-
- flowFile =
testRunner.getFlowFilesForRelationship(EncryptContent.REL_SUCCESS).get(0);
- flowFile.assertContentEquals("A cool plaintext!");
- }
- }
- }
-
- @Test
- public void testPGPCiphers() throws Exception {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncryptContent());
- testRunner.setProperty(EncryptContent.PASSWORD, "passwordpassword");
// a >= 16 characters password
- testRunner.setProperty(EncryptContent.KEY_DERIVATION_FUNCTION,
KeyDerivationFunction.NONE.name());
-
- List<String> pgpAlgorithms = new ArrayList<>();
- pgpAlgorithms.add("PGP");
- pgpAlgorithms.add("PGP_ASCII_ARMOR");
-
- for (String algorithm : pgpAlgorithms) {
-
- testRunner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
algorithm);
- for (AllowableValue cipher :
Objects.requireNonNull(getPGPCipherList())) {
-
testRunner.setProperty(EncryptContent.PGP_SYMMETRIC_ENCRYPTION_CIPHER,
cipher.getValue());
- testRunner.setProperty(EncryptContent.MODE,
EncryptContent.ENCRYPT_MODE);
-
- testRunner.enqueue("A cool plaintext!");
- testRunner.clearTransferState();
- testRunner.run();
-
-
testRunner.assertAllFlowFilesTransferred(EncryptContent.REL_SUCCESS, 1);
-
- MockFlowFile flowFile =
testRunner.getFlowFilesForRelationship(EncryptContent.REL_SUCCESS).get(0);
- testRunner.assertQueueEmpty();
-
- // Other than the round trip, checks that the provided cipher
is actually used, inferring it from the ciphertext
- InputStream ciphertext = new
ByteArrayInputStream(flowFile.toByteArray());
- BCPGInputStream pgpin = new
BCPGInputStream(getDecoderStream(ciphertext));
- assertEquals(3, pgpin.nextPacketTag());
- assertEquals(Integer.parseInt(cipher.getValue()),
- ((SymmetricKeyEncSessionPacket)
pgpin.readPacket()).getEncAlgorithm());
- pgpin.close();
- }
- }
- }
-
@Test
public void testShouldDetermineMaxKeySizeForAlgorithms() {
final String AES_ALGORITHM =
EncryptionMethod.MD5_256AES.getAlgorithm();
@@ -320,143 +221,6 @@ public class TestEncryptContent {
runner.assertAllFlowFilesTransferred(EncryptContent.REL_FAILURE, 1);
}
- @Test
- public void testPGPDecrypt() throws IOException {
- final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
- runner.setProperty(EncryptContent.MODE, EncryptContent.DECRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP_ASCII_ARMOR.name());
- runner.setProperty(EncryptContent.PASSWORD, "Hello, World!");
-
-
runner.enqueue(Paths.get("src/test/resources/TestEncryptContent/text.txt.asc"));
- runner.run();
-
- runner.assertAllFlowFilesTransferred(EncryptContent.REL_SUCCESS, 1);
- final MockFlowFile flowFile =
runner.getFlowFilesForRelationship(EncryptContent.REL_SUCCESS).get(0);
-
flowFile.assertContentEquals(Paths.get("src/test/resources/TestEncryptContent/text.txt"));
- }
-
- @Test
- public void testShouldValidatePGPPublicKeyringRequiresUserId() {
- // Arrange
- final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
- Collection<ValidationResult> results;
- MockProcessContext pc;
-
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP.name());
- runner.setProperty(EncryptContent.PUBLIC_KEYRING,
"src/test/resources/TestEncryptContent/pubring.gpg");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
-
- // Act
- results = pc.validate();
-
- // Assert
- assertEquals(1, results.size());
- ValidationResult vr = (ValidationResult) results.toArray()[0];
- String expectedResult = " encryption without a " +
EncryptContent.PASSWORD.getDisplayName() + " requires both "
- + EncryptContent.PUBLIC_KEYRING.getDisplayName() + " and "
- + EncryptContent.PUBLIC_KEY_USERID.getDisplayName();
- String message = "'" + vr.toString() + "' contains '" + expectedResult
+ "'";
- assertTrue(vr.toString().contains(expectedResult), message);
- }
-
- @Test
- public void testShouldValidatePGPPublicKeyringExists() {
- // Arrange
- final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
- Collection<ValidationResult> results;
- MockProcessContext pc;
-
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP.name());
- runner.setProperty(EncryptContent.PUBLIC_KEYRING,
"src/test/resources/TestEncryptContent/pubring.gpg.missing");
- runner.setProperty(EncryptContent.PUBLIC_KEY_USERID, "USERID");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
-
- // Act
- results = pc.validate();
-
- // Assert
- assertEquals(1, results.size());
- ValidationResult vr = (ValidationResult) results.toArray()[0];
- String expectedResult = "java.io.FileNotFoundException";
- String message = "'" + vr.toString() + "' contains '" + expectedResult
+ "'";
- assertTrue(vr.toString().contains(expectedResult), message);
- }
-
- @Test
- public void testShouldValidatePGPPublicKeyringIsProperFormat() {
- // Arrange
- final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
- Collection<ValidationResult> results;
- MockProcessContext pc;
-
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP.name());
- runner.setProperty(EncryptContent.PUBLIC_KEYRING,
"src/test/resources/TestEncryptContent/text.txt");
- runner.setProperty(EncryptContent.PUBLIC_KEY_USERID, "USERID");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
-
- // Act
- results = pc.validate();
-
- // Assert
- assertEquals(1, results.size());
- ValidationResult vr = (ValidationResult) results.toArray()[0];
- String expectedResult = " java.io.IOException: invalid header
encountered";
- String message = "'" + vr.toString() + "' contains '" + expectedResult
+ "'";
- assertTrue(vr.toString().contains(expectedResult), message);
- }
-
- @Test
- public void testShouldValidatePGPPublicKeyringContainsUserId() {
- // Arrange
- final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
- Collection<ValidationResult> results;
- MockProcessContext pc;
-
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP.name());
- runner.setProperty(EncryptContent.PUBLIC_KEYRING,
"src/test/resources/TestEncryptContent/pubring.gpg");
- runner.setProperty(EncryptContent.PUBLIC_KEY_USERID, "USERID");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
-
- // Act
- results = pc.validate();
-
- // Assert
- assertEquals(1, results.size());
- ValidationResult vr = (ValidationResult) results.toArray()[0];
- String expectedResult = "PGPException: Could not find a public key
with the given userId";
- String message = "'" + vr.toString() + "' contains '" + expectedResult
+ "'";
- assertTrue(vr.toString().contains(expectedResult), message);
- }
-
- @Test
- public void testShouldExtractPGPPublicKeyFromKeyring() {
- // Arrange
- final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
- Collection<ValidationResult> results;
- MockProcessContext pc;
-
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP.name());
- runner.setProperty(EncryptContent.PUBLIC_KEYRING,
"src/test/resources/TestEncryptContent/pubring.gpg");
- runner.setProperty(EncryptContent.PUBLIC_KEY_USERID, "NiFi PGP Test
Key (Short test key for NiFi PGP unit tests)
<[email protected]>");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
-
- // Act
- results = pc.validate();
-
- // Assert
- assertEquals(0, results.size());
- }
-
@Test
public void testValidation() {
final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
@@ -491,112 +255,6 @@ public class TestEncryptContent {
results = pc.validate();
assertEquals(0, results.size(), results.toString());
-
- runner.removeProperty(EncryptContent.PASSWORD);
-
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP.name());
- runner.setProperty(EncryptContent.PUBLIC_KEYRING,
"src/test/resources/TestEncryptContent/text.txt");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
- results = pc.validate();
- assertEquals(1, results.size());
- for (final ValidationResult vr : results) {
- assertTrue(vr.toString().contains(
- " encryption without a " +
EncryptContent.PASSWORD.getDisplayName() + " requires both "
- + EncryptContent.PUBLIC_KEYRING.getDisplayName() +
" and "
- +
EncryptContent.PUBLIC_KEY_USERID.getDisplayName()));
- }
-
- // Legacy tests moved to individual tests to comply with new library
-
- // TODO: Move secring tests out to individual as well
-
- runner.removeProperty(EncryptContent.PUBLIC_KEYRING);
- runner.removeProperty(EncryptContent.PUBLIC_KEY_USERID);
-
- runner.setProperty(EncryptContent.MODE, EncryptContent.DECRYPT_MODE);
- runner.setProperty(EncryptContent.PRIVATE_KEYRING,
"src/test/resources/TestEncryptContent/secring.gpg");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
- results = pc.validate();
- assertEquals(1, results.size());
- for (final ValidationResult vr : results) {
- assertTrue(vr.toString().contains(
- " decryption without a " +
EncryptContent.PASSWORD.getDisplayName() + " requires both "
- + EncryptContent.PRIVATE_KEYRING.getDisplayName()
+ " and "
- +
EncryptContent.PRIVATE_KEYRING_PASSPHRASE.getDisplayName()));
-
- }
-
- runner.setProperty(EncryptContent.PRIVATE_KEYRING_PASSPHRASE,
"PASSWORD");
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
- results = pc.validate();
- assertEquals(1, results.size());
- for (final ValidationResult vr : results) {
- assertTrue(vr.toString().contains(
- " could not be opened with the provided " +
EncryptContent.PRIVATE_KEYRING_PASSPHRASE.getDisplayName()));
-
- }
- runner.removeProperty(EncryptContent.PRIVATE_KEYRING_PASSPHRASE);
-
- // This configuration is invalid because
PGP_SYMMETRIC_ENCRYPTION_CIPHER is outside the allowed [1-13] interval
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM, "PGP");
- runner.setProperty(EncryptContent.PASSWORD, "PASSWORD");
- runner.setProperty(EncryptContent.PGP_SYMMETRIC_ENCRYPTION_CIPHER,
"256");
- runner.assertNotValid();
-
- // This configuration is invalid because
PGP_SYMMETRIC_ENCRYPTION_CIPHER points to SAFER cipher which is unsupported
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM, "PGP");
- runner.setProperty(EncryptContent.PASSWORD, "PASSWORD");
- runner.setProperty(EncryptContent.PGP_SYMMETRIC_ENCRYPTION_CIPHER,
"5");
- runner.assertNotValid();
-
- // This configuration is valid
- runner.setProperty(EncryptContent.MODE, EncryptContent.DECRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM, "PGP");
- runner.setProperty(EncryptContent.PASSWORD, "PASSWORD");
- runner.removeProperty(EncryptContent.PGP_SYMMETRIC_ENCRYPTION_CIPHER);
- runner.assertValid();
-
- // This configuration is valid because the default value will be used
for PGP_SYMMETRIC_ENCRYPTION_CIPHER
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM, "PGP");
- runner.setProperty(EncryptContent.PASSWORD, "PASSWORD");
- runner.removeProperty(EncryptContent.PGP_SYMMETRIC_ENCRYPTION_CIPHER);
- runner.assertValid();
- }
-
- @Test
- void testShouldValidateMaxKeySizeForAlgorithmsOnUnlimitedStrengthJVM() {
- final TestRunner runner =
TestRunners.newTestRunner(EncryptContent.class);
- Collection<ValidationResult> results;
- MockProcessContext pc;
-
- EncryptionMethod encryptionMethod = EncryptionMethod.AES_CBC;
-
- // Integer.MAX_VALUE or 128, so use 256 or 128
- final int MAX_KEY_LENGTH =
Math.min(PasswordBasedEncryptor.getMaxAllowedKeyLength(encryptionMethod.getAlgorithm()),
256);
- final String TOO_LONG_KEY_HEX = StringUtils.repeat("ab",
(MAX_KEY_LENGTH / 8 + 1));
-
- runner.setProperty(EncryptContent.MODE, EncryptContent.ENCRYPT_MODE);
- runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
encryptionMethod.name());
- runner.setProperty(EncryptContent.KEY_DERIVATION_FUNCTION,
KeyDerivationFunction.NONE.name());
- runner.setProperty(EncryptContent.RAW_KEY_HEX, TOO_LONG_KEY_HEX);
-
- runner.enqueue(new byte[0]);
- pc = (MockProcessContext) runner.getProcessContext();
-
- results = pc.validate();
-
- assertEquals(1, results.size());
- ValidationResult vr = results.iterator().next();
-
- String expectedResult = "'raw-key-hex' is invalid because Key must be
valid length [128, 192, 256]";
- String message = "'" + vr.toString() + "' contains '" + expectedResult
+ "'";
- assertTrue(vr.toString().contains(expectedResult), message);
}
@Test
@@ -728,7 +386,7 @@ public class TestEncryptContent {
// Scenario 2 - PW w/ KDF in [BCRYPT, SCRYPT, PBKDF2, ARGON2] & em
in [CBC, CTR, GCM] (no RKH)
final List<KeyDerivationFunction> validKDFs = Arrays
.stream(KeyDerivationFunction.values())
- .filter(it -> it.isStrongKDF())
+ .filter(KeyDerivationFunction::isStrongKDF)
.collect(Collectors.toList());
for (final KeyDerivationFunction kdf : validKDFs) {
runner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
kem.name());
@@ -872,7 +530,7 @@ public class TestEncryptContent {
assertEquals(EXPECTED_SALT_HEX,
flowFile.getAttribute("encryptcontent.salt"));
assertEquals("16",
flowFile.getAttribute("encryptcontent.salt_length"));
assertEquals(EXPECTED_KDF_SALT,
flowFile.getAttribute("encryptcontent.kdf_salt"));
- final int kdfSaltLength =
Integer.valueOf(flowFile.getAttribute("encryptcontent.kdf_salt_length"));
+ final int kdfSaltLength =
Integer.parseInt(flowFile.getAttribute("encryptcontent.kdf_salt_length"));
assertTrue(kdfSaltLength >= 29 && kdfSaltLength <= 54);
assertEquals(EXPECTED_IV_HEX,
flowFile.getAttribute("encryptcontent.iv"));
assertEquals("16", flowFile.getAttribute("encryptcontent.iv_length"));
@@ -1071,38 +729,6 @@ public class TestEncryptContent {
}
}
- @Test
- void testPGPPasswordShouldSupportExpressionLanguage() {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncryptContent());
- testRunner.setProperty(EncryptContent.MODE,
EncryptContent.DECRYPT_MODE);
- testRunner.setProperty(EncryptContent.ENCRYPTION_ALGORITHM,
EncryptionMethod.PGP.name());
- testRunner.setProperty(EncryptContent.PRIVATE_KEYRING,
"src/test/resources/TestEncryptContent/secring.gpg");
-
- Collection<ValidationResult> results;
- MockProcessContext pc;
-
- // Verify this is the correct password
- final String passphraseWithoutEL = "thisIsABadPassword";
- testRunner.setProperty(EncryptContent.PRIVATE_KEYRING_PASSPHRASE,
passphraseWithoutEL);
-
- testRunner.clearTransferState();
- testRunner.enqueue(new byte[0]);
- pc = (MockProcessContext) testRunner.getProcessContext();
-
- results = pc.validate();
- assertEquals(0, results.size(), results.toString());
-
- final String passphraseWithEL = "${literal('thisIsABadPassword')}";
- testRunner.setProperty(EncryptContent.PRIVATE_KEYRING_PASSPHRASE,
passphraseWithEL);
-
- testRunner.clearTransferState();
- testRunner.enqueue(new byte[0]);
-
- results = pc.validate();
-
- assertEquals(0, results.size(), results.toString());
- }
-
@Test
void testArgon2ShouldIncludeFullSalt() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new
EncryptContent());
@@ -1142,8 +768,7 @@ public class TestEncryptContent {
private static String extractRawSaltHexFromFullSalt(byte[] fullSaltBytes,
KeyDerivationFunction kdf) {
// Salt will be in Base64 (or Radix64) for strong KDFs
byte[] rawSaltBytes = CipherUtility.extractRawSalt(fullSaltBytes, kdf);
- String rawSaltHex = Hex.encodeHexString(rawSaltBytes);
- return rawSaltHex;
+ return Hex.encodeHexString(rawSaltBytes);
}
private static TimeDuration calculateTimestampDifference(Date date, String
timestamp) throws ParseException {
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/security/util/crypto/OpenPGPKeyBasedEncryptorTest.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/security/util/crypto/OpenPGPKeyBasedEncryptorTest.java
deleted file mode 100644
index e5d6421dc8..0000000000
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/security/util/crypto/OpenPGPKeyBasedEncryptorTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.security.util.crypto;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-import org.apache.nifi.processor.io.StreamCallback;
-import org.apache.nifi.security.util.EncryptionMethod;
-import org.bouncycastle.openpgp.PGPEncryptedData;
-
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-
-public class OpenPGPKeyBasedEncryptorTest {
- private static final String FILENAME =
OpenPGPKeyBasedEncryptorTest.class.getSimpleName();
-
- private static final String SECRET_KEYRING_PATH =
"src/test/resources/TestEncryptContent/secring.gpg";
-
- private static final String PUBLIC_KEYRING_PATH =
"src/test/resources/TestEncryptContent/pubring.gpg";
-
- private static final String USER_ID = "NiFi PGP Test Key (Short test key
for NiFi PGP unit tests) <[email protected]>";
-
- private static final String PASSWORD = "thisIsABadPassword";
-
- private static final int CIPHER = PGPEncryptedData.AES_128;
-
- private static final byte[] PLAINTEXT = new byte[]{0, 1, 2, 3, 4, 5, 6, 7,
8};
-
- @Test
- public void testEncryptDecrypt() throws Exception {
- final ByteArrayInputStream plainStream = new
ByteArrayInputStream(PLAINTEXT);
- final OpenPGPKeyBasedEncryptor encryptor = new
OpenPGPKeyBasedEncryptor(
- EncryptionMethod.PGP.getAlgorithm(), CIPHER,
EncryptionMethod.PGP.getProvider(), PUBLIC_KEYRING_PATH, USER_ID, new char[0],
FILENAME);
- StreamCallback encryptionCallback = encryptor.getEncryptionCallback();
-
- OpenPGPKeyBasedEncryptor decryptor = new OpenPGPKeyBasedEncryptor(
- EncryptionMethod.PGP.getAlgorithm(), CIPHER,
EncryptionMethod.PGP.getProvider(), SECRET_KEYRING_PATH, USER_ID,
PASSWORD.toCharArray(), FILENAME);
- StreamCallback decryptionCallback = decryptor.getDecryptionCallback();
-
- final ByteArrayOutputStream encryptedStream = new
ByteArrayOutputStream();
- encryptionCallback.process(plainStream, encryptedStream);
-
- final InputStream encryptedInputStream = new
ByteArrayInputStream(encryptedStream.toByteArray());
- final ByteArrayOutputStream decryptedStream = new
ByteArrayOutputStream();
- decryptionCallback.process(encryptedInputStream, decryptedStream);
-
- byte[] decryptedBytes = decryptedStream.toByteArray();
- assertArrayEquals(PLAINTEXT, decryptedBytes);
- }
-}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/security/util/crypto/OpenPGPPasswordBasedEncryptorTest.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/security/util/crypto/OpenPGPPasswordBasedEncryptorTest.java
deleted file mode 100644
index d335778341..0000000000
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/security/util/crypto/OpenPGPPasswordBasedEncryptorTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.nifi.security.util.crypto;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-
-import org.apache.nifi.processor.io.StreamCallback;
-import org.apache.nifi.security.util.EncryptionMethod;
-import org.bouncycastle.openpgp.PGPEncryptedData;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-
-public class OpenPGPPasswordBasedEncryptorTest {
- private static final String FILENAME =
OpenPGPPasswordBasedEncryptorTest.class.getSimpleName();
-
- private static final int CIPHER = PGPEncryptedData.AES_128;
-
- private static final byte[] PLAINTEXT = new byte[]{0, 1, 2, 3, 4, 5, 6, 7,
8};
-
- private static final String PASSWORD =
OpenPGPPasswordBasedEncryptorTest.class.getName();
-
- @Test
- public void testEncryptDecrypt() throws Exception {
- final ByteArrayInputStream plainStream = new
ByteArrayInputStream(PLAINTEXT);
-
- final OpenPGPPasswordBasedEncryptor encryptor = new
OpenPGPPasswordBasedEncryptor(EncryptionMethod.PGP.getAlgorithm(),
- CIPHER, EncryptionMethod.PGP.getProvider(),
PASSWORD.toCharArray(), FILENAME);
-
- final StreamCallback encryptionCallback =
encryptor.getEncryptionCallback();
- final StreamCallback decryptionCallback =
encryptor.getDecryptionCallback();
-
- final ByteArrayOutputStream encryptedStream = new
ByteArrayOutputStream();
- encryptionCallback.process(plainStream, encryptedStream);
-
- final InputStream encryptedInputStream = new
ByteArrayInputStream(encryptedStream.toByteArray());
- final ByteArrayOutputStream decryptedStream = new
ByteArrayOutputStream();
- decryptionCallback.process(encryptedInputStream, decryptedStream);
-
- byte[] decryptedBytes = decryptedStream.toByteArray();
- assertArrayEquals(PLAINTEXT, decryptedBytes);
- }
-}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/pubring.gpg
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/pubring.gpg
deleted file mode 100644
index c32ef145f1..0000000000
Binary files
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/pubring.gpg
and /dev/null differ
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/secring.gpg
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/secring.gpg
deleted file mode 100644
index 26af32ab31..0000000000
Binary files
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/secring.gpg
and /dev/null differ
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.asc
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.asc
deleted file mode 100644
index 7607f83bca..0000000000
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.asc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
------BEGIN PGP MESSAGE-----
-Version: GnuPG v2
-
-jA0EAwMC54x6GeEEmLy3ycE/pY5T6vawFMS9/Io8chEQGD8UNAbZFzqXcVEvvy5f
-wJQggyuF6Lo1RZGnhxdGoz0do1DZzR0lVaTL8dR0/jtz/kRZ1omz+OxICuo9BaRX
-M+fT2mdna5lhDGJmE7nCctDaGwXqjglEXPqOdi8j/tL225HViTKP1VmlKuu8AjiH
-lMGuC65bqILSWCaE2jewCbsmjHPgLGmH9NN6EAo2kiFEMOrA+UYo35PuShkgQsZp
-gA0m2A31JjLW28SUsNd1vLk5bWBZaIFA1UvhR7u0pagv3qtu5f8qls19nHnAT/bz
-Kh2KrnIm0peWWVEPGQkFoK3Lt9vJTjmHdHPUXQHyg+SMN1PIGA2sxwiSrkQlAyon
-uNg/I24ctydWU+qndz+ycDWR6zBziA09KHw7uKo5CDtTm+Zo3K9U9uf9y8iZ+AKd
-vgF/4Nw2lJTqQfNtkmK+N+cKEyZNmJa4r+uDzJF/dCv8R5jGj2dBYRTLxj5tgllU
-4GiwuJR6w09hK0S0oe9XTdcNciWigb12H9z6U6JOse+1S/fYoUa0CZRJg9Bgeqym
-uuT/mNSKwRVcWN27vOGy+zGf0tqw6A5idLrK+8FZzd1sgxtKsgkYz8FcZgo9rq1f
-PHR9KF4JhaGpqNJmEu/GucYIAgq3aeo9GoV/RpDZtoHAVBuqPwcDTzGHeiAoZ49U
-6Q==
-=H5nf
------END PGP MESSAGE-----
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.gpg
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.gpg
deleted file mode 100644
index 0b78a99daf..0000000000
Binary files
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.gpg
and /dev/null differ
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.unsigned.gpg
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.unsigned.gpg
deleted file mode 100644
index c7bba1cb89..0000000000
Binary files
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/resources/TestEncryptContent/text.txt.unsigned.gpg
and /dev/null differ