[
https://issues.apache.org/jira/browse/NIFI-1257?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15129002#comment-15129002
]
ASF GitHub Bot commented on NIFI-1257:
--------------------------------------
Github user markap14 commented on a diff in the pull request:
https://github.com/apache/nifi/pull/201#discussion_r51632415
--- Diff:
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/crypto/CipherUtility.java
---
@@ -0,0 +1,271 @@
+/*
+ * 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.crypto;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.processor.exception.ProcessException;
+import org.apache.nifi.stream.io.ByteArrayOutputStream;
+import org.apache.nifi.stream.io.StreamUtils;
+
+import javax.crypto.Cipher;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class CipherUtility {
+
+ public static final int BUFFER_SIZE = 65536;
+
+ /**
+ * Returns the cipher algorithm from the full algorithm name. Useful
for getting key lengths, etc.
+ * <p/>
+ * Ex: PBEWITHMD5AND128BITAES-CBC-OPENSSL -> AES
+ *
+ * @param algorithm the full algorithm name
+ * @return the generic cipher name or the full algorithm if one cannot
be extracted
+ */
+ public static String parseCipherFromAlgorithm(final String algorithm) {
+ if (StringUtils.isEmpty(algorithm)) {
+ return algorithm;
+ }
+ String formattedAlgorithm = algorithm.toUpperCase();
+
+ // This is not optimal but the algorithms do not have a standard
format
+ final String AES = "AES";
+ final String TDES = "TRIPLEDES";
+ final String TDES_ALTERNATE = "DESEDE";
+ final String DES = "DES";
+ final String RC4 = "RC4";
+ final String RC2 = "RC2";
+ final String TWOFISH = "TWOFISH";
+ final List<String> SYMMETRIC_CIPHERS = Arrays.asList(AES, TDES,
TDES_ALTERNATE, DES, RC4, RC2, TWOFISH);
+
+ // The algorithms contain "TRIPLEDES" but the cipher name is
"DESede"
+ final String ACTUAL_TDES_CIPHER = "DESede";
+
+ for (String cipher : SYMMETRIC_CIPHERS) {
+ if (formattedAlgorithm.contains(cipher)) {
+ if (cipher.equals(TDES) || cipher.equals(TDES_ALTERNATE)) {
+ return ACTUAL_TDES_CIPHER;
+ } else {
+ return cipher;
+ }
+ }
+ }
+
+ return algorithm;
+ }
+
+ /**
+ * Returns the cipher key length from the full algorithm name. Useful
for getting key lengths, etc.
+ * <p/>
+ * Ex: PBEWITHMD5AND128BITAES-CBC-OPENSSL -> 128
+ *
+ * @param algorithm the full algorithm name
+ * @return the key length or -1 if one cannot be extracted
+ */
+ public static int parseKeyLengthFromAlgorithm(final String algorithm) {
+ int keyLength = parseActualKeyLengthFromAlgorithm(algorithm);
+ if (keyLength != -1) {
+ return keyLength;
+ } else {
+ // Key length not explicitly named in algorithm
+ String cipher = parseCipherFromAlgorithm(algorithm);
+ return getDefaultKeyLengthForCipher(cipher);
+ }
+ }
+
+ private static int parseActualKeyLengthFromAlgorithm(final String
algorithm) {
+ Pattern pattern = Pattern.compile("([\\d]+)BIT");
+ Matcher matcher = pattern.matcher(algorithm);
+ if (matcher.find()) {
+ return Integer.parseInt(matcher.group(1));
+ } else {
+ return -1;
+ }
+ }
+
+ /**
+ * Returns true if the provided key length is a valid key length for
the provided cipher family. Does not reflect if the Unlimited Strength
Cryptography Jurisdiction Policies are installed.
+ * Does not reflect if the key length is correct for a specific
combination of cipher and PBE-derived key length.
+ * <p/>
+ * Ex:
+ * <p/>
+ * 256 is valid for {@code AES/CBC/PKCS7Padding} but not {@code
PBEWITHMD5AND128BITAES-CBC-OPENSSL}. However, this method will return {@code
true} for both because it only gets the cipher
+ * family, {@code AES}.
+ * <p/>
+ * 64, AES -> false
+ * [128, 192, 256], AES -> true
+ *
+ * @param keyLength the key length in bits
+ * @param cipher the cipher family
+ * @return true if this key length is valid
+ */
+ public static boolean isValidKeyLength(int keyLength, final String
cipher) {
+ if (StringUtils.isEmpty(cipher)) {
+ return false;
+ }
+ return getValidKeyLengthsForAlgorithm(cipher).contains(keyLength);
+ }
+
+ /**
+ * Returns true if the provided key length is a valid key length for
the provided algorithm. Does not reflect if the Unlimited Strength Cryptography
Jurisdiction Policies are installed.
+ * <p/>
+ * Ex:
+ * <p/>
+ * 256 is valid for {@code AES/CBC/PKCS7Padding} but not {@code
PBEWITHMD5AND128BITAES-CBC-OPENSSL}.
+ * <p/>
+ * 64, AES/CBC/PKCS7Padding -> false
+ * [128, 192, 256], AES/CBC/PKCS7Padding -> true
+ * <p/>
+ * 128, PBEWITHMD5AND128BITAES-CBC-OPENSSL -> true
+ * [192, 256], PBEWITHMD5AND128BITAES-CBC-OPENSSL -> false
+ *
+ * @param keyLength the key length in bits
+ * @param algorithm the specific algorithm
+ * @return true if this key length is valid
+ */
+ public static boolean isValidKeyLengthForAlgorithm(int keyLength,
final String algorithm) {
+ if (StringUtils.isEmpty(algorithm)) {
+ return false;
+ }
+ return
getValidKeyLengthsForAlgorithm(algorithm).contains(keyLength);
+ }
+
+ public static List<Integer> getValidKeyLengthsForAlgorithm(String
algorithm) {
+ List<Integer> validKeyLengths = new ArrayList<>();
+ if (StringUtils.isEmpty(algorithm)) {
+ return validKeyLengths;
+ }
+
+ // Some algorithms specify a single key size
+ int keyLength = parseActualKeyLengthFromAlgorithm(algorithm);
+ if (keyLength != -1) {
+ validKeyLengths.add(keyLength);
+ return validKeyLengths;
+ }
+
+ // The algorithm does not specify a key size
+ String cipher = parseCipherFromAlgorithm(algorithm);
+ switch (cipher.toUpperCase()) {
+ case "DESEDE":
+ // 3DES keys have the cryptographic strength of 7/8
because of parity bits, but are often represented with n*8 bytes
+ return Arrays.asList(56, 64, 112, 128, 168, 192);
+ case "DES":
+ return Arrays.asList(56, 64);
+ case "RC2":
+ case "RC4":
+ case "RC5":
+ /** These ciphers can have arbitrary length keys but
that's a really bad idea, {@see http://crypto.stackexchange.com/a/9963/12569}.
+ * Also, RC* is deprecated and should be considered
insecure */
+ for (int i = 40; i <= 2048; i++) {
+ validKeyLengths.add(i);
+ }
+ return validKeyLengths;
+ case "AES":
+ case "TWOFISH":
+ return Arrays.asList(128, 192, 256);
+ default:
+ return validKeyLengths;
+ }
+ }
+
+ private static int getDefaultKeyLengthForCipher(String cipher) {
+ if (StringUtils.isEmpty(cipher)) {
+ return -1;
+ }
+ cipher = cipher.toUpperCase();
+ switch (cipher) {
+ case "DESEDE":
+ return 112;
+ case "DES":
+ return 64;
+ case "RC2":
+ case "RC4":
+ case "RC5":
+ default:
+ return 128;
+ }
+ }
+
+ public static void processStreams(Cipher cipher, InputStream in,
OutputStream out) {
+ try {
+ final byte[] buffer = new byte[BUFFER_SIZE];
+ int len;
+ while ((len = in.read(buffer)) > 0) {
+ final byte[] decryptedBytes = cipher.update(buffer, 0,
len);
+ if (decryptedBytes != null) {
+ out.write(decryptedBytes);
+ }
+ }
+
+ try {
--- End diff --
Can remove this try/catch, as the handling of Exception is the same as the
outer try/catch
> Provide additional KDFs for EncryptContent
> ------------------------------------------
>
> Key: NIFI-1257
> URL: https://issues.apache.org/jira/browse/NIFI-1257
> Project: Apache NiFi
> Issue Type: Improvement
> Components: Core Framework
> Affects Versions: 0.4.0
> Reporter: Andy LoPresto
> Assignee: Andy LoPresto
> Priority: Critical
> Labels: encryption, security
> Fix For: 0.5.0
>
>
> Currently, the two key derivation functions (KDF) supported are NiFi Legacy
> (1000 iterations of MD5 digest over a password and optional salt) and OpenSSL
> PKCS#5 v1.5 (a single iteration of MD5 digest over a password and optional
> salt).
> Both of these are very weak -- they use a deprecated cryptographic hash
> function (CHF) with known weakness and susceptibility to collisions (with
> demonstrated attacks) and a non-configurable and tightly coupled iteration
> count to derive the key and IV.
> Current best practice KDFs (with work factor recommendations) are as follows:
> * PBKDF2 with variable hash function (SHA1, SHA256, SHA384, SHA512, or
> ideally HMAC variants of these functions) and variable iteration count (in
> the 10k - 1M range).
> * bcrypt with work factor of 12 - 16
> * scrypt with work factor of (2^14 - 2^20, 8, 1)
> The salt and iteration count should be stored alongside the hashed record
> (bcrypt handles this natively).
> Notes:
> * http://wildlyinaccurate.com/bcrypt-choosing-a-work-factor/
> * http://blog.ircmaxell.com/2012/12/seven-ways-to-screw-up-bcrypt.html
> *
> http://security.stackexchange.com/questions/17207/recommended-of-rounds-for-bcrypt
> *
> http://security.stackexchange.com/questions/3959/recommended-of-iterations-when-using-pkbdf2-sha256/3993#3993
> *
> http://security.stackexchange.com/questions/4781/do-any-security-experts-recommend-bcrypt-for-password-storage/6415
>
> *
> http://web.archive.org/web/20130407190430/http://chargen.matasano.com/chargen/2007/9/7/enough-with-the-rainbow-tables-what-you-need-to-know-about-s.html
> *
> https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2015/march/enough-with-the-salts-updates-on-secure-password-schemes/
> * http://www.tarsnap.com/scrypt.html
> * http://www.tarsnap.com/scrypt/scrypt.pdf
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)