/*
* Copyright (C) 2014 SCVNGR, Inc. d/b/a LevelUp
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.scvngr.levelup.core.util;
import android.support.annotation.NonNull;
import com.scvngr.levelup.core.annotation.LevelUpApi;
import com.scvngr.levelup.core.annotation.LevelUpApi.Contract;
import net.jcip.annotations.ThreadSafe;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* This is a utility class to generate cryptographic hashes.
*/
@LevelUpApi(contract = Contract.INTERNAL)
@ThreadSafe
public final class CryptographicHashUtil {
/*
* Text encoding for UTF-8.
*/
@NonNull
private static final String UTF8 = "UTF-8";
/**
* Sorted array of hex characters.
* <p>
* Useful for converting from decimal to hexadecimal.
*/
@NonNull
private static final char[] HEXDIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
/**
* Set of cryptographic hashing algorithms that can be used with
* {@link CryptographicHashUtil#getHexHash(String, Algorithms)}.
*/
@ThreadSafe
public static enum Algorithms {
/**
* SHA-256 algorithm.
*/
@NonNull
SHA256,
/**
* SHA1 algorithm.
*/
@NonNull
SHA1
}
/**
* Takes any string and returns a cryptographic hash of that string in hexadecimal.
*
* @param toHash String to hash.
* @param algorithm The hashing algorithm to use.
* @return cryptographic hash of {@code toHash} in hexadecimal.
*/
@NonNull
public static String getHexHash(@NonNull final String toHash,
@NonNull final Algorithms algorithm) {
PreconditionUtil.assertNotNull(toHash, "toHash");
PreconditionUtil.assertNotNull(toHash, "algorithm");
String hash = "";
try {
final byte[] data =
NullUtils.nonNullContract(MessageDigest.getInstance(algorithm.name()).digest(
toHash.getBytes(UTF8)));
hash = convertBytesToHex(data);
} catch (final UnsupportedEncodingException e) {
// this should never occur
throw new RuntimeException(e);
} catch (final NoSuchAlgorithmException e) {
// this should never occur
throw new RuntimeException(e);
}
return hash;
}
/**
* Helper method to convert a byte[] into a hexadecimal string.
*
* @param data data to convert.
* @return A hex version of the input.
*/
@NonNull
private static String convertBytesToHex(@NonNull final byte[] data) {
final int length = data.length;
final char[] chars = new char[2 * length];
for (int x = 0; x < length; x++) {
// CHECKSTYLE:OFF hex math, not really magic numbers.
// Shift the masked bits into the lower positions so we can index the array.
chars[2 * x] = HEXDIGITS[(data[x] & 0xF0) >>> 4];
chars[2 * x + 1] = HEXDIGITS[data[x] & 0x0F];
// CHECKSTYLE:ON
}
return NullUtils.nonNullContract(String.valueOf(chars));
}
/**
* Private constructor to prevent instantiation.
*/
private CryptographicHashUtil() {
throw new UnsupportedOperationException("This class is non-instantiable");
}
}