RANGER-5388: Actual calculated salt size should be updated into the DB (#721)

diff --git a/kms/src/main/java/org/apache/hadoop/crypto/key/RangerMasterKey.java b/kms/src/main/java/org/apache/hadoop/crypto/key/RangerMasterKey.java
index 8fb4b6d..2e840cb 100755
--- a/kms/src/main/java/org/apache/hadoop/crypto/key/RangerMasterKey.java
+++ b/kms/src/main/java/org/apache/hadoop/crypto/key/RangerMasterKey.java
@@ -94,22 +94,23 @@ public static void getPasswordParam(String paddedEncryptedPwd) {
         if (encryptedPwd != null && encryptedPwd.length >= 7) {
             int index = 0;
 
-            mkCipher       = encryptedPwd[index];
-            mkKeySize      = Integer.parseInt(encryptedPwd[++index]);
-            saltSize       = Integer.parseInt(encryptedPwd[++index]);
-            pbeAlgo        = encryptedPwd[++index];
-            mdAlgo         = encryptedPwd[++index];
-            iterationCount = Integer.parseInt(encryptedPwd[++index]);
-            salt           = encryptedPwd[++index];
-            password       = encryptedPwd[++index];
+            mkCipher            = encryptedPwd[index];
+            mkKeySize           = Integer.parseInt(encryptedPwd[++index]);
+            int tempSaltSize    = Integer.parseInt(encryptedPwd[++index]);
+            pbeAlgo             = encryptedPwd[++index];
+            saltSize            = calculateCompliantSaltSize(tempSaltSize, SupportedPBECryptoAlgo.valueOf(pbeAlgo));
+            mdAlgo              = encryptedPwd[++index];
+            iterationCount      = Integer.parseInt(encryptedPwd[++index]);
+            salt                = encryptedPwd[++index];
+            password            = encryptedPwd[++index];
         } else {
-            mkCipher  = DEFAULT_MK_CIPHER;
-            mkKeySize = DEFAULT_MK_KeySize;
-            saltSize  = DEFAULT_SALT_SIZE;
-            pbeAlgo   = isFipsEnabled ? SupportedPBECryptoAlgo.PBEWithMD5AndTripleDES.getAlgoName() : defaultCryptAlgo.getAlgoName();
-            mdAlgo    = defaultMdAlgo;
-            password  = paddedEncryptedPwd;
-            salt      = password;
+            mkCipher            = DEFAULT_MK_CIPHER;
+            mkKeySize           = DEFAULT_MK_KeySize;
+            pbeAlgo             = isFipsEnabled ? SupportedPBECryptoAlgo.PBEWithMD5AndTripleDES.getAlgoName() : defaultCryptAlgo.getAlgoName();
+            saltSize            = calculateCompliantSaltSize(DEFAULT_SALT_SIZE, SupportedPBECryptoAlgo.valueOf(pbeAlgo));
+            mdAlgo              = defaultMdAlgo;
+            password            = paddedEncryptedPwd;
+            salt                = password;
 
             if (password != null) {
                 iterationCount = password.toCharArray().length + 1;
@@ -181,17 +182,16 @@ public void init() {
         defaultCryptAlgo    = isFipsEnabled ? SupportedPBECryptoAlgo.PBKDF2WithHmacSHA256 : defaultCryptAlgo;
         mkCipher            = getConfig("ranger.kms.service.masterkey.password.cipher", DEFAULT_MK_CIPHER);
         mkKeySize           = getIntConfig("ranger.kms.service.masterkey.password.size", DEFAULT_MK_KeySize);
-        saltSize            = getIntConfig("ranger.kms.service.masterkey.password.salt.size", DEFAULT_SALT_SIZE);
-        salt                = getConfig("ranger.kms.service.masterkey.password.salt", DEFAULT_SALT);
         pbeAlgo             = getConfig("ranger.kms.service.masterkey.password.encryption.algorithm", defaultCryptAlgo.getAlgoName());
         encrCryptoAlgo      = SupportedPBECryptoAlgo.valueOf(pbeAlgo);
+        saltSize            = calculateCompliantSaltSize(getIntConfig("ranger.kms.service.masterkey.password.salt.size", DEFAULT_SALT_SIZE), encrCryptoAlgo);
+        salt                = getConfig("ranger.kms.service.masterkey.password.salt", DEFAULT_SALT);
         mdAlgo              = getConfig("ranger.kms.service.masterkey.password.md.algorithm", defaultMdAlgo);
         iterationCount      = getIntConfig("ranger.kms.service.masterkey.password.iteration.count", DEFAULT_ITERATION_COUNT);
         paddingString       = Joiner.on(",").skipNulls().join(mkCipher, mkKeySize, saltSize, pbeAlgo, mdAlgo, iterationCount, salt);
 
         logger.info("Selected DEFAULT_CRYPT_ALGO={}", defaultCryptAlgo);
-        logger.info("Selected MD_ALGO={}", mdAlgo);
-        logger.info("Selected ENCR_CRYPTO_ALGO={}", encrCryptoAlgo);
+        logger.info("MK metadata={}", paddingString);
         logger.debug("<== RangerMasterKey.init()");
     }
 
@@ -541,15 +541,12 @@ private PBEKeySpec getPBEParameterSpec(String password, SupportedPBECryptoAlgo e
         logger.debug("==> RangerMasterKey.getPBEParameterSpec()");
 
         PBEKeySpec pbeKeySpec;
+        char[] compliantPwd = getCompliantPassword(password, encrAlgo).toCharArray();
+
         if (SupportedPBECryptoAlgo.isFIPSCompliantAlgorithm(encrAlgo)) {
-            // For FIPS, salt size must be at least 128 bits, that is, at least 16 in length.
-            int saltSize = RangerMasterKey.saltSize;
-            while (saltSize < 16) {
-                saltSize = saltSize * 2;
-            }
-            pbeKeySpec = new PBEKeySpec(getFIPSCompliantPassword(password).toCharArray(), generateSalt(saltSize), iterationCount, encrAlgo.getKeyLength());
+            pbeKeySpec = new PBEKeySpec(compliantPwd, generateSalt(saltSize), iterationCount, encrAlgo.getKeyLength());
         } else {
-            pbeKeySpec = new PBEKeySpec(password.toCharArray(), generateSalt(RangerMasterKey.saltSize), iterationCount);
+            pbeKeySpec = new PBEKeySpec(compliantPwd, generateSalt(saltSize), iterationCount);
         }
         return pbeKeySpec;
     }
@@ -570,14 +567,32 @@ private PBEKeySpec getPBEParameterSpec(String password, SupportedPBECryptoAlgo e
         If provided password is less than 14, this method appends the same password till it reaches the minimum length of 14.
         And it is for FIPS only.
      */
-    private String getFIPSCompliantPassword(String password) {
+    private String getCompliantPassword(String password, SupportedPBECryptoAlgo encrAlgo) {
         String newPwd = password;
-        while (newPwd.length() < 14) {
-            newPwd = newPwd.concat(password);
+
+        if (encrAlgo.getMinPwdLength().isPresent()) {
+            int requiredPwdLength = encrAlgo.getMinPwdLength().get();
+            while (newPwd.length() < requiredPwdLength) {
+                newPwd = newPwd.concat(password);
+            }
         }
+
         return newPwd;
     }
 
+    // For FIPS, salt size must be at least 128 bits, that is, at least 16 in length.
+    private static int calculateCompliantSaltSize(int saltSize, SupportedPBECryptoAlgo encrAlgo) {
+        int compliantSaltSize = saltSize;
+        if (encrAlgo.getMinSaltSize().isPresent()) {
+            int minSaltSize = encrAlgo.getMinSaltSize().get();
+            while (compliantSaltSize < minSaltSize) {
+                compliantSaltSize = compliantSaltSize * 2;
+            }
+        }
+
+        return compliantSaltSize;
+    }
+
     private byte[] encryptKey(byte[] data, PBEKeySpec keyspec) throws Throwable {
         logger.debug("==> RangerMasterKey.encryptKey()");
 
diff --git a/kms/src/main/java/org/apache/hadoop/crypto/key/SupportedPBECryptoAlgo.java b/kms/src/main/java/org/apache/hadoop/crypto/key/SupportedPBECryptoAlgo.java
index d2ad0e9..58a9ec6 100644
--- a/kms/src/main/java/org/apache/hadoop/crypto/key/SupportedPBECryptoAlgo.java
+++ b/kms/src/main/java/org/apache/hadoop/crypto/key/SupportedPBECryptoAlgo.java
@@ -22,29 +22,34 @@
 import javax.crypto.spec.PBEParameterSpec;
 
 import java.security.spec.AlgorithmParameterSpec;
+import java.util.Optional;
 import java.util.function.Function;
 
 public enum SupportedPBECryptoAlgo {
     @Deprecated
     PBEWithMD5AndTripleDES("PBEWithMD5AndTripleDES",
       "PBEWithMD5AndTripleDES",
-      0, keySpec -> new PBEParameterSpec(keySpec.getSalt(), keySpec.getIterationCount())),
+      0, Optional.empty(),  Optional.empty(), keySpec -> new PBEParameterSpec(keySpec.getSalt(), keySpec.getIterationCount())),
     @Deprecated
     PBEWithMD5AndDES("PBEWithMD5AndDES",
       "PBEWithMD5AndDES",
-      0, keySpec -> new PBEParameterSpec(keySpec.getSalt(), keySpec.getIterationCount())),
+      0, Optional.empty(),  Optional.empty(), keySpec -> new PBEParameterSpec(keySpec.getSalt(), keySpec.getIterationCount())),
     PBKDF2WithHmacSHA256("PBKDF2WithHmacSHA256",
       "AES/CBC/PKCS7Padding",
-      64 * 4, keySpec -> new IvParameterSpec(keySpec.getSalt()));
+      64 * 4, Optional.of(16), Optional.of(14),  keySpec -> new IvParameterSpec(keySpec.getSalt()));
     private final String encrAlgoName;
     private final String  cipherTransformation;
-    private final int     keyLength;
+    private final int               keyLength;
+    private final Optional<Integer> minSaltSize;
+    private final Optional<Integer> minPwdLength;
     private final Function<PBEKeySpec, AlgorithmParameterSpec> algoParamSpecFunc;
 
-    SupportedPBECryptoAlgo(String encrAlgoName, String cipherTransformation, int keyLength, Function<PBEKeySpec, AlgorithmParameterSpec> algoParamSpecFunc) {
+    SupportedPBECryptoAlgo(String encrAlgoName, String cipherTransformation, int keyLength, Optional<Integer> minSaltSize, Optional<Integer> minPwdLength, Function<PBEKeySpec, AlgorithmParameterSpec> algoParamSpecFunc) {
         this.encrAlgoName         = encrAlgoName;
         this.cipherTransformation = cipherTransformation;
         this.keyLength            = keyLength;
+        this.minSaltSize          = minSaltSize;
+        this.minPwdLength         = minPwdLength;
         this.algoParamSpecFunc    = algoParamSpecFunc;
     }
 
@@ -60,6 +65,14 @@ public String getCipherTransformation() {
         return this.cipherTransformation;
     }
 
+    public Optional<Integer> getMinSaltSize() {
+        return this.minSaltSize;
+    }
+
+    public Optional<Integer> getMinPwdLength() {
+        return this.minPwdLength;
+    }
+
     public AlgorithmParameterSpec getAlgoParamSpec(PBEKeySpec keySpec) {
         return this.algoParamSpecFunc.apply(keySpec);
     }