View Javadoc

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      //~ Static fields/initializers /////////////////////////////////////////////
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      //~ Instance fields ////////////////////////////////////////////////////////
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      //~ Constructors ///////////////////////////////////////////////////////////
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      //~ Methods ////////////////////////////////////////////////////////////////
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         // add the pad bytes.
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         // fill the current word
201         //
202         while ((xBufOff != 0) && (len > 0))
203         {
204             update(in[inOff]);
205 
206             inOff++;
207             len--;
208         }
209 
210         //
211         // process whole words.
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         // load in the remainder.
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         // expand 16 word block into 80 word blocks.
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         // set up working variables.
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         // reset the offset and clean out the word buffer.
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         //left blank as no dependencies need to be met.
396     }
397 }
398