1 package org.cacert.gigi.util;
3 import java.io.UnsupportedEncodingException;
4 import java.security.MessageDigest;
5 import java.security.NoSuchAlgorithmException;
6 import java.util.Properties;
8 import com.lambdaworks.crypto.SCryptUtil;
10 public class PasswordHash {
13 * Verifies a password hash.
16 * The password that should result in the given hash.
18 * The hash to verify the password against.
21 * <li><code>null</code>, if the password was valid</li>
22 * <li><code>hash</code>, if the password is valid and the hash
23 * doesn't need to be updated</li>
24 * <li>a new hash, if the password is valid but the hash in the
25 * database needs to be updated.</li>
28 public static String verifyHash(String password, String hash) {
29 if (password == null || password.isEmpty()) {
32 if (hash.contains("$")) {
33 if (SCryptUtil.check(password, hash)) {
39 String newhash = sha1(password);
41 if (newhash.length() != hash.length()) {
44 for (int i = 0; i < newhash.length(); i++) {
45 match &= newhash.charAt(i) == hash.charAt(i);
48 return hash(password);
54 public static String sha1(String password) {
56 MessageDigest md = MessageDigest.getInstance("SHA1");
57 byte[] digest = md.digest(password.getBytes("UTF-8"));
58 StringBuffer res = new StringBuffer(digest.length * 2);
59 for (int i = 0; i < digest.length; i++) {
60 res.append(Integer.toHexString((digest[i] & 0xF0) >> 4));
61 res.append(Integer.toHexString(digest[i] & 0xF));
63 return res.toString();
64 } catch (NoSuchAlgorithmException e) {
66 } catch (UnsupportedEncodingException e) {
71 public static String hash(String password) {
72 return SCryptUtil.scrypt(password, N, r, p);
75 private static int N = 1 << 14;
77 private static int r = 8;
79 private static int p = 1;
81 private static boolean initialized = false;
83 public static synchronized void init(Properties prop) {
85 throw new IllegalStateException("Already initialized.");
87 String val = prop.getProperty("scrypt.params", "14;8;1");
88 String[] parts = val.split(";", 3);
89 int N = 1 << Integer.parseInt(parts[0]);
90 int r = Integer.parseInt(parts[1]);
91 int p = Integer.parseInt(parts[2]);
92 checkScryptParams(N, r, p);
99 private static void checkScryptParams(int N, int r, int p) {
100 if (N < 2 || (N & (N - 1)) != 0) {
101 throw new IllegalArgumentException("N must be a power of 2 greater than 1");
104 throw new IllegalArgumentException("Parameter r zero or negative");
107 throw new IllegalArgumentException("Parameter p zero or negative");
110 if (N > Integer.MAX_VALUE / 128 / r) {
111 throw new IllegalArgumentException("Parameter N is too large");
113 if (r > Integer.MAX_VALUE / 128 / p) {
114 throw new IllegalArgumentException("Parameter r is too large");