package org.jboss.seam.security.management;
import static org.jboss.seam.ScopeType.STATELESS;
import static org.jboss.seam.annotations.Install.BUILT_IN;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.security.crypto.BinTools;
import org.jboss.seam.security.crypto.PBKDF2;
import org.jboss.seam.security.crypto.PBKDF2Engine;
import org.jboss.seam.security.crypto.PBKDF2Parameters;
import org.jboss.seam.util.Base64;
/**
* Password hashing utility functions
*
* @author Shane Bryzak
*/
@Scope(STATELESS)
@Name("org.jboss.seam.security.passwordHash")
@Install(precedence = BUILT_IN)
@BypassInterceptors
public class PasswordHash
{
public static final String ALGORITHM_MD5 = "MD5";
public static final String ALGORITHM_SHA = "SHA";
private static final String DEFAULT_ALGORITHM = ALGORITHM_MD5;
/*
* If specified, use the JCE instead of the built in algorithm
*/
private String hashAlgorithm = null;
/*
* default password salt length, in bytes
*/
private int saltLength = 8;
@Deprecated
public String generateHash(String password)
{
return generateHash(password, DEFAULT_ALGORITHM);
}
@Deprecated
public String generateHash(String password, String algorithm)
{
return generateSaltedHash(password, null, algorithm);
}
@Deprecated
public String generateSaltedHash(String password, String saltPhrase)
{
return generateSaltedHash(password, saltPhrase, DEFAULT_ALGORITHM);
}
/**
* @deprecated Use PasswordHash.createPasswordKey() instead
*/
@Deprecated
public String generateSaltedHash(String password, String saltPhrase, String algorithm)
{
try {
MessageDigest md = MessageDigest.getInstance(algorithm);
if (saltPhrase != null)
{
md.update(saltPhrase.getBytes());
byte[] salt = md.digest();
md.reset();
md.update(password.getBytes());
md.update(salt);
}
else
{
md.update(password.getBytes());
}
byte[] raw = md.digest();
return Base64.encodeBytes(raw);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public byte[] generateRandomSalt()
{
byte[] salt = new byte[saltLength];
new SecureRandom().nextBytes(salt);
return salt;
}
/**
*
*/
public String createPasswordKey(char[] password, byte[] salt, int iterations)
throws GeneralSecurityException
{
if (hashAlgorithm != null)
{
PBEKeySpec passwordKeySpec = new PBEKeySpec(password, salt, iterations, 256);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(hashAlgorithm);
SecretKey passwordKey = secretKeyFactory.generateSecret(passwordKeySpec);
passwordKeySpec.clearPassword();
return BinTools.bin2hex(passwordKey.getEncoded());
}
else
{
PBKDF2Parameters params = new PBKDF2Parameters("HmacSHA1", "ISO-8859-1", salt, iterations);
PBKDF2 pbkdf2 = new PBKDF2Engine(params);
return BinTools.bin2hex(pbkdf2.deriveKey(new String(password)));
}
}
public static PasswordHash instance()
{
return (PasswordHash) Component.getInstance(PasswordHash.class, ScopeType.STATELESS);
}
public String getHashAlgorithm()
{
return hashAlgorithm;
}
public void setHashAlgorithm(String hashAlgorithm)
{
this.hashAlgorithm = hashAlgorithm;
}
public int getSaltLength()
{
return saltLength;
}
public void setSaltLength(int saltLength)
{
this.saltLength = saltLength;
}
}