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