package org.bouncycastle.crypto.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.StreamCipher;
import org.bouncycastle.crypto.engines.HC128Engine;
import org.bouncycastle.crypto.engines.HC256Engine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
public class HCFamilyVecTest
extends SimpleTest
{
private static class PeekableLineReader extends BufferedReader
{
public PeekableLineReader(Reader r) throws IOException
{
super(r);
peek = super.readLine();
}
public String peekLine()
{
return peek;
}
public String readLine() throws IOException
{
String tmp = peek;
peek = super.readLine();
return tmp;
}
private String peek;
}
public String getName()
{
return "HC-128 and HC-256 (ecrypt)";
}
public void performTest() throws Exception
{
runTests(new HC128Engine(), "ecrypt_HC-128.txt");
runTests(new HC256Engine(), "ecrypt_HC-256_128K_128IV.txt");
runTests(new HC256Engine(), "ecrypt_HC-256_256K_128IV.txt");
runTests(new HC256Engine(), "ecrypt_HC-256_128K_256IV.txt");
runTests(new HC256Engine(), "ecrypt_HC-256_256K_256IV.txt");
}
private void runTests(StreamCipher hc, String fileName) throws IOException
{
Reader resource = new InputStreamReader(getClass().getResourceAsStream(fileName));
PeekableLineReader r = new PeekableLineReader(resource);
runAllVectors(hc, fileName, r);
}
private void runAllVectors(StreamCipher hc, String fileName, PeekableLineReader r)
throws IOException
{
for (;;)
{
String line = r.readLine();
if (line == null)
{
break;
}
line = line.trim();
if (line.startsWith("Set "))
{
runVector(hc, fileName, r, dellChar(line, ':'));
}
}
}
private String dellChar(String s, char c)
{
StringBuffer b = new StringBuffer();
for (int i = 0; i != s.length(); i++)
{
if (s.charAt(i) != c)
{
b.append(s.charAt(i));
}
}
return b.toString();
}
private void runVector(StreamCipher hc, String fileName, PeekableLineReader r, String vectorName)
throws IOException
{
String hexKey = readBlock(r);
String hexIV = readBlock(r);
CipherParameters cp = new KeyParameter(Hex.decode(hexKey));
cp = new ParametersWithIV(cp, Hex.decode(hexIV));
hc.init(true, cp);
byte[] input = new byte[64];
byte[] output = new byte[64];
byte[] digest = new byte[64];
int pos = 0;
for (;;)
{
String line1 = r.peekLine().trim();
int equalsPos = line1.indexOf('=');
String lead = line1.substring(0, equalsPos - 1);
String hexData = readBlock(r);
byte[] data = Hex.decode(hexData);
if (lead.equals("xor-digest"))
{
if (!Arrays.areEqual(data, digest))
{
fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead);
}
break;
}
int posA = lead.indexOf('[');
int posB = lead.indexOf("..");
int posC = lead.indexOf(']');
int start = Integer.parseInt(lead.substring(posA + 1, posB));
int end = Integer.parseInt(lead.substring(posB + 2, posC));
if (start % 64 != 0 || (end - start != 63))
{
throw new IllegalStateException(vectorName + ": " + lead + " not on 64 byte boundaries");
}
while (pos < end)
{
hc.processBytes(input, 0, input.length, output, 0);
xor(digest, output);
pos += 64;
}
if (!Arrays.areEqual(data, output))
{
fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead);
}
}
}
private static String readBlock(PeekableLineReader r) throws IOException
{
String first = r.readLine().trim();
String result = first.substring(first.lastIndexOf(' ') + 1);
for (;;)
{
String peek = r.peekLine().trim();
if (peek.length() < 1 || peek.indexOf('=') >= 0)
{
break;
}
result += r.readLine().trim();
}
return result;
}
private static void xor(byte[] digest, byte[] block)
{
for (int i = 0; i < digest.length; ++i)
{
digest[i] ^= block[i];
}
}
public static void main(String[] args)
{
runTest(new HCFamilyVecTest());
}
}