public static boolean passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(final int passwordLength, EncryptionMethod encryptionMethod) { if (encryptionMethod == null) { throw new IllegalArgumentException("Cannot evaluate an empty encryption method algorithm"); } return passwordLength <= getMaximumPasswordLengthForAlgorithmOnLimitedStrengthCrypto(encryptionMethod); }
/** * 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); }
protected Cipher getInitializedCipher(EncryptionMethod encryptionMethod, String password, byte[] salt, byte[] iv, int keyLength, boolean encryptMode) throws Exception { if (encryptionMethod == null) { throw new IllegalArgumentException("The encryption method must be specified"); } if (!encryptionMethod.isCompatibleWithStrongKDFs()) { throw new IllegalArgumentException(encryptionMethod.name() + " is not compatible with Bcrypt"); } if (StringUtils.isEmpty(password)) { throw new IllegalArgumentException("Encryption with an empty password is not supported"); } String algorithm = encryptionMethod.getAlgorithm(); String provider = encryptionMethod.getProvider(); final String cipherName = CipherUtility.parseCipherFromAlgorithm(algorithm); if (!CipherUtility.isValidKeyLength(keyLength, cipherName)) { throw new IllegalArgumentException(String.valueOf(keyLength) + " is not a valid key length for " + cipherName); } String bcryptSalt = formatSaltForBcrypt(salt); String hash = BCrypt.hashpw(password, bcryptSalt); /* The SHA-512 hash is required in order to derive a key longer than 184 bits (the resulting size of the Bcrypt hash) and ensuring the avalanche effect causes higher key entropy (if all derived keys follow a consistent pattern, it weakens the strength of the encryption) */ MessageDigest digest = MessageDigest.getInstance("SHA-512", provider); byte[] dk = digest.digest(hash.getBytes(StandardCharsets.UTF_8)); dk = Arrays.copyOf(dk, keyLength / 8); SecretKey tempKey = new SecretKeySpec(dk, algorithm); KeyedCipherProvider keyedCipherProvider = new AESKeyedCipherProvider(); return keyedCipherProvider.getCipher(encryptionMethod, tempKey, iv, encryptMode); }
/** * 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); } }
int keyLength = parseActualKeyLengthFromAlgorithm(algorithm); if (keyLength != -1) { validKeyLengths.add(keyLength); String cipher = parseCipherFromAlgorithm(algorithm); switch (cipher.toUpperCase()) { case "DESEDE":
private boolean paramsAreValid() { boolean algorithmAndProviderValid = algorithmIsValid(algorithm) && providerIsValid(provider); boolean secretIsValid = false; if (CipherUtility.isPBECipher(algorithm)) { secretIsValid = passwordIsValid(password); } else if (CipherUtility.isKeyedCipher(algorithm)) { secretIsValid = keyIsValid(key, algorithm); } return algorithmAndProviderValid && secretIsValid; }
public static int getMaxAllowedKeyLength(final String algorithm) { if (StringUtils.isEmpty(algorithm)) { return DEFAULT_MAX_ALLOWED_KEY_LENGTH; } String parsedCipher = CipherUtility.parseCipherFromAlgorithm(algorithm); try { return Cipher.getMaxAllowedKeyLength(parsedCipher); } catch (NoSuchAlgorithmException e) { // Default algorithm max key length on unmodified JRE return DEFAULT_MAX_ALLOWED_KEY_LENGTH; } }
int keyLength = CipherUtility.parseKeyLengthFromAlgorithm(encryptionMethod.getAlgorithm()); cipher = cipherProvider.getCipher(encryptionMethod, new String(password.getPassword()), salt, keyLength, false); CipherUtility.processStreams(cipher, in, out); } catch (Exception e) { throw new ProcessException(e);
public KeyedEncryptor(final EncryptionMethod encryptionMethod, final byte[] keyBytes, final byte[] iv) { super(); try { if (encryptionMethod == null) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with null encryption method"); } if (!encryptionMethod.isKeyedCipher()) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with encryption method " + encryptionMethod.name()); } this.encryptionMethod = encryptionMethod; if (keyBytes == null || keyBytes.length == 0) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with empty key"); } if (!CipherUtility.isValidKeyLengthForAlgorithm(keyBytes.length * 8, encryptionMethod.getAlgorithm())) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with key of length " + keyBytes.length); } String cipherName = CipherUtility.parseCipherFromAlgorithm(encryptionMethod.getAlgorithm()); this.key = new SecretKeySpec(keyBytes, cipherName); this.iv = iv; } catch (Exception e) { throw new ProcessException(e); } }
" due to lacking JCE Unlimited Strength Jurisdiction Policy files. See Admin Guide.").build()); if (!CipherUtility.isValidKeyLengthForAlgorithm(keyBytes.length * 8, encryptionMethod.getAlgorithm())) { List<Integer> validKeyLengths = CipherUtility.getValidKeyLengthsForAlgorithm(encryptionMethod.getAlgorithm()); validationResults.add(new ValidationResult.Builder().subject(RAW_KEY_HEX.getName()) .explanation("Key must be valid length [" + StringUtils.join(validKeyLengths, ", ") + "]. See Admin Guide.").build());
final boolean passwordLongerThanLimit = !CipherUtility.passwordLengthIsValidForAlgorithmOnLimitedStrengthCrypto(passwordBytesLength, encryptionMethod); if (passwordLongerThanLimit) { int maxPasswordLength = CipherUtility.getMaximumPasswordLengthForAlgorithmOnLimitedStrengthCrypto(encryptionMethod); validationResults.add(new ValidationResult.Builder().subject(PASSWORD.getName()) .explanation("Password length greater than " + maxPasswordLength + " characters is not supported by this JVM" +
private byte[] decryptPBE(byte[] cipherBytes) { PBECipherProvider pbecp = (PBECipherProvider) cipherProvider; final EncryptionMethod encryptionMethod = EncryptionMethod.forAlgorithm(algorithm); // Extract salt int saltLength = CipherUtility.getSaltLengthForAlgorithm(algorithm); byte[] salt = new byte[saltLength]; System.arraycopy(cipherBytes, 0, salt, 0, saltLength); byte[] actualCipherBytes = Arrays.copyOfRange(cipherBytes, saltLength, cipherBytes.length); // Determine necessary key length int keyLength = CipherUtility.parseKeyLengthFromAlgorithm(algorithm); // Generate cipher try { Cipher cipher = pbecp.getCipher(encryptionMethod, new String(password.getPassword()), salt, keyLength, false); // Write IV if necessary (allows for future use of PBKDF2, Bcrypt, or Scrypt) // byte[] iv = new byte[0]; // if (cipherProvider instanceof RandomIVPBECipherProvider) { // iv = cipher.getIV(); // } // Decrypt the plaintext return cipher.doFinal(actualCipherBytes); } catch (Exception e) { throw new EncryptionException("Could not decrypt sensitive value", e); } }
private byte[] encryptPBE(String plaintext) { PBECipherProvider pbecp = (PBECipherProvider) cipherProvider; final EncryptionMethod encryptionMethod = EncryptionMethod.forAlgorithm(algorithm); // Generate salt byte[] salt; // NiFi legacy code determined the salt length based on the cipher block size if (pbecp instanceof org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) { salt = ((org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) pbecp).generateSalt(encryptionMethod); } else { salt = pbecp.generateSalt(); } // Determine necessary key length int keyLength = CipherUtility.parseKeyLengthFromAlgorithm(algorithm); // Generate cipher try { Cipher cipher = pbecp.getCipher(encryptionMethod, new String(password.getPassword()), salt, keyLength, true); // Write IV if necessary (allows for future use of PBKDF2, Bcrypt, or Scrypt) // byte[] iv = new byte[0]; // if (cipherProvider instanceof RandomIVPBECipherProvider) { // iv = cipher.getIV(); // } // Encrypt the plaintext byte[] cipherBytes = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)); // Combine the output // byte[] rawBytes = CryptoUtils.concatByteArrays(salt, iv, cipherBytes); return CryptoUtils.concatByteArrays(salt, cipherBytes); } catch (Exception e) { throw new EncryptionException("Could not encrypt sensitive value", e); } }
private static String formatHash(byte[] salt, int n, int r, int p, byte[] derived) { StringBuilder sb = new StringBuilder((salt.length + derived.length) * 2); sb.append(formatSalt(salt, n, r, p)).append('$'); sb.append(CipherUtility.encodeBase64NoPadding(derived)); return sb.toString(); }
protected void initialize() { if (isInitialized()) { logger.debug("Attempted to initialize an already-initialized StringEncryptor"); return; } if (paramsAreValid()) { if (CipherUtility.isPBECipher(algorithm)) { cipherProvider = CipherProviderFactory.getCipherProvider(KeyDerivationFunction.NIFI_LEGACY); } else { cipherProvider = CipherProviderFactory.getCipherProvider(KeyDerivationFunction.NONE); } } else { throw new EncryptionException("Cannot initialize the StringEncryptor because some configuration values are invalid"); } }
/** * 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); } }
public static int getMaxAllowedKeyLength(final String algorithm) { if (StringUtils.isEmpty(algorithm)) { return DEFAULT_MAX_ALLOWED_KEY_LENGTH; } String parsedCipher = CipherUtility.parseCipherFromAlgorithm(algorithm); try { return Cipher.getMaxAllowedKeyLength(parsedCipher); } catch (NoSuchAlgorithmException e) { // Default algorithm max key length on unmodified JRE return DEFAULT_MAX_ALLOWED_KEY_LENGTH; } }
@Override public void process(final InputStream in, final OutputStream out) throws IOException { // Initialize cipher provider PBECipherProvider cipherProvider = (PBECipherProvider) CipherProviderFactory.getCipherProvider(kdf); // Generate salt byte[] salt; // NiFi legacy code determined the salt length based on the cipher block size if (cipherProvider instanceof org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) { salt = ((org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) cipherProvider).generateSalt(encryptionMethod); } else { salt = cipherProvider.generateSalt(); } // Write to output stream cipherProvider.writeSalt(salt, out); // Determine necessary key length int keyLength = CipherUtility.parseKeyLengthFromAlgorithm(encryptionMethod.getAlgorithm()); // Generate cipher try { Cipher cipher = cipherProvider.getCipher(encryptionMethod, new String(password.getPassword()), salt, keyLength, true); // Write IV if necessary if (cipherProvider instanceof RandomIVPBECipherProvider) { ((RandomIVPBECipherProvider) cipherProvider).writeIV(cipher.getIV(), out); } CipherUtility.processStreams(cipher, in, out); } catch (Exception e) { throw new ProcessException(e); } } }
public KeyedEncryptor(final EncryptionMethod encryptionMethod, final byte[] keyBytes, final byte[] iv) { super(); try { if (encryptionMethod == null) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with null encryption method"); } if (!encryptionMethod.isKeyedCipher()) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with encryption method " + encryptionMethod.name()); } this.encryptionMethod = encryptionMethod; if (keyBytes == null || keyBytes.length == 0) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with empty key"); } if (!CipherUtility.isValidKeyLengthForAlgorithm(keyBytes.length * 8, encryptionMethod.getAlgorithm())) { throw new IllegalArgumentException("Cannot instantiate a keyed encryptor with key of length " + keyBytes.length); } String cipherName = CipherUtility.parseCipherFromAlgorithm(encryptionMethod.getAlgorithm()); this.key = new SecretKeySpec(keyBytes, cipherName); this.iv = iv; } catch (Exception e) { throw new ProcessException(e); } }
int keyLength = parseActualKeyLengthFromAlgorithm(algorithm); if (keyLength != -1) { validKeyLengths.add(keyLength); String cipher = parseCipherFromAlgorithm(algorithm); switch (cipher.toUpperCase()) { case "DESEDE":