📄 whirlpool.java
字号:
Arrays.fill(bitLength, (byte)0);
bufferBits = bufferPos = 0;
buffer[0] = 0; // it's only necessary to cleanup buffer[bufferPos].
Arrays.fill(hash, 0L); // initial value
}
/**
* Delivers input data to the hashing algorithm.
*
* @param source plaintext data to hash.
* @param sourceBits how many bits of plaintext to process.
*
* This method maintains the invariant: bufferBits < 512
*/
public void NESSIEadd(byte[] source, long sourceBits) {
/*
sourcePos
|
+-------+-------+-------
||||||||||||||||||||| source
+-------+-------+-------
+-------+-------+-------+-------+-------+-------
|||||||||||||||||||||| buffer
+-------+-------+-------+-------+-------+-------
|
bufferPos
*/
int sourcePos = 0; // index of leftmost source byte containing data (1 to 8 bits).
int sourceGap = (8 - ((int)sourceBits & 7)) & 7; // space on source[sourcePos].
int bufferRem = bufferBits & 7; // occupied bits on buffer[bufferPos].
int b;
// tally the length of the added data:
long value = sourceBits;
for (int i = 31, carry = 0; i >= 0; i--) {
carry += (bitLength[i] & 0xff) + ((int)value & 0xff);
bitLength[i] = (byte)carry;
carry >>>= 8;
value >>>= 8;
}
// process data in chunks of 8 bits:
while (sourceBits > 8) { // at least source[sourcePos] and source[sourcePos+1] contain data.
// take a byte from the source:
b = ((source[sourcePos] << sourceGap) & 0xff) |
((source[sourcePos + 1] & 0xff) >>> (8 - sourceGap));
if (b < 0 || b >= 256) {
throw new RuntimeException("LOGIC ERROR");
}
// process this byte:
buffer[bufferPos++] |= b >>> bufferRem;
bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos;
if (bufferBits == 512) {
// process data block:
processBuffer();
// reset buffer:
bufferBits = bufferPos = 0;
}
buffer[bufferPos] = (byte)((b << (8 - bufferRem)) & 0xff);
bufferBits += bufferRem;
// proceed to remaining data:
sourceBits -= 8;
sourcePos++;
}
// now 0 <= sourceBits <= 8;
// furthermore, all data (if any is left) is in source[sourcePos].
if (sourceBits > 0) {
b = (source[sourcePos] << sourceGap) & 0xff; // bits are left-justified on b.
// process the remaining bits:
buffer[bufferPos] |= b >>> bufferRem;
} else {
b = 0;
}
if (bufferRem + sourceBits < 8) {
// all remaining data fits on buffer[bufferPos], and there still remains some space.
bufferBits += sourceBits;
} else {
// buffer[bufferPos] is full:
bufferPos++;
bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos;
sourceBits -= 8 - bufferRem;
// now 0 <= sourceBits < 8; furthermore, all data is in source[sourcePos].
if (bufferBits == 512) {
// process data block:
processBuffer();
// reset buffer:
bufferBits = bufferPos = 0;
}
buffer[bufferPos] = (byte)((b << (8 - bufferRem)) & 0xff);
bufferBits += (int)sourceBits;
}
}
/**
* Get the hash value from the hashing state.
*
* This method uses the invariant: bufferBits < 512
*/
public void NESSIEfinalize(byte[] digest) {
// append a '1'-bit:
buffer[bufferPos] |= 0x80 >>> (bufferBits & 7);
bufferPos++; // all remaining bits on the current byte are set to zero.
// pad with zero bits to complete 512N + 256 bits:
if (bufferPos > 32) {
while (bufferPos < 64) {
buffer[bufferPos++] = 0;
}
// process data block:
processBuffer();
// reset buffer:
bufferPos = 0;
}
while (bufferPos < 32) {
buffer[bufferPos++] = 0;
}
// append bit length of hashed data:
System.arraycopy(bitLength, 0, buffer, 32, 32);
// process data block:
processBuffer();
// return the completed message digest:
for (int i = 0, j = 0; i < 8; i++, j += 8) {
long h = hash[i];
digest[j ] = (byte)(h >>> 56);
digest[j + 1] = (byte)(h >>> 48);
digest[j + 2] = (byte)(h >>> 40);
digest[j + 3] = (byte)(h >>> 32);
digest[j + 4] = (byte)(h >>> 24);
digest[j + 5] = (byte)(h >>> 16);
digest[j + 6] = (byte)(h >>> 8);
digest[j + 7] = (byte)(h );
}
}
/**
* Delivers string input data to the hashing algorithm.
*
* @param source plaintext data to hash (ASCII text string).
*
* This method maintains the invariant: bufferBits < 512
*/
public void NESSIEadd(String source) {
if (source.length() > 0) {
byte[] data = new byte[source.length()];
for (int i = 0; i < source.length(); i++) {
data[i] = (byte)source.charAt(i);
}
NESSIEadd(data, 8*data.length);
}
}
private static String display(byte[] array) {
char[] val = new char[2*array.length];
String hex = "0123456789ABCDEF";
for (int i = 0; i < array.length; i++) {
int b = array[i] & 0xff;
val[2*i] = hex.charAt(b >>> 4);
val[2*i + 1] = hex.charAt(b & 15);
}
return String.valueOf(val);
}
private static final int LONG_ITERATION = 100000000;
/**
* Generate the NESSIE test vector set for Whirlpool.
*
* The test consists of:
* 1. hashing all bit strings containing only zero bits
* for all lengths from 0 to 1023;
* 2. hashing all 512-bit strings containing a single set bit;
* 3. the iterated hashing of the 512-bit string of zero bits a large number of times.
*/
public static void makeNESSIETestVectors() {
Whirlpool w = new Whirlpool();
byte[] digest = new byte[64];
byte[] data = new byte[128];
Arrays.fill(data, (byte)0);
System.out.println("Message digests of strings of 0-bits and length L:");
for (int i = 0; i < 1024; i++) {
w.NESSIEinit();
w.NESSIEadd(data, i);
w.NESSIEfinalize(digest);
String s = Integer.toString(i);
s = " ".substring(s.length()) + s;
System.out.println(" L =" + s + ": " + display(digest));
}
System.out.println("Message digests of all 512-bit strings S containing a single 1-bit:");
data = new byte[512/8];
Arrays.fill(data, (byte)0);
for (int i = 0; i < 512; i++) {
// set bit i:
data[i/8] |= 0x80 >>> (i % 8);
w.NESSIEinit();
w.NESSIEadd(data, 512);
w.NESSIEfinalize(digest);
System.out.println(" S = " + display(data) + ": " + display(digest));
// reset bit i:
data[i/8] = 0;
}
for (int i = 0; i < digest.length; i++) {
digest[i] = 0;
}
for (int i = 0; i < LONG_ITERATION; i++) {
w.NESSIEinit();
w.NESSIEadd(digest, 512);
w.NESSIEfinalize(digest);
}
System.out.println("Iterated message digest computation (" + LONG_ITERATION + " times): " + display(digest));
}
/**
* Generate the ISO/IEC 10118-3 test vector set for Whirlpool.
*/
public static void makeISOTestVectors() {
Whirlpool w = new Whirlpool();
byte[] digest = new byte[DIGESTBYTES];
byte[] data = new byte[1000000];
Arrays.fill(data, (byte)0);
System.out.println("1. In this example the data-string is the empty string, i.e. the string of length zero.\n");
w.NESSIEinit();
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
System.out.println("2. In this example the data-string consists of a single byte, namely the ASCII-coded version of the letter 'a'.\n");
w.NESSIEinit();
w.NESSIEadd("a");
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
System.out.println("3. In this example the data-string is the three-byte string consisting of the ASCII-coded version of 'abc'.\n");
w.NESSIEinit();
w.NESSIEadd("abc");
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
System.out.println("4. In this example the data-string is the 14-byte string consisting of the ASCII-coded version of 'message digest'.\n");
w.NESSIEinit();
w.NESSIEadd("message digest");
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
System.out.println("5. In this example the data-string is the 26-byte string consisting of the ASCII-coded version of 'abcdefghijklmnopqrstuvwxyz'.\n");
w.NESSIEinit();
w.NESSIEadd("abcdefghijklmnopqrstuvwxyz");
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
System.out.println("6. In this example the data-string is the 62-byte string consisting of the ASCII-coded version of 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.\n");
w.NESSIEinit();
w.NESSIEadd("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
System.out.println("7. In this example the data-string is the 80-byte string consisting of the ASCII-coded version of eight repetitions of '1234567890'.\n");
w.NESSIEinit();
w.NESSIEadd("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
System.out.println("8. In this example the data-string is the 32-byte string consisting of the ASCII-coded version of 'abcdbcdecdefdefgefghfghighijhijk'.\n");
w.NESSIEinit();
w.NESSIEadd("abcdbcdecdefdefgefghfghighijhijk");
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
Arrays.fill(data, (byte)'a');
System.out.println("9. In this example the data-string is the 1000000-byte string consisting of the ASCII-coded version of 'a' repeated 10^6 times.\n");
w.NESSIEinit();
w.NESSIEadd(data, 8*1000000);
w.NESSIEfinalize(digest);
System.out.println("The hash-code is the following 512-bit string.\n\n" + display(digest) + "\n");
}
public static void main(String[] args) {
//makeNESSIETestVectors();
makeISOTestVectors();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -