Sha2Crypt.java

  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. import java.security.MessageDigest;
  19. import java.security.NoSuchAlgorithmException;
  20. import java.util.Arrays;
  21. import java.util.regex.Matcher;
  22. import java.util.regex.Pattern;

  23. import org.apache.commons.codec.Charsets;

  24. /**
  25.  * SHA2-based Unix crypt implementation.
  26.  * <p>
  27.  * Based on the C implementation released into the Public Domain by Ulrich Drepper &lt;drepper@redhat.com&gt;
  28.  * http://www.akkadia.org/drepper/SHA-crypt.txt
  29.  * <p>
  30.  * Conversion to Kotlin and from there to Java in 2012 by Christian Hammers &lt;ch@lathspell.de&gt; and likewise put
  31.  * into the Public Domain.
  32.  * <p>
  33.  * This class is immutable and thread-safe.
  34.  *
  35.  * @version $Id: Sha2Crypt.java 1744746 2016-05-20 14:19:43Z sebb $
  36.  * @since 1.7
  37.  */
  38. public class Sha2Crypt {

  39.     /** Default number of rounds if not explicitly specified. */
  40.     private static final int ROUNDS_DEFAULT = 5000;

  41.     /** Maximum number of rounds. */
  42.     private static final int ROUNDS_MAX = 999999999;

  43.     /** Minimum number of rounds. */
  44.     private static final int ROUNDS_MIN = 1000;

  45.     /** Prefix for optional rounds specification. */
  46.     private static final String ROUNDS_PREFIX = "rounds=";

  47.     /** The number of bytes the final hash value will have (SHA-256 variant). */
  48.     private static final int SHA256_BLOCKSIZE = 32;

  49.     /** The prefixes that can be used to identify this crypt() variant (SHA-256). */
  50.     static final String SHA256_PREFIX = "$5$";

  51.     /** The number of bytes the final hash value will have (SHA-512 variant). */
  52.     private static final int SHA512_BLOCKSIZE = 64;

  53.     /** The prefixes that can be used to identify this crypt() variant (SHA-512). */
  54.     static final String SHA512_PREFIX = "$6$";

  55.     /** The pattern to match valid salt values. */
  56.     private static final Pattern SALT_PATTERN = Pattern
  57.             .compile("^\\$([56])\\$(rounds=(\\d+)\\$)?([\\.\\/a-zA-Z0-9]{1,16}).*");

  58.     /**
  59.      * Generates a libc crypt() compatible "$5$" hash value with random salt.
  60.      * <p>
  61.      * See {@link Crypt#crypt(String, String)} for details.
  62.      *
  63.      * @param keyBytes
  64.      *            plaintext to hash
  65.      * @return complete hash value
  66.      * @throws RuntimeException
  67.      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
  68.      */
  69.     public static String sha256Crypt(final byte[] keyBytes) {
  70.         return sha256Crypt(keyBytes, null);
  71.     }

  72.     /**
  73.      * Generates a libc6 crypt() compatible "$5$" hash value.
  74.      * <p>
  75.      * See {@link Crypt#crypt(String, String)} for details.
  76.      *
  77.      * @param keyBytes
  78.      *            plaintext to hash
  79.      * @param salt
  80.      *            real salt value without prefix or "rounds="
  81.      * @return complete hash value including salt
  82.      * @throws IllegalArgumentException
  83.      *             if the salt does not match the allowed pattern
  84.      * @throws RuntimeException
  85.      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
  86.      */
  87.     public static String sha256Crypt(final byte[] keyBytes, String salt) {
  88.         if (salt == null) {
  89.             salt = SHA256_PREFIX + B64.getRandomSalt(8);
  90.         }
  91.         return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, MessageDigestAlgorithms.SHA_256);
  92.     }

  93.     /**
  94.      * Generates a libc6 crypt() compatible "$5$" or "$6$" SHA2 based hash value.
  95.      * <p>
  96.      * This is a nearly line by line conversion of the original C function. The numbered comments are from the algorithm
  97.      * description, the short C-style ones from the original C code and the ones with "Remark" from me.
  98.      * <p>
  99.      * See {@link Crypt#crypt(String, String)} for details.
  100.      *
  101.      * @param keyBytes
  102.      *            plaintext to hash
  103.      * @param salt
  104.      *            real salt value without prefix or "rounds="
  105.      * @param saltPrefix
  106.      *            either $5$ or $6$
  107.      * @param blocksize
  108.      *            a value that differs between $5$ and $6$
  109.      * @param algorithm
  110.      *            {@link MessageDigest} algorithm identifier string
  111.      * @return complete hash value including prefix and salt
  112.      * @throws IllegalArgumentException
  113.      *             if the given salt is <code>null</code> or does not match the allowed pattern
  114.      * @throws IllegalArgumentException
  115.      *             when a {@link NoSuchAlgorithmException} is caught
  116.      * @see MessageDigestAlgorithms
  117.      */
  118.     private static String sha2Crypt(final byte[] keyBytes, final String salt, final String saltPrefix,
  119.             final int blocksize, final String algorithm) {

  120.         final int keyLen = keyBytes.length;

  121.         // Extracts effective salt and the number of rounds from the given salt.
  122.         int rounds = ROUNDS_DEFAULT;
  123.         boolean roundsCustom = false;
  124.         if (salt == null) {
  125.             throw new IllegalArgumentException("Salt must not be null");
  126.         }

  127.         final Matcher m = SALT_PATTERN.matcher(salt);
  128.         if (!m.find()) {
  129.             throw new IllegalArgumentException("Invalid salt value: " + salt);
  130.         }
  131.         if (m.group(3) != null) {
  132.             rounds = Integer.parseInt(m.group(3));
  133.             rounds = Math.max(ROUNDS_MIN, Math.min(ROUNDS_MAX, rounds));
  134.             roundsCustom = true;
  135.         }
  136.         final String saltString = m.group(4);
  137.         final byte[] saltBytes = saltString.getBytes(Charsets.UTF_8);
  138.         final int saltLen = saltBytes.length;

  139.         // 1. start digest A
  140.         // Prepare for the real work.
  141.         MessageDigest ctx = DigestUtils.getDigest(algorithm);

  142.         // 2. the password string is added to digest A
  143.         /*
  144.          * Add the key string.
  145.          */
  146.         ctx.update(keyBytes);

  147.         // 3. the salt string is added to digest A. This is just the salt string
  148.         // itself without the enclosing '$', without the magic salt_prefix $5$ and
  149.         // $6$ respectively and without the rounds=<N> specification.
  150.         //
  151.         // NB: the MD5 algorithm did add the $1$ salt_prefix. This is not deemed
  152.         // necessary since it is a constant string and does not add security
  153.         // and /possibly/ allows a plain text attack. Since the rounds=<N>
  154.         // specification should never be added this would also create an
  155.         // inconsistency.
  156.         /*
  157.          * The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character
  158.          * (for compatibility with existing implementations).
  159.          */
  160.         ctx.update(saltBytes);

  161.         // 4. start digest B
  162.         /*
  163.          * Compute alternate sha512 sum with input KEY, SALT, and KEY. The final result will be added to the first
  164.          * context.
  165.          */
  166.         MessageDigest altCtx = DigestUtils.getDigest(algorithm);

  167.         // 5. add the password to digest B
  168.         /*
  169.          * Add key.
  170.          */
  171.         altCtx.update(keyBytes);

  172.         // 6. add the salt string to digest B
  173.         /*
  174.          * Add salt.
  175.          */
  176.         altCtx.update(saltBytes);

  177.         // 7. add the password again to digest B
  178.         /*
  179.          * Add key again.
  180.          */
  181.         altCtx.update(keyBytes);

  182.         // 8. finish digest B
  183.         /*
  184.          * Now get result of this (32 bytes) and add it to the other context.
  185.          */
  186.         byte[] altResult = altCtx.digest();

  187.         // 9. For each block of 32 or 64 bytes in the password string (excluding
  188.         // the terminating NUL in the C representation), add digest B to digest A
  189.         /*
  190.          * Add for any character in the key one byte of the alternate sum.
  191.          */
  192.         /*
  193.          * (Remark: the C code comment seems wrong for key length > 32!)
  194.          */
  195.         int cnt = keyBytes.length;
  196.         while (cnt > blocksize) {
  197.             ctx.update(altResult, 0, blocksize);
  198.             cnt -= blocksize;
  199.         }

  200.         // 10. For the remaining N bytes of the password string add the first
  201.         // N bytes of digest B to digest A
  202.         ctx.update(altResult, 0, cnt);

  203.         // 11. For each bit of the binary representation of the length of the
  204.         // password string up to and including the highest 1-digit, starting
  205.         // from to lowest bit position (numeric value 1):
  206.         //
  207.         // a) for a 1-digit add digest B to digest A
  208.         //
  209.         // b) for a 0-digit add the password string
  210.         //
  211.         // NB: this step differs significantly from the MD5 algorithm. It
  212.         // adds more randomness.
  213.         /*
  214.          * Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0
  215.          * the key.
  216.          */
  217.         cnt = keyBytes.length;
  218.         while (cnt > 0) {
  219.             if ((cnt & 1) != 0) {
  220.                 ctx.update(altResult, 0, blocksize);
  221.             } else {
  222.                 ctx.update(keyBytes);
  223.             }
  224.             cnt >>= 1;
  225.         }

  226.         // 12. finish digest A
  227.         /*
  228.          * Create intermediate result.
  229.          */
  230.         altResult = ctx.digest();

  231.         // 13. start digest DP
  232.         /*
  233.          * Start computation of P byte sequence.
  234.          */
  235.         altCtx = DigestUtils.getDigest(algorithm);

  236.         // 14. for every byte in the password (excluding the terminating NUL byte
  237.         // in the C representation of the string)
  238.         //
  239.         // add the password to digest DP
  240.         /*
  241.          * For every character in the password add the entire password.
  242.          */
  243.         for (int i = 1; i <= keyLen; i++) {
  244.             altCtx.update(keyBytes);
  245.         }

  246.         // 15. finish digest DP
  247.         /*
  248.          * Finish the digest.
  249.          */
  250.         byte[] tempResult = altCtx.digest();

  251.         // 16. produce byte sequence P of the same length as the password where
  252.         //
  253.         // a) for each block of 32 or 64 bytes of length of the password string
  254.         // the entire digest DP is used
  255.         //
  256.         // b) for the remaining N (up to 31 or 63) bytes use the first N
  257.         // bytes of digest DP
  258.         /*
  259.          * Create byte sequence P.
  260.          */
  261.         final byte[] pBytes = new byte[keyLen];
  262.         int cp = 0;
  263.         while (cp < keyLen - blocksize) {
  264.             System.arraycopy(tempResult, 0, pBytes, cp, blocksize);
  265.             cp += blocksize;
  266.         }
  267.         System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp);

  268.         // 17. start digest DS
  269.         /*
  270.          * Start computation of S byte sequence.
  271.          */
  272.         altCtx = DigestUtils.getDigest(algorithm);

  273.         // 18. repeast the following 16+A[0] times, where A[0] represents the first
  274.         // byte in digest A interpreted as an 8-bit unsigned value
  275.         //
  276.         // add the salt to digest DS
  277.         /*
  278.          * For every character in the password add the entire password.
  279.          */
  280.         for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) {
  281.             altCtx.update(saltBytes);
  282.         }

  283.         // 19. finish digest DS
  284.         /*
  285.          * Finish the digest.
  286.          */
  287.         tempResult = altCtx.digest();

  288.         // 20. produce byte sequence S of the same length as the salt string where
  289.         //
  290.         // a) for each block of 32 or 64 bytes of length of the salt string
  291.         // the entire digest DS is used
  292.         //
  293.         // b) for the remaining N (up to 31 or 63) bytes use the first N
  294.         // bytes of digest DS
  295.         /*
  296.          * Create byte sequence S.
  297.          */
  298.         // Remark: The salt is limited to 16 chars, how does this make sense?
  299.         final byte[] sBytes = new byte[saltLen];
  300.         cp = 0;
  301.         while (cp < saltLen - blocksize) {
  302.             System.arraycopy(tempResult, 0, sBytes, cp, blocksize);
  303.             cp += blocksize;
  304.         }
  305.         System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp);

  306.         // 21. repeat a loop according to the number specified in the rounds=<N>
  307.         // specification in the salt (or the default value if none is
  308.         // present). Each round is numbered, starting with 0 and up to N-1.
  309.         //
  310.         // The loop uses a digest as input. In the first round it is the
  311.         // digest produced in step 12. In the latter steps it is the digest
  312.         // produced in step 21.h. The following text uses the notation
  313.         // "digest A/C" to describe this behavior.
  314.         /*
  315.          * Repeatedly run the collected hash value through sha512 to burn CPU cycles.
  316.          */
  317.         for (int i = 0; i <= rounds - 1; i++) {
  318.             // a) start digest C
  319.             /*
  320.              * New context.
  321.              */
  322.             ctx = DigestUtils.getDigest(algorithm);

  323.             // b) for odd round numbers add the byte sequense P to digest C
  324.             // c) for even round numbers add digest A/C
  325.             /*
  326.              * Add key or last result.
  327.              */
  328.             if ((i & 1) != 0) {
  329.                 ctx.update(pBytes, 0, keyLen);
  330.             } else {
  331.                 ctx.update(altResult, 0, blocksize);
  332.             }

  333.             // d) for all round numbers not divisible by 3 add the byte sequence S
  334.             /*
  335.              * Add salt for numbers not divisible by 3.
  336.              */
  337.             if (i % 3 != 0) {
  338.                 ctx.update(sBytes, 0, saltLen);
  339.             }

  340.             // e) for all round numbers not divisible by 7 add the byte sequence P
  341.             /*
  342.              * Add key for numbers not divisible by 7.
  343.              */
  344.             if (i % 7 != 0) {
  345.                 ctx.update(pBytes, 0, keyLen);
  346.             }

  347.             // f) for odd round numbers add digest A/C
  348.             // g) for even round numbers add the byte sequence P
  349.             /*
  350.              * Add key or last result.
  351.              */
  352.             if ((i & 1) != 0) {
  353.                 ctx.update(altResult, 0, blocksize);
  354.             } else {
  355.                 ctx.update(pBytes, 0, keyLen);
  356.             }

  357.             // h) finish digest C.
  358.             /*
  359.              * Create intermediate result.
  360.              */
  361.             altResult = ctx.digest();
  362.         }

  363.         // 22. Produce the output string. This is an ASCII string of the maximum
  364.         // size specified above, consisting of multiple pieces:
  365.         //
  366.         // a) the salt salt_prefix, $5$ or $6$ respectively
  367.         //
  368.         // b) the rounds=<N> specification, if one was present in the input
  369.         // salt string. A trailing '$' is added in this case to separate
  370.         // the rounds specification from the following text.
  371.         //
  372.         // c) the salt string truncated to 16 characters
  373.         //
  374.         // d) a '$' character
  375.         /*
  376.          * Now we can construct the result string. It consists of three parts.
  377.          */
  378.         final StringBuilder buffer = new StringBuilder(saltPrefix);
  379.         if (roundsCustom) {
  380.             buffer.append(ROUNDS_PREFIX);
  381.             buffer.append(rounds);
  382.             buffer.append("$");
  383.         }
  384.         buffer.append(saltString);
  385.         buffer.append("$");

  386.         // e) the base-64 encoded final C digest. The encoding used is as
  387.         // follows:
  388.         // [...]
  389.         //
  390.         // Each group of three bytes from the digest produces four
  391.         // characters as output:
  392.         //
  393.         // 1. character: the six low bits of the first byte
  394.         // 2. character: the two high bits of the first byte and the
  395.         // four low bytes from the second byte
  396.         // 3. character: the four high bytes from the second byte and
  397.         // the two low bits from the third byte
  398.         // 4. character: the six high bits from the third byte
  399.         //
  400.         // The groups of three bytes are as follows (in this sequence).
  401.         // These are the indices into the byte array containing the
  402.         // digest, starting with index 0. For the last group there are
  403.         // not enough bytes left in the digest and the value zero is used
  404.         // in its place. This group also produces only three or two
  405.         // characters as output for SHA-512 and SHA-512 respectively.

  406.         // This was just a safeguard in the C implementation:
  407.         // int buflen = salt_prefix.length() - 1 + ROUNDS_PREFIX.length() + 9 + 1 + salt_string.length() + 1 + 86 + 1;

  408.         if (blocksize == 32) {
  409.             B64.b64from24bit(altResult[0], altResult[10], altResult[20], 4, buffer);
  410.             B64.b64from24bit(altResult[21], altResult[1], altResult[11], 4, buffer);
  411.             B64.b64from24bit(altResult[12], altResult[22], altResult[2], 4, buffer);
  412.             B64.b64from24bit(altResult[3], altResult[13], altResult[23], 4, buffer);
  413.             B64.b64from24bit(altResult[24], altResult[4], altResult[14], 4, buffer);
  414.             B64.b64from24bit(altResult[15], altResult[25], altResult[5], 4, buffer);
  415.             B64.b64from24bit(altResult[6], altResult[16], altResult[26], 4, buffer);
  416.             B64.b64from24bit(altResult[27], altResult[7], altResult[17], 4, buffer);
  417.             B64.b64from24bit(altResult[18], altResult[28], altResult[8], 4, buffer);
  418.             B64.b64from24bit(altResult[9], altResult[19], altResult[29], 4, buffer);
  419.             B64.b64from24bit((byte) 0, altResult[31], altResult[30], 3, buffer);
  420.         } else {
  421.             B64.b64from24bit(altResult[0], altResult[21], altResult[42], 4, buffer);
  422.             B64.b64from24bit(altResult[22], altResult[43], altResult[1], 4, buffer);
  423.             B64.b64from24bit(altResult[44], altResult[2], altResult[23], 4, buffer);
  424.             B64.b64from24bit(altResult[3], altResult[24], altResult[45], 4, buffer);
  425.             B64.b64from24bit(altResult[25], altResult[46], altResult[4], 4, buffer);
  426.             B64.b64from24bit(altResult[47], altResult[5], altResult[26], 4, buffer);
  427.             B64.b64from24bit(altResult[6], altResult[27], altResult[48], 4, buffer);
  428.             B64.b64from24bit(altResult[28], altResult[49], altResult[7], 4, buffer);
  429.             B64.b64from24bit(altResult[50], altResult[8], altResult[29], 4, buffer);
  430.             B64.b64from24bit(altResult[9], altResult[30], altResult[51], 4, buffer);
  431.             B64.b64from24bit(altResult[31], altResult[52], altResult[10], 4, buffer);
  432.             B64.b64from24bit(altResult[53], altResult[11], altResult[32], 4, buffer);
  433.             B64.b64from24bit(altResult[12], altResult[33], altResult[54], 4, buffer);
  434.             B64.b64from24bit(altResult[34], altResult[55], altResult[13], 4, buffer);
  435.             B64.b64from24bit(altResult[56], altResult[14], altResult[35], 4, buffer);
  436.             B64.b64from24bit(altResult[15], altResult[36], altResult[57], 4, buffer);
  437.             B64.b64from24bit(altResult[37], altResult[58], altResult[16], 4, buffer);
  438.             B64.b64from24bit(altResult[59], altResult[17], altResult[38], 4, buffer);
  439.             B64.b64from24bit(altResult[18], altResult[39], altResult[60], 4, buffer);
  440.             B64.b64from24bit(altResult[40], altResult[61], altResult[19], 4, buffer);
  441.             B64.b64from24bit(altResult[62], altResult[20], altResult[41], 4, buffer);
  442.             B64.b64from24bit((byte) 0, (byte) 0, altResult[63], 2, buffer);
  443.         }

  444.         /*
  445.          * Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps
  446.          * cannot get any information.
  447.          */
  448.         // Is there a better way to do this with the JVM?
  449.         Arrays.fill(tempResult, (byte) 0);
  450.         Arrays.fill(pBytes, (byte) 0);
  451.         Arrays.fill(sBytes, (byte) 0);
  452.         ctx.reset();
  453.         altCtx.reset();
  454.         Arrays.fill(keyBytes, (byte) 0);
  455.         Arrays.fill(saltBytes, (byte) 0);

  456.         return buffer.toString();
  457.     }

  458.     /**
  459.      * Generates a libc crypt() compatible "$6$" hash value with random salt.
  460.      * <p>
  461.      * See {@link Crypt#crypt(String, String)} for details.
  462.      *
  463.      * @param keyBytes
  464.      *            plaintext to hash
  465.      * @return complete hash value
  466.      * @throws RuntimeException
  467.      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
  468.      */
  469.     public static String sha512Crypt(final byte[] keyBytes) {
  470.         return sha512Crypt(keyBytes, null);
  471.     }

  472.     /**
  473.      * Generates a libc6 crypt() compatible "$6$" hash value.
  474.      * <p>
  475.      * See {@link Crypt#crypt(String, String)} for details.
  476.      *
  477.      * @param keyBytes
  478.      *            plaintext to hash
  479.      * @param salt
  480.      *            real salt value without prefix or "rounds="
  481.      * @return complete hash value including salt
  482.      * @throws IllegalArgumentException
  483.      *             if the salt does not match the allowed pattern
  484.      * @throws RuntimeException
  485.      *             when a {@link java.security.NoSuchAlgorithmException} is caught.
  486.      */
  487.     public static String sha512Crypt(final byte[] keyBytes, String salt) {
  488.         if (salt == null) {
  489.             salt = SHA512_PREFIX + B64.getRandomSalt(8);
  490.         }
  491.         return sha2Crypt(keyBytes, salt, SHA512_PREFIX, SHA512_BLOCKSIZE, MessageDigestAlgorithms.SHA_512);
  492.     }
  493. }