Github user alopresto commented on the pull request:

    https://github.com/apache/nifi/pull/140#issuecomment-162039927
  
    After debugging, this is related to the JCE Unlimited Strength 
Cryptographic Policies that must be installed to allow the JRE to use key 
lengths above export limits. AES is restricted to 128 bit (16 bytes) by default 
without these policy files. 
    
    However, in examining the code, we believe we have found a larger issue in 
Java's handling of the key when using password-based encryption. In a normal 
scenario, the key is generated or derived and then used to initialize the 
cipher as follows:
    
    ```java
                    MessageDigest sha1 = MessageDigest.getInstance("SHA1");
                    String key = 
Hex.encodeHexString(sha1.digest("thisIsABadPassword".getBytes())).substring(0, 
31);
                    String iv = 
Hex.encodeHexString(sha1.digest("thisIsABadIv".getBytes())).substring(0, 31);
                    
                    SecretKey secretKey = new 
SecretKeySpec(Hex.decodeHex(key.toCharArray()), "AES");
                    IvParameterSpec ivParameterSpec = new 
IvParameterSpec(Hex.decodeHex(iv.toCharArray()));
                    
                    cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
                    cipher.init(Cipher.ENCRYPT_MODE, secretKey, 
ivParameterSpec);
                    
                    String message = "This is a plaintext message.";
                    
                    byte[] cipherBytes = cipher.doFinal(message.getBytes());
                    
                    cipher.init(Cipher.DECRYPT_MODE, secretKey, 
ivParameterSpec);
                    
                    byte[] recoveredBytes = cipher.doFinal(cipherBytes);
                    
                    System.out.println("Recovered message: " + new 
String(recoveredBytes));
                    
                } catch (Exception e) {
                    fail(e.getMessage());
                }
    ```
    
    During `cipher.init()`, the system checks 
`Cipher.getMaxAllowedKeyLength("AES")` for the key limit in bits. As 32 hex == 
16 bytes == 128 bits, this will run on a vanilla JRE installation. However, 
using the password-based encryption `PBEParameterSpec` is slightly different. 
    
    ```java
            String password = "thisIsABadPassword";
            String salt = "SALTSALT";
    
            PBEKeySpec keySpec = new PBEKeySpec(password);
    SecretKeyFactory keyFactory = 
SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
            SecretKey key = keyFactory.generateSecret(keySpec);
            
            PBEParameterSpec saltSpec = new 
PBEParameterSpec(salt.getBytes("US-ASCII"), 0);
            
            Cipher cipher = 
Cipher.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
            cipher.init(Cipher.ENCRYPT_MODE, key, saltSpec);
    
            String message = "This is a plaintext message.";
    
            byte[] cipherBytes = cipher.doFinal(message.getBytes());
    
            cipher.init(Cipher.DECRYPT_MODE, key, saltSpec);
    
            byte[] recoveredBytes = cipher.doFinal(cipherBytes);
    
            System.out.println("Recovered message: " + new 
String(recoveredBytes));
    
        } catch (Exception e) {
            fail(e.getMessage());
        }
    ```
    
    The actual key is not derived until **during** `cipher.init()`, so at the 
time the key length check is done, it is actually checking the length of the 
raw password. This means that a vanilla JRE installation can use 256-bit AES to 
encrypt or decrypt a file provided the password is <= 16 bytes. The tests above 
fail because the provided password is 18 bytes. However, the algorithm used is 
still AES-256-CBC, which means the derived key is 32 bytes. This has been 
verified on a vanilla JRE installation decrypting OpenSSL AES-256-CBC encrypted 
files. 
    
    I will look at @apiri 's patch on NIFI-1242 but this is a serious issue and 
should be well-documented. The usual test of "is available on a vanilla JRE 
because the key length is <= 128 bits (for AES)" is no longer sufficient 
because the supplied password length now affects the determination. 


---
If your project is set up for it, you can reply to this email and have your
reply appear on GitHub as well. If your project does not have this feature
enabled and wishes so, or if the feature is enabled but not working, please
contact infrastructure at [email protected] or file a JIRA ticket
with INFRA.
---

Reply via email to