This is an automated email from the ASF dual-hosted git repository.

alopresto pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d25b63  NIFI-1474 Added method to check p boundary. Added a unit 
test. NIFI-1474 Added unit test for constructor p boundaries. Added p boundary 
conditions. NIFI-1474 Updated documentation regarding p boundary. NIFI-1474 
Added r validation and unit tests. Added Javadoc for new methods.
4d25b63 is described below

commit 4d25b6341ccba0ee24da15198d030d8132972e7c
Author: mtien <[email protected]>
AuthorDate: Wed Oct 23 17:34:37 2019 -0700

    NIFI-1474 Added method to check p boundary. Added a unit test.
    NIFI-1474 Added unit test for constructor p boundaries. Added p boundary 
conditions.
    NIFI-1474 Updated documentation regarding p boundary.
    NIFI-1474 Added r validation and unit tests. Added Javadoc for new methods.
    
    This closes #3844.
    
    Signed-off-by: Andy LoPresto <[email protected]>
---
 .../security/util/crypto/ScryptCipherProvider.java |  33 ++++++-
 .../crypto/ScryptCipherProviderGroovyTest.groovy   | 105 +++++++++++++++++++++
 .../src/main/asciidoc/administration-guide.adoc    |   2 +-
 3 files changed, 138 insertions(+), 2 deletions(-)

diff --git 
a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/ScryptCipherProvider.java
 
b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/ScryptCipherProvider.java
index b532d8e..7bc1882 100644
--- 
a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/ScryptCipherProvider.java
+++ 
b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/util/crypto/ScryptCipherProvider.java
@@ -25,6 +25,7 @@ import java.util.regex.Pattern;
 import javax.crypto.Cipher;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
