1 package com.atlassian.user.impl.osuser.security.password;
2
3 import com.atlassian.user.security.password.PasswordEncryptor;
4 import com.atlassian.user.util.Base64Encoder;
5
6 import java.util.HashMap;
7
8
9 /**
10 * Password digester based on BouncyCastle's SHA1-512 implementation
11 *
12 * @author Victor Salaman (salaman@qoretech.com)
13 */
14 public class OSUPasswordEncryptor implements PasswordEncryptor
15 {
16
17
18 private static final int DIGEST_LENGTH = 64;
19 static final long[] K = {
20 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL,
21 0xe9b5dba58189dbbcL, 0x3956c25bf348b538L, 0x59f111f1b605d019L,
22 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, 0xd807aa98a3030242L,
23 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L,
24 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L,
25 0xc19bf174cf692694L, 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L,
26 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, 0x2de92c6f592b0275L,
27 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L,
28 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL,
29 0xbf597fc7beef0ee4L, 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L,
30 0x06ca6351e003826fL, 0x142929670a0e6e70L, 0x27b70a8546d22ffcL,
31 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL,
32 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L,
33 0x92722c851482353bL, 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L,
34 0xc24b8b70d0f89791L, 0xc76c51a30654be30L, 0xd192e819d6ef5218L,
35 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L,
36 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L,
37 0x34b0bcb5e19b48a8L, 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL,
38 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, 0x748f82ee5defb2fcL,
39 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL,
40 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L,
41 0xc67178f2e372532bL, 0xca273eceea26619cL, 0xd186b8c721c0c207L,
42 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, 0x06f067aa72176fbaL,
43 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL,
44 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL,
45 0x431d67c49c100d4cL, 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL,
46 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L
47 };
48
49
50
51 protected long H1;
52 protected long H2;
53 protected long H3;
54 protected long H4;
55 protected long H5;
56 protected long H6;
57 protected long H7;
58 protected long H8;
59 private long[] W = new long[80];
60 private byte[] xBuf;
61 private int wOff;
62 private int xBufOff;
63 private long byteCount1;
64 private long byteCount2;
65
66
67
68 public OSUPasswordEncryptor()
69 {
70 xBuf = new byte[8];
71 xBufOff = 0;
72
73 reset();
74 }
75
76 protected OSUPasswordEncryptor(OSUPasswordEncryptor t)
77 {
78 xBuf = new byte[t.xBuf.length];
79 System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length);
80
81 xBufOff = t.xBufOff;
82 byteCount1 = t.byteCount1;
83 byteCount2 = t.byteCount2;
84
85 H1 = t.H1;
86 H2 = t.H2;
87 H3 = t.H3;
88 H4 = t.H4;
89 H5 = t.H5;
90 H6 = t.H6;
91 H7 = t.H7;
92 H8 = t.H8;
93
94 System.arraycopy(t.W, 0, W, 0, t.W.length);
95 wOff = t.wOff;
96 }
97
98
99
100 public static byte[] digest(byte[] input)
101 {
102 OSUPasswordEncryptor digester = new OSUPasswordEncryptor();
103 byte[] output = new byte[digester.getDigestSize()];
104 digester.update(input, 0, input.length);
105 digester.doFinal(output, 0);
106
107 return output;
108 }
109
110 public int getDigestSize()
111 {
112 return DIGEST_LENGTH;
113 }
114
115 public int doFinal(byte[] out, int outOff)
116 {
117 finish();
118
119 unpackWord(H1, out, outOff);
120 unpackWord(H2, out, outOff + 8);
121 unpackWord(H3, out, outOff + 16);
122 unpackWord(H4, out, outOff + 24);
123 unpackWord(H5, out, outOff + 32);
124 unpackWord(H6, out, outOff + 40);
125 unpackWord(H7, out, outOff + 48);
126 unpackWord(H8, out, outOff + 56);
127
128 reset();
129
130 return DIGEST_LENGTH;
131 }
132
133 public void finish()
134 {
135 adjustByteCounts();
136
137 long lowBitLength = byteCount1 << 3;
138 long hiBitLength = byteCount2;
139
140
141
142
143 update((byte) 128);
144
145 while (xBufOff != 0)
146 {
147 update((byte) 0);
148 }
149
150 processLength(lowBitLength, hiBitLength);
151
152 processBlock();
153 }
154
155 public void reset()
156 {
157 byteCount1 = 0;
158 byteCount2 = 0;
159
160 xBufOff = 0;
161
162 for (int i = 0; i < xBuf.length; i++)
163 {
164 xBuf[i] = 0;
165 }
166
167 wOff = 0;
168
169 for (int i = 0; i != W.length; i++)
170 {
171 W[i] = 0;
172 }
173
174 H1 = 0x6a09e667f3bcc908L;
175 H2 = 0xbb67ae8584caa73bL;
176 H3 = 0x3c6ef372fe94f82bL;
177 H4 = 0xa54ff53a5f1d36f1L;
178 H5 = 0x510e527fade682d1L;
179 H6 = 0x9b05688c2b3e6c1fL;
180 H7 = 0x1f83d9abfb41bd6bL;
181 H8 = 0x5be0cd19137e2179L;
182 }
183
184 public void update(byte in)
185 {
186 xBuf[xBufOff++] = in;
187
188 if (xBufOff == xBuf.length)
189 {
190 processWord(xBuf, 0);
191 xBufOff = 0;
192 }
193
194 byteCount1++;
195 }
196
197 public void update(byte[] in, int inOff, int len)
198 {
199
200
201
202 while ((xBufOff != 0) && (len > 0))
203 {
204 update(in[inOff]);
205
206 inOff++;
207 len--;
208 }
209
210
211
212
213 while (len > xBuf.length)
214 {
215 processWord(in, inOff);
216
217 inOff += xBuf.length;
218 len -= xBuf.length;
219 byteCount1 += xBuf.length;
220 }
221
222
223
224
225 while (len > 0)
226 {
227 update(in[inOff]);
228
229 inOff++;
230 len--;
231 }
232 }
233
234 protected void processBlock()
235 {
236 adjustByteCounts();
237
238
239
240
241 for (int t = 16; t <= 79; t++)
242 {
243 W[t] = Sigma1(W[t - 2]) + W[t - 7] + Sigma0(W[t - 15]) + W[t - 16];
244 }
245
246
247
248
249 long a = H1;
250 long b = H2;
251 long c = H3;
252 long d = H4;
253 long e = H5;
254 long f = H6;
255 long g = H7;
256 long h = H8;
257
258 for (int t = 0; t <= 79; t++)
259 {
260 long T1;
261 long T2;
262
263 T1 = h + Sum1(e) + Ch(e, f, g) + K[t] + W[t];
264 T2 = Sum0(a) + Maj(a, b, c);
265 h = g;
266 g = f;
267 f = e;
268 e = d + T1;
269 d = c;
270 c = b;
271 b = a;
272 a = T1 + T2;
273 }
274
275 H1 += a;
276 H2 += b;
277 H3 += c;
278 H4 += d;
279 H5 += e;
280 H6 += f;
281 H7 += g;
282 H8 += h;
283
284
285
286
287 wOff = 0;
288
289 for (int i = 0; i != W.length; i++)
290 {
291 W[i] = 0;
292 }
293 }
294
295 protected void processLength(long lowW, long hiW)
296 {
297 if (wOff > 14)
298 {
299 processBlock();
300 }
301
302 W[14] = hiW;
303 W[15] = lowW;
304 }
305
306 protected void processWord(byte[] in, int inOff)
307 {
308 W[wOff++] = ((long) (in[inOff] & 0xff) << 56) | ((long) (in[inOff + 1] & 0xff) << 48)
309 | ((long) (in[inOff + 2] & 0xff) << 40) | ((long) (in[inOff + 3] & 0xff) << 32)
310 | ((long) (in[inOff + 4] & 0xff) << 24) | ((long) (in[inOff + 5] & 0xff) << 16)
311 | ((long) (in[inOff + 6] & 0xff) << 8) | ((long) (in[inOff + 7] & 0xff));
312
313 if (wOff == 16)
314 {
315 processBlock();
316 }
317 }
318
319 protected void unpackWord(long word, byte[] out, int outOff)
320 {
321 out[outOff] = (byte) (word >>> 56);
322 out[outOff + 1] = (byte) (word >>> 48);
323 out[outOff + 2] = (byte) (word >>> 40);
324 out[outOff + 3] = (byte) (word >>> 32);
325 out[outOff + 4] = (byte) (word >>> 24);
326 out[outOff + 5] = (byte) (word >>> 16);
327 out[outOff + 6] = (byte) (word >>> 8);
328 out[outOff + 7] = (byte) word;
329 }
330
331 private long Ch(long x, long y, long z)
332 {
333 return ((x & y) ^ ((~x) & z));
334 }
335
336 private long Maj(long x, long y, long z)
337 {
338 return ((x & y) ^ (x & z) ^ (y & z));
339 }
340
341 private long Sigma0(long x)
342 {
343 return rotateRight(x, 1) ^ rotateRight(x, 8) ^ (x >>> 7);
344 }
345
346 private long Sigma1(long x)
347 {
348 return rotateRight(x, 19) ^ rotateRight(x, 61) ^ (x >>> 6);
349 }
350
351 private long Sum0(long x)
352 {
353 return rotateRight(x, 28) ^ rotateRight(x, 34) ^ rotateRight(x, 39);
354 }
355
356 private long Sum1(long x)
357 {
358 return rotateRight(x, 14) ^ rotateRight(x, 18) ^ rotateRight(x, 41);
359 }
360
361 /**
362 * adjust the byte counts so that byteCount2 represents the
363 * upper long (less 3 bits) word of the byte count.
364 */
365 private void adjustByteCounts()
366 {
367 if (byteCount1 > 0x1fffffffffffffffL)
368 {
369 byteCount2 += (byteCount1 >>> 61);
370 byteCount1 &= 0x1fffffffffffffffL;
371 }
372 }
373
374 private long rotateRight(long x, int n)
375 {
376 return (x >>> n) | (x << (64 - n));
377 }
378
379 /**
380 * @return an encrypted version of the original {@link String} unencryptedPassword
381 */
382 public String encrypt(String unencryptedPassword)
383 {
384 byte[] digested = digest(unencryptedPassword.getBytes());
385 byte[]encoded = Base64Encoder.encode(digested);
386 return new String(encoded);
387 }
388
389 /**
390 * @deprecated since 13 March 2007, use constructor instead.
391 * @see PasswordEncryptor#init(HashMap)
392 */
393 public void init(HashMap args)
394 {
395
396 }
397 }
398