/* Copyright (c) 2009 Graham Edgecombe, Blake Beaupain and Brett Russell * * More information about Hyperion may be found on this website: * http://hyperion.grahamedgecombe.com/ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.asteria.net; /** * <p> * An implementation of an ISAAC cipher. See <a * href="http://en.wikipedia.org/wiki/ISAAC_(cipher)"> * http://en.wikipedia.org/wiki/ISAAC_(cipher)</a> for more information. * </p> * <p> * <p> * This implementation is based on the one written by Bob Jenkins, which is * available at <a href="http://www.burtleburtle.net/bob/java/rand/Rand.java"> * http://www.burtleburtle.net/bob/java/rand/Rand.java</a>. * </p> * * @author Graham Edgecombe */ public final class ISAACCipher { /** * The golden ratio. */ private static final int RATIO = 0x9e3779b9; /** * The log of the size of the results and memory arrays. */ private static final int SIZE_LOG = 8; /** * The size of the results and memory arrays. */ private static final int SIZE = 1 << SIZE_LOG; /** * For pseudorandom lookup. */ private static final int MASK = (SIZE - 1) << 2; /** * The count through the results. */ private int count = 0; /** * The results. */ private int results[] = new int[SIZE]; /** * The internal memory state. */ private int memory[] = new int[SIZE]; /** * The accumulator. */ private int a; /** * The last result. */ private int b; /** * The counter. */ private int c; /** * Creates the ISAAC cipher. * * @param seed * The seed. */ public ISAACCipher(int[] seed) { for (int i = 0; i < seed.length; i++) { results[i] = seed[i]; } init(true); } /** * Gets the next value. * * @return The next value. */ public int getKey() { if (count-- == 0) { isaac(); count = SIZE - 1; } return results[count]; } /** * Generates 256 results. */ public void isaac() { int i, j, x, y; b += ++c; for (i = 0, j = SIZE / 2; i < SIZE / 2;) { x = memory[i]; a ^= a << 13; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; x = memory[i]; a ^= a >>> 6; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; x = memory[i]; a ^= a << 2; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; x = memory[i]; a ^= a >>> 16; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; } for (j = 0; j < SIZE / 2;) { x = memory[i]; a ^= a << 13; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; x = memory[i]; a ^= a >>> 6; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; x = memory[i]; a ^= a << 2; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; x = memory[i]; a ^= a >>> 16; a += memory[j++]; memory[i] = y = memory[(x & MASK) >> 2] + a + b; results[i++] = b = memory[((y >> SIZE_LOG) & MASK) >> 2] + x; } } /** * Initializes the ISAAC. * * @param flag * Flag indicating if we should perform a second pass. */ public void init(boolean flag) { int i; int a, b, c, d, e, f, g, h; a = b = c = d = e = f = g = h = RATIO; for (i = 0; i < 4; ++i) { a ^= b << 11; d += a; b += c; b ^= c >>> 2; e += b; c += d; c ^= d << 8; f += c; d += e; d ^= e >>> 16; g += d; e += f; e ^= f << 10; h += e; f += g; f ^= g >>> 4; a += f; g += h; g ^= h << 8; b += g; h += a; h ^= a >>> 9; c += h; a += b; } for (i = 0; i < SIZE; i += 8) { if (flag) { a += results[i]; b += results[i + 1]; c += results[i + 2]; d += results[i + 3]; e += results[i + 4]; f += results[i + 5]; g += results[i + 6]; h += results[i + 7]; } a ^= b << 11; d += a; b += c; b ^= c >>> 2; e += b; c += d; c ^= d << 8; f += c; d += e; d ^= e >>> 16; g += d; e += f; e ^= f << 10; h += e; f += g; f ^= g >>> 4; a += f; g += h; g ^= h << 8; b += g; h += a; h ^= a >>> 9; c += h; a += b; memory[i] = a; memory[i + 1] = b; memory[i + 2] = c; memory[i + 3] = d; memory[i + 4] = e; memory[i + 5] = f; memory[i + 6] = g; memory[i + 7] = h; } if (flag) { for (i = 0; i < SIZE; i += 8) { a += memory[i]; b += memory[i + 1]; c += memory[i + 2]; d += memory[i + 3]; e += memory[i + 4]; f += memory[i + 5]; g += memory[i + 6]; h += memory[i + 7]; a ^= b << 11; d += a; b += c; b ^= c >>> 2; e += b; c += d; c ^= d << 8; f += c; d += e; d ^= e >>> 16; g += d; e += f; e ^= f << 10; h += e; f += g; f ^= g >>> 4; a += f; g += h; g ^= h << 8; b += g; h += a; h ^= a >>> 9; c += h; a += b; memory[i] = a; memory[i + 1] = b; memory[i + 2] = c; memory[i + 3] = d; memory[i + 4] = e; memory[i + 5] = f; memory[i + 6] = g; memory[i + 7] = h; } } isaac(); count = SIZE; } }