com.redhat.rhn.common.util.SHA256Crypt.java Source code

Java tutorial

Introduction

Here is the source code for com.redhat.rhn.common.util.SHA256Crypt.java

Source

/**
 * Copyright (c) 2014 Red Hat, Inc.
 *
 * This software is licensed to you under the GNU General Public License,
 * version 2 (GPLv2). There is NO WARRANTY for this software, express or
 * implied, including the implied warranties of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
 * along with this software; if not, see
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
 *
 * Red Hat trademarks are not licensed under GPLv2. No permission is
 * granted to use or replicate Red Hat trademarks that are incorporated
 * in this software or its documentation.
 */

package com.redhat.rhn.common.util;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.codec.binary.Hex;

/**
 * SHA256Crypt
 * Utility class to create/check SHA256 passwords
 * Passwords are in the format of $1$salt$encodedpassword.
 */
public class SHA256Crypt {

    private static Integer saltLength = 16; // SHA-256 encoded password salt length

    /**
     * SHA256Crypt
     */
    private SHA256Crypt() {
    }

    /**
     * getSHA256MD - get SHA256 MessageDigest object instance
     * @return MessageDigest object instance
     */
    private static MessageDigest getSHA256MD() {
        MessageDigest md;

        try {
            md = MessageDigest.getInstance("SHA-256");
        } catch (NoSuchAlgorithmException e) {
            throw new SHA256CryptException("Problem getting SHA-256 message digest");
        }

        return md;
    }