+
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.binary.Hex;
@@ -78,6 +79,36 @@ public class ScryptCipherProvider extends 
RandomIVPBECipherProvider {
         if (p < DEFAULT_P) {
             logger.warn("The provided parallelization factor {} is below the 
recommended minimum {}", p, DEFAULT_P);
         }
+        if (!isPValid(r, p)) {
+            logger.warn("Based on the provided block size {}, the provided 
parallelization factor {} is out of bounds", r, p);
+            throw new IllegalArgumentException("Invalid p value exceeds p 
boundary");
+        }
+    }
+
+    /**
+     * Returns whether the provided parallelization factor (p value) is within 
boundaries. The lower bound > 0 and the
+     * upper bound is calculated based on the provided block size (r value).
+     * @param r the block size in bytes
+     * @param p the parallelization factor
+     * @return true if p is within boundaries
+     */
+    public static boolean isPValid(int r, int p) {
+        if (!isRValid(r)){
+            logger.warn("The provided block size {} must be greater than 0", 
r);
+            throw new IllegalArgumentException("Invalid r value; must be 
greater than 0");
+        }
+        // Calculate p boundary
+        double pBoundary = ((Math.pow(2, 32)) - 1) * (32.0 / (r * 128));
+        return p <= pBoundary && p > 0;
+    }
+
+    /**
+     * Returns whether the provided block size (r value) is a positive integer 
or not.
+     * @param r the block size in bytes
+     * @return true if r is a positive integer
+     */
+    public static boolean isRValid(int r) {
+        return r > 0;
     }
 
     /**
@@ -112,7 +143,7 @@ public class ScryptCipherProvider extends 
RandomIVPBECipherProvider {
 
     /**
      * Returns an initialized cipher for the specified algorithm. The key (and 
IV if necessary) are derived by the KDF of the implementation.
-     *
+     * <p>
      * The IV can be retrieved by the calling method using {@link 
Cipher#getIV()}.
      *
      * @param encryptionMethod the {@link EncryptionMethod}
diff --git 
a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/crypto/ScryptCipherProviderGroovyTest.groovy
 
b/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/crypto/ScryptCipherProviderGroovyTest.groovy
index 0e469ab..7b912da 100644
--- 
a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/crypto/ScryptCipherProviderGroovyTest.groovy
+++ 
b/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/util/crypto/ScryptCipherProviderGroovyTest.groovy
@@ -513,6 +513,111 @@ class ScryptCipherProviderGroovyTest {
         assert params[2] == EXPECTED_P
     }
 
+    @Test
+    void testShouldVerifyPBoundary() throws Exception {
+        // Arrange
+        final int r = 8;
+        final int p = 1;
+
+        // Act
+        boolean valid = ScryptCipherProvider.isPValid(r, p)
+
+        // Assert
+        assert valid
+    }
+
+    @Test
+    void testShouldFailPBoundary() throws Exception {
+        // Arrange
+        // The p upper bound is calculated with the formula below, when r = 8:
+        // pBoundary = ((Math.pow(2,32))-1) * (32.0/(r * 128)), where 
pBoundary = 134217727.96875;
+        Map costParameters = [8:134217729, 128:8388608, 4096: 0]
+
+        // Act
+        def results = costParameters.collectEntries { r, p ->
+            def isValid = ScryptCipherProvider.isPValid(r, p)
+            [r, isValid]
+        }
+
+        // Assert
+        results.each { r, isPValid ->
+            logger.info("For r ${r}, p is ${isPValid}")
+            assert !isPValid
+        }
+    }
+
+    @Test
+    void testShouldVerifyRValue() throws Exception {
+        // Arrange
+        final int r = 8;
+
+        // Act
+        boolean valid = ScryptCipherProvider.isRValid(r)
+
+        // Assert
+        assert valid
+    }
+
+    @Test
+    void testShouldFailRValue() throws Exception {
+        // Arrange
+        final int r = 0;
+
+        // Act
+        boolean valid = ScryptCipherProvider.isRValid(r)
+
+        // Assert
+        assert !valid
+    }
+
+    @Test
+    void testShouldValidateScryptCipherProviderPBoundary() throws Exception {
+        // Arrange
+        final int n = 64;
+        final int r = 8;
+        final int p = 1;
+
+        // Act
+        ScryptCipherProvider testCipherProvider = new ScryptCipherProvider(n, 
r, p)
+
+        // Assert
+        assert testCipherProvider
+    }
+
+    @Test
+    void testShouldCatchInvalidP() throws Exception {
+        // Arrange
+        final int n = 64;
+        final int r = 8;
+        final int p = 0;
+
+        // Act
+        def msg = shouldFail(IllegalArgumentException) {
+            ScryptCipherProvider testCipherProvider = new 
ScryptCipherProvider(n, r, p)
+        }
+        logger.expected(msg)
+
+        // Assert
+        assert msg =~ "Invalid p value exceeds p boundary"
+    }
+
+    @Test
+    void testShouldCatchInvalidR() throws Exception {
+        // Arrange
+        final int n = 64;
+        final int r = 0;
+        final int p = 0;
+
+        // Act
+        def msg = shouldFail(IllegalArgumentException) {
+            ScryptCipherProvider testCipherProvider = new 
ScryptCipherProvider(n, r, p)
+        }
+        logger.expected(msg)
+
+        // Assert
+        assert msg =~ "Invalid r value; must be greater than 0"
+    }
+
     @Ignore("This test can be run on a specific machine to evaluate if the 
default parameters are sufficient")
     @Test
     void testDefaultConstructorShouldProvideStrongParameters() {
diff --git a/nifi-docs/src/main/asciidoc/administration-guide.adoc 
b/nifi-docs/src/main/asciidoc/administration-guide.adoc
index 81fb811..07b0a46 100644
--- a/nifi-docs/src/main/asciidoc/administration-guide.adoc
+++ b/nifi-docs/src/main/asciidoc/administration-guide.adoc
@@ -1392,7 +1392,7 @@ Here are the KDFs currently supported by NiFi (primarily 
in the `EncryptContent`
 * Scrypt
 ** This KDF was added in v0.5.0.
 ** link:https://en.wikipedia.org/wiki/Scrypt[Scrypt^] is an adaptive function 
designed in response to `bcrypt`. This KDF is recommended as it requires 
relatively large amounts of memory for each derivation, making it resistant to 
hardware brute-force attacks.
-** The recommended minimum cost is `N`=2^14^, `r`=8, `p`=1 (as of 2/1/2016 on 
commodity hardware) and should be increased to the threshold at which 
legitimate systems will encounter detrimental delays (see schedule below or use 
`ScryptCipherProviderGroovyTest#testDefaultConstructorShouldProvideStrongParameters()`
 to calculate safe minimums).
+** The recommended minimum cost is `N`=2^14^, `r`=8, `p`=1 (as of 2/1/2016 on 
commodity hardware). `p` must be a positive integer and less than `(2^32 − 1) * 
(Hlen/MFlen)` where `Hlen` is the length in octets of the digest function 
output (32 for SHA-256) and `MFlen` is the length in octets of the mixing 
function output, defined as `r * 128`. These parameters should be increased to 
the threshold at which legitimate systems will encounter detrimental delays 
(see schedule below or use `Scr [...]
 ** The salt format is `$s0$e0101$ABCDEFGHIJKLMNOPQRSTUV`. The salt is 
delimited by `$` and the three sections are as follows:
 *** `s0` - the version of the format. NiFi currently uses `s0` for all salts 
generated internally.
 *** `e0101` - the cost parameters. This is actually a hexadecimal encoding of 
`N`, `r`, `p` using shifts. This can be formed/parsed using 
`Scrypt#encodeParams()` and `Scrypt#parseParameters()`.

Reply via email to