EMMA Coverage Report (generated Wed Aug 10 12:30:04 EDT 2011)
[all classes][org.jclouds.crypto]

COVERAGE SUMMARY FOR SOURCE FILE [Sha512Crypt.java]

nameclass, %method, %block, %line, %
Sha512Crypt.java50%  (1/2)20%  (2/10)88%  (681/774)82%  (98.6/120)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Sha512Crypt$Function0%   (0/1)0%   (0/6)0%   (0/46)0%   (0/10)
<static initializer> 0%   (0/1)0%   (0/14)0%   (0/2)
Sha512Crypt$Function (String, int): void 0%   (0/1)0%   (0/15)0%   (0/6)
apply (String): String 0%   (0/1)0%   (0/6)0%   (0/1)
toString (): String 0%   (0/1)0%   (0/2)0%   (0/1)
valueOf (String): Sha512Crypt$Function 0%   (0/1)0%   (0/5)0%   (0/1)
values (): Sha512Crypt$Function [] 0%   (0/1)0%   (0/4)0%   (0/1)
     
class Sha512Crypt100% (1/1)50%  (2/4)94%  (681/728)89%  (98.6/111)
Sha512Crypt (): void 0%   (0/1)0%   (0/3)0%   (0/2)
function (): Function 0%   (0/1)0%   (0/2)0%   (0/1)
makeShadowLine (String, String, Crypto): String 100% (1/1)94%  (642/684)91%  (92.6/102)
b64_from_24bit (byte, byte, byte, int): String 100% (1/1)100% (39/39)100% (6/6)

