530 lines
17 KiB
Java
530 lines
17 KiB
Java
|
|
/*
|
||
|
|
* Copyright (c) 2009 Declarative Engineering LLC.
|
||
|
|
* All rights reserved. This program and the accompanying materials
|
||
|
|
* are made available under the terms of the Declarative Engineering LLC
|
||
|
|
* verson 1 which accompanies this distribution, and is available at
|
||
|
|
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||
|
|
*/
|
||
|
|
package com.common.security;
|
||
|
|
|
||
|
|
import java.io.IOException;
|
||
|
|
import java.io.InputStream;
|
||
|
|
import com.common.util.StringSupport;
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Used the SHA512 specs and the Bouncy Castle LongDigest implementation as guides.
|
||
|
|
* <p>The point of having this in the framework isn't to be different, but rather to cut out all the dependancies and make the hash super easy to be used in application code without extra lines in the classpath or consideration to licensing.</p>
|
||
|
|
*/
|
||
|
|
public class Sha512 implements IHashAlgorithm {
|
||
|
|
/** Constants */
|
||
|
|
private static final long K[] = {
|
||
|
|
0x428A2F98D728AE22L, 0x7137449123EF65CDL, 0xB5C0FBCFEC4D3B2FL, 0xE9B5DBA58189DBBCL,
|
||
|
|
0x3956C25BF348B538L, 0x59F111F1B605D019L, 0x923F82A4AF194F9BL, 0xAB1C5ED5DA6D8118L,
|
||
|
|
0xD807AA98A3030242L, 0x12835B0145706FBEL, 0x243185BE4EE4B28CL, 0x550C7DC3D5FFB4E2L,
|
||
|
|
0x72BE5D74F27B896FL, 0x80DEB1FE3B1696B1L, 0x9BDC06A725C71235L, 0xC19BF174CF692694L,
|
||
|
|
0xE49B69C19EF14AD2L, 0xEFBE4786384F25E3L, 0x0FC19DC68B8CD5B5L, 0x240CA1CC77AC9C65L,
|
||
|
|
0x2DE92C6F592B0275L, 0x4A7484AA6EA6E483L, 0x5CB0A9DCBD41FBD4L, 0x76F988DA831153B5L,
|
||
|
|
0x983E5152EE66DFABL, 0xA831C66D2DB43210L, 0xB00327C898FB213FL, 0xBF597FC7BEEF0EE4L,
|
||
|
|
0xC6E00BF33DA88FC2L, 0xD5A79147930AA725L, 0x06CA6351E003826FL, 0x142929670A0E6E70L,
|
||
|
|
0x27B70A8546D22FFCL, 0x2E1B21385C26C926L, 0x4D2C6DFC5AC42AEDL, 0x53380D139D95B3DFL,
|
||
|
|
0x650A73548BAF63DEL, 0x766A0ABB3C77B2A8L, 0x81C2C92E47EDAEE6L, 0x92722C851482353BL,
|
||
|
|
0xA2BFE8A14CF10364L, 0xA81A664BBC423001L, 0xC24B8B70D0F89791L, 0xC76C51A30654BE30L,
|
||
|
|
0xD192E819D6EF5218L, 0xD69906245565A910L, 0xF40E35855771202AL, 0x106AA07032BBD1B8L,
|
||
|
|
0x19A4C116B8D2D0C8L, 0x1E376C085141AB53L, 0x2748774CDF8EEB99L, 0x34B0BCB5E19B48A8L,
|
||
|
|
0x391C0CB3C5C95A63L, 0x4ED8AA4AE3418ACBL, 0x5B9CCA4F7763E373L, 0x682E6FF3D6B2B8A3L,
|
||
|
|
0x748F82EE5DEFB2FCL, 0x78A5636F43172F60L, 0x84C87814A1F0AB72L, 0x8CC702081A6439ECL,
|
||
|
|
0x90BEFFFA23631E28L, 0xA4506CEBDE82BDE9L, 0xBEF9A3F7B2C67915L, 0xC67178F2E372532BL,
|
||
|
|
0xCA273ECEEA26619CL, 0xD186B8C721C0C207L, 0xEADA7DD6CDE0EB1EL, 0xF57D4F7FEE6ED178L,
|
||
|
|
0x06F067AA72176FBAL, 0x0A637DC5A2C898A6L, 0x113F9804BEF90DAEL, 0x1B710B35131C471BL,
|
||
|
|
0x28DB77F523047D84L, 0x32CAAB7B40C72493L, 0x3C9EBE0A15C9BEBCL, 0x431D67C49C100D4CL,
|
||
|
|
0x4CC5D4BECB3E42B6L, 0x597F299CFC657E2AL, 0x5FCB6FAB3AD6FAECL, 0x6C44198C4A475817L
|
||
|
|
};
|
||
|
|
/** The size of a resulting hash in bytes (8 longs used to store the hash * 8 bytes per long). */
|
||
|
|
private static final int HASH_SIZE = 64;
|
||
|
|
/** The size of a block of source to be hashed (in bytes). (16 longs store a block of unhashed data, 8 bytes per long.) */
|
||
|
|
private static final int BLOCK_SIZE = 128;
|
||
|
|
/** The source size. */
|
||
|
|
private long sourceSize;
|
||
|
|
/** The overflow source size. */
|
||
|
|
private long sourceSize2;
|
||
|
|
/**
|
||
|
|
* A buffer containing the bytes yet to be added to the digest.
|
||
|
|
* This buffer will always be DATA_LENGTH in size and the digest will be updated when it is filled (so that this buffer can be emptied and reused).
|
||
|
|
*/
|
||
|
|
private byte[] sourceBuffer;
|
||
|
|
private int sourceBufferLength;
|
||
|
|
/**
|
||
|
|
* The digest integers as an array.
|
||
|
|
* This is where the digest actually gets stored until the hash has completely finished and the digest bytes are given to the user.
|
||
|
|
*/
|
||
|
|
private long[] hashBuffer;
|
||
|
|
private long[] internalHashBuffer;
|
||
|
|
private long[] internalBuffer;
|
||
|
|
/**
|
||
|
|
* Constructs SHA-512 algorithm used to generate digests from source data.
|
||
|
|
*/
|
||
|
|
public Sha512() {
|
||
|
|
initialize();
|
||
|
|
}//Sha512()//
|
||
|
|
/**
|
||
|
|
* Sha512 copy constructor.
|
||
|
|
* @param algorithm The algorithm to be copied.
|
||
|
|
*/
|
||
|
|
private Sha512(Sha512 algorithm) {
|
||
|
|
sourceSize = algorithm.sourceSize;
|
||
|
|
sourceSize2 = algorithm.sourceSize2;
|
||
|
|
sourceBufferLength = algorithm.sourceBufferLength;
|
||
|
|
sourceBuffer = (byte[]) algorithm.sourceBuffer.clone();
|
||
|
|
internalHashBuffer = (long[]) algorithm.internalHashBuffer.clone();
|
||
|
|
hashBuffer = (long[]) algorithm.hashBuffer.clone();
|
||
|
|
internalBuffer = (long[]) algorithm.internalBuffer.clone();
|
||
|
|
}//Sha512()//
|
||
|
|
/**
|
||
|
|
* Initializes the hash algorithm.
|
||
|
|
*/
|
||
|
|
private void initialize() {
|
||
|
|
//Initialize the buffers.//
|
||
|
|
sourceBuffer = new byte[BLOCK_SIZE];
|
||
|
|
hashBuffer = new long[8];
|
||
|
|
internalHashBuffer = new long[BLOCK_SIZE/8];
|
||
|
|
internalBuffer = new long[80];
|
||
|
|
reset(); //Prepare the algorithm for its first hash.//
|
||
|
|
}//initialize()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#reset()
|
||
|
|
*/
|
||
|
|
public void reset() {
|
||
|
|
sourceBufferLength = 0;
|
||
|
|
sourceSize = 0;
|
||
|
|
sourceSize2 = 0;
|
||
|
|
hashBuffer[0] = 0x6A09E667F3BCC908L;
|
||
|
|
hashBuffer[1] = 0xBB67AE8584CAA73BL;
|
||
|
|
hashBuffer[2] = 0x3C6EF372FE94F82BL;
|
||
|
|
hashBuffer[3] = 0xA54FF53A5F1D36F1L;
|
||
|
|
hashBuffer[4] = 0x510E527FADE682D1L;
|
||
|
|
hashBuffer[5] = 0x9B05688C2B3E6C1FL;
|
||
|
|
hashBuffer[6] = 0x1F83D9ABFB41BD6BL;
|
||
|
|
hashBuffer[7] = 0x5BE0CD19137E2179L;
|
||
|
|
}//reset()//
|
||
|
|
/**
|
||
|
|
* Manages overflowing the source size into a second long value.
|
||
|
|
*/
|
||
|
|
private void updateSourceSize() {
|
||
|
|
//Check if we have to use the overflow source size.//
|
||
|
|
//Note: We always clear the last 3 bits because we will multiply the source size by 8 to get a bit count when finishing the hash.//
|
||
|
|
if(sourceSize > 0x1FFFFFFFFFFFFFFFL) {
|
||
|
|
//Add the top 3 bits to the overflow source size.//
|
||
|
|
sourceSize2 += (sourceSize >>> 61);
|
||
|
|
//Clear the top 3 bits of the source size.//
|
||
|
|
sourceSize &= 0x1FFFFFFFFFFFFFFFL;
|
||
|
|
}//if//
|
||
|
|
}//updateSourceSize()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.io.IWriter#write(byte)
|
||
|
|
*/
|
||
|
|
public void write(byte b) {
|
||
|
|
add(b);
|
||
|
|
}//write()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.io.IWriter#write(byte[], int, int)
|
||
|
|
*/
|
||
|
|
public void write(byte[] bytes, int offset, int length) {
|
||
|
|
add(bytes, offset, length);
|
||
|
|
}//write()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.io.IWriter#write(byte[])
|
||
|
|
*/
|
||
|
|
public void write(byte[] bytes) {
|
||
|
|
add(bytes);
|
||
|
|
}//write()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#add(byte)
|
||
|
|
*/
|
||
|
|
public void add(byte b) {
|
||
|
|
sourceSize++;
|
||
|
|
sourceBuffer[sourceBufferLength++] = b;
|
||
|
|
|
||
|
|
if(sourceBufferLength == BLOCK_SIZE) {
|
||
|
|
//Transform the bytes into longs.//
|
||
|
|
convert(sourceBuffer, 0, internalHashBuffer);
|
||
|
|
//Update the hash.//
|
||
|
|
transform(internalHashBuffer);
|
||
|
|
sourceBufferLength = 0;
|
||
|
|
}//if//
|
||
|
|
}//add()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#add(byte[])
|
||
|
|
*/
|
||
|
|
public void add(byte[] buffer) {
|
||
|
|
if(buffer != null && buffer.length > 0) {
|
||
|
|
add(buffer, 0, buffer.length);
|
||
|
|
}//if//
|
||
|
|
}//add()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#add(byte[], int, int)
|
||
|
|
*/
|
||
|
|
public void add(byte[] buffer, int bufferOffset, int bufferLength) {
|
||
|
|
if(bufferLength > 0) {
|
||
|
|
int size = 0;
|
||
|
|
|
||
|
|
sourceSize += bufferLength;
|
||
|
|
|
||
|
|
//Hash the source in blocks.//
|
||
|
|
while((size = BLOCK_SIZE - sourceBufferLength) <= bufferLength) {
|
||
|
|
//Fill the source buffer.//
|
||
|
|
System.arraycopy(buffer, bufferOffset, sourceBuffer, sourceBufferLength, size);
|
||
|
|
//Transform the bytes into longs.//
|
||
|
|
convert(sourceBuffer, 0, internalHashBuffer);
|
||
|
|
//Update the hash.//
|
||
|
|
transform(internalHashBuffer);
|
||
|
|
bufferLength -= size;
|
||
|
|
bufferOffset += size;
|
||
|
|
sourceBufferLength = 0;
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
if(bufferLength > 0) {
|
||
|
|
//Save partial source in the source buffer.//
|
||
|
|
System.arraycopy(buffer, bufferOffset, sourceBuffer, sourceBufferLength, bufferLength);
|
||
|
|
sourceBufferLength += bufferLength;
|
||
|
|
}//if//
|
||
|
|
}//if//
|
||
|
|
}//add()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#add(java.io.InputStream)
|
||
|
|
*/
|
||
|
|
public void add(InputStream in) throws IOException {
|
||
|
|
byte[] buffer = new byte[10000];
|
||
|
|
int readCount = 0;
|
||
|
|
|
||
|
|
while(readCount >= 0) {
|
||
|
|
readCount = in.read(buffer);
|
||
|
|
|
||
|
|
if(readCount > 0) {
|
||
|
|
add(buffer, 0, readCount);
|
||
|
|
}//if//
|
||
|
|
}//while//
|
||
|
|
}//add()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#add(String)
|
||
|
|
*/
|
||
|
|
public void add(String source) {
|
||
|
|
if(source != null && source.length() > 0) {
|
||
|
|
add(StringSupport.toUtf8Bytes(source));
|
||
|
|
}//if//
|
||
|
|
}//add()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#add(char[])
|
||
|
|
*/
|
||
|
|
public void add(char[] source) {
|
||
|
|
if(source != null && source.length > 0) {
|
||
|
|
add(StringSupport.toUtf8Bytes(source));
|
||
|
|
}//if//
|
||
|
|
}//add()//
|
||
|
|
/**
|
||
|
|
* Adds the last of the source to the hash. At the very least this adds the source size to the hash.
|
||
|
|
*/
|
||
|
|
private void addFinal() {
|
||
|
|
int position = sourceBufferLength;
|
||
|
|
|
||
|
|
sourceBuffer[position++] = (byte) 0x80;
|
||
|
|
|
||
|
|
//If there isn't room for two more longs (the message size in # of bits), then process the source block with zero's padding the end.//
|
||
|
|
if(position > BLOCK_SIZE - 16) {
|
||
|
|
//Add trailing zeros.//
|
||
|
|
while(position < BLOCK_SIZE) {
|
||
|
|
sourceBuffer[position++] = 0;
|
||
|
|
}//while//
|
||
|
|
|
||
|
|
convert(sourceBuffer, 0, internalHashBuffer);
|
||
|
|
transform(internalHashBuffer);
|
||
|
|
position = 0;
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
//Pad all but the last 2 long values of the buffers.//
|
||
|
|
for(int i = position; i < BLOCK_SIZE - 16; i ++) {
|
||
|
|
sourceBuffer[i] = 0;
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
//Convert the source bytes to longs.//
|
||
|
|
convert(sourceBuffer, 0, internalHashBuffer);
|
||
|
|
updateSourceSize();
|
||
|
|
//Add the message size to the longs.//
|
||
|
|
internalHashBuffer[internalHashBuffer.length - 2] = sourceSize2;
|
||
|
|
internalHashBuffer[internalHashBuffer.length - 1] = sourceSize << 3;
|
||
|
|
//Run the final transform.//
|
||
|
|
transform(internalHashBuffer);
|
||
|
|
}//addFinal()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#cleanup()
|
||
|
|
*/
|
||
|
|
public void cleanup() {
|
||
|
|
}//cleanup()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see java.lang.Object#clone()
|
||
|
|
*/
|
||
|
|
public Object clone() {
|
||
|
|
return new Sha512(this);
|
||
|
|
}//clone()//
|
||
|
|
/**
|
||
|
|
* Convers bytes into longs.
|
||
|
|
*/
|
||
|
|
private void convert(byte[] source, int sourceOffset, long[] destination) {
|
||
|
|
int destinationOffset = 0;
|
||
|
|
int destinationLength = destination.length;
|
||
|
|
|
||
|
|
while(destinationLength-- > 0) {
|
||
|
|
//Big Endian//
|
||
|
|
destination[destinationOffset++] = ((long) (source[sourceOffset++] & 0xFF) << 56) | ((long) (source[sourceOffset++] & 0xFF) << 48) | ((long) (source[sourceOffset++] & 0xFF) << 40) | ((long) (source[sourceOffset++] & 0xFF) << 32) | ((long) (source[sourceOffset++] & 0xFF) << 24) | ((long) (source[sourceOffset++] & 0xFF) << 16) | ((long) (source[sourceOffset++] & 0xFF) << 8) | (source[sourceOffset++] & 0xFF);
|
||
|
|
}//while//
|
||
|
|
}//convert()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#getHashSize()
|
||
|
|
*/
|
||
|
|
public int getHashSize() {
|
||
|
|
return HASH_SIZE;
|
||
|
|
}//getHashSize()//
|
||
|
|
/**
|
||
|
|
* Performs the final hash using a custom buffer. This is the same as the hash() methods, but allows reuse of the buffer.
|
||
|
|
* @param hash The buffer to place the hash in. Must have space for the hash size.
|
||
|
|
* @param offset The offset in the hash array where the first hash byte will be placed.
|
||
|
|
*/
|
||
|
|
public void finish(byte[] hash, int offset) {
|
||
|
|
if(hash.length - offset < HASH_SIZE) {
|
||
|
|
throw new IllegalArgumentException();
|
||
|
|
}//if//
|
||
|
|
|
||
|
|
internalHash(hash, 0);
|
||
|
|
}//finish()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hash()
|
||
|
|
*/
|
||
|
|
public byte[] hash() {
|
||
|
|
return internalHash();
|
||
|
|
}//hash()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hash(byte[], int, int)
|
||
|
|
*/
|
||
|
|
public byte[] hash(byte[] source, int sourceOffset, int sourceLength) {
|
||
|
|
add(source, sourceOffset, sourceLength);
|
||
|
|
|
||
|
|
return internalHash();
|
||
|
|
}//hash()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hash(byte[], int, int, byte[], int)
|
||
|
|
*/
|
||
|
|
public void hash(byte[] source, int sourceOffset, int sourceLength, byte[] hashBuffer, int hashBufferOffset) {
|
||
|
|
add(source, sourceOffset, sourceLength);
|
||
|
|
internalHash(hashBuffer, hashBufferOffset);
|
||
|
|
}//hash()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hash(String)
|
||
|
|
*/
|
||
|
|
public byte[] hash(String source) {
|
||
|
|
add(source);
|
||
|
|
|
||
|
|
return internalHash();
|
||
|
|
}//hash()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hash(String, byte[], int)
|
||
|
|
*/
|
||
|
|
public void hash(String source, byte[] hashBuffer, int hashBufferOffset) {
|
||
|
|
add(source);
|
||
|
|
internalHash(hashBuffer, hashBufferOffset);
|
||
|
|
}//hash()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hash(char[])
|
||
|
|
*/
|
||
|
|
public byte[] hash(char[] source) {
|
||
|
|
add(source);
|
||
|
|
|
||
|
|
return internalHash();
|
||
|
|
}//hash()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hash(char[], byte[], int)
|
||
|
|
*/
|
||
|
|
public void hash(char[] source, byte[] hashBuffer, int hashBufferOffset) {
|
||
|
|
add(source);
|
||
|
|
internalHash(hashBuffer, hashBufferOffset);
|
||
|
|
}//hash()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hashToString()
|
||
|
|
*/
|
||
|
|
public String hashToString() {
|
||
|
|
return hashToString((String) null);
|
||
|
|
}//hashToString()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hashToString(String)
|
||
|
|
*/
|
||
|
|
public String hashToString(String source) {
|
||
|
|
byte[] hashBuffer = source != null ? hash(source) : hash();
|
||
|
|
|
||
|
|
return StringSupport.fromUnicode16Bytes(hashBuffer, 0, hashBuffer.length);
|
||
|
|
}//hashToString()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hashToString(char[])
|
||
|
|
*/
|
||
|
|
public String hashToString(char[] source) {
|
||
|
|
byte[] hashBuffer = source != null ? hash(source) : hash();
|
||
|
|
|
||
|
|
return StringSupport.fromUnicode16Bytes(hashBuffer, 0, hashBuffer.length);
|
||
|
|
}//hashToString()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hashToHex()
|
||
|
|
*/
|
||
|
|
public String hashToHex() {
|
||
|
|
return hashToHex(null);
|
||
|
|
}//hashToHex()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see com.common.security.IHashAlgorithm#hashToHex(String)
|
||
|
|
*/
|
||
|
|
public String hashToHex(String source) {
|
||
|
|
byte[] hashBuffer = source != null ? hash(source) : hash();
|
||
|
|
|
||
|
|
return StringSupport.toHexString(hashBuffer, 0, hashBuffer.length);
|
||
|
|
}//hashToHex()//
|
||
|
|
/**
|
||
|
|
* Creates a hash of the previously supplied source.
|
||
|
|
* @return The hash bytes.
|
||
|
|
*/
|
||
|
|
protected byte[] internalHash() {
|
||
|
|
byte[] buffer = new byte[HASH_SIZE];
|
||
|
|
|
||
|
|
internalHash(buffer, 0);
|
||
|
|
|
||
|
|
return buffer;
|
||
|
|
}//internalHash()//
|
||
|
|
/**
|
||
|
|
* Creates a hash of the previously supplied source.
|
||
|
|
* @param hashBuffer The buffer to place the hash in.
|
||
|
|
* @param hashBufferOffset The index of the first hash byte.
|
||
|
|
*/
|
||
|
|
protected void internalHash(byte[] hashBuffer, int hashBufferOffset) {
|
||
|
|
//Add any final source into the mix.//
|
||
|
|
addFinal();
|
||
|
|
|
||
|
|
//Copy the hash into the result buffer in Big Endian format.//
|
||
|
|
for(int i = 0; i < this.hashBuffer.length; ++i) {
|
||
|
|
long value = this.hashBuffer[i];
|
||
|
|
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) (value >>> 56);
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) (value >>> 48);
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) (value >>> 40);
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) (value >>> 32);
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) (value >>> 24);
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) (value >>> 16);
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) (value >>> 8);
|
||
|
|
hashBuffer[hashBufferOffset++] = (byte) value;
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
//Reset the algorithm.//
|
||
|
|
reset();
|
||
|
|
}//internalHash()//
|
||
|
|
/**
|
||
|
|
* The SHA-512 transform method which maintains the current hashBuffer by adding/transforming blocks of source data.
|
||
|
|
* @param data The 8 longs containing the source data to be added to the current hashBuffer.
|
||
|
|
*/
|
||
|
|
private void transform(long[] data) {
|
||
|
|
long a = hashBuffer[0];
|
||
|
|
long b = hashBuffer[1];
|
||
|
|
long c = hashBuffer[2];
|
||
|
|
long d = hashBuffer[3];
|
||
|
|
long e = hashBuffer[4];
|
||
|
|
long f = hashBuffer[5];
|
||
|
|
long g = hashBuffer[6];
|
||
|
|
long h = hashBuffer[7];
|
||
|
|
long[] w = internalBuffer;
|
||
|
|
|
||
|
|
updateSourceSize();
|
||
|
|
|
||
|
|
//Copy the data buffer into the first 16 positions in the working buffer.//
|
||
|
|
for(int i = 0; i < 16; i++) {
|
||
|
|
w[i] = data[i];
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
//Expand the data into the remaining working longs.//
|
||
|
|
for(int i = 16; i < 80; i++) {
|
||
|
|
long v1 = (w[i - 2] << 45 | w[i - 2] >>> 19) ^ (w[i - 2] << 3 | w[i - 2] >>> 61) ^ (w[i - 2] >>> 6);
|
||
|
|
long v2 = (w[i - 15] << 63 | w[i - 15] >>> 1) ^ (w[i - 15] << 56 | w[i - 15] >>> 8) ^ (w[i - 15] >>> 7);
|
||
|
|
|
||
|
|
w[i] = v1 + w[i - 7] + v2 + w[i - 16];
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
//Mix it all up.//
|
||
|
|
for(int i = 0, t = 0; i < 10; i++) {
|
||
|
|
h += f4(e) + f1(e, f, g) + K[t] + w[t++];
|
||
|
|
d += h;
|
||
|
|
h += f3(a) + f2(a, b, c);
|
||
|
|
|
||
|
|
g += f4(d) + f1(d, e, f) + K[t] + w[t++];
|
||
|
|
c += g;
|
||
|
|
g += f3(h) + f2(h, a, b);
|
||
|
|
|
||
|
|
f += f4(c) + f1(c, d, e) + K[t] + w[t++];
|
||
|
|
b += f;
|
||
|
|
f += f3(g) + f2(g, h, a);
|
||
|
|
|
||
|
|
e += f4(b) + f1(b, c, d) + K[t] + w[t++];
|
||
|
|
a += e;
|
||
|
|
e += f3(f) + f2(f, g, h);
|
||
|
|
|
||
|
|
d += f4(a) + f1(a, b, c) + K[t] + w[t++];
|
||
|
|
h += d;
|
||
|
|
d += f3(e) + f2(e, f, g);
|
||
|
|
|
||
|
|
c += f4(h) + f1(h, a, b) + K[t] + w[t++];
|
||
|
|
g += c;
|
||
|
|
c += f3(d) + f2(d, e, f);
|
||
|
|
|
||
|
|
b += f4(g) + f1(g, h, a) + K[t] + w[t++];
|
||
|
|
f += b;
|
||
|
|
b += f3(c) + f2(c, d, e);
|
||
|
|
|
||
|
|
a += f4(f) + f1(f, g, h) + K[t] + w[t++];
|
||
|
|
e += a;
|
||
|
|
a += f3(b) + f2(b, c, d);
|
||
|
|
}//for//
|
||
|
|
|
||
|
|
hashBuffer[0] += a;
|
||
|
|
hashBuffer[1] += b;
|
||
|
|
hashBuffer[2] += c;
|
||
|
|
hashBuffer[3] += d;
|
||
|
|
hashBuffer[4] += e;
|
||
|
|
hashBuffer[5] += f;
|
||
|
|
hashBuffer[6] += g;
|
||
|
|
hashBuffer[7] += h;
|
||
|
|
}//transform()//
|
||
|
|
/**
|
||
|
|
* Transform 1.
|
||
|
|
*/
|
||
|
|
private long f1(long x, long y, long z) {
|
||
|
|
return ((x & y) ^ ((~x) & z));
|
||
|
|
}//f1()//
|
||
|
|
/**
|
||
|
|
* Transform 2.
|
||
|
|
*/
|
||
|
|
private long f2(long x, long y, long z) {
|
||
|
|
return ((x & y) ^ (x & z) ^ (y & z));
|
||
|
|
}//f2()//
|
||
|
|
/**
|
||
|
|
* Transform 3.
|
||
|
|
*/
|
||
|
|
private long f3(long x) {
|
||
|
|
return ((x << 36)|(x >>> 28)) ^ ((x << 30)|(x >>> 34)) ^ ((x << 25)|(x >>> 39));
|
||
|
|
}//f3()//
|
||
|
|
/**
|
||
|
|
* Transform 4.
|
||
|
|
*/
|
||
|
|
private long f4(long x) {
|
||
|
|
return ((x << 50)|(x >>> 14)) ^ ((x << 46)|(x >>> 18)) ^ ((x << 23)|(x >>> 41));
|
||
|
|
}//f4()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see java.io.Externalizable#readExternal(java.io.ObjectInput)
|
||
|
|
*/
|
||
|
|
public void readExternal(java.io.ObjectInput in) throws java.io.IOException, ClassNotFoundException {
|
||
|
|
}//readExternal()//
|
||
|
|
/* (non-Javadoc)
|
||
|
|
* @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
|
||
|
|
*/
|
||
|
|
public void writeExternal(java.io.ObjectOutput out) throws java.io.IOException {
|
||
|
|
}//writeExternal()//
|
||
|
|
}//Sha1//
|