7d2cb3342e92b0d4f6921c54b2191ce783c6083e
[gigi.git] / src / club / wpia / gigi / util / PasswordHash.java
1 package club.wpia.gigi.util;
2
3 import java.util.Properties;
4
5 import com.lambdaworks.crypto.SCryptUtil;
6
7 public class PasswordHash {
8
9     /**
10      * Verifies a password hash.
11      * 
12      * @param password
13      *            The password that should result in the given hash.
14      * @param hash
15      *            The hash to verify the password against.
16      * @return
17      *         <ul>
18      *         <li><code>null</code>, if the password was valid</li>
19      *         <li><code>hash</code>, if the password is valid and the hash
20      *         doesn't need to be updated</li>
21      *         <li>a new hash, if the password is valid but the hash in the
22      *         database needs to be updated.</li>
23      *         </ul>
24      */
25     public static String verifyHash(String password, String hash) {
26         if (password == null || password.isEmpty()) {
27             return null;
28         }
29
30         if (hash.contains("$")) {
31             if (SCryptUtil.check(password, hash)) {
32                 return hash;
33             } else {
34                 return null;
35             }
36         }
37
38         return null;
39     }
40
41     public static String hash(String password) {
42         return SCryptUtil.scrypt(password, N, r, p);
43     }
44
45     private static int N = 1 << 14;
46
47     private static int r = 8;
48
49     private static int p = 1;
50
51     private static boolean initialized = false;
52
53     public static synchronized void init(Properties prop) {
54         if (initialized) {
55             throw new IllegalStateException("Already initialized.");
56         }
57         String val = prop.getProperty("scrypt.params", "14;8;1");
58         String[] parts = val.split(";", 3);
59         int N = 1 << Integer.parseInt(parts[0]);
60         int r = Integer.parseInt(parts[1]);
61         int p = Integer.parseInt(parts[2]);
62         checkScryptParams(N, r, p);
63         PasswordHash.N = N;
64         PasswordHash.r = r;
65         PasswordHash.p = p;
66         initialized = true;
67     }
68
69     private static void checkScryptParams(int N, int r, int p) {
70         if (N < 2 || (N & (N - 1)) != 0) {
71             throw new IllegalArgumentException("N must be a power of 2 greater than 1");
72         }
73         if (r <= 0) {
74             throw new IllegalArgumentException("Parameter r zero or negative");
75         }
76         if (p <= 0) {
77             throw new IllegalArgumentException("Parameter p zero or negative");
78         }
79
80         if (N > Integer.MAX_VALUE / 128 / r) {
81             throw new IllegalArgumentException("Parameter N is too large");
82         }
83         if (r > Integer.MAX_VALUE / 128 / p) {
84             throw new IllegalArgumentException("Parameter r is too large");
85         }
86     }
87 }