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

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