package com.thinkbiganalytics.nifi.v2.sqoop.security;
/*-
* #%L
* thinkbig-nifi-hadoop-processors
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* Licensed 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.
* #L%
*/
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
/**
* A utility to decrypt passwords, provided in Base64 encoding.
*/
/* Uses Sqoop's decryption algorithm
References:
1) https://github.com/apache/sqoop/blob/trunk/src/java/org/apache/sqoop/util/password/CryptoFileLoader.java
2) http://ingest.tips/2015/03/12/managing-passwords-sqoop/
*/
public class DecryptPassword {
/**
* Decrypt a password encrypted using Sqoop encryption utility
*
* @param base64EncodedEncryptedPassword base64 string representing encrypted password
* @param passPhrase passphrase used to encrypt password
* @return decrypted password
* @throws IOException if encounters issues with decryption
*/
public static String decryptPassword(String base64EncodedEncryptedPassword, String passPhrase) throws IOException {
if (base64EncodedEncryptedPassword == null || base64EncodedEncryptedPassword.isEmpty() || passPhrase == null || passPhrase.isEmpty()) {
throw new IllegalArgumentException("Either encoded password or passphrase is provided as null/empty.");
}
byte[] encryptedPassword = Base64.getDecoder().decode(base64EncodedEncryptedPassword);
String algorithmFull = EncryptPasswordConfiguration.FILE_ENCRYPTION_ALGORITHM_FULL;
String algorithmOnly = EncryptPasswordConfiguration.FILE_ENCRYPTION_ALGORITHM_ONLY;
String keySalt = EncryptPasswordConfiguration.KEY_SALT;
int numPbkdf2Iterations = EncryptPasswordConfiguration.NUM_PBKDF2_ITERATIONS;
int keyLength = EncryptPasswordConfiguration.KEY_LENGTH;
SecretKeyFactory factory;
try {
factory = SecretKeyFactory.getInstance(EncryptPasswordConfiguration.KEY_DERIVATION_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
throw new IOException("Can't load SecretKeyFactory", e);
}
SecretKeySpec key;
try {
key = new SecretKeySpec(factory.generateSecret(new PBEKeySpec(passPhrase.toCharArray(),
keySalt.getBytes(StandardCharsets.UTF_8),
numPbkdf2Iterations,
keyLength)).getEncoded(),
algorithmOnly);
} catch (Exception e) {
throw new IOException("Can't generate secret key", e);
}
Cipher crypto;
try {
crypto = Cipher.getInstance(algorithmFull);
} catch (Exception e) {
throw new IOException("Can't initialize the decryptor", e);
}
byte[] decryptedBytes;
try {
crypto.init(Cipher.DECRYPT_MODE, key);
decryptedBytes = crypto.doFinal(encryptedPassword);
} catch (Exception e) {
throw new IOException("Can't decrypt the password", e);
}
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
}