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; } }