package io.github.lucaseasedup.logit.security.model; import io.github.lucaseasedup.logit.security.lib.Whirlpool; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Random; public final class CommonHashingModel implements HashingModel { public CommonHashingModel(Algorithm algorithm, int rounds) { if (algorithm == null || rounds <= 0) throw new IllegalArgumentException(); this.algorithm = algorithm; this.rounds = rounds; } @Override public String getHash(String string) { String output = ""; for (int i = 0; i < rounds; i++) { output = getSingleHash(output + string); } return output; } @Override public String getHash(String string, String salt) { String output = ""; for (int i = 0; i < rounds; i++) { output = getSingleHash(output + string + salt); } return output; } private String getSingleHash(String string) { switch (algorithm) { case PLAIN: return string; case MD2: return getMd2(string); case MD5: return getMd5(string); case SHA1: return getSha1(string); case SHA256: return getSha256(string); case SHA384: return getSha384(string); case SHA512: return getSha512(string); case WHIRLPOOL: return getWhirlpool(string); default: { throw new IllegalArgumentException( "Unsupported algorithm: " + algorithm ); } } } @Override public boolean verify(String string, String hash) { return hash.equals(getHash(string)); } @Override public boolean verify(String string, String salt, String hash) { return hash.equals(getHash(string, salt)); } @Override public String generateSalt() { char[] charTable = { '1','2','3','4','5','6','7','8','9','0','_', 'a','b','c','d','e','f','g','h','i','j','k', 'l','m','n','o','p','q','r','s','t','u','v','w','x','y','z', 'A','B','C','D','E','F','G','H','I','J','K', 'L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z', }; StringBuilder sb = new StringBuilder(20); Random random = new Random(); for (int i = 0, n = charTable.length; i < 20; i++) { sb.append(charTable[random.nextInt(n)]); } return sb.toString(); } @Override public String encode() { return algorithm.encode() + "(" + rounds + ")"; } public Algorithm getAlgorithm() { return algorithm; } public int getRounds() { return rounds; } /** * Returns an MD2 hash of the given string. * * @param string the string to be hashed. * @return hashed string. */ public static String getMd2(String string) { return getOriginHash(string, "MD2"); } /** * Returns an MD5 hash of the given string. * * @param string the string to be hashed. * @return hashed string. */ public static String getMd5(String string) { return getOriginHash(string, "MD5"); } /** * Returns a SHA-1 hash of the given string. * * @param string the string to be hashed. * @return hashed string. */ public static String getSha1(String string) { return getOriginHash(string, "SHA-1"); } /** * Returns a SHA-256 hash of the given string. * * @param string the string to be hashed. * @return hashed string. */ public static String getSha256(String string) { return getOriginHash(string, "SHA-256"); } /** * Returns a SHA-384 hash of the given string. * * @param string the string to be hashed. * @return hashed string. */ public static String getSha384(String string) { return getOriginHash(string, "SHA-384"); } /** * Returns a SHA-512 hash of the given string. * * @param string the string to be hashed. * @return hashed string. */ public static String getSha512(String string) { return getOriginHash(string, "SHA-512"); } /** * Returns a Whirlpool hash of the given string. * * @param string the string to be hashed. * @return hashed string. */ public static String getWhirlpool(String string) { Whirlpool whirlpool = new Whirlpool(); byte[] digest = new byte[64]; whirlpool.NESSIEinit(); whirlpool.NESSIEadd(string); whirlpool.NESSIEfinalize(digest); return Whirlpool.display(digest); } private static String getOriginHash(String string, String algorithm) { MessageDigest digest; try { digest = MessageDigest.getInstance(algorithm); digest.update(string.getBytes()); } catch (NoSuchAlgorithmException ex) { return null; } byte[] bytes = digest.digest(); StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(Integer.toString((b & 0xFF) + 0x100, 16).substring(1)); } return sb.toString(); } public static enum Algorithm { PLAIN("plain"), MD2("md2"), MD5("md5"), SHA1("sha-1"), SHA256("sha-256"), SHA384("sha-384"), SHA512("sha-512"), WHIRLPOOL("whirlpool"); private Algorithm(String name) { if (name == null) throw new IllegalArgumentException("Null name"); this.name = name; } /** * Returns a string representation of this {@code Algorithm}. * * @return the string representation of this {@code Algorithm}. */ public String encode() { return name; } /** * Decodes a string into a {@code Algorithm}. * * @param name string representation of a {@code Algorithm}. * * @return the corresponding {@code Algorithm}, or {@code null} if * no {@code Algorithm} was found for the given string. */ public static Algorithm decode(String name) { for (Algorithm value : values()) { if (value.encode().equals(name)) { return value; } } return null; } private final String name; } private final Algorithm algorithm; private final int rounds; }