
org.spongycastle.crypto.engines.HC256Engine Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
Spongy Castle is a package-rename (org.bouncycastle.* to org.spongycastle.*) of Bouncy Castle
intended for the Android platform. Android unfortunately ships with a stripped-down version of
Bouncy Castle, which prevents easy upgrades - Spongy Castle overcomes this and provides a full,
up-to-date version of the Bouncy Castle cryptographic libs.
package org.spongycastle.crypto.engines;
import org.spongycastle.crypto.CipherParameters;
import org.spongycastle.crypto.DataLengthException;
import org.spongycastle.crypto.OutputLengthException;
import org.spongycastle.crypto.StreamCipher;
import org.spongycastle.crypto.params.KeyParameter;
import org.spongycastle.crypto.params.ParametersWithIV;
/**
* HC-256 is a software-efficient stream cipher created by Hongjun Wu. It
* generates keystream from a 256-bit secret key and a 256-bit initialization
* vector.
*
* http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
*
* Its brother, HC-128, is a third phase candidate in the eStream contest.
* The algorithm is patent-free. No attacks are known as of today (April 2007).
* See
*
* http://www.ecrypt.eu.org/stream/hcp3.html
*
*/
public class HC256Engine
implements StreamCipher
{
private int[] p = new int[1024];
private int[] q = new int[1024];
private int cnt = 0;
private int step()
{
int j = cnt & 0x3FF;
int ret;
if (cnt < 1024)
{
int x = p[(j - 3 & 0x3FF)];
int y = p[(j - 1023 & 0x3FF)];
p[j] += p[(j - 10 & 0x3FF)]
+ (rotateRight(x, 10) ^ rotateRight(y, 23))
+ q[((x ^ y) & 0x3FF)];
x = p[(j - 12 & 0x3FF)];
ret = (q[x & 0xFF] + q[((x >> 8) & 0xFF) + 256]
+ q[((x >> 16) & 0xFF) + 512] + q[((x >> 24) & 0xFF) + 768])
^ p[j];
}
else
{
int x = q[(j - 3 & 0x3FF)];
int y = q[(j - 1023 & 0x3FF)];
q[j] += q[(j - 10 & 0x3FF)]
+ (rotateRight(x, 10) ^ rotateRight(y, 23))
+ p[((x ^ y) & 0x3FF)];
x = q[(j - 12 & 0x3FF)];
ret = (p[x & 0xFF] + p[((x >> 8) & 0xFF) + 256]
+ p[((x >> 16) & 0xFF) + 512] + p[((x >> 24) & 0xFF) + 768])
^ q[j];
}
cnt = cnt + 1 & 0x7FF;
return ret;
}
private byte[] key, iv;
private boolean initialised;
private void init()
{
if (key.length != 32 && key.length != 16)
{
throw new IllegalArgumentException(
"The key must be 128/256 bits long");
}
if (iv.length < 16)
{
throw new IllegalArgumentException(
"The IV must be at least 128 bits long");
}
if (key.length != 32)
{
byte[] k = new byte[32];
System.arraycopy(key, 0, k, 0, key.length);
System.arraycopy(key, 0, k, 16, key.length);
key = k;
}
if (iv.length < 32)
{
byte[] newIV = new byte[32];
System.arraycopy(iv, 0, newIV, 0, iv.length);
System.arraycopy(iv, 0, newIV, iv.length, newIV.length - iv.length);
iv = newIV;
}
idx = 0;
cnt = 0;
int[] w = new int[2560];
for (int i = 0; i < 32; i++)
{
w[i >> 2] |= (key[i] & 0xff) << (8 * (i & 0x3));
}
for (int i = 0; i < 32; i++)
{
w[(i >> 2) + 8] |= (iv[i] & 0xff) << (8 * (i & 0x3));
}
for (int i = 16; i < 2560; i++)
{
int x = w[i - 2];
int y = w[i - 15];
w[i] = (rotateRight(x, 17) ^ rotateRight(x, 19) ^ (x >>> 10))
+ w[i - 7]
+ (rotateRight(y, 7) ^ rotateRight(y, 18) ^ (y >>> 3))
+ w[i - 16] + i;
}
System.arraycopy(w, 512, p, 0, 1024);
System.arraycopy(w, 1536, q, 0, 1024);
for (int i = 0; i < 4096; i++)
{
step();
}
cnt = 0;
}
public String getAlgorithmName()
{
return "HC-256";
}
/**
* Initialise a HC-256 cipher.
*
* @param forEncryption whether or not we are for encryption. Irrelevant, as
* encryption and decryption are the same.
* @param params the parameters required to set up the cipher.
* @throws IllegalArgumentException if the params argument is
* inappropriate (ie. the key is not 256 bit long).
*/
public void init(boolean forEncryption, CipherParameters params)
throws IllegalArgumentException
{
CipherParameters keyParam = params;
if (params instanceof ParametersWithIV)
{
iv = ((ParametersWithIV)params).getIV();
keyParam = ((ParametersWithIV)params).getParameters();
}
else
{
iv = new byte[0];
}
if (keyParam instanceof KeyParameter)
{
key = ((KeyParameter)keyParam).getKey();
init();
}
else
{
throw new IllegalArgumentException(
"Invalid parameter passed to HC256 init - "
+ params.getClass().getName());
}
initialised = true;
}
private byte[] buf = new byte[4];
private int idx = 0;
private byte getByte()
{
if (idx == 0)
{
int step = step();
buf[0] = (byte)(step & 0xFF);
step >>= 8;
buf[1] = (byte)(step & 0xFF);
step >>= 8;
buf[2] = (byte)(step & 0xFF);
step >>= 8;
buf[3] = (byte)(step & 0xFF);
}
byte ret = buf[idx];
idx = idx + 1 & 0x3;
return ret;
}
public int processBytes(byte[] in, int inOff, int len, byte[] out,
int outOff) throws DataLengthException
{
if (!initialised)
{
throw new IllegalStateException(getAlgorithmName()
+ " not initialised");
}
if ((inOff + len) > in.length)
{
throw new DataLengthException("input buffer too short");
}
if ((outOff + len) > out.length)
{
throw new OutputLengthException("output buffer too short");
}
for (int i = 0; i < len; i++)
{
out[outOff + i] = (byte)(in[inOff + i] ^ getByte());
}
return len;
}
public void reset()
{
init();
}
public byte returnByte(byte in)
{
return (byte)(in ^ getByte());
}
private static int rotateRight(
int x,
int bits)
{
return (x >>> bits) | (x << -bits);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy