001: /**
002: * The Whirlpool hashing function.
003: *
004: * <P>
005: * <b>References</b>
006: *
007: * <P>
008: * The Whirlpool algorithm was developed by
009: * <a href="mailto:pbarreto@scopus.com.br">Paulo S. L. M. Barreto</a> and
010: * <a href="mailto:vincent.rijmen@cryptomathic.com">Vincent Rijmen</a>.
011: *
012: * See
013: * P.S.L.M. Barreto, V. Rijmen,
014: * ``The Whirlpool hashing function,''
015: * First NESSIE workshop, 2000 (tweaked version, 2003),
016: * <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip>
017: *
018: * @author Paulo S.L.M. Barreto
019: * @author Vincent Rijmen.
020: *
021: * @version 3.0 (2003.03.12)
022: *
023: * =============================================================================
024: *
025: * Differences from version 2.1:
026: *
027: * - Suboptimal diffusion matrix replaced by cir(1, 1, 4, 1, 8, 5, 2, 9).
028: *
029: * =============================================================================
030: *
031: * Differences from version 2.0:
032: *
033: * - Generation of ISO/IEC 10118-3 test vectors.
034: * - Bug fix: nonzero carry was ignored when tallying the data length
035: * (this bug apparently only manifested itself when feeding data
036: * in pieces rather than in a single chunk at once).
037: *
038: * Differences from version 1.0:
039: *
040: * - Original S-box replaced by the tweaked, hardware-efficient version.
041: *
042: * =============================================================================
043: *
044: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
045: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
046: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
047: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
048: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
049: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
050: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
051: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
052: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
053: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
054: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
055: *
056: */package com.uwyn.rife.tools;
057:
058: import java.util.Arrays;
059:
060: class Whirlpool {
061:
062: /**
063: * The message digest size (in bits)
064: */
065: public static final int DIGESTBITS = 512;
066:
067: /**
068: * The message digest size (in bytes)
069: */
070: public static final int DIGESTBYTES = DIGESTBITS >>> 3;
071:
072: /**
073: * The number of rounds of the internal dedicated block cipher.
074: */
075: protected static final int R = 10;
076:
077: /**
078: * The substitution box.
079: */
080: private static final String sbox = "\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152"
081: + "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57"
082: + "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85"
083: + "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8"
084: + "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333"
085: + "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0"
086: + "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE"
087: + "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d"
088: + "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF"
089: + "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A"
090: + "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c"
091: + "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04"
092: + "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB"
093: + "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9"
094: + "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1"
095: + "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886";
096:
097: private static long[][] C = new long[8][256];
098: private static long[] rc = new long[R + 1];
099:
100: static {
101: for (int x = 0; x < 256; x++) {
102: char c = sbox.charAt(x / 2);
103: long v1 = ((x & 1) == 0) ? c >>> 8 : c & 0xff;
104: long v2 = v1 << 1;
105: if (v2 >= 0x100L) {
106: v2 ^= 0x11dL;
107: }
108: long v4 = v2 << 1;
109: if (v4 >= 0x100L) {
110: v4 ^= 0x11dL;
111: }
112: long v5 = v4 ^ v1;
113: long v8 = v4 << 1;
114: if (v8 >= 0x100L) {
115: v8 ^= 0x11dL;
116: }
117: long v9 = v8 ^ v1;
118: /*
119: * build the circulant table C[0][x] = S[x].[1, 1, 4, 1, 8, 5, 2, 9]:
120: */
121: C[0][x] = (v1 << 56) | (v1 << 48) | (v4 << 40) | (v1 << 32)
122: | (v8 << 24) | (v5 << 16) | (v2 << 8) | (v9);
123: /*
124: * build the remaining circulant tables C[t][x] = C[0][x] rotr t
125: */
126: for (int t = 1; t < 8; t++) {
127: C[t][x] = (C[t - 1][x] >>> 8) | ((C[t - 1][x] << 56));
128: }
129: }
130: /*
131: for (int t = 0; t < 8; t++) {
132: System.out.println("static const u64 C" + t + "[256] = {");
133: for (int i = 0; i < 64; i++) {
134: System.out.print(" ");
135: for (int j = 0; j < 4; j++) {
136: String v = Long.toHexString(C[t][4*i + j]);
137: while (v.length() < 16) {
138: v = "0" + v;
139: }
140: System.out.print(" LL(0x" + v + "),");
141: }
142: System.out.println();
143: }
144: System.out.println("};");
145: System.out.println();
146: }
147: System.out.println();
148: //*/
149:
150: /*
151: * build the round constants:
152: */
153: rc[0] = 0L; /* not used (assigment kept only to properly initialize all variables) */
154: for (int r = 1; r <= R; r++) {
155: int i = 8 * (r - 1);
156: rc[r] = (C[0][i] & 0xff00000000000000L)
157: ^ (C[1][i + 1] & 0x00ff000000000000L)
158: ^ (C[2][i + 2] & 0x0000ff0000000000L)
159: ^ (C[3][i + 3] & 0x000000ff00000000L)
160: ^ (C[4][i + 4] & 0x00000000ff000000L)
161: ^ (C[5][i + 5] & 0x0000000000ff0000L)
162: ^ (C[6][i + 6] & 0x000000000000ff00L)
163: ^ (C[7][i + 7] & 0x00000000000000ffL);
164: }
165: /*
166: System.out.println("static const u64 rc[R + 1] = {");
167: for (int r = 0; r <= R; r++) {
168: String v = Long.toHexString(rc[r]);
169: while (v.length() < 16) {
170: v = "0" + v;
171: }
172: System.out.println(" LL(0x" + v + "),");
173: }
174: System.out.println("};");
175: System.out.println();
176: //*/
177: }
178:
179: /**
180: * Global number of hashed bits (256-bit counter).
181: */
182: protected byte[] bitLength = new byte[32];
183:
184: /**
185: * Buffer of data to hash.
186: */
187: protected byte[] buffer = new byte[64];
188:
189: /**
190: * Current number of bits on the buffer.
191: */
192: protected int bufferBits = 0;
193:
194: /**
195: * Current (possibly incomplete) byte slot on the buffer.
196: */
197: protected int bufferPos = 0;
198:
199: /**
200: * The hashing state.
201: */
202: protected long[] hash = new long[8];
203: protected long[] K = new long[8]; // the round key
204: protected long[] L = new long[8];
205: protected long[] block = new long[8]; // mu(buffer)
206: protected long[] state = new long[8]; // the cipher state
207:
208: public Whirlpool() {
209: }
210:
211: /**
212: * The core Whirlpool transform.
213: */
214: protected void processBuffer() {
215: /*
216: * map the buffer to a block:
217: */
218: for (int i = 0, j = 0; i < 8; i++, j += 8) {
219: block[i] = (((long) buffer[j]) << 56)
220: ^ (((long) buffer[j + 1] & 0xffL) << 48)
221: ^ (((long) buffer[j + 2] & 0xffL) << 40)
222: ^ (((long) buffer[j + 3] & 0xffL) << 32)
223: ^ (((long) buffer[j + 4] & 0xffL) << 24)
224: ^ (((long) buffer[j + 5] & 0xffL) << 16)
225: ^ (((long) buffer[j + 6] & 0xffL) << 8)
226: ^ (((long) buffer[j + 7] & 0xffL));
227: }
228: /*
229: * compute and apply K^0 to the cipher state:
230: */
231: for (int i = 0; i < 8; i++) {
232: state[i] = block[i] ^ (K[i] = hash[i]);
233: }
234: /*
235: * iterate over all rounds:
236: */
237: for (int r = 1; r <= R; r++) {
238: /*
239: * compute K^r from K^{r-1}:
240: */
241: for (int i = 0; i < 8; i++) {
242: L[i] = 0L;
243: for (int t = 0, s = 56; t < 8; t++, s -= 8) {
244: L[i] ^= C[t][(int) (K[(i - t) & 7] >>> s) & 0xff];
245: }
246: }
247: System.arraycopy(L, 0, K, 0, 8);
248: K[0] ^= rc[r];
249: /*
250: * apply the r-th round transformation:
251: */
252: for (int i = 0; i < 8; i++) {
253: L[i] = K[i];
254: for (int t = 0, s = 56; t < 8; t++, s -= 8) {
255: L[i] ^= C[t][(int) (state[(i - t) & 7] >>> s) & 0xff];
256: }
257: }
258: System.arraycopy(L, 0, state, 0, 8);
259: }
260: /*
261: * apply the Miyaguchi-Preneel compression function:
262: */
263: for (int i = 0; i < 8; i++) {
264: hash[i] ^= state[i] ^ block[i];
265: }
266: }
267:
268: /**
269: * Initialize the hashing state.
270: */
271: public void NESSIEinit() {
272: Arrays.fill(bitLength, (byte) 0);
273: bufferBits = bufferPos = 0;
274: buffer[0] = 0; // it's only necessary to cleanup buffer[bufferPos].
275: Arrays.fill(hash, 0L); // initial value
276: }
277:
278: /**
279: * Delivers input data to the hashing algorithm.
280: *
281: * @param source plaintext data to hash.
282: * @param sourceBits how many bits of plaintext to process.
283: *
284: * This method maintains the invariant: bufferBits < 512
285: */
286: public void NESSIEadd(byte[] source, long sourceBits) {
287: /*
288: sourcePos
289: |
290: +-------+-------+-------
291: ||||||||||||||||||||| source
292: +-------+-------+-------
293: +-------+-------+-------+-------+-------+-------
294: |||||||||||||||||||||| buffer
295: +-------+-------+-------+-------+-------+-------
296: |
297: bufferPos
298: */
299: int sourcePos = 0; // index of leftmost source byte containing data (1 to 8 bits).
300: int sourceGap = (8 - ((int) sourceBits & 7)) & 7; // space on source[sourcePos].
301: int bufferRem = bufferBits & 7; // occupied bits on buffer[bufferPos].
302: int b;
303: // tally the length of the added data:
304: long value = sourceBits;
305: for (int i = 31, carry = 0; i >= 0; i--) {
306: carry += (bitLength[i] & 0xff) + ((int) value & 0xff);
307: bitLength[i] = (byte) carry;
308: carry >>>= 8;
309: value >>>= 8;
310: }
311: // process data in chunks of 8 bits:
312: while (sourceBits > 8) { // at least source[sourcePos] and source[sourcePos+1] contain data.
313: // take a byte from the source:
314: b = ((source[sourcePos] << sourceGap) & 0xff)
315: | ((source[sourcePos + 1] & 0xff) >>> (8 - sourceGap));
316: if (b < 0 || b >= 256) {
317: throw new RuntimeException("LOGIC ERROR");
318: }
319: // process this byte:
320: buffer[bufferPos++] |= b >>> bufferRem;
321: bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos;
322: if (bufferBits == 512) {
323: // process data block:
324: processBuffer();
325: // reset buffer:
326: bufferBits = bufferPos = 0;
327: }
328: buffer[bufferPos] = (byte) ((b << (8 - bufferRem)) & 0xff);
329: bufferBits += bufferRem;
330: // proceed to remaining data:
331: sourceBits -= 8;
332: sourcePos++;
333: }
334: // now 0 <= sourceBits <= 8;
335: // furthermore, all data (if any is left) is in source[sourcePos].
336: if (sourceBits > 0) {
337: b = (source[sourcePos] << sourceGap) & 0xff; // bits are left-justified on b.
338: // process the remaining bits:
339: buffer[bufferPos] |= b >>> bufferRem;
340: } else {
341: b = 0;
342: }
343: if (bufferRem + sourceBits < 8) {
344: // all remaining data fits on buffer[bufferPos], and there still remains some space.
345: bufferBits += sourceBits;
346: } else {
347: // buffer[bufferPos] is full:
348: bufferPos++;
349: bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos;
350: sourceBits -= 8 - bufferRem;
351: // now 0 <= sourceBits < 8; furthermore, all data is in source[sourcePos].
352: if (bufferBits == 512) {
353: // process data block:
354: processBuffer();
355: // reset buffer:
356: bufferBits = bufferPos = 0;
357: }
358: buffer[bufferPos] = (byte) ((b << (8 - bufferRem)) & 0xff);
359: bufferBits += (int) sourceBits;
360: }
361: }
362:
363: /**
364: * Get the hash value from the hashing state.
365: *
366: * This method uses the invariant: bufferBits < 512
367: */
368: public void NESSIEfinalize(byte[] digest) {
369: // append a '1'-bit:
370: buffer[bufferPos] |= 0x80 >>> (bufferBits & 7);
371: bufferPos++; // all remaining bits on the current byte are set to zero.
372: // pad with zero bits to complete 512N + 256 bits:
373: if (bufferPos > 32) {
374: while (bufferPos < 64) {
375: buffer[bufferPos++] = 0;
376: }
377: // process data block:
378: processBuffer();
379: // reset buffer:
380: bufferPos = 0;
381: }
382: while (bufferPos < 32) {
383: buffer[bufferPos++] = 0;
384: }
385: // append bit length of hashed data:
386: System.arraycopy(bitLength, 0, buffer, 32, 32);
387: // process data block:
388: processBuffer();
389: // return the completed message digest:
390: for (int i = 0, j = 0; i < 8; i++, j += 8) {
391: long h = hash[i];
392: digest[j] = (byte) (h >>> 56);
393: digest[j + 1] = (byte) (h >>> 48);
394: digest[j + 2] = (byte) (h >>> 40);
395: digest[j + 3] = (byte) (h >>> 32);
396: digest[j + 4] = (byte) (h >>> 24);
397: digest[j + 5] = (byte) (h >>> 16);
398: digest[j + 6] = (byte) (h >>> 8);
399: digest[j + 7] = (byte) (h);
400: }
401: }
402:
403: /**
404: * Delivers string input data to the hashing algorithm.
405: *
406: * @param source plaintext data to hash (ASCII text string).
407: *
408: * This method maintains the invariant: bufferBits < 512
409: */
410: public void NESSIEadd(String source) {
411: if (source.length() > 0) {
412: byte[] data = new byte[source.length()];
413: for (int i = 0; i < source.length(); i++) {
414: data[i] = (byte) source.charAt(i);
415: }
416: NESSIEadd(data, 8 * data.length);
417: }
418: }
419:
420: private static String display(byte[] array) {
421: char[] val = new char[2 * array.length];
422: String hex = "0123456789ABCDEF";
423: for (int i = 0; i < array.length; i++) {
424: int b = array[i] & 0xff;
425: val[2 * i] = hex.charAt(b >>> 4);
426: val[2 * i + 1] = hex.charAt(b & 15);
427: }
428: return String.valueOf(val);
429: }
430:
431: private static final int LONG_ITERATION = 100000000;
432:
433: /**
434: * Generate the NESSIE test vector set for Whirlpool.
435: *
436: * The test consists of:
437: * 1. hashing all bit strings containing only zero bits
438: * for all lengths from 0 to 1023;
439: * 2. hashing all 512-bit strings containing a single set bit;
440: * 3. the iterated hashing of the 512-bit string of zero bits a large number of times.
441: */
442: public static void makeNESSIETestVectors() {
443: Whirlpool w = new Whirlpool();
444: byte[] digest = new byte[64];
445: byte[] data = new byte[128];
446: Arrays.fill(data, (byte) 0);
447: System.out
448: .println("Message digests of strings of 0-bits and length L:");
449: for (int i = 0; i < 1024; i++) {
450: w.NESSIEinit();
451: w.NESSIEadd(data, i);
452: w.NESSIEfinalize(digest);
453: String s = Integer.toString(i);
454: s = " ".substring(s.length()) + s;
455: System.out.println(" L =" + s + ": " + display(digest));
456: }
457: System.out
458: .println("Message digests of all 512-bit strings S containing a single 1-bit:");
459: data = new byte[512 / 8];
460: Arrays.fill(data, (byte) 0);
461: for (int i = 0; i < 512; i++) {
462: // set bit i:
463: data[i / 8] |= 0x80 >>> (i % 8);
464: w.NESSIEinit();
465: w.NESSIEadd(data, 512);
466: w.NESSIEfinalize(digest);
467: System.out.println(" S = " + display(data) + ": "
468: + display(digest));
469: // reset bit i:
470: data[i / 8] = 0;
471: }
472: for (int i = 0; i < digest.length; i++) {
473: digest[i] = 0;
474: }
475: for (int i = 0; i < LONG_ITERATION; i++) {
476: w.NESSIEinit();
477: w.NESSIEadd(digest, 512);
478: w.NESSIEfinalize(digest);
479: }
480: System.out.println("Iterated message digest computation ("
481: + LONG_ITERATION + " times): " + display(digest));
482: }
483:
484: /**
485: * Generate the ISO/IEC 10118-3 test vector set for Whirlpool.
486: */
487: public static void makeISOTestVectors() {
488: Whirlpool w = new Whirlpool();
489: byte[] digest = new byte[DIGESTBYTES];
490: byte[] data = new byte[1000000];
491:
492: Arrays.fill(data, (byte) 0);
493:
494: System.out
495: .println("1. In this example the data-string is the empty string, i.e. the string of length zero.\n");
496: w.NESSIEinit();
497: w.NESSIEfinalize(digest);
498: System.out
499: .println("The hash-code is the following 512-bit string.\n\n"
500: + display(digest) + "\n");
501:
502: System.out
503: .println("2. In this example the data-string consists of a single byte, namely the ASCII-coded version of the letter 'a'.\n");
504: w.NESSIEinit();
505: w.NESSIEadd("a");
506: w.NESSIEfinalize(digest);
507: System.out
508: .println("The hash-code is the following 512-bit string.\n\n"
509: + display(digest) + "\n");
510:
511: System.out
512: .println("3. In this example the data-string is the three-byte string consisting of the ASCII-coded version of 'abc'.\n");
513: w.NESSIEinit();
514: w.NESSIEadd("abc");
515: w.NESSIEfinalize(digest);
516: System.out
517: .println("The hash-code is the following 512-bit string.\n\n"
518: + display(digest) + "\n");
519:
520: System.out
521: .println("4. In this example the data-string is the 14-byte string consisting of the ASCII-coded version of 'message digest'.\n");
522: w.NESSIEinit();
523: w.NESSIEadd("message digest");
524: w.NESSIEfinalize(digest);
525: System.out
526: .println("The hash-code is the following 512-bit string.\n\n"
527: + display(digest) + "\n");
528:
529: System.out
530: .println("5. In this example the data-string is the 26-byte string consisting of the ASCII-coded version of 'abcdefghijklmnopqrstuvwxyz'.\n");
531: w.NESSIEinit();
532: w.NESSIEadd("abcdefghijklmnopqrstuvwxyz");
533: w.NESSIEfinalize(digest);
534: System.out
535: .println("The hash-code is the following 512-bit string.\n\n"
536: + display(digest) + "\n");
537:
538: System.out
539: .println("6. In this example the data-string is the 62-byte string consisting of the ASCII-coded version of 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.\n");
540: w.NESSIEinit();
541: w
542: .NESSIEadd("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
543: w.NESSIEfinalize(digest);
544: System.out
545: .println("The hash-code is the following 512-bit string.\n\n"
546: + display(digest) + "\n");
547:
548: System.out
549: .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");
550: w.NESSIEinit();
551: w
552: .NESSIEadd("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
553: w.NESSIEfinalize(digest);
554: System.out
555: .println("The hash-code is the following 512-bit string.\n\n"
556: + display(digest) + "\n");
557:
558: System.out
559: .println("8. In this example the data-string is the 32-byte string consisting of the ASCII-coded version of 'abcdbcdecdefdefgefghfghighijhijk'.\n");
560: w.NESSIEinit();
561: w.NESSIEadd("abcdbcdecdefdefgefghfghighijhijk");
562: w.NESSIEfinalize(digest);
563: System.out
564: .println("The hash-code is the following 512-bit string.\n\n"
565: + display(digest) + "\n");
566:
567: Arrays.fill(data, (byte) 'a');
568: System.out
569: .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");
570: w.NESSIEinit();
571: w.NESSIEadd(data, 8 * 1000000);
572: w.NESSIEfinalize(digest);
573: System.out
574: .println("The hash-code is the following 512-bit string.\n\n"
575: + display(digest) + "\n");
576: }
577:
578: public static void main(String[] args) {
579: //makeNESSIETestVectors();
580: makeISOTestVectors();
581: }
582: }
|