[ 
https://issues.apache.org/jira/browse/NIFI-1257?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15132928#comment-15132928
 ] 

ASF GitHub Bot commented on NIFI-1257:
--------------------------------------

Github user alopresto commented on a diff in the pull request:

    https://github.com/apache/nifi/pull/201#discussion_r51930434
  
    --- Diff: 
nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/groovy/org/apache/nifi/processors/standard/util/crypto/CipherUtilityGroovyTest.groovy
 ---
    @@ -0,0 +1,251 @@
    +/*
    + * 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.nifi.security.util.EncryptionMethod
    +import org.bouncycastle.jce.provider.BouncyCastleProvider
    +import org.junit.After
    +import org.junit.Before
    +import org.junit.BeforeClass
    +import org.junit.Test
    +import org.junit.runner.RunWith
    +import org.junit.runners.JUnit4
    +import org.slf4j.Logger
    +import org.slf4j.LoggerFactory
    +
    +import java.security.Security
    +
    +@RunWith(JUnit4.class)
    +class CipherUtilityGroovyTest extends GroovyTestCase {
    +    private static final Logger logger = 
LoggerFactory.getLogger(CipherUtilityGroovyTest.class)
    +
    +    // TripleDES must precede DES for automatic grouping precedence
    +    private static final List<String> CIPHERS = ["AES", "TRIPLEDES", 
"DES", "RC2", "RC4", "RC5", "TWOFISH"]
    +    private static final List<String> SYMMETRIC_ALGORITHMS = 
EncryptionMethod.values().findAll { it.algorithm.startsWith("PBE") || 
it.algorithm.startsWith("AES") }*.algorithm
    +    private static final Map<String, List<String>> 
ALGORITHMS_MAPPED_BY_CIPHER = SYMMETRIC_ALGORITHMS.groupBy { String algorithm 
-> CIPHERS.find { algorithm.contains(it) } }
    +
    +    // Manually mapped as of 01/19/16 0.5.0
    +    private static final Map<Integer, List<String>> 
ALGORITHMS_MAPPED_BY_KEY_LENGTH = [
    +            (40) : ["PBEWITHSHAAND40BITRC2-CBC",
    +                    "PBEWITHSHAAND40BITRC4"],
    +            (64) : ["PBEWITHMD5ANDDES",
    +                    "PBEWITHSHA1ANDDES"],
    +            (112): ["PBEWITHSHAAND2-KEYTRIPLEDES-CBC",
    +                    "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"],
    +            (128): ["PBEWITHMD5AND128BITAES-CBC-OPENSSL",
    +                    "PBEWITHMD5ANDRC2",
    +                    "PBEWITHSHA1ANDRC2",
    +                    "PBEWITHSHA256AND128BITAES-CBC-BC",
    +                    "PBEWITHSHAAND128BITAES-CBC-BC",
    +                    "PBEWITHSHAAND128BITRC2-CBC",
    +                    "PBEWITHSHAAND128BITRC4",
    +                    "PBEWITHSHAANDTWOFISH-CBC",
    +                    "AES/CBC/PKCS7Padding",
    +                    "AES/CTR/NoPadding",
    +                    "AES/GCM/NoPadding"],
    +            (192): ["PBEWITHMD5AND192BITAES-CBC-OPENSSL",
    +                    "PBEWITHSHA256AND192BITAES-CBC-BC",
    +                    "PBEWITHSHAAND192BITAES-CBC-BC",
    +                    "AES/CBC/PKCS7Padding",
    +                    "AES/CTR/NoPadding",
    +                    "AES/GCM/NoPadding"],
    +            (256): ["PBEWITHMD5AND256BITAES-CBC-OPENSSL",
    +                    "PBEWITHSHA256AND256BITAES-CBC-BC",
    +                    "PBEWITHSHAAND256BITAES-CBC-BC",
    +                    "AES/CBC/PKCS7Padding",
    +                    "AES/CTR/NoPadding",
    +                    "AES/GCM/NoPadding"]
    +    ]
    +
    +    @BeforeClass
    +    static void setUpOnce() {
    +        Security.addProvider(new BouncyCastleProvider());
    +
    +        // Fix because TRIPLEDES -> DESede
    +        def tripleDESAlgorithms = 
ALGORITHMS_MAPPED_BY_CIPHER.remove("TRIPLEDES")
    +        ALGORITHMS_MAPPED_BY_CIPHER.put("DESede", tripleDESAlgorithms)
    +
    +        logger.info("Mapped algorithms: ${ALGORITHMS_MAPPED_BY_CIPHER}")
    +    }
    +
    +    @Before
    +    void setUp() throws Exception {
    +
    +    }
    +
    +    @After
    +    void tearDown() throws Exception {
    +
    +    }
    +
    +    @Test
    +    void testShouldParseCipherFromAlgorithm() {
    +        // Arrange
    +        final def EXPECTED_ALGORITHMS = ALGORITHMS_MAPPED_BY_CIPHER
    +
    +        // Act
    +        SYMMETRIC_ALGORITHMS.each { String algorithm ->
    +            String cipher = 
CipherUtility.parseCipherFromAlgorithm(algorithm)
    +            logger.info("Extracted ${cipher} from ${algorithm}")
    +
    +            // Assert
    +            assert EXPECTED_ALGORITHMS.get(cipher).contains(algorithm)
    +        }
    +    }
    +
    +    @Test
    +    void testShouldParseKeyLengthFromAlgorithm() {
    +        // Arrange
    +        final def EXPECTED_ALGORITHMS = ALGORITHMS_MAPPED_BY_KEY_LENGTH
    +
    +        // Act
    +        SYMMETRIC_ALGORITHMS.each { String algorithm ->
    +            int keyLength = 
CipherUtility.parseKeyLengthFromAlgorithm(algorithm)
    +            logger.info("Extracted ${keyLength} from ${algorithm}")
    +
    +            // Assert
    +            assert EXPECTED_ALGORITHMS.get(keyLength).contains(algorithm)
    +        }
    +    }
    +
    +    @Test
    +    void testShouldDetermineValidKeyLength() {
    +        // Arrange
    +
    +        // Act
    +        ALGORITHMS_MAPPED_BY_KEY_LENGTH.each { int keyLength, List<String> 
algorithms ->
    +            algorithms.each { String algorithm ->
    +                logger.info("Checking ${keyLength} for ${algorithm}")
    +
    +                // Assert
    +                assert CipherUtility.isValidKeyLength(keyLength, 
CipherUtility.parseCipherFromAlgorithm(algorithm))
    +            }
    +        }
    +    }
    +
    +    @Test
    +    void testShouldDetermineInvalidKeyLength() {
    +        // Arrange
    +
    +        // Act
    +        ALGORITHMS_MAPPED_BY_KEY_LENGTH.each { int keyLength, List<String> 
algorithms ->
    +            algorithms.each { String algorithm ->
    +                def invalidKeyLengths = [-1, 0, 1]
    +                if (algorithm =~ "RC\\d") {
    +                    invalidKeyLengths += [39, 2049]
    +                } else {
    +                    invalidKeyLengths += keyLength + 1
    +                }
    +                logger.info("Checking ${invalidKeyLengths.join(", ")} for 
${algorithm}")
    +
    +                // Assert
    +                invalidKeyLengths.each { int invalidKeyLength ->
    +                    assert 
!CipherUtility.isValidKeyLength(invalidKeyLength, 
CipherUtility.parseCipherFromAlgorithm(algorithm))
    +                }
    +            }
    +        }
    +    }
    +
    +    @Test
    +    void testShouldDetermineValidKeyLengthForAlgorithm() {
    +        // Arrange
    +
    +        // Act
    +        ALGORITHMS_MAPPED_BY_KEY_LENGTH.each { int keyLength, List<String> 
algorithms ->
    +            algorithms.each { String algorithm ->
    +                logger.info("Checking ${keyLength} for ${algorithm}")
    +
    +                // Assert
    +                assert 
CipherUtility.isValidKeyLengthForAlgorithm(keyLength, algorithm)
    +            }
    +        }
    +    }
    +
    +    @Test
    +    void testShouldDetermineInvalidKeyLengthForAlgorithm() {
    +        // Arrange
    +
    +        // Act
    +        ALGORITHMS_MAPPED_BY_KEY_LENGTH.each { int keyLength, List<String> 
algorithms ->
    +            algorithms.each { String algorithm ->
    +                def invalidKeyLengths = [-1, 0, 1]
    +                if (algorithm =~ "RC\\d") {
    +                    invalidKeyLengths += [39, 2049]
    +                } else {
    +                    invalidKeyLengths += keyLength + 1
    +                }
    +                logger.info("Checking ${invalidKeyLengths.join(", ")} for 
${algorithm}")
    +
    +                // Assert
    +                invalidKeyLengths.each { int invalidKeyLength ->
    +                    assert 
!CipherUtility.isValidKeyLengthForAlgorithm(invalidKeyLength, algorithm)
    +                }
    +            }
    +        }
    +
    +        // Extra hard-coded checks
    +        ["PBEWITHSHA256AND256BITAES-CBC-BC": 192].each { String algorithm, 
int invalidKeyLength ->
    --- End diff --
    
    Done. 


> 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)

Reply via email to