package org.bouncycastle.crypto.test;
import java.security.SecureRandom;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.StreamCipher;
import org.bouncycastle.crypto.engines.ChaChaEngine;
import org.bouncycastle.crypto.engines.Grain128Engine;
import org.bouncycastle.crypto.engines.Grainv1Engine;
import org.bouncycastle.crypto.engines.HC128Engine;
import org.bouncycastle.crypto.engines.HC256Engine;
import org.bouncycastle.crypto.engines.ISAACEngine;
import org.bouncycastle.crypto.engines.RC4Engine;
import org.bouncycastle.crypto.engines.Salsa20Engine;
import org.bouncycastle.crypto.engines.XSalsa20Engine;
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 StreamCipherResetTest
extends SimpleTest
{
public String getName()
{
return "Stream Cipher Reset";
}
public void performTest()
throws Exception
{
testReset(new Salsa20Engine(), new Salsa20Engine(), new ParametersWithIV(new KeyParameter(random(32)),
random(8)));
testReset(new Salsa20Engine(), new Salsa20Engine(), new ParametersWithIV(new KeyParameter(random(16)),
random(8)));
testReset(new XSalsa20Engine(), new XSalsa20Engine(), new ParametersWithIV(new KeyParameter(random(32)),
random(24)));
testReset(new ChaChaEngine(), new ChaChaEngine(), new ParametersWithIV(new KeyParameter(random(32)), random(8)));
testReset(new ChaChaEngine(), new ChaChaEngine(), new ParametersWithIV(new KeyParameter(random(16)), random(8)));
testReset(new RC4Engine(), new RC4Engine(), new KeyParameter(random(16)));
testReset(new ISAACEngine(), new ISAACEngine(), new KeyParameter(random(16)));
testReset(new HC128Engine(), new HC128Engine(), new ParametersWithIV(new KeyParameter(random(16)), random(16)));
testReset(new HC256Engine(), new HC256Engine(), new ParametersWithIV(new KeyParameter(random(16)), random(16)));
testReset(new Grainv1Engine(), new Grainv1Engine(), new ParametersWithIV(new KeyParameter(random(16)),
random(8)));
testReset(new Grain128Engine(), new Grain128Engine(), new ParametersWithIV(new KeyParameter(random(16)),
random(12)));
}
private static final SecureRandom RAND = new SecureRandom();
private byte[] random(int size)
{
final byte[] data = new byte[size];
RAND.nextBytes(data);
return data;
}
private void testReset(StreamCipher cipher1, StreamCipher cipher2, CipherParameters params)
throws InvalidCipherTextException
{
cipher1.init(true, params);
byte[] plaintext = new byte[1023];
byte[] ciphertext = new byte[plaintext.length];
cipher1.processBytes(plaintext, 0, plaintext.length, ciphertext, 0);
checkReset(cipher1, params, true, plaintext, ciphertext);
cipher2.init(false, params);
checkReset(cipher2, params, false, ciphertext, plaintext);
}
private void checkReset(StreamCipher cipher,
CipherParameters params,
boolean encrypt,
byte[] pretext,
byte[] posttext)
throws InvalidCipherTextException
{
byte[] output = new byte[posttext.length];
cipher.processBytes(pretext, 0, pretext.length, output, 0);
cipher.init(encrypt, params);
try
{
cipher.processBytes(pretext, 0, pretext.length, output, 0);
}
catch (Exception e)
{
fail(cipher.getAlgorithmName() + " init did not reset: " + e.getMessage());
}
if (!Arrays.areEqual(output, posttext))
{
fail(cipher.getAlgorithmName() + " init did not reset.", new String(Hex.encode(posttext)),
new String(Hex.encode(output)));
}
cipher.reset();
try
{
cipher.processBytes(pretext, 0, pretext.length, output, 0);
}
catch (Exception e)
{
fail(cipher.getAlgorithmName() + " reset did not reset: " + e.getMessage());
}
if (!Arrays.areEqual(output, posttext))
{
fail(cipher.getAlgorithmName() + " reset did not reset.");
}
}
public static void main(String[] args)
{
runTest(new StreamCipherResetTest());
}
}