/* Copyright (c) 2011 Danish Maritime Authority.
*
* 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 net.maritimecloud.internal.message;
import static java.util.Objects.requireNonNull;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* Various utility method for hashing objects and primitives.
*
* @author Kasper Nielsen
*/
public class Hashing {
/** @return a MessageDigest that uses SHA-1 */
private static MessageDigest getSHA1MessageDigest() {
try {
return MessageDigest.getInstance("SHA-1");
} catch (NoSuchAlgorithmException e) {
// /CLOVER:OFF
throw new Error("All java implementations should be able to create SHA-1 digests", e);
// /CLOVER:ON
}
}
/** @return a MessageDigest that uses SHA-256 */
private static MessageDigest getSHA256MessageDigest() {
try {
return MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
// /CLOVER:OFF
throw new Error("All java implementations should be able to create SHA-256 digests", e);
// /CLOVER:ON
}
}
/**
* Returns the hash code of the specified object, returning 0 for the {@code null} object. This method is equivalent
* to {@link Objects#hashCode(Object)}
*
* @param o
* the object to calculate the hash code for
* @return the hash code of the specified object
*/
public static int hashcode(Object o) {
return o == null ? 0 : o.hashCode();
}
/**
* Applies the supplementary hash function used by {@link IdentityHashMap} to the specified integer.
*
* @param h
* the integer to hash
* @return the hashed integer
*/
public static int identityHash(int h) {
return (h << 1) - (h << 8);
}
/**
* Applies the supplementary hash function used by {@link HashMap} to the specified integer.
*
* @param h
* the integer to hash
* @return the hashed integer
*/
public static int juHashMapHash(int h) {
h ^= h >>> 20 ^ h >>> 12;
return h ^ h >>> 7 ^ h >>> 4;
}
/**
* Applies the supplementary hash function used by {@link ConcurrentHashMap} to the specified integer.
*
* @param h
* the integer to hash
* @return the hashed integer
*/
public static int wangJenkinsHash(int h) {
// FOREIGN_CODE
// Taken from ConcurrentHashMap
// http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/ConcurrentHashMap.java?view=markup
// Spread bits to regularize both segment and index locations,
// using variant of single-word Wang/Jenkins hash.
h += h << 15 ^ 0xffffcd7d;
h ^= h >>> 10;
h += h << 3;
h ^= h >>> 6;
h += (h << 2) + (h << 14);
return h ^ h >>> 16;
}
/**
* Applies a supplemental hash function to a given hashCode, which defends against poor quality hash functions. The
* result must be non-negative, and for reasonable performance must have good avalanche properties; i.e., that each
* bit of the argument affects each bit (except sign bit) of the result.
*/
public static final int murmur3BaseStep(int h) {
// FOREIGN_CODE
// Taken from ConcurrentHashMap
// http://http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/ConcurrentHashMapV8.java?revision=1.23&view=markup
// Apply base step of MurmurHash; see http://code.google.com/p/smhasher/
h ^= h >>> 16;
h *= 0x85ebca6b;
h ^= h >>> 13;
h *= 0xc2b2ae35;
return h >>> 16; // mask out sign bit
}
/**
* Returns a SHA-1 hash of the specified byte array.
*
* @param bytes
* the array to calculate the hash of
* @return a SHA-1 hash of the specified byte array
*/
public static byte[] SHA1(byte[] bytes) {
requireNonNull(bytes, "bytes is null");
MessageDigest md = getSHA1MessageDigest();
return md.digest(bytes);
}
/**
* Returns a SHA-256 hash of the specified byte array.
*
* @param bytes
* the array to calculate the hash of
* @return a SHA-256 hash of the specified byte array
*/
public static byte[] SHA256(byte[] bytes) {
requireNonNull(bytes, "bytes is null");
MessageDigest md = getSHA256MessageDigest();
return md.digest(bytes);
}
}