package kr.co.gt1000.security; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; /** * Spring 을 사용하지 않는 시스템을 위한 스프링 코드 포팅 * @author CheonJeongDae * */ public class SpringSecurityShaPasswordEncoder { private final String algorithm; private boolean encodeHashAsBase64 = false; private int iterations = 1; public SpringSecurityShaPasswordEncoder() { this(1); } public SpringSecurityShaPasswordEncoder(int strength) { if(strength != 1 && strength != 224 && strength != 256 && strength != 384 && strength != 512) { throw new IllegalArgumentException("No such algorithm [" + strength + "]"); } algorithm = "SHA-" + strength; getMessageDigest(); } /** * 비밀번호 암호화 * @param rawPass * @param salt * @return */ public String encodePassword(String rawPass, Object salt) { String saltedPass = mergePasswordAndSalt(rawPass, salt, false); MessageDigest messageDigest = getMessageDigest(); byte[] digest = messageDigest.digest(SpringSecurityUtf8.encode(saltedPass)); for (int i = 1; i < this.iterations; ++i) { digest = messageDigest.digest(digest); } if (encodeHashAsBase64) { return SpringSecurityUtf8.decode(SpringSecurityBase64.encode(digest)); } return new String(SpringSecurityHex.encode(digest)); } protected final MessageDigest getMessageDigest() throws IllegalArgumentException { try { return MessageDigest.getInstance(this.algorithm); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException("No such algorithm [" + this.algorithm + "]"); } } /** * 비밀번호 비교 * @param encPass * @param rawPass * @param salt * @return */ public boolean isPasswordValid(String encPass, String rawPass, Object salt) { String pass1 = "" + encPass; String pass2 = encodePassword(rawPass, salt); return SpringSecurityPasswordEncoderUtils.equals(pass1, pass2); } public String getAlgorithm() { return this.algorithm; } public void setIterations(int iterations) { if (!(iterations > 0)) throw new IllegalArgumentException("Iterations value must be greater than zero"); this.iterations = iterations; } public void setEncodeHashAsBase64(boolean encodeHashAsBase64) { this.encodeHashAsBase64 = encodeHashAsBase64; } protected String[] demergePasswordAndSalt(String mergedPasswordSalt) { if ((mergedPasswordSalt == null) || ("".equals(mergedPasswordSalt))) { throw new IllegalArgumentException("Cannot pass a null or empty String"); } String password = mergedPasswordSalt; String salt = ""; int saltBegins = mergedPasswordSalt.lastIndexOf("{"); if ((saltBegins != -1) && (saltBegins + 1 < mergedPasswordSalt.length())) { salt = mergedPasswordSalt.substring(saltBegins + 1, mergedPasswordSalt.length() - 1); password = mergedPasswordSalt.substring(0, saltBegins); } return new String[] { password, salt }; } /** * 비밀번호와 salt를 merge * @param password * @param salt * @param strict * @return */ protected String mergePasswordAndSalt(String password, Object salt, boolean strict) { if (password == null) { password = ""; } if ((strict) && (salt != null) && (((salt.toString().lastIndexOf("{") != -1) || (salt.toString().lastIndexOf("}") != -1)))) { throw new IllegalArgumentException("Cannot use { or } in salt.toString()"); } if ((salt == null) || ("".equals(salt))) { return password; } return password + "{" + salt.toString() + "}"; } }