1/*
2   Sha512Crypt.java
3 
4   Created: 18 December 2007
5   Last Changed By: $Author: broccol $
6   Version: $Revision: 7692 $
7   Last Mod Date: $Date: 2007-12-30 01:55:31 -0600 (Sun, 30 Dec 2007) $
8 
9   Java Port By: James Ratcliff, falazar@arlut.utexas.edu
10 
11   This class implements the new generation, scalable, SHA512-based
12   Unix 'crypt' algorithm developed by a group of engineers from Red
13   Hat, Sun, IBM, and HP for common use in the Unix and Linux
14   /etc/shadow files.
15 
16   The Linux glibc library (starting at version 2.7) includes support
17   for validating passwords hashed using this algorithm.
18 
19   The algorithm itself was released into the Public Domain by Ulrich
20   Drepper <drepper@redhat.com>.  A discussion of the rationale and
21   development of this algorithm is at
22 
23   http://people.redhat.com/drepper/sha-crypt.html
24 
25   and the specification and a sample C language implementation is at
26 
27   http://people.redhat.com/drepper/SHA-crypt.txt
28 
29   This Java Port is  
30 
31     Copyright (c) 2008 The University of Texas at Austin.
32 
33     All rights reserved.
34 
35     Redistribution and use in source and binary form are permitted
36     provided that distributions retain this entire copyright notice
37     and comment. Neither the name of the University nor the names of
38     its contributors may be used to endorse or promote products
39     derived from this software without specific prior written
40     permission. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY
41     EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE
42     IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
43     PARTICULAR PURPOSE.
44 
45 */
46 
47package org.jclouds.crypto;
48 
49import java.security.MessageDigest;
50 
51import javax.annotation.Nullable;
52 
53import org.jclouds.encryption.internal.JCECrypto;
54 
55import com.google.common.base.Throwables;
56 
57/**
58 * This class defines a method,
59 * {@link Sha512Crypt#Sha512_crypt(java.lang.String, java.lang.String, int)
60 * Sha512_crypt()}, which takes a password and a salt string and generates a
61 * Sha512 encrypted password entry.
62 * 
63 * This class implements the new generation, scalable, SHA512-based Unix 'crypt'
64 * algorithm developed by a group of engineers from Red Hat, Sun, IBM, and HP
65 * for common use in the Unix and Linux /etc/shadow files.
66 * 
67 * The Linux glibc library (starting at version 2.7) includes support for
68 * validating passwords hashed using this algorithm.
69 * 
70 * The algorithm itself was released into the Public Domain by Ulrich Drepper
71 * &lt;drepper@redhat.com&gt;. A discussion of the rationale and development of
72 * this algorithm is at
73 * 
74 * http://people.redhat.com/drepper/sha-crypt.html
75 * 
76 * and the specification and a sample C language implementation is at
77 * 
78 * http://people.redhat.com/drepper/SHA-crypt.txt
79 */
80public class Sha512Crypt {
81   public static com.google.common.base.Function<String, String> function() {
82      return Function.INSTANCE;
83   }
84 
85   public static enum Function implements com.google.common.base.Function<String, String> {
86      INSTANCE;
87      private Crypto crypto;
88 
89      Function() {
90         try {
91            this.crypto = new JCECrypto();
92         } catch (Exception e) {
93            Throwables.propagate(e);
94         }
95      }
96 
97      @Override
98      public String apply(String input) {
99         return Sha512Crypt.makeShadowLine(input, null, crypto);
100      }
101 
102      @Override
103      public String toString() {
104         return "sha512Crypt()";
105      }
106 
107   }
108 
109   static private final String sha512_salt_prefix = "$6$";
110   static private final String sha512_rounds_prefix = "rounds=";
111   static private final int SALT_LEN_MAX = 16;
112   static private final int ROUNDS_DEFAULT = 5000;
113   static private final int ROUNDS_MIN = 1000;
114   static private final int ROUNDS_MAX = 999999999;
115   static private final String SALTCHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
116   static private final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
117 
118   /**
119    * This method actually generates an Sha512 crypted password hash from a
120    * plaintext password and a salt.
121    * 
122    * <p>
123    * The resulting string will be in the form
124    * '$6$&lt;rounds=n&gt;$&lt;salt&gt;$&lt;hashed mess&gt;
125    * </p>
126    * 
127    * @param password
128    *           Plaintext password
129    * 
130    * @param shadowPrefix
131    *           An encoded salt/rounds which will be consulted to determine the
132    *           salt and round count, if not null
133    * 
134    * @return The Sha512 Unix Crypt hash text for the password
135    */
136   public static String makeShadowLine(String password, @Nullable String shadowPrefix, Crypto crypto) {
137      MessageDigest ctx = crypto.sha512();
138      MessageDigest alt_ctx = crypto.sha512();
139 
140      byte[] alt_result;
141      byte[] temp_result;
142      byte[] p_bytes = null;
143      byte[] s_bytes = null;
144      int cnt, cnt2;
145      int rounds = ROUNDS_DEFAULT; // Default number of rounds.
146      StringBuffer buffer;
147 
148      /* -- */
149 
150      if (shadowPrefix != null) {
151         if (shadowPrefix.startsWith(sha512_salt_prefix)) {
152            shadowPrefix = shadowPrefix.substring(sha512_salt_prefix.length());
153         }
154 
155         if (shadowPrefix.startsWith(sha512_rounds_prefix)) {
156            String num = shadowPrefix.substring(sha512_rounds_prefix.length(), shadowPrefix.indexOf('$'));
157            int srounds = Integer.valueOf(num).intValue();
158            shadowPrefix = shadowPrefix.substring(shadowPrefix.indexOf('$') + 1);
159            rounds = Math.max(ROUNDS_MIN, Math.min(srounds, ROUNDS_MAX));
160         }
161 
162         if (shadowPrefix.length() > SALT_LEN_MAX) {
163            shadowPrefix = shadowPrefix.substring(0, SALT_LEN_MAX);
164         }
165      } else {
166         java.util.Random randgen = new java.util.Random();
167         StringBuffer saltBuf = new StringBuffer();
168 
169         while (saltBuf.length() < 16) {
170            int index = (int) (randgen.nextFloat() * SALTCHARS.length());
171            saltBuf.append(SALTCHARS.substring(index, index + 1));
172         }
173 
174         shadowPrefix = saltBuf.toString();
175      }
176 
177      byte[] key = password.getBytes();
178      byte[] salts = shadowPrefix.getBytes();
179 
180      ctx.reset();
181      ctx.update(key, 0, key.length);
182      ctx.update(salts, 0, salts.length);
183 
184      alt_ctx.reset();
185      alt_ctx.update(key, 0, key.length);
186      alt_ctx.update(salts, 0, salts.length);
187      alt_ctx.update(key, 0, key.length);
188 
189      alt_result = alt_ctx.digest();
190 
191      for (cnt = key.length; cnt > 64; cnt -= 64) {
192         ctx.update(alt_result, 0, 64);
193      }
194 
195      ctx.update(alt_result, 0, cnt);
196 
197      for (cnt = key.length; cnt > 0; cnt >>= 1) {
198         if ((cnt & 1) != 0) {
199            ctx.update(alt_result, 0, 64);
200         } else {
201            ctx.update(key, 0, key.length);
202         }
203      }
204 
205      alt_result = ctx.digest();
206 
207      alt_ctx.reset();
208 
209      for (cnt = 0; cnt < key.length; ++cnt) {
210         alt_ctx.update(key, 0, key.length);
211      }
212 
213      temp_result = alt_ctx.digest();
214 
215      p_bytes = new byte[key.length];
216 
217      for (cnt2 = 0, cnt = p_bytes.length; cnt >= 64; cnt -= 64) {
218         System.arraycopy(temp_result, 0, p_bytes, cnt2, 64);
219         cnt2 += 64;
220      }
221 
222      System.arraycopy(temp_result, 0, p_bytes, cnt2, cnt);
223 
224      alt_ctx.reset();
225 
226      for (cnt = 0; cnt < 16 + (alt_result[0] & 0xFF); ++cnt) {
227         alt_ctx.update(salts, 0, salts.length);
228      }
229 
230      temp_result = alt_ctx.digest();
231 
232      s_bytes = new byte[salts.length];
233 
234      for (cnt2 = 0, cnt = s_bytes.length; cnt >= 64; cnt -= 64) {
235         System.arraycopy(temp_result, 0, s_bytes, cnt2, 64);
236         cnt2 += 64;
237      }
238 
239      System.arraycopy(temp_result, 0, s_bytes, cnt2, cnt);
240 
241      /*
242       * Repeatedly run the collected hash value through SHA512 to burn CPU
243       * cycles.
244       */
245 
246      for (cnt = 0; cnt < rounds; ++cnt) {
247         ctx.reset();
248 
249         if ((cnt & 1) != 0) {
250            ctx.update(p_bytes, 0, key.length);
251         } else {
252            ctx.update(alt_result, 0, 64);
253         }
254 
255         if (cnt % 3 != 0) {
256            ctx.update(s_bytes, 0, salts.length);
257         }
258 
259         if (cnt % 7 != 0) {
260            ctx.update(p_bytes, 0, key.length);
261         }
262 
263         if ((cnt & 1) != 0) {
264            ctx.update(alt_result, 0, 64);
265         } else {
266            ctx.update(p_bytes, 0, key.length);
267         }
268 
269         alt_result = ctx.digest();
270      }
271 
272      buffer = new StringBuffer(sha512_salt_prefix);
273 
274      if (rounds != 5000) {
275         buffer.append(sha512_rounds_prefix);
276         buffer.append(rounds);
277         buffer.append("$");
278      }
279 
280      buffer.append(shadowPrefix);
281      buffer.append("$");
282 
283      buffer.append(b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4));
284      buffer.append(b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4));
285      buffer.append(b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4));
286      buffer.append(b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4));
287      buffer.append(b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4));
288      buffer.append(b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4));
289      buffer.append(b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4));
290      buffer.append(b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4));
291      buffer.append(b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4));
292      buffer.append(b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4));
293      buffer.append(b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4));
294      buffer.append(b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4));
295      buffer.append(b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4));
296      buffer.append(b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4));
297      buffer.append(b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4));
298      buffer.append(b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4));
299      buffer.append(b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4));
300      buffer.append(b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4));
301      buffer.append(b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4));
302      buffer.append(b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4));
303      buffer.append(b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4));
304      buffer.append(b64_from_24bit((byte) 0x00, (byte) 0x00, alt_result[63], 2));
305 
306      /*
307       * Clear the buffer for the intermediate result so that people attaching
308       * to processes or reading core dumps cannot get any information.
309       */
310 
311      ctx.reset();
312 
313      return buffer.toString();
314   }
315 
316   private static final String b64_from_24bit(byte B2, byte B1, byte B0, int size) {
317      int v = ((((int) B2) & 0xFF) << 16) | ((((int) B1) & 0xFF) << 8) | ((int) B0 & 0xff);
318 
319      StringBuffer result = new StringBuffer();
320 
321      while (--size >= 0) {
322         result.append(itoa64.charAt((int) (v & 0x3f)));
323         v >>>= 6;
324      }
325 
326      return result.toString();
327   }
328 
329}

[all classes][org.jclouds.crypto]
EMMA 2.0.5312 (C) Vladimir Roubtsov