]> WPIA git - gigi.git/blob - lib/scrypt/com/lambdaworks/crypto/SCrypt.java
add: import scrypt 1.4.0
[gigi.git] / lib / scrypt / com / lambdaworks / crypto / SCrypt.java
1 // Copyright (C) 2011 - Will Glozer.  All rights reserved.
2
3 package com.lambdaworks.crypto;
4
5 import com.lambdaworks.jni.*;
6
7 import javax.crypto.Mac;
8 import javax.crypto.spec.SecretKeySpec;
9 import java.security.GeneralSecurityException;
10
11 import static java.lang.Integer.MAX_VALUE;
12 import static java.lang.System.arraycopy;
13
14 /**
15  * An implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt</a>
16  * key derivation function. This class will attempt to load a native library
17  * containing the optimized C implementation from
18  * <a href="http://www.tarsnap.com/scrypt.html">http://www.tarsnap.com/scrypt.html<a> and
19  * fall back to the pure Java version if that fails.
20  *
21  * @author  Will Glozer
22  */
23 public class SCrypt {
24     private static final boolean native_library_loaded;
25
26     static {
27         LibraryLoader loader = LibraryLoaders.loader();
28         native_library_loaded = loader.load("scrypt", true);
29     }
30
31     /**
32      * Implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a>.
33      * Calls the native implementation {@link #scryptN} when the native library was successfully
34      * loaded, otherwise calls {@link #scryptJ}.
35      *
36      * @param passwd    Password.
37      * @param salt      Salt.
38      * @param N         CPU cost parameter.
39      * @param r         Memory cost parameter.
40      * @param p         Parallelization parameter.
41      * @param dkLen     Intended length of the derived key.
42      *
43      * @return The derived key.
44      *
45      * @throws GeneralSecurityException when HMAC_SHA256 is not available.
46      */
47     public static byte[] scrypt(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
48         return native_library_loaded ? scryptN(passwd, salt, N, r, p, dkLen) : scryptJ(passwd, salt, N, r, p, dkLen);
49     }
50
51     /**
52      * Native C implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a> using
53      * the code from <a href="http://www.tarsnap.com/scrypt.html">http://www.tarsnap.com/scrypt.html<a>.
54      *
55      * @param passwd    Password.
56      * @param salt      Salt.
57      * @param N         CPU cost parameter.
58      * @param r         Memory cost parameter.
59      * @param p         Parallelization parameter.
60      * @param dkLen     Intended length of the derived key.
61      *
62      * @return The derived key.
63      */
64     public static native byte[] scryptN(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen);
65
66     /**
67      * Pure Java implementation of the <a href="http://www.tarsnap.com/scrypt/scrypt.pdf"/>scrypt KDF</a>.
68      *
69      * @param passwd    Password.
70      * @param salt      Salt.
71      * @param N         CPU cost parameter.
72      * @param r         Memory cost parameter.
73      * @param p         Parallelization parameter.
74      * @param dkLen     Intended length of the derived key.
75      *
76      * @return The derived key.
77      *
78      * @throws GeneralSecurityException when HMAC_SHA256 is not available.
79      */
80     public static byte[] scryptJ(byte[] passwd, byte[] salt, int N, int r, int p, int dkLen) throws GeneralSecurityException {
81         if (N < 2 || (N & (N - 1)) != 0) throw new IllegalArgumentException("N must be a power of 2 greater than 1");
82
83         if (N > MAX_VALUE / 128 / r) throw new IllegalArgumentException("Parameter N is too large");
84         if (r > MAX_VALUE / 128 / p) throw new IllegalArgumentException("Parameter r is too large");
85
86         Mac mac = Mac.getInstance("HmacSHA256");
87         mac.init(new SecretKeySpec(passwd, "HmacSHA256"));
88
89         byte[] DK = new byte[dkLen];
90
91         byte[] B  = new byte[128 * r * p];
92         byte[] XY = new byte[256 * r];
93         byte[] V  = new byte[128 * r * N];
94         int i;
95
96         PBKDF.pbkdf2(mac, salt, 1, B, p * 128 * r);
97
98         for (i = 0; i < p; i++) {
99             smix(B, i * 128 * r, r, N, V, XY);
100         }
101
102         PBKDF.pbkdf2(mac, B, 1, DK, dkLen);
103
104         return DK;
105     }
106
107     public static void smix(byte[] B, int Bi, int r, int N, byte[] V, byte[] XY) {
108         int Xi = 0;
109         int Yi = 128 * r;
110         int i;
111
112         arraycopy(B, Bi, XY, Xi, 128 * r);
113
114         for (i = 0; i < N; i++) {
115             arraycopy(XY, Xi, V, i * (128 * r), 128 * r);
116             blockmix_salsa8(XY, Xi, Yi, r);
117         }
118
119         for (i = 0; i < N; i++) {
120             int j = integerify(XY, Xi, r) & (N - 1);
121             blockxor(V, j * (128 * r), XY, Xi, 128 * r);
122             blockmix_salsa8(XY, Xi, Yi, r);
123         }
124
125         arraycopy(XY, Xi, B, Bi, 128 * r);
126     }
127
128     public static void blockmix_salsa8(byte[] BY, int Bi, int Yi, int r) {
129         byte[] X = new byte[64];
130         int i;
131
132         arraycopy(BY, Bi + (2 * r - 1) * 64, X, 0, 64);
133
134         for (i = 0; i < 2 * r; i++) {
135             blockxor(BY, i * 64, X, 0, 64);
136             salsa20_8(X);
137             arraycopy(X, 0, BY, Yi + (i * 64), 64);
138         }
139
140         for (i = 0; i < r; i++) {
141             arraycopy(BY, Yi + (i * 2) * 64, BY, Bi + (i * 64), 64);
142         }
143
144         for (i = 0; i < r; i++) {
145             arraycopy(BY, Yi + (i * 2 + 1) * 64, BY, Bi + (i + r) * 64, 64);
146         }
147     }
148
149     public static int R(int a, int b) {
150         return (a << b) | (a >>> (32 - b));
151     }
152
153     public static void salsa20_8(byte[] B) {
154         int[] B32 = new int[16];
155         int[] x   = new int[16];
156         int i;
157
158         for (i = 0; i < 16; i++) {
159             B32[i]  = (B[i * 4 + 0] & 0xff) << 0;
160             B32[i] |= (B[i * 4 + 1] & 0xff) << 8;
161             B32[i] |= (B[i * 4 + 2] & 0xff) << 16;
162             B32[i] |= (B[i * 4 + 3] & 0xff) << 24;
163         }
164
165         arraycopy(B32, 0, x, 0, 16);
166
167         for (i = 8; i > 0; i -= 2) {
168             x[ 4] ^= R(x[ 0]+x[12], 7);  x[ 8] ^= R(x[ 4]+x[ 0], 9);
169             x[12] ^= R(x[ 8]+x[ 4],13);  x[ 0] ^= R(x[12]+x[ 8],18);
170             x[ 9] ^= R(x[ 5]+x[ 1], 7);  x[13] ^= R(x[ 9]+x[ 5], 9);
171             x[ 1] ^= R(x[13]+x[ 9],13);  x[ 5] ^= R(x[ 1]+x[13],18);
172             x[14] ^= R(x[10]+x[ 6], 7);  x[ 2] ^= R(x[14]+x[10], 9);
173             x[ 6] ^= R(x[ 2]+x[14],13);  x[10] ^= R(x[ 6]+x[ 2],18);
174             x[ 3] ^= R(x[15]+x[11], 7);  x[ 7] ^= R(x[ 3]+x[15], 9);
175             x[11] ^= R(x[ 7]+x[ 3],13);  x[15] ^= R(x[11]+x[ 7],18);
176             x[ 1] ^= R(x[ 0]+x[ 3], 7);  x[ 2] ^= R(x[ 1]+x[ 0], 9);
177             x[ 3] ^= R(x[ 2]+x[ 1],13);  x[ 0] ^= R(x[ 3]+x[ 2],18);
178             x[ 6] ^= R(x[ 5]+x[ 4], 7);  x[ 7] ^= R(x[ 6]+x[ 5], 9);
179             x[ 4] ^= R(x[ 7]+x[ 6],13);  x[ 5] ^= R(x[ 4]+x[ 7],18);
180             x[11] ^= R(x[10]+x[ 9], 7);  x[ 8] ^= R(x[11]+x[10], 9);
181             x[ 9] ^= R(x[ 8]+x[11],13);  x[10] ^= R(x[ 9]+x[ 8],18);
182             x[12] ^= R(x[15]+x[14], 7);  x[13] ^= R(x[12]+x[15], 9);
183             x[14] ^= R(x[13]+x[12],13);  x[15] ^= R(x[14]+x[13],18);
184         }
185
186         for (i = 0; i < 16; ++i) B32[i] = x[i] + B32[i];
187
188         for (i = 0; i < 16; i++) {
189             B[i * 4 + 0] = (byte) (B32[i] >> 0  & 0xff);
190             B[i * 4 + 1] = (byte) (B32[i] >> 8  & 0xff);
191             B[i * 4 + 2] = (byte) (B32[i] >> 16 & 0xff);
192             B[i * 4 + 3] = (byte) (B32[i] >> 24 & 0xff);
193         }
194     }
195
196     public static void blockxor(byte[] S, int Si, byte[] D, int Di, int len) {
197         for (int i = 0; i < len; i++) {
198             D[Di + i] ^= S[Si + i];
199         }
200     }
201
202     public static int integerify(byte[] B, int Bi, int r) {
203         int n;
204
205         Bi += (2 * r - 1) * 64;
206
207         n  = (B[Bi + 0] & 0xff) << 0;
208         n |= (B[Bi + 1] & 0xff) << 8;
209         n |= (B[Bi + 2] & 0xff) << 16;
210         n |= (B[Bi + 3] & 0xff) << 24;
211
212         return n;
213     }
214 }