package org.bouncycastle.crypto.test;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.engines.AESLightEngine;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.bouncycastle.crypto.engines.CAST5Engine;
import org.bouncycastle.crypto.engines.CAST6Engine;
import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.engines.NoekeonEngine;
import org.bouncycastle.crypto.engines.RC6Engine;
import org.bouncycastle.crypto.engines.SEEDEngine;
import org.bouncycastle.crypto.engines.SerpentEngine;
import org.bouncycastle.crypto.engines.TEAEngine;
import org.bouncycastle.crypto.engines.TwofishEngine;
import org.bouncycastle.crypto.engines.XTEAEngine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.modes.GOFBBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
import org.bouncycastle.crypto.modes.PGPCFBBlockCipher;
import org.bouncycastle.crypto.modes.SICBlockCipher;
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 BlockCipherResetTest
extends SimpleTest
{
public String getName()
{
return "Block Cipher Reset";
}
public void performTest()
throws Exception
{
testReset("AESFastEngine", new AESFastEngine(), new AESFastEngine(), new KeyParameter(new byte[16]));
testReset("AESEngine", new AESEngine(), new AESEngine(), new KeyParameter(new byte[16]));
testReset("AESLightEngine", new AESLightEngine(), new AESLightEngine(), new KeyParameter(new byte[16]));
testReset("Twofish", new TwofishEngine(), new TwofishEngine(), new KeyParameter(new byte[16]));
testReset("NoekeonEngine", new NoekeonEngine(), new NoekeonEngine(), new KeyParameter(new byte[16]));
testReset("SerpentEngine", new SerpentEngine(), new SerpentEngine(), new KeyParameter(new byte[16]));
testReset("SEEDEngine", new SEEDEngine(), new SEEDEngine(), new KeyParameter(new byte[16]));
testReset("CAST6Engine", new CAST6Engine(), new CAST6Engine(), new KeyParameter(new byte[16]));
testReset("RC6Engine", new RC6Engine(), new RC6Engine(), new KeyParameter(new byte[16]));
testReset("DESEngine", new DESEngine(), new DESEngine(), new KeyParameter(new byte[8]));
testReset("BlowfishEngine", new BlowfishEngine(), new BlowfishEngine(), new KeyParameter(new byte[8]));
testReset("CAST5Engine", new CAST5Engine(), new CAST5Engine(), new KeyParameter(new byte[8]));
testReset("DESedeEngine", new DESedeEngine(), new DESedeEngine(), new KeyParameter(new byte[24]));
testReset("TEAEngine", new TEAEngine(), new TEAEngine(), new KeyParameter(new byte[16]));
testReset("XTEAEngine", new XTEAEngine(), new XTEAEngine(), new KeyParameter(new byte[16]));
testModeReset("AES/CBC", new CBCBlockCipher(new AESEngine()), new CBCBlockCipher(new AESEngine()),
new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]));
testModeReset("AES/SIC", new SICBlockCipher(new AESEngine()), new SICBlockCipher(new AESEngine()),
new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]));
testModeReset("AES/CFB", new CFBBlockCipher(new AESEngine(), 128), new CFBBlockCipher(new AESEngine(), 128),
new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]));
testModeReset("AES/OFB", new OFBBlockCipher(new AESEngine(), 128), new OFBBlockCipher(new AESEngine(), 128),
new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]));
testModeReset("AES/GCTR", new GOFBBlockCipher(new DESEngine()), new GOFBBlockCipher(new DESEngine()),
new ParametersWithIV(new KeyParameter(new byte[8]), new byte[8]));
testModeReset("AES/OpenPGPCFB", new OpenPGPCFBBlockCipher(new AESEngine()), new OpenPGPCFBBlockCipher(
new AESEngine()), new KeyParameter(new byte[16]));
testModeReset("AES/PGPCFB", new PGPCFBBlockCipher(new AESEngine(), false), new PGPCFBBlockCipher(
new AESEngine(), false), new KeyParameter(new byte[16]));
}
private void testModeReset(String test, BlockCipher cipher1, BlockCipher cipher2, CipherParameters params)
throws InvalidCipherTextException
{
testReset(test, false, cipher1, cipher2, params);
}
private void testReset(String test, BlockCipher cipher1, BlockCipher cipher2, CipherParameters params)
throws InvalidCipherTextException
{
testReset(test, true, cipher1, cipher2, params);
}
private void testReset(String test,
boolean testCryptReset,
BlockCipher cipher1,
BlockCipher cipher2,
CipherParameters params)
throws InvalidCipherTextException
{
cipher1.init(true, params);
byte[] plaintext = new byte[cipher1.getBlockSize()];
byte[] ciphertext = new byte[(cipher1.getAlgorithmName().indexOf("PGPCFBwithIV")) > -1 ? 2 * cipher1.getBlockSize() + 2
: cipher1.getBlockSize()];
crypt(cipher1, true, plaintext, ciphertext);
checkReset(test, testCryptReset, cipher1, params, true, plaintext, ciphertext);
cipher2.init(false, params);
checkReset(test, testCryptReset, cipher2, params, false, ciphertext, plaintext);
}
private void checkReset(String test,
boolean testCryptReset,
BlockCipher cipher,
CipherParameters params,
boolean encrypt,
byte[] pretext,
byte[] posttext)
throws InvalidCipherTextException
{
byte[] output = new byte[posttext.length];
crypt(cipher, encrypt, pretext, output);
if (testCryptReset)
{
crypt(cipher, encrypt, pretext, output);
if (!Arrays.areEqual(output, posttext))
{
fail(test + (encrypt ? " encrypt" : " decrypt") + " did not reset cipher.");
}
}
cipher.processBlock(pretext, 0, output, 0);
cipher.init(encrypt, params);
try
{
crypt(cipher, encrypt, pretext, output);
}
catch (DataLengthException e)
{
fail(test + " init did not reset data.");
}
if (!Arrays.areEqual(output, posttext))
{
fail(test + " init did not reset data.", new String(Hex.encode(posttext)), new String(Hex.encode(output)));
}
cipher.processBlock(pretext, 0, output, 0);
cipher.reset();
try
{
crypt(cipher, encrypt, pretext, output);
}
catch (DataLengthException e)
{
fail(test + " reset did not reset data.");
}
if (!Arrays.areEqual(output, posttext))
{
fail(test + " reset did not reset data.");
}
}
private static void crypt(BlockCipher cipher1, boolean encrypt, byte[] plaintext, byte[] output)
throws InvalidCipherTextException
{
cipher1.processBlock(plaintext, 0, output, 0);
if ((cipher1.getAlgorithmName().indexOf("PGPCFBwithIV") > -1) && !encrypt)
{
cipher1.processBlock(plaintext, cipher1.getBlockSize(), output, 0);
}
}
public static void main(String[] args)
{
runTest(new BlockCipherResetTest());
}
}