Java tutorial
/** * 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; } }