Created
May 7, 2012 18:33
-
-
Save jsfeng/2629511 to your computer and use it in GitHub Desktop.
Simple Hash Utility Tool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.Random; | |
import java.io.UnsupportedEncodingException; | |
import java.security.MessageDigest; | |
import java.security.NoSuchAlgorithmException; | |
import java.security.SecureRandom; | |
import org.apache.commons.codec.binary.Base64; | |
public class SimpleHashUtil { | |
/** | |
* Generates a hash for the given plain text value and returns a | |
* base64-encoded result. Before the hash is computed, a random salt is | |
* generated and appended to the plain text. This salt is stored at the end | |
* of the hash value, so it can be used later for hash verification. | |
* | |
* @param plainText | |
* Plaintext value to be hashed. The function does not check | |
* whether this parameter is null. | |
* @param hashAlgorithm | |
* Name of the hash algorithm. Allowed values are: "MD5", "SHA1", | |
* "SHA256", "SHA384", and "SHA512" (if any other value is | |
* specified MD5 hashing algorithm will be used). This value is | |
* case-insensitive. | |
* @param saltBytes | |
* this parameter can be null, in which case a random salt value | |
* will be generated. | |
* @return hash value formatted as a base64-encoded String. | |
*/ | |
public static String computeHash(String plainText, String hashAlgorithm, | |
byte[] saltBytes) { | |
try { | |
// If salt is not specified, generate it on the fly. | |
if (saltBytes == null) { | |
// Define min and max salt sizes. | |
int minSaltSize = 4; | |
int maxSaltSize = 8; | |
// Generate a random number for the size of the salt. | |
Random random = new Random(); | |
int saltSize = random.nextInt(maxSaltSize - minSaltSize +1) + minSaltSize; | |
// Allocate a byte array, which will hold the salt. | |
saltBytes = new byte[saltSize]; | |
// Initialize a random number generator. | |
SecureRandom sr; | |
try { | |
sr = SecureRandom.getInstance("SHA1PRNG"); | |
// Fill the salt with cryptographically strong byte values. | |
sr.nextBytes(saltBytes); | |
} catch (NoSuchAlgorithmException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
} | |
// Convert plain text into a byte array. | |
byte[] plainTextBytes= {}; | |
try { | |
plainTextBytes = plainText.getBytes("UTF8"); | |
} catch (UnsupportedEncodingException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
// Allocate array, which will hold plain text and salt. | |
byte[] plainTextWithSaltBytes = new byte[plainTextBytes.length | |
+ saltBytes.length]; | |
// Copy plain text bytes into resulting array. | |
for (int i = 0; i < plainTextBytes.length; i++) | |
plainTextWithSaltBytes[i] = plainTextBytes[i]; | |
// Append salt bytes to the resulting array. | |
for (int i = 0; i < saltBytes.length; i++) | |
plainTextWithSaltBytes[plainTextBytes.length + i] = saltBytes[i]; | |
// Because we support multiple hashing algorithms, we must define | |
// hash object as a common (abstract) base class. We will specify the | |
// actual hashing algorithm class later during object creation. | |
MessageDigest md = null; | |
// Make sure hashing algorithm name is specified. | |
if (hashAlgorithm == null) | |
hashAlgorithm = ""; | |
hashAlgorithm = hashAlgorithm.toUpperCase(); | |
if(hashAlgorithm.equals("SHA1")){ | |
md = MessageDigest.getInstance("SHA-1"); | |
}else if(hashAlgorithm.equals("SHA256")){ | |
md = MessageDigest.getInstance("SHA-256"); | |
}else if(hashAlgorithm.equals("SHA384")){ | |
md = MessageDigest.getInstance("SHA-384"); | |
}else if(hashAlgorithm.equals("SHA512")){ | |
md = MessageDigest.getInstance("SHA-512"); | |
}else{ | |
md = MessageDigest.getInstance("MD5"); | |
} | |
md.update(plainTextWithSaltBytes); | |
// Compute hash value of our plain text with appended salt. | |
byte[] hashBytes = md.digest(); | |
// Create array which will hold hash and original salt bytes. | |
byte[] hashWithSaltBytes = new byte[hashBytes.length + saltBytes.length]; | |
// Copy hash bytes into resulting array. | |
for (int i = 0; i < hashBytes.length; i++) | |
hashWithSaltBytes[i] = hashBytes[i]; | |
// Append salt bytes to the result. | |
for (int i = 0; i < saltBytes.length; i++) | |
hashWithSaltBytes[hashBytes.length + i] = saltBytes[i]; | |
// Convert result into a base64-encoded String. | |
String hashValue = Base64.encodeBase64String(hashWithSaltBytes); | |
// Return the result. | |
return hashValue; | |
} catch (NoSuchAlgorithmException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(); | |
} | |
return null; | |
} | |
/** | |
* Compares a hash of the specified plain text value to a given hash value. | |
* Plain text is hashed with the same salt value as the original hash. | |
* | |
* @param plainText | |
* Plain text to be verified against the specified hash. The | |
* function does not check whether this parameter is null. | |
* @param hashAlgorithm | |
* Name of the hash algorithm. Allowed values are: "MD5", "SHA1", | |
* "SHA256", "SHA384", and "SHA512" (if any other value is | |
* specified, MD5 hashing algorithm will be used). This value is | |
* case-insensitive. | |
* @param hashValue | |
* Base64-encoded hash value produced by ComputeHash function. | |
* This value includes the original salt appended to it. | |
* @return If computed hash mathes the specified hash the function the | |
* return value is true; otherwise, the function returns false. | |
*/ | |
public static boolean verifyHash(String plainText, String hashAlgorithm, | |
String hashValue) { | |
// Convert base64-encoded hash value into a byte array. | |
byte[] hashWithSaltBytes = {}; | |
hashWithSaltBytes = Base64.decodeBase64(hashValue); | |
// We must know size of hash (without salt). | |
int hashSizeInBits, hashSizeInBytes; | |
// Make sure that hashing algorithm name is specified. | |
if (hashAlgorithm == null) | |
hashAlgorithm = ""; | |
hashAlgorithm = hashAlgorithm.toUpperCase(); | |
// Size of hash is based on the specified algorithm. | |
if(hashAlgorithm.equals("SHA1")){ | |
hashSizeInBits = 160; | |
}else if(hashAlgorithm.equals("SHA256")){ | |
hashSizeInBits = 256; | |
}else if(hashAlgorithm.equals("SHA384")){ | |
hashSizeInBits = 384; | |
}else if(hashAlgorithm.equals("SHA512")){ | |
hashSizeInBits = 512; | |
}else{ | |
hashSizeInBits = 128; | |
} | |
// Convert size of hash from bits to bytes. | |
hashSizeInBytes = hashSizeInBits / 8; | |
// Make sure that the specified hash value is long enough. | |
if (hashWithSaltBytes.length < hashSizeInBytes) | |
return false; | |
// Allocate array to hold original salt bytes retrieved from hash. | |
byte[] saltBytes = new byte[hashWithSaltBytes.length - hashSizeInBytes]; | |
// Copy salt from the end of the hash to the new array. | |
for (int i = 0; i < saltBytes.length; i++) | |
saltBytes[i] = hashWithSaltBytes[hashSizeInBytes + i]; | |
// Compute a new hash String. | |
String expectedHashString = computeHash(plainText, hashAlgorithm, | |
saltBytes); | |
// If the computed hash matches the specified hash, the plain text value must be correct. | |
return (hashValue.equals(expectedHashString)); | |
} | |
public static void main(String args[]) { | |
String hashString = SimpleHashUtil.computeHash("abcdefghijklmn", "SHA512", null); | |
System.out.println("hashString: " + hashString); | |
boolean verifyResult = SimpleHashUtil.verifyHash("abcdefghijklmn", "SHA512", hashString); | |
System.out.println("verifyResult: " + verifyResult); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment