PasswordFunctions.java 4.82 KB
package fi.insomnia.bortal.utilities;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PasswordFunctions {

	private static final String SSHA_PREFIX = "{SSHA}";

	private static final Logger logger = LoggerFactory
			.getLogger(PasswordFunctions.class);

	private static final boolean UGLY_FIX = true;

	/**
	 * Returns the MD5 sum of the @param fields separated by @param separator e
	 * eg separator = "+" fields {"ONE", "TWO", "THREE"} return value
	 * ONE+TWO+THREE
	 * 
	 * @param separator
	 * @param fields
	 * @return
	 */
	public static String calculateMd5(String separator, String... fields)
	{

		StringBuilder sb = new StringBuilder();
		boolean first = true;
		for (String field : fields)
		{
			if (first) {
				first = false;
			} else {
				sb.append(separator);
			}
			sb.append(field);
		}
		logger.info("Calculating md5 from {}", sb.toString());

		return calculateMd5(sb.toString());
	}

	public static String calculateMd5(String str)
	{
		String ret = null;
		try {
			final MessageDigest algo = MessageDigest.getInstance("MD5");
			final byte[] resultByte = algo.digest(str.getBytes());
			ret = new String(Hex.encodeHex(resultByte)).toUpperCase();
		} catch (NoSuchAlgorithmException e) {
			logger.warn("THIS SHOULD NEVER HAPPEN! (md5 hashfunction should always exist)", e);
		}
		return ret;
	}

	public static String getEncryptedPassword(String password) {
		byte[] salt = new byte[SALT_LENGTH];
		Random random = new Random();
		random.nextBytes(salt);

		String base64Str = shaWithSaltToBase64(password, salt);
		String ssha = SSHA_PREFIX + base64Str;
		return ssha;
	}

	private static String shaWithSaltToBase64(String password, byte[] salt) {
		MessageDigest algo = null;
		try {
			algo = MessageDigest.getInstance("SHA");

			byte[] prehash = concatBytearrays(password.getBytes(), salt);
			byte[] hashed = algo.digest(prehash);

			byte[] both = concatBytearrays(hashed, salt);

			String base64Str = new String(Base64.encodeBase64(both), "UTF-8");
			logger.debug("Encoded {} to {}", both, base64Str);
			return base64Str;
		} catch (NoSuchAlgorithmException e) {
			logger.error("WTF!! digest function not found!!", e);
		} catch (UnsupportedEncodingException e) {
			logger.error("WTF! charset UTF-8 Not found!", e);
		}
		return null;
	}

	public static byte[] concatBytearrays(byte[]... arrays) {
		int length = 0;
		for (byte[] arr : arrays) {
			length += arr.length;
		}
		byte[] ret = new byte[length];
		int addpoint = 0;
		for (byte[] arr : arrays) {
			System.arraycopy(arr, 0, ret, addpoint, arr.length);
			addpoint += arr.length;
		}
		return ret;
	}

	public static boolean checkPlainPassword(String plainPassword,
			String saltedPassword) {
		if (saltedPassword == null || plainPassword == null) {
			logger.info("Got null password at passwordCheck");
			return false;
		}

		// TODO: Stream passwordhack Remove when not used anymore!
		if (!saltedPassword.startsWith(SSHA_PREFIX)) {
			logger.info("Streamparty legacy password used!");
			return StreampartyLegacyPwdcheck.streampartyOldAlgoMatch(plainPassword, saltedPassword);
		}

		String oldBase64 = saltedPassword.substring(SSHA_PREFIX.length());
		byte[] decodedHashedAndSalt = Base64.decodeBase64(oldBase64);
		logger.debug("Decoded Str {} to {}", oldBase64, decodedHashedAndSalt);

		byte[] salt = new byte[SALT_LENGTH];
		System.arraycopy(decodedHashedAndSalt, decodedHashedAndSalt.length - SALT_LENGTH, salt, 0, SALT_LENGTH);

		// String salt =
		// decodedHashedAndSalt.substring(decodedHashedAndSalt.length()
		// - SALT_LENGTH, decodedHashedAndSalt.length());

		logger.debug("Hash : {} salt: {}", decodedHashedAndSalt, salt);

		String newBase64 = shaWithSaltToBase64(plainPassword, salt);

		logger.debug("comparing old {} to new {}", oldBase64, newBase64);
		boolean theSame = oldBase64.equals(newBase64);

		if (!theSame && UGLY_FIX) {
			theSame = new UglyFix(newBase64, oldBase64).check();

		}
		return theSame;
	}

	private static final int SALT_LENGTH = 4;

	public static final String ALLOWED_PASSWORD_CHARS = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz";

	public static final String ALL_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

	public static String generateRandomString(int length) {
		return generateRandomString(length, ALLOWED_PASSWORD_CHARS);
	}

	public static String generateRandomString(int length, String allowedCharacters) {
		Random random = new Random();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < length; i++) {
			int index = random.nextInt(allowedCharacters.length());
			sb.append(allowedCharacters.charAt(index));
		}
		return sb.toString();
	}

}