    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.codec.digest;
    018
    019    import java.security.MessageDigest;
    020    import java.security.NoSuchAlgorithmException;
    021    import java.util.Arrays;
    022    import java.util.regex.Matcher;
    023    import java.util.regex.Pattern;
    024
    025    import org.apache.commons.codec.Charsets;
    026
    027    /**
    028     * SHA2-based Unix crypt implementation.
    029     * <p>
    030     * Based on the C implementation released into the Public Domain by Ulrich Drepper &lt;drepper@redhat.com&gt;
    031     * http://www.akkadia.org/drepper/SHA-crypt.txt
    032     * <p>
    033     * Conversion to Kotlin and from there to Java in 2012 by Christian Hammers &lt;ch@lathspell.de&gt; and likewise put
    034     * into the Public Domain.
    035     * <p>
    036     * This class is immutable and thread-safe.
    037     *
    038     * @version $Id: Sha2Crypt.java 1435550 2013-01-19 14:09:52Z tn $
    039     * @since 1.7
    040     */
    041    public class Sha2Crypt {
    042
    043        /** Default number of rounds if not explicitly specified. */
    044        private static final int ROUNDS_DEFAULT = 5000;
    045
    046        /** Maximum number of rounds. */
    047        private static final int ROUNDS_MAX = 999999999;
    048
    049        /** Minimum number of rounds. */
    050        private static final int ROUNDS_MIN = 1000;
    051
    052        /** Prefix for optional rounds specification. */
    053        private static final String ROUNDS_PREFIX = "rounds=";
    054
    055        /** The number of bytes the final hash value will have (SHA-256 variant). */
    056        private static final int SHA256_BLOCKSIZE = 32;
    057
    058        /** The prefixes that can be used to identify this crypt() variant (SHA-256). */
    059        static final String SHA256_PREFIX = "$5$";
    060
    061        /** The number of bytes the final hash value will have (SHA-512 variant). */
    062        private static final int SHA512_BLOCKSIZE = 64;
    063
    064        /** The prefixes that can be used to identify this crypt() variant (SHA-512). */
    065        static final String SHA512_PREFIX = "$6$";
    066
    067        /** The pattern to match valid salt values. */
    068        private static final Pattern SALT_PATTERN = Pattern
    069                .compile("^\\$([56])\\$(rounds=(\\d+)\\$)?([\\.\\/a-zA-Z0-9]{1,16}).*");
    070
    071        /**
    072         * Generates a libc crypt() compatible "$5$" hash value with random salt.
    073         * <p>
    074         * See {@link Crypt#crypt(String, String)} for details.
    075         *
    076         * @throws RuntimeException
    077         *             when a {@link java.security.NoSuchAlgorithmException} is caught.
    078         */
    079        public static String sha256Crypt(final byte[] keyBytes) {
    080            return sha256Crypt(keyBytes, null);
    081        }
    082
    083        /**
    084         * Generates a libc6 crypt() compatible "$5$" hash value.
    085         * <p>
    086         * See {@link Crypt#crypt(String, String)} for details.
    087         *
    088         * @throws IllegalArgumentException
    089         *             if the salt does not match the allowed pattern
    090         * @throws RuntimeException
    091         *             when a {@link java.security.NoSuchAlgorithmException} is caught.
    092         */
    093        public static String sha256Crypt(final byte[] keyBytes, String salt) {
    094            if (salt == null) {
    095                salt = SHA256_PREFIX + B64.getRandomSalt(8);
    096            }
    097            return sha2Crypt(keyBytes, salt, SHA256_PREFIX, SHA256_BLOCKSIZE, MessageDigestAlgorithms.SHA_256);
    098        }
    099
    100        /**
    101         * Generates a libc6 crypt() compatible "$5$" or "$6$" SHA2 based hash value.
    102         * <p>
    103         * This is a nearly line by line conversion of the original C function. The numbered comments are from the
    104         * algorithm description, the short C-style ones from the original C code and the ones with "Remark" from me.
    105         * <p>
    106         * See {@link Crypt#crypt(String, String)} for details.
    107         *
    108         * @param keyBytes
    109         *            plaintext that should be hashed
    110         * @param salt
    111         *            real salt value without prefix or "rounds="
    112         * @param saltPrefix
    113         *            either $5$ or $6$
    114         * @param blocksize
    115         *            a value that differs between $5$ and $6$
    116         * @param algorithm
    117         *            {@link MessageDigest} algorithm identifier string
    118         * @return complete hash value including prefix and salt
    119         * @throws IllegalArgumentException
    120         *             if the given salt is {@code null} or does not match the allowed pattern
    121         * @throws IllegalArgumentException
    122         *             when a {@link NoSuchAlgorithmException} is caught
    123         * @see MessageDigestAlgorithms
    124         */
    125        private static String sha2Crypt(final byte[] keyBytes, final String salt, final String saltPrefix,
    126                                        final int blocksize, final String algorithm) {
    127
    128            final int keyLen = keyBytes.length;
    129
    130            // Extracts effective salt and the number of rounds from the given salt.
    131            int rounds = ROUNDS_DEFAULT;
    132            boolean roundsCustom = false;
    133            if (salt == null) {
    134                throw new IllegalArgumentException("Salt must not be null");
    135            }
    136
    137            final Matcher m = SALT_PATTERN.matcher(salt);
    138            if (m == null || !m.find()) {
    139                throw new IllegalArgumentException("Invalid salt value: " + salt);
    140            }
    141            if (m.group(3) != null) {
    142                rounds = Integer.parseInt(m.group(3));
    143                rounds = Math.max(ROUNDS_MIN, Math.min(ROUNDS_MAX, rounds));
    144                roundsCustom = true;
    145            }
    146            final String saltString = m.group(4);
    147            final byte[] saltBytes = saltString.getBytes(Charsets.UTF_8);
    148            final int saltLen = saltBytes.length;
    149
    150            // 1. start digest A
    151            // Prepare for the real work.
    152            MessageDigest ctx = DigestUtils.getDigest(algorithm);
    153
    154            // 2. the password string is added to digest A
    155            /*
    156             * Add the key string.
    157             */
    158            ctx.update(keyBytes);
    159
    160            // 3. the salt string is added to digest A. This is just the salt string
    161            // itself without the enclosing '$', without the magic salt_prefix $5$ and
    162            // $6$ respectively and without the rounds=<N> specification.
    163            //
    164            // NB: the MD5 algorithm did add the $1$ salt_prefix. This is not deemed
    165            // necessary since it is a constant string and does not add security
    166            // and /possibly/ allows a plain text attack. Since the rounds=<N>
    167            // specification should never be added this would also create an
    168            // inconsistency.
    169            /*
    170             * The last part is the salt string. This must be at most 16 characters and it ends at the first `$' character
    171             * (for compatibility with existing implementations).
    172             */
    173            ctx.update(saltBytes);
    174
    175            // 4. start digest B
    176            /*
    177             * Compute alternate sha512 sum with input KEY, SALT, and KEY. The final result will be added to the first
    178             * context.
    179             */
    180            MessageDigest altCtx = DigestUtils.getDigest(algorithm);
    181
    182            // 5. add the password to digest B
    183            /*
    184             * Add key.
    185             */
    186            altCtx.update(keyBytes);
    187
    188            // 6. add the salt string to digest B
    189            /*
    190             * Add salt.
    191             */
    192            altCtx.update(saltBytes);
    193
    194            // 7. add the password again to digest B
    195            /*
    196             * Add key again.
    197             */
    198            altCtx.update(keyBytes);
    199
    200            // 8. finish digest B
    201            /*
    202             * Now get result of this (32 bytes) and add it to the other context.
    203             */
    204            byte[] altResult = altCtx.digest();
    205
    206            // 9. For each block of 32 or 64 bytes in the password string (excluding
    207            // the terminating NUL in the C representation), add digest B to digest A
    208            /*
    209             * Add for any character in the key one byte of the alternate sum.
    210             */
    211            /*
    212             * (Remark: the C code comment seems wrong for key length > 32!)
    213             */
    214            int cnt = keyBytes.length;
    215            while (cnt > blocksize) {
    216                ctx.update(altResult, 0, blocksize);
    217                cnt -= blocksize;
    218            }
    219
    220            // 10. For the remaining N bytes of the password string add the first
    221            // N bytes of digest B to digest A
    222            ctx.update(altResult, 0, cnt);
    223
    224            // 11. For each bit of the binary representation of the length of the
    225            // password string up to and including the highest 1-digit, starting
    226            // from to lowest bit position (numeric value 1):
    227            //
    228            // a) for a 1-digit add digest B to digest A
    229            //
    230            // b) for a 0-digit add the password string
    231            //
    232            // NB: this step differs significantly from the MD5 algorithm. It
    233            // adds more randomness.
    234            /*
    235             * Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0
    236             * the key.
    237             */
    238            cnt = keyBytes.length;
    239            while (cnt > 0) {
    240                if ((cnt & 1) != 0) {
    241                    ctx.update(altResult, 0, blocksize);
    242                } else {
    243                    ctx.update(keyBytes);
    244                }
    245                cnt >>= 1;
    246            }
    247
    248            // 12. finish digest A
    249            /*
    250             * Create intermediate result.
    251             */
    252            altResult = ctx.digest();
    253
    254            // 13. start digest DP
    255            /*
    256             * Start computation of P byte sequence.
    257             */
    258            altCtx = DigestUtils.getDigest(algorithm);
    259
    260            // 14. for every byte in the password (excluding the terminating NUL byte
    261            // in the C representation of the string)
    262            //
    263            // add the password to digest DP
    264            /*
    265             * For every character in the password add the entire password.
    266             */
    267            for (int i = 1; i <= keyLen; i++) {
    268                altCtx.update(keyBytes);
    269            }
    270
    271            // 15. finish digest DP
    272            /*
    273             * Finish the digest.
    274             */
    275            byte[] tempResult = altCtx.digest();
    276
    277            // 16. produce byte sequence P of the same length as the password where
    278            //
    279            // a) for each block of 32 or 64 bytes of length of the password string
    280            // the entire digest DP is used
    281            //
    282            // b) for the remaining N (up to 31 or 63) bytes use the first N
    283            // bytes of digest DP
    284            /*
    285             * Create byte sequence P.
    286             */
    287            final byte[] pBytes = new byte[keyLen];
    288            int cp = 0;
    289            while (cp < keyLen - blocksize) {
    290                System.arraycopy(tempResult, 0, pBytes, cp, blocksize);
    291                cp += blocksize;
    292            }
    293            System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp);
    294
    295            // 17. start digest DS
    296            /*
    297             * Start computation of S byte sequence.
    298             */
    299            altCtx = DigestUtils.getDigest(algorithm);
    300
    301            // 18. repeast the following 16+A[0] times, where A[0] represents the first
    302            // byte in digest A interpreted as an 8-bit unsigned value
    303            //
    304            // add the salt to digest DS
    305            /*
    306             * For every character in the password add the entire password.
    307             */
    308            for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) {
    309                altCtx.update(saltBytes);
    310            }
    311
    312            // 19. finish digest DS
    313            /*
    314             * Finish the digest.
    315             */
    316            tempResult = altCtx.digest();
    317
    318            // 20. produce byte sequence S of the same length as the salt string where
    319            //
    320            // a) for each block of 32 or 64 bytes of length of the salt string
    321            // the entire digest DS is used
    322            //
    323            // b) for the remaining N (up to 31 or 63) bytes use the first N
    324            // bytes of digest DS
    325            /*
    326             * Create byte sequence S.
    327             */
    328            // Remark: The salt is limited to 16 chars, how does this make sense?
    329            final byte[] sBytes = new byte[saltLen];
    330            cp = 0;
    331            while (cp < saltLen - blocksize) {
    332                System.arraycopy(tempResult, 0, sBytes, cp, blocksize);
    333                cp += blocksize;
    334            }
    335            System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp);
    336
    337            // 21. repeat a loop according to the number specified in the rounds=<N>
    338            // specification in the salt (or the default value if none is
    339            // present). Each round is numbered, starting with 0 and up to N-1.
    340            //
    341            // The loop uses a digest as input. In the first round it is the
    342            // digest produced in step 12. In the latter steps it is the digest
    343            // produced in step 21.h. The following text uses the notation
    344            // "digest A/C" to describe this behavior.
    345            /*
    346             * Repeatedly run the collected hash value through sha512 to burn CPU cycles.
    347             */
    348            for (int i = 0; i <= rounds - 1; i++) {
    349                // a) start digest C
    350                /*
    351                 * New context.
    352                 */
    353                ctx = DigestUtils.getDigest(algorithm);
    354
    355                // b) for odd round numbers add the byte sequense P to digest C
    356                // c) for even round numbers add digest A/C
    357                /*
    358                 * Add key or last result.
    359                 */
    360                if ((i & 1) != 0) {
    361                    ctx.update(pBytes, 0, keyLen);
    362                } else {
    363                    ctx.update(altResult, 0, blocksize);
    364                }
    365
    366                // d) for all round numbers not divisible by 3 add the byte sequence S
    367                /*
    368                 * Add salt for numbers not divisible by 3.
    369                 */
    370                if (i % 3 != 0) {
    371                    ctx.update(sBytes, 0, saltLen);
    372                }
    373
    374                // e) for all round numbers not divisible by 7 add the byte sequence P
    375                /*
    376                 * Add key for numbers not divisible by 7.
    377                 */
    378                if (i % 7 != 0) {
    379                    ctx.update(pBytes, 0, keyLen);
    380                }
    381
    382                // f) for odd round numbers add digest A/C
    383                // g) for even round numbers add the byte sequence P
    384                /*
    385                 * Add key or last result.
    386                 */
    387                if ((i & 1) != 0) {
    388                    ctx.update(altResult, 0, blocksize);
    389                } else {
    390                    ctx.update(pBytes, 0, keyLen);
    391                }
    392
    393                // h) finish digest C.
    394                /*
    395                 * Create intermediate result.
    396                 */
    397                altResult = ctx.digest();
    398            }
    399
    400            // 22. Produce the output string. This is an ASCII string of the maximum
    401            // size specified above, consisting of multiple pieces:
    402            //
    403            // a) the salt salt_prefix, $5$ or $6$ respectively
    404            //
    405            // b) the rounds=<N> specification, if one was present in the input
    406            // salt string. A trailing '$' is added in this case to separate
    407            // the rounds specification from the following text.
    408            //
    409            // c) the salt string truncated to 16 characters
    410            //
    411            // d) a '$' character
    412            /*
    413             * Now we can construct the result string. It consists of three parts.
    414             */
    415            final StringBuilder buffer = new StringBuilder(saltPrefix);
    416            if (roundsCustom) {
    417                buffer.append(ROUNDS_PREFIX);
    418                buffer.append(rounds);
    419                buffer.append("$");
    420            }
    421            buffer.append(saltString);
    422            buffer.append("$");
    423
    424            // e) the base-64 encoded final C digest. The encoding used is as
    425            // follows:
    426            // [...]
    427            //
    428            // Each group of three bytes from the digest produces four
    429            // characters as output:
    430            //
    431            // 1. character: the six low bits of the first byte
    432            // 2. character: the two high bits of the first byte and the
    433            // four low bytes from the second byte
    434            // 3. character: the four high bytes from the second byte and
    435            // the two low bits from the third byte
    436            // 4. character: the six high bits from the third byte
    437            //
    438            // The groups of three bytes are as follows (in this sequence).
    439            // These are the indices into the byte array containing the
    440            // digest, starting with index 0. For the last group there are
    441            // not enough bytes left in the digest and the value zero is used
    442            // in its place. This group also produces only three or two
    443            // characters as output for SHA-512 and SHA-512 respectively.
    444
    445            // This was just a safeguard in the C implementation:
    446            // int buflen = salt_prefix.length() - 1 + ROUNDS_PREFIX.length() + 9 + 1 + salt_string.length() + 1 + 86 + 1;
    447
    448            if (blocksize == 32) {
    449                B64.b64from24bit(altResult[0], altResult[10], altResult[20], 4, buffer);
    450                B64.b64from24bit(altResult[21], altResult[1], altResult[11], 4, buffer);
    451                B64.b64from24bit(altResult[12], altResult[22], altResult[2], 4, buffer);
    452                B64.b64from24bit(altResult[3], altResult[13], altResult[23], 4, buffer);
    453                B64.b64from24bit(altResult[24], altResult[4], altResult[14], 4, buffer);
    454                B64.b64from24bit(altResult[15], altResult[25], altResult[5], 4, buffer);
    455                B64.b64from24bit(altResult[6], altResult[16], altResult[26], 4, buffer);
    456                B64.b64from24bit(altResult[27], altResult[7], altResult[17], 4, buffer);
    457                B64.b64from24bit(altResult[18], altResult[28], altResult[8], 4, buffer);
    458                B64.b64from24bit(altResult[9], altResult[19], altResult[29], 4, buffer);
    459                B64.b64from24bit((byte) 0, altResult[31], altResult[30], 3, buffer);
    460            } else {
    461                B64.b64from24bit(altResult[0], altResult[21], altResult[42], 4, buffer);
    462                B64.b64from24bit(altResult[22], altResult[43], altResult[1], 4, buffer);
    463                B64.b64from24bit(altResult[44], altResult[2], altResult[23], 4, buffer);
    464                B64.b64from24bit(altResult[3], altResult[24], altResult[45], 4, buffer);
    465                B64.b64from24bit(altResult[25], altResult[46], altResult[4], 4, buffer);
    466                B64.b64from24bit(altResult[47], altResult[5], altResult[26], 4, buffer);
    467                B64.b64from24bit(altResult[6], altResult[27], altResult[48], 4, buffer);
    468                B64.b64from24bit(altResult[28], altResult[49], altResult[7], 4, buffer);
    469                B64.b64from24bit(altResult[50], altResult[8], altResult[29], 4, buffer);
    470                B64.b64from24bit(altResult[9], altResult[30], altResult[51], 4, buffer);
    471                B64.b64from24bit(altResult[31], altResult[52], altResult[10], 4, buffer);
    472                B64.b64from24bit(altResult[53], altResult[11], altResult[32], 4, buffer);
    473                B64.b64from24bit(altResult[12], altResult[33], altResult[54], 4, buffer);
    474                B64.b64from24bit(altResult[34], altResult[55], altResult[13], 4, buffer);
    475                B64.b64from24bit(altResult[56], altResult[14], altResult[35], 4, buffer);
    476                B64.b64from24bit(altResult[15], altResult[36], altResult[57], 4, buffer);
    477                B64.b64from24bit(altResult[37], altResult[58], altResult[16], 4, buffer);
    478                B64.b64from24bit(altResult[59], altResult[17], altResult[38], 4, buffer);
    479                B64.b64from24bit(altResult[18], altResult[39], altResult[60], 4, buffer);
    480                B64.b64from24bit(altResult[40], altResult[61], altResult[19], 4, buffer);
    481                B64.b64from24bit(altResult[62], altResult[20], altResult[41], 4, buffer);
    482                B64.b64from24bit((byte) 0, (byte) 0, altResult[63], 2, buffer);
    483            }
    484
    485            /*
    486             * Clear the buffer for the intermediate result so that people attaching to processes or reading core dumps
    487             * cannot get any information.
    488             */
    489            // Is there a better way to do this with the JVM?
    490            Arrays.fill(tempResult, (byte) 0);
    491            Arrays.fill(pBytes, (byte) 0);
    492            Arrays.fill(sBytes, (byte) 0);
    493            ctx.reset();
    494            altCtx.reset();
    495            Arrays.fill(keyBytes, (byte) 0);
    496            Arrays.fill(saltBytes, (byte) 0);
    497
    498            return buffer.toString();
    499        }
    500
    501        /**
    502         * Generates a libc crypt() compatible "$6$" hash value with random salt.
    503         * <p>
    504         * See {@link Crypt#crypt(String, String)} for details.
    505         *
    506         * @throws RuntimeException
    507         *             when a {@link java.security.NoSuchAlgorithmException} is caught.
    508         */
    509        public static String sha512Crypt(final byte[] keyBytes) {
    510            return sha512Crypt(keyBytes, null);
    511        }
    512
    513        /**
    514         * Generates a libc6 crypt() compatible "$6$" hash value.
    515         * <p>
    516         * See {@link Crypt#crypt(String, String)} for details.
    517         *
    518         * @throws IllegalArgumentException
    519         *             if the salt does not match the allowed pattern
    520         * @throws RuntimeException
    521         *             when a {@link java.security.NoSuchAlgorithmException} is caught.
    522         */
    523        public static String sha512Crypt(final byte[] keyBytes, String salt) {
    524            if (salt == null) {
    525                salt = SHA512_PREFIX + B64.getRandomSalt(8);
    526            }
    527            return sha2Crypt(keyBytes, salt, SHA512_PREFIX, SHA512_BLOCKSIZE, MessageDigestAlgorithms.SHA_512);
    528        }
    529    }