    /**
     * generateEncodedKey - Handles generating the encoded key from the final digest
     * @param digest - Digest to use for encoding
     * @param salt - salt to prepend to output
     * @return Returns encoded string $1$salt$encodedkey
     */
    private static String generateEncodedKey(byte[] digest, String salt) {
        StringBuilder out = new StringBuilder(CryptHelper.getSHA256Prefix());
        out.append(salt);
        out.append("$");

        int val = ((digest[0] << 16) & 0x00ffffff) | ((digest[10] << 8) & 0x00ffff) | (digest[20] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[21] << 16) & 0x00ffffff) | ((digest[1] << 8) & 0x00ffff) | (digest[11] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[12] << 16) & 0x00ffffff) | ((digest[22] << 8) & 0x00ffff) | (digest[2] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[3] << 16) & 0x00ffffff) | ((digest[13] << 8) & 0x00ffff) | (digest[23] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[24] << 16) & 0x00ffffff) | ((digest[4] << 8) & 0x00ffff) | (digest[14] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[15] << 16) & 0x00ffffff) | ((digest[25] << 8) & 0x00ffff) | (digest[5] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[6] << 16) & 0x00ffffff) | ((digest[16] << 8) & 0x00ffff) | (digest[26] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[27] << 16) & 0x00ffffff) | ((digest[7] << 8) & 0x00ffff) | (digest[17] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[18] << 16) & 0x00ffffff) | ((digest[28] << 8) & 0x00ffff) | (digest[8] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((digest[9] << 16) & 0x00ffffff) | ((digest[19] << 8) & 0x00ffff) | (digest[29] & 0xff);
        out.append(CryptHelper.to64(val, 4));

        val = ((((byte) 0) << 16) & 0x00ffffff) | ((digest[31] << 8) & 0x00ffff) | (digest[30] & 0xff);
        out.append(CryptHelper.to64(val, 3));

        return out.toString();
    }

    /**
     * crypt - method to help in setting passwords.
     * @param key - The key to encode
     * @return Returns a string in the form of "$1$RandomSalt$encodedkey"
     */
    public static String crypt(String key) {
        return crypt(key, CryptHelper.generateRandomSalt(saltLength));
    }

    /**
     * crypt
     * Encodes a key using a salt (s) in the same manner as the perl crypt() function
     * @param key - The key to encode
     * @param s - The salt
     * @return Returns a string in the form of "$1$salt$encodedkey"
     * @throws SHA256CryptException
     */
    public static String crypt(String key, String s) {
        final byte[] keyBytes = key.getBytes();
        final int keyLen = keyBytes.length;

        String salt = CryptHelper.getSalt(s, CryptHelper.getSHA256Prefix(), saltLength);
        final byte[] saltBytes = salt.getBytes();
        final int saltLen = saltBytes.length;

        final int blocksize = 32;

        MessageDigest ctx = getSHA256MD();
        ctx.update(keyBytes); // add the key/salt to the first digest
        ctx.update(saltBytes);

        MessageDigest altCtx = getSHA256MD();
        altCtx.update(keyBytes); // add the key/salt/key to the second digest
        altCtx.update(saltBytes);
        altCtx.update(keyBytes);

        byte[] altResult = altCtx.digest();

        int cnt = keyBytes.length;
        while (cnt > blocksize) {
            ctx.update(altResult, 0, blocksize);
            cnt -= blocksize;
        }

        ctx.update(altResult, 0, cnt);

        cnt = keyBytes.length;
        while (cnt > 0) {
            if ((cnt & 1) != 0) {
                ctx.update(altResult, 0, blocksize);
            } else {
                ctx.update(keyBytes);
            }
            cnt >>= 1;
        }

        altResult = ctx.digest();

        altCtx = getSHA256MD();

        for (int i = 1; i <= keyLen; i++) {
            altCtx.update(keyBytes);
        }

        byte[] tempResult = altCtx.digest();

        final byte[] pBytes = new byte[keyLen];
        int cp = 0;
        while (cp < keyLen - blocksize) {
            System.arraycopy(tempResult, 0, pBytes, cp, blocksize);
            cp += blocksize;
        }
        System.arraycopy(tempResult, 0, pBytes, cp, keyLen - cp);

        altCtx = getSHA256MD();

        for (int i = 1; i <= 16 + (altResult[0] & 0xff); i++) {
            altCtx.update(saltBytes);
        }

        tempResult = altCtx.digest();

        final byte[] sBytes = new byte[saltLen];
        cp = 0;
        while (cp < saltLen - blocksize) {
            System.arraycopy(tempResult, 0, sBytes, cp, blocksize);
            cp += blocksize;
        }
        System.arraycopy(tempResult, 0, sBytes, cp, saltLen - cp);

        for (int i = 0; i <= 5000 - 1; i++) {
            ctx = getSHA256MD();
            if ((i & 1) != 0) {
                ctx.update(pBytes, 0, keyLen);
            } else {
                ctx.update(altResult, 0, blocksize);
            }

            if (i % 3 != 0) {
                ctx.update(sBytes, 0, saltLen);
            }

            if (i % 7 != 0) {
                ctx.update(pBytes, 0, keyLen);
            }

            if ((i & 1) != 0) {
                ctx.update(altResult, 0, blocksize);
            } else {
                ctx.update(pBytes, 0, keyLen);
            }

            altResult = ctx.digest();
        }

        return generateEncodedKey(altResult, salt);
    }

    /**
     * SHA256 and Hexify a string.  Take the input string, SHA256 encode it
     * and then turn it into Hex.
     * @param inputString you want SHA256hexed
     * @return sha256hexed String.
     */
    public static String sha256Hex(String inputString) {
        byte[] secretBytes;
        try {
            secretBytes = inputString.getBytes("UTF-8");

        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UnsupportedEncodingException when"
                    + " trying to convert a String into UTF-8.  This shouldn't happen.", e);
        }
        return sha256Hex(secretBytes);
    }

    /**
     * SHA256 and Hexify an array of bytes.  Take the input array, SHA256 encodes it
     * and then turns it into Hex.
     * @param secretBytes you want sha256hexed
     * @return sha256hexed String.
     */
    public static String sha256Hex(byte[] secretBytes) {
        String retval = null;
        // add secret
        MessageDigest md;
        md = getSHA256MD();
        md.update(secretBytes);
        // generate the digest
        byte[] digest = md.digest();
        // hexify this puppy
        retval = new String(Hex.encodeHex(digest));
        return retval;
    }
}