001package com.identityworksllc.iiq.common; 002 003import sailpoint.tools.Base64; 004import sailpoint.tools.GeneralException; 005 006import java.security.MessageDigest; 007import java.security.NoSuchAlgorithmException; 008import java.util.function.Function; 009 010/** 011 * Utilities to return hexadecimal hashes of strings 012 */ 013public class HashUtilities { 014 private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); 015 016 /** 017 * Transforms the input byte array to Base64. This is intended as an input to 018 * {@link #hash(String, String, Function)}, as the encoder. 019 * 020 * @param bytes The input bytes 021 * @return A base64 string 022 */ 023 public static String bytesToBase64(byte[] bytes) { 024 return Base64.encodeBytes(bytes); 025 } 026 027 /** 028 * Transforms the given byte array to hexadecimal. This is intended as an input to 029 * {@link #hash(String, String, Function)}, as the encoder. 030 * 031 * @param bytes The input byte array 032 * @return The output as a hexadecimal string 033 */ 034 public static String bytesToHex(byte[] bytes) { 035 char[] hexChars = new char[bytes.length * 2]; 036 for (int j = 0; j < bytes.length; j++) { 037 int v = bytes[j] & 0xFF; 038 hexChars[j * 2] = HEX_ARRAY[v >>> 4]; 039 hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; 040 } 041 return new String(hexChars); 042 } 043 044 /** 045 * Performs a hash of the given input with the given hash function. This implementation 046 * takes care of the javax.crypto initialization for you. 047 * 048 * @param hashFunction The hash function to use 049 * @param input The input string to hash 050 * @return The hashed value as a hexadecimal string 051 * @throws GeneralException if any cryptographic failures occur 052 */ 053 public static String hash(String hashFunction, String input) throws GeneralException { 054 return hash(hashFunction, input, HashUtilities::bytesToHex); 055 } 056 057 /** 058 * Performs a hash of the given input with the given hash function. This method allows you 059 * to replace the encoding implementation if you don't wish to receive your output as a 060 * hexadecimal string. 061 * 062 * @param hashFunction The hash function to use 063 * @param input The input string to hash 064 * @param encoder A function to encode the byte array into a String if you wish to replace the hexadecimal implementation 065 * @return The hashed value as a hexadecimal string 066 * @throws GeneralException if any cryptographic failures occur 067 */ 068 public static String hash(String hashFunction, String input, Function<byte[], String> encoder) throws GeneralException { 069 try { 070 MessageDigest md = MessageDigest.getInstance(hashFunction); 071 md.update(input.getBytes()); 072 byte[] digest = md.digest(); 073 return encoder.apply(digest); 074 } catch(NoSuchAlgorithmException e) { 075 throw new GeneralException(e); 076 } 077 } 078 079 /** 080 * Hashes the input using the MD5 algorithm and returns it as a hex string 081 * @param input The input string 082 * @return The MD5 hash of the input string in hex 083 * @throws GeneralException if any cryptographic failures occur 084 */ 085 public static String md5(String input) throws GeneralException { 086 return hash("MD5", input); 087 } 088 089 /** 090 * Hashes the input using the SHA-256 algorithm and returns it as a hex string 091 * @param input The input string 092 * @return The SHA-256 hash of the input string in hex 093 * @throws GeneralException if any cryptographic failures occur 094 */ 095 public static String sha256(String input) throws GeneralException { 096 return hash("SHA-256", input); 097 } 098 099 /** 100 * Private utility constructor 101 */ 102 private HashUtilities() { 103 104 } 105}