protected Cipher getInitializedCipher(EncryptionMethod encryptionMethod, String password, byte[] salt, boolean encryptMode) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { if (encryptionMethod == null) { throw new IllegalArgumentException("The encryption method must be specified"); } if (StringUtils.isEmpty(password)) { throw new IllegalArgumentException("Encryption with an empty password is not supported"); } validateSalt(encryptionMethod, salt); String algorithm = encryptionMethod.getAlgorithm(); String provider = encryptionMethod.getProvider(); // Initialize secret key from password final PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); final SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm, provider); SecretKey tempKey = factory.generateSecret(pbeKeySpec); final PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, getIterationCount()); Cipher cipher = Cipher.getInstance(algorithm, provider); cipher.init(encryptMode ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, tempKey, parameterSpec); return cipher; }
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; } }
String provider = encryptionMethod.getProvider();
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); }
@Test public void testShouldDecryptExternalFile() throws Exception { // Arrange byte[] plainBytes = Files.readAllBytes(Paths.get(plainFile.getPath())); final String PLAINTEXT = new String(plainBytes, "UTF-8"); InputStream cipherStream = new FileInputStream(encryptedFile); OutputStream recoveredStream = new ByteArrayOutputStream(); // No file, just streams String filename = encryptedFile.getName(); OpenPGPPasswordBasedEncryptor encryptor = new OpenPGPPasswordBasedEncryptor(EncryptionMethod.PGP.getAlgorithm(), EncryptionMethod.PGP.getProvider(), LEGACY_PASSWORD.toCharArray(), filename); StreamCallback decryptionCallback = encryptor.getDecryptionCallback(); // Act decryptionCallback.process(cipherStream, recoveredStream); // Assert byte[] recoveredBytes = ((ByteArrayOutputStream) recoveredStream).toByteArray(); String recovered = new String(recoveredBytes, "UTF-8"); logger.info("Recovered: {}", recovered); Assert.assertEquals("Recovered text", PLAINTEXT, recovered); } }
@Test public void testShouldDecryptExternalFile() throws Exception { // Arrange byte[] plainBytes = Files.readAllBytes(Paths.get(plainFile.getPath())); final String PLAINTEXT = new String(plainBytes, "UTF-8"); InputStream cipherStream = new FileInputStream(unsignedFile); OutputStream recoveredStream = new ByteArrayOutputStream(); // No file, just streams String filename = unsignedFile.getName(); OpenPGPKeyBasedEncryptor encryptor = new OpenPGPKeyBasedEncryptor( EncryptionMethod.PGP.getAlgorithm(), EncryptionMethod.PGP.getProvider(), SECRET_KEYRING_PATH, USER_ID, PASSWORD.toCharArray(), filename); StreamCallback decryptionCallback = encryptor.getDecryptionCallback(); // Act decryptionCallback.process(cipherStream, recoveredStream); // Assert byte[] recoveredBytes = ((ByteArrayOutputStream) recoveredStream).toByteArray(); String recovered = new String(recoveredBytes, "UTF-8"); logger.info("Recovered: {}", recovered); Assert.assertEquals("Recovered text", PLAINTEXT, recovered); } }
@Test public void testShouldEncryptAndDecrypt() throws Exception { // Arrange final String PLAINTEXT = "This is a plaintext message."; logger.info("Plaintext: {}", PLAINTEXT); InputStream plainStream = new java.io.ByteArrayInputStream(PLAINTEXT.getBytes("UTF-8")); OutputStream cipherStream = new ByteArrayOutputStream(); OutputStream recoveredStream = new ByteArrayOutputStream(); // No file, just streams String filename = "tempFile.txt"; OpenPGPPasswordBasedEncryptor encryptor = new OpenPGPPasswordBasedEncryptor(EncryptionMethod.PGP.getAlgorithm(), EncryptionMethod.PGP.getProvider(), PASSWORD.toCharArray(), filename); StreamCallback encryptionCallback = encryptor.getEncryptionCallback(); StreamCallback decryptionCallback = encryptor.getDecryptionCallback(); // Act encryptionCallback.process(plainStream, cipherStream); final byte[] cipherBytes = ((ByteArrayOutputStream) cipherStream).toByteArray(); logger.info("Encrypted: {}", Hex.encodeHexString(cipherBytes)); InputStream cipherInputStream = new ByteArrayInputStream(cipherBytes); decryptionCallback.process(cipherInputStream, recoveredStream); // Assert byte[] recoveredBytes = ((ByteArrayOutputStream) recoveredStream).toByteArray(); String recovered = new String(recoveredBytes, "UTF-8"); logger.info("Recovered: {}", recovered); assert PLAINTEXT.equals(recovered); }
@Test public void testShouldEncryptAndDecrypt() throws Exception { // Arrange final String PLAINTEXT = "This is a plaintext message."; logger.info("Plaintext: {}", PLAINTEXT); InputStream plainStream = new ByteArrayInputStream(PLAINTEXT.getBytes("UTF-8")); OutputStream cipherStream = new ByteArrayOutputStream(); OutputStream recoveredStream = new ByteArrayOutputStream(); // No file, just streams String filename = "tempFile.txt"; // Encryptor does not require password OpenPGPKeyBasedEncryptor encryptor = new OpenPGPKeyBasedEncryptor( EncryptionMethod.PGP.getAlgorithm(), EncryptionMethod.PGP.getProvider(), PUBLIC_KEYRING_PATH, USER_ID, new char[0], filename); StreamCallback encryptionCallback = encryptor.getEncryptionCallback(); OpenPGPKeyBasedEncryptor decryptor = new OpenPGPKeyBasedEncryptor( EncryptionMethod.PGP.getAlgorithm(), EncryptionMethod.PGP.getProvider(), SECRET_KEYRING_PATH, USER_ID, PASSWORD.toCharArray(), filename); StreamCallback decryptionCallback = decryptor.getDecryptionCallback(); // Act encryptionCallback.process(plainStream, cipherStream); final byte[] cipherBytes = ((ByteArrayOutputStream) cipherStream).toByteArray(); logger.info("Encrypted: {}", Hex.encodeHexString(cipherBytes)); InputStream cipherInputStream = new ByteArrayInputStream(cipherBytes); decryptionCallback.process(cipherInputStream, recoveredStream); // Assert byte[] recoveredBytes = ((ByteArrayOutputStream) recoveredStream).toByteArray(); String recovered = new String(recoveredBytes, "UTF-8"); logger.info("Recovered: {}", recovered); assert PLAINTEXT.equals(recovered); }
.build()); } else { final String providerName = encryptionMethod.getProvider();
final String method = context.getProperty(ENCRYPTION_ALGORITHM).getValue(); final EncryptionMethod encryptionMethod = EncryptionMethod.valueOf(method); final String providerName = encryptionMethod.getProvider(); final String algorithm = encryptionMethod.getAlgorithm(); final String password = context.getProperty(PASSWORD).getValue();
protected Cipher getInitializedCipher(EncryptionMethod encryptionMethod, String password, byte[] salt, boolean encryptMode) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { if (encryptionMethod == null) { throw new IllegalArgumentException("The encryption method must be specified"); } if (StringUtils.isEmpty(password)) { throw new IllegalArgumentException("Encryption with an empty password is not supported"); } validateSalt(encryptionMethod, salt); String algorithm = encryptionMethod.getAlgorithm(); String provider = encryptionMethod.getProvider(); // Initialize secret key from password final PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); final SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm, provider); SecretKey tempKey = factory.generateSecret(pbeKeySpec); final PBEParameterSpec parameterSpec = new PBEParameterSpec(salt, getIterationCount()); Cipher cipher = Cipher.getInstance(algorithm, provider); cipher.init(encryptMode ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, tempKey, parameterSpec); return cipher; }
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; } }
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); }
String provider = encryptionMethod.getProvider();
.build()); } else { final String providerName = encryptionMethod.getProvider();
final String method = context.getProperty(ENCRYPTION_ALGORITHM).getValue(); final EncryptionMethod encryptionMethod = EncryptionMethod.valueOf(method); final String providerName = encryptionMethod.getProvider(); final String algorithm = encryptionMethod.getAlgorithm(); final String password = context.getProperty(PASSWORD).getValue();