View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.codec.digest;
18  
19  import java.nio.charset.StandardCharsets;
20  import java.security.MessageDigest;
21  import java.security.NoSuchAlgorithmException;
22  import java.security.SecureRandom;
23  import java.util.Arrays;
24  import java.util.Random;
25  import java.util.regex.Matcher;
26  import java.util.regex.Pattern;
27  
28  /**
29   * SHA2-based UNIX crypt implementation.
30   * <p>
31   * Based on the C implementation released into the Public Domain by Ulrich Drepper &lt;drepper@redhat.com&gt;
32   * http://www.akkadia.org/drepper/SHA-crypt.txt
33   * </p>
34   * <p>
35   * Conversion to Kotlin and from there to Java in 2012 by Christian Hammers &lt;ch@lathspell.de&gt; and likewise put
36   * into the Public Domain.
37   * </p>
38   * <p>
39   * This class is immutable and thread-safe.
40   * </p>
41   *
42   * @since 1.7
43   */
44  public class Sha2Crypt {
45  
46      /** Default number of rounds if not explicitly specified. */
47      private static final int ROUNDS_DEFAULT = 5000;
48  
49      /** Maximum number of rounds. */
50      private static final int ROUNDS_MAX = 999_999_999;
51  
52      /** Minimum number of rounds. */
53      private static final int ROUNDS_MIN = 1000;
54  
55      /** Prefix for optional rounds specification. */
56      private static final String ROUNDS_PREFIX = "rounds=";
57  
58      /** The number of bytes the final hash value will have (SHA-256 variant). */
59      private static final int SHA256_BLOCKSIZE = 32;
60  
61      /** The prefixes that can be used to identify this crypt() variant (SHA-256). */
62      static final String SHA256_PREFIX = "$5$";
63  
64      /** The number of bytes the final hash value will have (SHA-512 variant). */
65      private static final int SHA512_BLOCKSIZE = 64;
66  
67      /** The prefixes that can be used to identify this crypt() variant (SHA-512). */
68      static final String SHA512_PREFIX = "$6$";
69  
70      /** The pattern to match valid salt values. */
71      private static final Pattern SALT_PATTERN = Pattern
72              .compile("^\\$([56])\\$(rounds=(\\d+)\\$)?([\\.\\/a-zA-Z0-9]{1,16}).*");
73  
74      /**
75       * Generates a libc crypt() compatible "$5$" hash value with random salt.
76       * <p>
77       * See {@link Crypt#crypt(String, String)} for details.
78       * </p>
79       * <p>
80       * A salt is generated for you using {@link SecureRandom}.
81       * </p>
82       *
83       * @param keyBytes
84       *            plaintext to hash. Each array element is set to {@code 0} before returning.
85       * @return complete hash value
86       * @throws IllegalArgumentException
87       *             when a {@link java.security.NoSuchAlgorithmException} is caught.
88       */
89      public static String sha256Crypt(final byte[] keyBytes) {
90          return sha256Crypt(keyBytes, null);
91      }
92  
93      /**
94       * Generates a libc6 crypt() compatible "$5$" hash value.
95       * <p>
96       * See {@link Crypt#crypt(String, String)} for details.
97       * </p>
98       * @param keyBytes
99       *            plaintext to hash. Each array element is set to {@code 0} before returning.
100      * @param salt
101      *            real salt value without prefix or "rounds=". The salt may be null, in which case a salt
102      *            is generated for you using {@link SecureRandom}. If one does not want to use {@link SecureRandom},
103      *            you can pass your own {@link Random} in {@link #sha256Crypt(byte[], String, Random)}.
104      * @return complete hash value including salt
105      * @throws IllegalArgumentException
106      *             if the salt does not match the allowed pattern
107      * @throws IllegalArgumentException
108      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
109      */
110     public static String sha256Crypt(final byte[] keyBytes, String salt) {
111         if (salt == null) {
112             salt = SHA256_PREFIX + B64.getRandomSalt(8);
113         }
114         return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, MessageDigestAlgorithms.SHA_256);
115     }
116 
117     /**
118      * Generates a libc6 crypt() compatible "$5$" hash value.
119      * <p>
120      * See {@link Crypt#crypt(String, String)} for details.
121      * </p>
122      * @param keyBytes
123      *            plaintext to hash. Each array element is set to {@code 0} before returning.
124      * @param salt
125      *            real salt value without prefix or "rounds=".
126      * @param random
127      *            the instance of {@link Random} to use for generating the salt.
128      *            Consider using {@link SecureRandom} for more secure salts.
129      * @return complete hash value including salt
130      * @throws IllegalArgumentException
131      *             if the salt does not match the allowed pattern
132      * @throws IllegalArgumentException
133      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
134      * @since 1.12
135      */
136     public static String sha256Crypt(final byte[] keyBytes, String salt, final Random random) {
137         if (salt == null) {
138             salt = SHA256_PREFIX + B64.getRandomSalt(8, random);
139         }
140         return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, MessageDigestAlgorithms.SHA_256);
141     }
142 
143     /**
144      * Generates a libc6 crypt() compatible "$5$" or "$6$" SHA2 based hash value.
145      * <p>
146      * This is a nearly line by line conversion of the original C function. The numbered comments are from the algorithm
147      * description, the short C-style ones from the original C code and the ones with "Remark" from me.
148      * </p>
149      * <p>
150      * See {@link Crypt#crypt(String, String)} for details.
151      * </p>
152      *
153      * @param keyBytes
154      *            plaintext to hash. Each array element is set to {@code 0} before returning.
155      * @param salt
156      *            real salt value without prefix or "rounds="; may not be null
157      * @param saltPrefix
158      *            either $5$ or $6$
159      * @param blocksize
160      *            a value that differs between $5$ and $6$
161      * @param algorithm
162      *            {@link MessageDigest} algorithm identifier string
163      * @return complete hash value including prefix and salt
164      * @throws IllegalArgumentException
165      *             if the given salt is {@code null} or does not match the allowed pattern
166      * @throws IllegalArgumentException
167      *             when a {@link NoSuchAlgorithmException} is caught
168      * @see MessageDigestAlgorithms
169      */
170     private static String sha2Crypt(final byte[] keyBytes, final String salt, final String saltPrefix,
171             final int blocksize, final String algorithm) {
172 
173         final int keyLen = keyBytes.length;
174 
175         // Extracts effective salt and the number of rounds from the given salt.
176         int rounds = ROUNDS_DEFAULT;
177         boolean roundsCustom = false;
178         if (salt == null) {
179             throw new IllegalArgumentException("Salt must not be null");
180         }
181 
182         final Matcher m = SALT_PATTERN.matcher(salt);
183         if (!m.find()) {
184             throw new IllegalArgumentException("Invalid salt value: " + salt);
185         }
186         if (m.group(3) != null) {
187             rounds = Integer.parseInt(m.group(3));
188             rounds = Math.max(ROUNDS_MIN, Math.min(ROUNDS_MAX, rounds));
189             roundsCustom = true;
190         }
191         final String saltString = m.group(4);
192         final byte[] saltBytes = saltString.getBytes(StandardCharsets.UTF_8);
193         final int saltLen = saltBytes.length;
194 
195         // 1. start digest A
196         // Prepare for the real work.
197         MessageDigest ctx = DigestUtils.getDigest(algorithm);
198 
199         // 2. the password string is added to digest A
200         /*
201          * Add the key string.
202          */
203         ctx.update(keyBytes);
204 
205         // 3. the salt string is added to digest A. This is just the salt string
206         // itself without the enclosing '$', without the magic salt_prefix $5$ and
207         // $6$ respectively and without the rounds=<N> specification.
208         //
209         // NB: the MD5 algorithm did add the $1$ salt_prefix. This is not deemed
210         // necessary since it is a constant string and does not add security
211         // and /possibly/ allows a plain text attack. Since the rounds=<N>
212         // specification should never be added this would also create an
213         // inconsistency.
214         /*
215          * The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character
216          * (for compatibility with existing implementations).
217          */
218         ctx.update(saltBytes);
219 
220         // 4. start digest B
221         /*
222          * Compute alternate sha512 sum with input KEY, SALT, and KEY. The final result will be added to the first
223          * context.
224          */
225         MessageDigest altCtx = DigestUtils.getDigest(algorithm);
226 
227         // 5. add the password to digest B
228         /*
229          * Add key.
230          */
231         altCtx.update(keyBytes);
232 
233         // 6. add the salt string to digest B
234         /*
235          * Add salt.
236          */
237         altCtx.update(saltBytes);
238 
239         // 7. add the password again to digest B
240         /*
241          * Add key again.
242          */
243         altCtx.update(keyBytes);
244 
245         // 8. finish digest B
246         /*
247          * Now get result of this (32 bytes) and add it to the other context.
248          */
249         byte[] altResult = altCtx.digest();
250 
251         // 9. For each block of 32 or 64 bytes in the password string (excluding
252         // the terminating NUL in the C representation), add digest B to digest A
253         /*
254          * Add for any character in the key one byte of the alternate sum.
255          */
256         /*
257          * (Remark: the C code comment seems wrong for key length > 32!)
258          */
259         int cnt = keyBytes.length;
260         while (cnt > blocksize) {
261             ctx.update(altResult, 0, blocksize);
262             cnt -= blocksize;
263         }
264 
265         // 10. For the remaining N bytes of the password string add the first
266         // N bytes of digest B to digest A
267         ctx.update(altResult, 0, cnt);
268 
269         // 11. For each bit of the binary representation of the length of the
270         // password string up to and including the highest 1-digit, starting
271         // from to the lowest bit position (numeric value 1):
272         //
273         // a) for a 1-digit add digest B to digest A
274         //
275         // b) for a 0-digit add the password string
276         //
277         // NB: this step differs significantly from the MD5 algorithm. It
278         // adds more randomness.
279         /*
280          * Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0
281          * the key.
282          */
283         cnt = keyBytes.length;
284         while (cnt > 0) {
285             if ((cnt & 1) != 0) {
286                 ctx.update(altResult, 0, blocksize);
287             } else {
288                 ctx.update(keyBytes);
289             }
290             cnt >>= 1;
291         }
292 
293         // 12. finish digest A
294         /*
295          * Create intermediate result.
296          */
297         altResult = ctx.digest();
298 
299         // 13. start digest DP
300         /*
301          * Start computation of P byte sequence.
302          */
303         altCtx = DigestUtils.getDigest(algorithm);
304 
305         // 14. for every byte in the password (excluding the terminating NUL byte
306         // in the C representation of the string)
307         //
308         // add the password to digest DP
309         /*
310          * For every character in the password add the entire password.
311          */
312         for (int i = 1; i <= keyLen; i++) {
313             altCtx.update(keyBytes);
314         }
315 
316         // 15. finish digest DP
317         /*
318          * Finish the digest.
319          */
320         byte[] tempResult = altCtx.digest();
321 
322         // 16. produce byte sequence P of the same length as the password where
323         //
324         // a) for each block of 32 or 64 bytes of length of the password string
325         // the entire digest DP is used
326         //
327         // b) for the remaining N (up to 31 or 63) bytes use the first N
328         // bytes of digest DP
329         /*
330          * Create byte sequence P.
331          */
332         final byte[] pBytes = new byte[keyLen];
333         int cp = 0;
334         while (cp < keyLen - blocksize) {
335             System.arraycopy(tempResult, 0, pBytes, cp, blocksize);
336             cp += blocksize;
337         }
338         System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp);
339 
340         // 17. start digest DS
341         /*
342          * Start computation of S byte sequence.
343          */
344         altCtx = DigestUtils.getDigest(algorithm);
345 
346         // 18. repeat the following 16+A[0] times, where A[0] represents the first
347         // byte in digest A interpreted as an 8-bit unsigned value
348         //
349         // add the salt to digest DS
350         /*
351          * For every character in the password add the entire password.
352          */
353         for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) {
354             altCtx.update(saltBytes);
355         }
356 
357         // 19. finish digest DS
358         /*
359          * Finish the digest.
360          */
361         tempResult = altCtx.digest();
362 
363         // 20. produce byte sequence S of the same length as the salt string where
364         //
365         // a) for each block of 32 or 64 bytes of length of the salt string
366         // the entire digest DS is used
367         //
368         // b) for the remaining N (up to 31 or 63) bytes use the first N
369         // bytes of digest DS
370         /*
371          * Create byte sequence S.
372          */
373         // Remark: The salt is limited to 16 chars, how does this make sense?
374         final byte[] sBytes = new byte[saltLen];
375         cp = 0;
376         while (cp < saltLen - blocksize) {
377             System.arraycopy(tempResult, 0, sBytes, cp, blocksize);
378             cp += blocksize;
379         }
380         System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp);
381 
382         // 21. repeat a loop according to the number specified in the rounds=<N>
383         // specification in the salt (or the default value if none is
384         // present). Each round is numbered, starting with 0 and up to N-1.
385         //
386         // The loop uses a digest as input. In the first round it is the
387         // digest produced in step 12. In the latter steps it is the digest
388         // produced in step 21.h. The following text uses the notation
389         // "digest A/C" to describe this behavior.
390         /*
391          * Repeatedly run the collected hash value through sha512 to burn CPU cycles.
392          */
393         for (int i = 0; i <= rounds - 1; i++) {
394             // a) start digest C
395             /*
396              * New context.
397              */
398             ctx = DigestUtils.getDigest(algorithm);
399 
400             // b) for odd round numbers add the byte sequence P to digest C
401             // c) for even round numbers add digest A/C
402             /*
403              * Add key or last result.
404              */
405             if ((i & 1) != 0) {
406                 ctx.update(pBytes, 0, keyLen);
407             } else {
408                 ctx.update(altResult, 0, blocksize);
409             }
410 
411             // d) for all round numbers not divisible by 3 add the byte sequence S
412             /*
413              * Add salt for numbers not divisible by 3.
414              */
415             if (i % 3 != 0) {
416                 ctx.update(sBytes, 0, saltLen);
417             }
418 
419             // e) for all round numbers not divisible by 7 add the byte sequence P
420             /*
421              * Add key for numbers not divisible by 7.
422              */
423             if (i % 7 != 0) {
424                 ctx.update(pBytes, 0, keyLen);
425             }
426 
427             // f) for odd round numbers add digest A/C
428             // g) for even round numbers add the byte sequence P
429             /*
430              * Add key or last result.
431              */
432             if ((i & 1) != 0) {
433                 ctx.update(altResult, 0, blocksize);
434             } else {
435                 ctx.update(pBytes, 0, keyLen);
436             }
437 
438             // h) finish digest C.
439             /*
440              * Create intermediate result.
441              */
442             altResult = ctx.digest();
443         }
444 
445         // 22. Produce the output string. This is an ASCII string of the maximum
446         // size specified above, consisting of multiple pieces:
447         //
448         // a) the salt salt_prefix, $5$ or $6$ respectively
449         //
450         // b) the rounds=<N> specification, if one was present in the input
451         // salt string. A trailing '$' is added in this case to separate
452         // the rounds specification from the following text.
453         //
454         // c) the salt string truncated to 16 characters
455         //
456         // d) a '$' character
457         /*
458          * Now we can construct the result string. It consists of three parts.
459          */
460         final StringBuilder buffer = new StringBuilder(saltPrefix);
461         if (roundsCustom) {
462             buffer.append(ROUNDS_PREFIX);
463             buffer.append(rounds);
464             buffer.append("$");
465         }
466         buffer.append(saltString);
467         buffer.append("$");
468 
469         // e) the base-64 encoded final C digest. The encoding used is as
470         // follows:
471         // [...]
472         //
473         // Each group of three bytes from the digest produces four
474         // characters as output:
475         //
476         // 1. character: the six low bits of the first byte
477         // 2. character: the two high bits of the first byte and the
478         // four low bytes from the second byte
479         // 3. character: the four high bytes from the second byte and
480         // the two low bits from the third byte
481         // 4. character: the six high bits from the third byte
482         //
483         // The groups of three bytes are as follows (in this sequence).
484         // These are the indices into the byte array containing the
485         // digest, starting with index 0. For the last group there are
486         // not enough bytes left in the digest and the value zero is used
487         // in its place. This group also produces only three or two
488         // characters as output for SHA-512 and SHA-512 respectively.
489 
490         // This was just a safeguard in the C implementation:
491         // int buflen = salt_prefix.length() - 1 + ROUNDS_PREFIX.length() + 9 + 1 + salt_string.length() + 1 + 86 + 1;
492 
493         if (blocksize == 32) {
494             B64.b64from24bit(altResult[0], altResult[10], altResult[20], 4, buffer);
495             B64.b64from24bit(altResult[21], altResult[1], altResult[11], 4, buffer);
496             B64.b64from24bit(altResult[12], altResult[22], altResult[2], 4, buffer);
497             B64.b64from24bit(altResult[3], altResult[13], altResult[23], 4, buffer);
498             B64.b64from24bit(altResult[24], altResult[4], altResult[14], 4, buffer);
499             B64.b64from24bit(altResult[15], altResult[25], altResult[5], 4, buffer);
500             B64.b64from24bit(altResult[6], altResult[16], altResult[26], 4, buffer);
501             B64.b64from24bit(altResult[27], altResult[7], altResult[17], 4, buffer);
502             B64.b64from24bit(altResult[18], altResult[28], altResult[8], 4, buffer);
503             B64.b64from24bit(altResult[9], altResult[19], altResult[29], 4, buffer);
504             B64.b64from24bit((byte) 0, altResult[31], altResult[30], 3, buffer);
505         } else {
506             B64.b64from24bit(altResult[0], altResult[21], altResult[42], 4, buffer);
507             B64.b64from24bit(altResult[22], altResult[43], altResult[1], 4, buffer);
508             B64.b64from24bit(altResult[44], altResult[2], altResult[23], 4, buffer);
509             B64.b64from24bit(altResult[3], altResult[24], altResult[45], 4, buffer);
510             B64.b64from24bit(altResult[25], altResult[46], altResult[4], 4, buffer);
511             B64.b64from24bit(altResult[47], altResult[5], altResult[26], 4, buffer);
512             B64.b64from24bit(altResult[6], altResult[27], altResult[48], 4, buffer);
513             B64.b64from24bit(altResult[28], altResult[49], altResult[7], 4, buffer);
514             B64.b64from24bit(altResult[50], altResult[8], altResult[29], 4, buffer);
515             B64.b64from24bit(altResult[9], altResult[30], altResult[51], 4, buffer);
516             B64.b64from24bit(altResult[31], altResult[52], altResult[10], 4, buffer);
517             B64.b64from24bit(altResult[53], altResult[11], altResult[32], 4, buffer);
518             B64.b64from24bit(altResult[12], altResult[33], altResult[54], 4, buffer);
519             B64.b64from24bit(altResult[34], altResult[55], altResult[13], 4, buffer);
520             B64.b64from24bit(altResult[56], altResult[14], altResult[35], 4, buffer);
521             B64.b64from24bit(altResult[15], altResult[36], altResult[57], 4, buffer);
522             B64.b64from24bit(altResult[37], altResult[58], altResult[16], 4, buffer);
523             B64.b64from24bit(altResult[59], altResult[17], altResult[38], 4, buffer);
524             B64.b64from24bit(altResult[18], altResult[39], altResult[60], 4, buffer);
525             B64.b64from24bit(altResult[40], altResult[61], altResult[19], 4, buffer);
526             B64.b64from24bit(altResult[62], altResult[20], altResult[41], 4, buffer);
527             B64.b64from24bit((byte) 0, (byte) 0, altResult[63], 2, buffer);
528         }
529 
530         /*
531          * Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps
532          * cannot get any information.
533          */
534         // Is there a better way to do this with the JVM?
535         Arrays.fill(tempResult, (byte) 0);
536         Arrays.fill(pBytes, (byte) 0);
537         Arrays.fill(sBytes, (byte) 0);
538         ctx.reset();
539         altCtx.reset();
540         Arrays.fill(keyBytes, (byte) 0);
541         Arrays.fill(saltBytes, (byte) 0);
542 
543         return buffer.toString();
544     }
545 
546     /**
547      * Generates a libc crypt() compatible "$6$" hash value with random salt.
548      * <p>
549      * See {@link Crypt#crypt(String, String)} for details.
550      * </p>
551      * <p>
552      * A salt is generated for you using {@link SecureRandom}
553      * </p>
554      *
555      * @param keyBytes
556      *            plaintext to hash. Each array element is set to {@code 0} before returning.
557      * @return complete hash value
558      * @throws IllegalArgumentException
559      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
560      */
561     public static String sha512Crypt(final byte[] keyBytes) {
562         return sha512Crypt(keyBytes, null);
563     }
564 
565     /**
566      * Generates a libc6 crypt() compatible "$6$" hash value.
567      * <p>
568      * See {@link Crypt#crypt(String, String)} for details.
569      * </p>
570      * @param keyBytes
571      *            plaintext to hash. Each array element is set to {@code 0} before returning.
572      * @param salt
573      *            real salt value without prefix or "rounds=". The salt may be null, in which case a salt is generated
574      *            for you using {@link SecureRandom}; if you want to use a {@link Random} object other than
575      *            {@link SecureRandom} then we suggest you provide it using
576      *            {@link #sha512Crypt(byte[], String, Random)}.
577      * @return complete hash value including salt
578      * @throws IllegalArgumentException
579      *             if the salt does not match the allowed pattern
580      * @throws IllegalArgumentException
581      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
582      */
583     public static String sha512Crypt(final byte[] keyBytes, String salt) {
584         if (salt == null) {
585             salt = SHA512_PREFIX + B64.getRandomSalt(8);
586         }
587         return sha2Crypt(keyBytes, salt, SHA512_PREFIX, SHA512_BLOCKSIZE, MessageDigestAlgorithms.SHA_512);
588     }
589 
590     /**
591      * Generates a libc6 crypt() compatible "$6$" hash value.
592      * <p>
593      * See {@link Crypt#crypt(String, String)} for details.
594      * </p>
595      * @param keyBytes
596      *            plaintext to hash. Each array element is set to {@code 0} before returning.
597      * @param salt
598      *            real salt value without prefix or "rounds=". The salt may be null, in which case a salt
599      *            is generated for you using {@link SecureRandom}.
600      * @param random
601      *            the instance of {@link Random} to use for generating the salt.
602      *            Consider using {@link SecureRandom} for more secure salts.
603      * @return complete hash value including salt
604      * @throws IllegalArgumentException
605      *             if the salt does not match the allowed pattern
606      * @throws IllegalArgumentException
607      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
608      * @since 1.12
609      */
610     public static String sha512Crypt(final byte[] keyBytes, String salt, final Random random) {
611         if (salt == null) {
612             salt = SHA512_PREFIX + B64.getRandomSalt(8, random);
613         }
614         return sha2Crypt(keyBytes, salt, SHA512_PREFIX, SHA512_BLOCKSIZE, MessageDigestAlgorithms.SHA_512);
615     }
616 }