IBM Security Access Manager for Enterprise Single Sign-On, Version 8.2

CryptoUtil.java file

Use the CryptoUtils class to decrypt application passwords and return the password as plain text. Call the getDecryptedAppPassword method with the encryptedAppPassword, the salt, and the ISAM ESSO password.

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.util.logging.*;

/*
 * Password-Based Encryption(PBE)

* In this class we are using the ISAMESSO password to encrypt the application 
* passwords which are returned in the RSTR. In this process we generate a secret key 
* using the ISAMESSO password and a collection of random bytes called the 'Salt'. This 
* key is then used to encrypt the application password using the AES-128 encryption 
* algorithm. 
* The algorithm to generate the key is as follows:
*  1. Append the Salt(a collection of random bytes) to the password and generate a hash 
*     using the SHA-256 hashing algorithm.
*  2. Append the Salt to the digest and generate the hash using the SHA-256 algorithm. 
*     Repeat this process 1000 times.
*  3. The first 16 bytes of the final digest is our key.
* 
* 
* This class provides functions to implement PBE
*/
public class CryptoUtils {
	
	/**This decrypts the encryptedAppPassword and returns it as plain-text. It converts 
   * the byte array returned by decrypt into UTF-8
	 * @param Encrypted Application Password
	 * @param Salt
	 * @param Esso Password
	 * @return Decrypted Application Password
	 */
	
	private static final String CLASS = CryptoUtils.class.getName();
	private static final Logger log = Logger.getLogger(CLASS);
	
	private static final String ENCRYPTION_ALGO = "AES";
	private static final String HASHING_ALGO = "SHA-256";
	private static final String PROVIDER = "com.ibm.crypto.fips.provider.IBMJCEFIPS";
  //JCE provider
	private static final String ENCODING = "UTF-8";
	private static final int ITERATIONS = 1000; 
  //number of ITERATIONS for generating the Secret Key
	
	public static String getDecryptedAppPassword(String encryptedAppPassword,
             String salt,String essoPassword)
	throws IllegalArgumentException
	{		
		String methodName_ = "getDecryptedAppPassword()";
		log.entering(CLASS, methodName_);
		if(encryptedAppPassword==null||salt==null||essoPassword==null) throw 
             new IllegalArgumentException
		("One or more of the parameters are Null");
		String result = null;
		try{
			Security.addProvider((Provider) ((Class.forName(PROVIDER))
				       .newInstance()));
			byte[] encryptedAppPassword1 = Base64.decode(encryptedAppPassword);
			byte[] salt1 = Base64.decode(salt);			
			byte[] arr = decrypt(essoPassword.getBytes(ENCODING),encryptedAppPassword1,salt1);
			result = new String(arr,ENCODING);
			log.exiting(CLASS,methodName_);
		}
		catch(Exception e){
			log.log(Level.WARNING,e.getMessage(),e);
		}
		return result;	
	}

	/**This decrypts the encryptedAppPassword and returns it as a byte array 
   * given the Salt and the essoPassword using PBE
	 * @param essoPassword
	 * @param appPassword
	 * @param salt
	 * @return De-crypted Application Password as an array of bytes
	 */
	public static byte[] decrypt(byte[] essoPassword,byte[] appPassword,byte[] salt)
	throws IllegalArgumentException
	{
		String methodName_ = "decrypt";
		log.entering(CLASS, methodName_);
		if(essoPassword==null||appPassword==null||salt==null) throw 
                  new IllegalArgumentException
		("One or more of the parameters are Null");
		byte[] result = null;
		try{	
			if(essoPassword==null||appPassword==null||salt==null) throw 
                    new NullPointerException();
			SecretKey key = generateKey(essoPassword,salt);
			Cipher aesCipher;
			aesCipher = Cipher.getInstance(ENCRYPTION_ALGO);					 
			aesCipher.init(Cipher.DECRYPT_MODE,key);
			log.exiting(CLASS,methodName_);
			result = aesCipher.doFinal(appPassword);
		}
		catch(Exception e){
			log.log(Level.WARNING,e.getMessage(),e);
		}
		return result;
	}
	
	/**This encrypts the AppPassword and returns it as a byte array given the 
   * Salt and the essoPassword using PBE
	 * @param essoPassword
	 * @param appPassword
	 * @param salt
	 * @return De-crypted Application Password as an array of bytes
	 * @throws IllegalArgumentException
	 */
	public static byte[] encrypt(byte[] essoPassword,byte[] appPassword,byte[] salt)
	throws IllegalArgumentException
	{
		String methodName_ = "encrypt";
		log.entering(CLASS,methodName_);
		if(essoPassword==null||appPassword==null||salt==null) throw 
                         new IllegalArgumentException
		("One or more of the parameters are Null");
		byte[] result = null;
		try{
			SecretKey key = generateKey(essoPassword,salt);
			Cipher aesCipher;
			aesCipher = Cipher.getInstance("AES");					 
			aesCipher.init(Cipher.ENCRYPT_MODE,key);
			log.entering(CLASS,methodName_);
			result = aesCipher.doFinal(appPassword);
		}
		catch(Exception e){
			log.log(Level.WARNING,e.getMessage(),e);
		}
		return result;
	}
	
	/**This generates the secret key given the essoPassword and Salt using PBE
	 * @param essoPassword
	 * @param salt
	 * @return SecretKey obtained from the ESSO password using PBE
	 * @throws IllegalArgumentException
	 */
	public static SecretKey generateKey(byte[] essoPassword,byte[] salt)
	throws IllegalArgumentException
	{
		String methodName_ = "generateSecretKey";
		log.entering(CLASS, methodName_);
		if(essoPassword==null||salt==null) throw new IllegalArgumentException
		("One or more of the parameters are Null");
		SecretKey aesKey = null;
		try{
			essoPassword = append(essoPassword,salt);
			SecretKeyFactory factory = SecretKeyFactory.getInstance(ENCRYPTION_ALGO);
			MessageDigest md = MessageDigest.getInstance(HASHING_ALGO);
			byte[] hashedKey = md.digest(essoPassword);
			for(int i=0;i<ITERATIONS-1;i++){
			    hashedKey = append(hashedKey,salt);
			    hashedKey = md.digest(hashedKey);
			}
			SecretKeySpec keySpec = new SecretKeySpec(hashedKey,0,16,HASHING_ALGO);
			aesKey = factory.generateSecret(keySpec);
		}
		catch(Exception e){
			log.log(Level.WARNING,e.getMessage(),e);
		}
		return aesKey;
	}
	
	/**This appends the second byte array to the first one.
	 * @param array1
	 * @param array2
	 * @return array2 appended to array1
	 */
	private static byte[] append(byte[] array1,byte[] array2){
		byte[] array3 = new byte[array1.length+array2.length];
		int index = 0;
		for(int i=0;i<array1.length;i++){
			array3[index++] = array1[i];
		}
		for(int i=0;i<array2.length;i++){
			array3[index++] = array2[i];
		}
		return array3;
	}	
}


Feedback