org.bouncycastle.crypto.test.SHAKEDigestTest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcprov-ext-jdk15on Show documentation
Show all versions of bcprov-ext-jdk15on Show documentation
The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 to JDK 1.8. Note: this package includes the NTRU encryption algorithms.
package org.bouncycastle.crypto.test;
import java.io.BufferedReader;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import org.bouncycastle.crypto.digests.SHAKEDigest;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
/**
* SHAKE Digest Test
*/
public class SHAKEDigestTest
extends SimpleTest
{
static class MySHAKEDigest extends SHAKEDigest
{
MySHAKEDigest(int bitLength)
{
super(bitLength);
}
int myDoFinal(byte[] out, int outOff, int outLen, byte partialByte, int partialBits)
{
return doFinal(out, outOff, outLen, partialByte, partialBits);
}
}
SHAKEDigestTest()
{
}
public String getName()
{
return "SHAKE";
}
public void performTest() throws Exception
{
testVectors();
}
public void testVectors() throws Exception
{
BufferedReader r = new BufferedReader(new InputStreamReader(
getClass().getResourceAsStream("SHAKETestVectors.txt")));
String line;
while (null != (line = readLine(r)))
{
if (line.length() != 0)
{
TestVector v = readTestVector(r, line);
runTestVector(v);
}
}
r.close();
}
private MySHAKEDigest createDigest(String algorithm) throws Exception
{
if (algorithm.startsWith("SHAKE-"))
{
int bits = parseDecimal(algorithm.substring("SHAKE-".length()));
return new MySHAKEDigest(bits);
}
throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
}
private byte[] decodeBinary(String block)
{
int bits = block.length();
int fullBytes = bits / 8;
int totalBytes = (bits + 7) / 8;
byte[] result = new byte[totalBytes];
for (int i = 0; i < fullBytes; ++i)
{
String byteStr = reverse(block.substring(i * 8, (i + 1) * 8));
result[i] = (byte)parseBinary(byteStr);
}
if (totalBytes > fullBytes)
{
String byteStr = reverse(block.substring(fullBytes * 8));
result[fullBytes] = (byte)parseBinary(byteStr);
}
return result;
}
private int parseBinary(String s)
{
return Integer.parseInt(s, 2);
}
private int parseDecimal(String s)
{
return Integer.parseInt(s);
}
private String readBlock(BufferedReader r) throws IOException
{
StringBuffer b = new StringBuffer();
String line;
while ((line = readBlockLine(r)) != null)
{
b.append(line);
}
return b.toString();
}
private String readBlockLine(BufferedReader r) throws IOException
{
String line = readLine(r);
if (line == null || line.length() == 0)
{
return null;
}
char[] chars = line.toCharArray();
int pos = 0;
for (int i = 0; i != chars.length; i++)
{
if (chars[i] != ' ')
{
chars[pos++] = chars[i];
}
}
return new String(chars, 0, pos);
}
private TestVector readTestVector(BufferedReader r, String header) throws IOException
{
String[] parts = splitAround(header, TestVector.SAMPLE_OF);
String algorithm = parts[0];
int bits = parseDecimal(stripFromChar(parts[1], '-'));
skipUntil(r, TestVector.MSG_HEADER);
String messageBlock = readBlock(r);
if (messageBlock.length() != bits)
{
throw new IllegalStateException("Test vector length mismatch");
}
byte[] message = decodeBinary(messageBlock);
skipUntil(r, TestVector.OUTPUT_HEADER);
byte[] output = Hex.decode(readBlock(r));
return new TestVector(algorithm, bits, message, output);
}
private String readLine(BufferedReader r) throws IOException
{
String line = r.readLine();
return line == null ? null : stripFromChar(line, '#').trim();
}
private String requireLine(BufferedReader r) throws IOException
{
String line = readLine(r);
if (line == null)
{
throw new EOFException();
}
return line;
}
private String reverse(String s)
{
return new StringBuffer(s).reverse().toString();
}
private void runTestVector(TestVector v) throws Exception
{
int bits = v.getBits();
int partialBits = bits % 8;
byte[] expected = v.getOutput();
// System.out.println(v.getAlgorithm() + " " + bits + "-bit");
// System.out.println(Hex.toHexString(v.getMessage()).toUpperCase());
// System.out.println(Hex.toHexString(expected).toUpperCase());
int outLen = expected.length;
MySHAKEDigest d = createDigest(v.getAlgorithm());
byte[] output = new byte[outLen];
byte[] m = v.getMessage();
if (partialBits == 0)
{
d.update(m, 0, m.length);
d.doFinal(output, 0, outLen);
}
else
{
d.update(m, 0, m.length - 1);
d.myDoFinal(output, 0, outLen, m[m.length - 1], partialBits);
}
if (!Arrays.areEqual(expected, output))
{
fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector hash mismatch");
// System.err.println(v.getAlgorithm() + " " + v.getBits() + "-bit test vector hash mismatch");
// System.err.println(Hex.toHexString(output).toUpperCase());
}
if (partialBits == 0)
{
d = createDigest(v.getAlgorithm());
m = v.getMessage();
d.update(m, 0, m.length);
d.doOutput(output, 0, outLen / 2);
d.doOutput(output, outLen / 2, output.length - outLen / 2);
if (!Arrays.areEqual(expected, output))
{
fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector extended hash mismatch");
}
try
{
d.update((byte)0x01);
fail("no exception");
}
catch (IllegalStateException e)
{
isTrue("wrong exception", "attempt to absorb while squeezing".equals(e.getMessage()));
}
d = createDigest(v.getAlgorithm());
m = v.getMessage();
d.update(m, 0, m.length);
d.doOutput(output, 0, outLen / 2);
d.doFinal(output, outLen / 2, output.length - outLen / 2);
if (!Arrays.areEqual(expected, output))
{
fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector extended doFinal hash mismatch");
}
d.update((byte)0x01); // this should be okay as we've reset on doFinal()
}
}
private void skipUntil(BufferedReader r, String header) throws IOException
{
String line;
do
{
line = requireLine(r);
}
while (line.length() == 0);
if (!line.equals(header))
{
throw new IOException("Expected: " + header);
}
}
private String[] splitAround(String s, String separator)
{
List strings = new ArrayList();
String remaining = s;
int index;
while ((index = remaining.indexOf(separator)) > 0)
{
strings.add(remaining.substring(0, index));
remaining = remaining.substring(index + separator.length());
}
strings.add(remaining);
return (String[])strings.toArray(new String[strings.size()]);
}
private String stripFromChar(String s, char c)
{
int i = s.indexOf(c);
if (i >= 0)
{
s = s.substring(0, i);
}
return s;
}
public static void main(
String[] args)
{
runTest(new SHAKEDigestTest());
}
private static class TestVector
{
private static String SAMPLE_OF = " sample of ";
private static String MSG_HEADER = "Msg as bit string";
private static String OUTPUT_HEADER = "Output val is";
private String algorithm;
private int bits;
private byte[] message;
private byte[] output;
private TestVector(String algorithm, int bits, byte[] message, byte[] output)
{
this.algorithm = algorithm;
this.bits = bits;
this.message = message;
this.output = output;
}
public String getAlgorithm()
{
return algorithm;
}
public int getBits()
{
return bits;
}
public byte[] getMessage()
{
return message;
}
public byte[] getOutput()
{
return output;
}
}
}