| 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; |
| |
| /** |
| * Test whether block ciphers implement reset contract on init, encrypt/decrypt and reset. |
| */ |
| 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]; |
| |
| // Establish baseline answer |
| cipher1.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); |
| |
| // Test encryption resets |
| checkReset(cipher1, params, true, plaintext, ciphertext); |
| |
| // Test decryption resets with fresh instance |
| 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 |
| { |
| // Do initial run |
| byte[] output = new byte[posttext.length]; |
| cipher.processBytes(pretext, 0, pretext.length, output, 0); |
| |
| // Check encrypt resets cipher |
| 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))); |
| } |
| |
| // Check reset resets data |
| 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()); |
| } |
| |
| } |