@Override public byte[] readSalt(InputStream in) throws IOException, ProcessException { return readSalt(EncryptionMethod.AES_CBC, in); }
protected void validateSalt(EncryptionMethod encryptionMethod, byte[] salt) { final int saltLength = calculateSaltLength(encryptionMethod); if (salt.length != saltLength && salt.length != 0) { throw new IllegalArgumentException("Salt must be " + saltLength + " bytes or empty"); } }
private int calculateSaltLength(EncryptionMethod encryptionMethod) { try { Cipher cipher = Cipher.getInstance(encryptionMethod.getAlgorithm(), encryptionMethod.getProvider()); return cipher.getBlockSize() > 0 ? cipher.getBlockSize() : getDefaultSaltLength(); } catch (Exception e) { logger.warn("Encountered exception determining salt length from encryption method {}", encryptionMethod.getAlgorithm(), e); final int defaultSaltLength = getDefaultSaltLength(); logger.warn("Returning default length: {} bytes", defaultSaltLength); return defaultSaltLength; } }
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); } }
/** * Returns an initialized cipher for the specified algorithm. The key (and IV if necessary) are derived using the NiFi legacy code, based on @see org.apache.nifi.crypto * .OpenSSLPKCS5CipherProvider#getCipher(java.lang.String, java.lang.String, java.lang.String, byte[], boolean) [essentially {@code MD5(password || salt) * 1000 }]. * * @param encryptionMethod the {@link EncryptionMethod} * @param password the secret input * @param salt the salt * @param keyLength the desired key length in bits (ignored because OpenSSL ciphers provide key length in algorithm name) * @param encryptMode true for encrypt, false for decrypt * @return the initialized cipher * @throws Exception if there is a problem initializing the cipher */ @Override public Cipher getCipher(EncryptionMethod encryptionMethod, String password, byte[] salt, int keyLength, boolean encryptMode) throws Exception { try { // This method is defined in the OpenSSL implementation and just uses a locally-overridden iteration count return getInitializedCipher(encryptionMethod, password, salt, encryptMode); } catch (IllegalArgumentException e) { throw e; } catch (Exception e) { throw new ProcessException("Error initializing the cipher", e); } }
@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); } } }
/** * Returns an initialized cipher for the specified algorithm. The key (and IV if necessary) are derived using the NiFi legacy code, based on @see org.apache.nifi.crypto * .OpenSSLPKCS5CipherProvider#getCipher(java.lang.String, java.lang.String, java.lang.String, byte[], boolean) [essentially {@code MD5(password || salt) * 1000 }]. * * @param encryptionMethod the {@link EncryptionMethod} * @param password the secret input * @param salt the salt * @param keyLength the desired key length in bits (ignored because OpenSSL ciphers provide key length in algorithm name) * @param encryptMode true for encrypt, false for decrypt * @return the initialized cipher * @throws Exception if there is a problem initializing the cipher */ @Override public Cipher getCipher(EncryptionMethod encryptionMethod, String password, byte[] salt, int keyLength, boolean encryptMode) throws Exception { try { // This method is defined in the OpenSSL implementation and just uses a locally-overridden iteration count return getInitializedCipher(encryptionMethod, password, salt, encryptMode); } catch (IllegalArgumentException e) { throw e; } catch (Exception e) { throw new ProcessException("Error initializing the cipher", e); } }
salt = ((org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) cipherProvider).readSalt(encryptionMethod, in); } else { salt = cipherProvider.readSalt(in);
@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 byte[] generateSalt(EncryptionMethod encryptionMethod) { byte[] salt = new byte[calculateSaltLength(encryptionMethod)]; new SecureRandom().nextBytes(salt); return salt; }
private int calculateSaltLength(EncryptionMethod encryptionMethod) { try { Cipher cipher = Cipher.getInstance(encryptionMethod.getAlgorithm(), encryptionMethod.getProvider()); return cipher.getBlockSize() > 0 ? cipher.getBlockSize() : getDefaultSaltLength(); } catch (Exception e) { logger.warn("Encountered exception determining salt length from encryption method {}", encryptionMethod.getAlgorithm(), e); final int defaultSaltLength = getDefaultSaltLength(); logger.warn("Returning default length: {} bytes", defaultSaltLength); return defaultSaltLength; } }
@Override public byte[] readSalt(InputStream in) throws IOException, ProcessException { return readSalt(EncryptionMethod.AES_CBC, in); }
/** * Returns the salt provided as part of the cipher stream, or throws an exception if one cannot be detected. * This method is only implemented by {@link NiFiLegacyCipherProvider} because the legacy salt generation was dependent on the cipher block size. * * @param encryptionMethod the encryption method * @param in the cipher InputStream * @return the salt */ public byte[] readSalt(EncryptionMethod encryptionMethod, InputStream in) throws IOException { if (in == null) { throw new IllegalArgumentException("Cannot read salt from null InputStream"); } // The first 8-16 bytes (depending on the cipher blocksize) of the input stream are the salt final int saltLength = calculateSaltLength(encryptionMethod); if (in.available() < saltLength) { throw new ProcessException("The cipher stream is too small to contain the salt"); } byte[] salt = new byte[saltLength]; StreamUtils.fillBuffer(in, salt); return salt; }
salt = ((org.apache.nifi.security.util.crypto.NiFiLegacyCipherProvider) cipherProvider).readSalt(encryptionMethod, in); } else { salt = cipherProvider.readSalt(in);
protected void validateSalt(EncryptionMethod encryptionMethod, byte[] salt) { final int saltLength = calculateSaltLength(encryptionMethod); if (salt.length != saltLength && salt.length != 0) { throw new IllegalArgumentException("Salt must be " + saltLength + " bytes or empty"); } }
public byte[] generateSalt(EncryptionMethod encryptionMethod) { byte[] salt = new byte[calculateSaltLength(encryptionMethod)]; new SecureRandom().nextBytes(salt); return salt; }
/** * Returns the salt provided as part of the cipher stream, or throws an exception if one cannot be detected. * This method is only implemented by {@link NiFiLegacyCipherProvider} because the legacy salt generation was dependent on the cipher block size. * * @param encryptionMethod the encryption method * @param in the cipher InputStream * @return the salt */ public byte[] readSalt(EncryptionMethod encryptionMethod, InputStream in) throws IOException { if (in == null) { throw new IllegalArgumentException("Cannot read salt from null InputStream"); } // The first 8-16 bytes (depending on the cipher blocksize) of the input stream are the salt final int saltLength = calculateSaltLength(encryptionMethod); if (in.available() < saltLength) { throw new ProcessException("The cipher stream is too small to contain the salt"); } byte[] salt = new byte[saltLength]; StreamUtils.fillBuffer(in, salt); return salt; }