Repository: commons-crypto Updated Branches: refs/heads/master 92d129aa5 -> 4920d2729
http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java b/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java new file mode 100644 index 0000000..e48d548 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/cipher/AbstractCipherTest.java @@ -0,0 +1,242 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.cipher; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.GeneralSecurityException; +import java.security.SecureRandom; +import java.util.Properties; +import java.util.Random; +import javax.xml.bind.DatatypeConverter; + +import org.apache.commons.crypto.conf.ConfigurationKeys; +import org.apache.commons.crypto.utils.ReflectionUtils; +import org.apache.commons.crypto.utils.Utils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public abstract class AbstractCipherTest { + + // data + public static final int BYTEBUFFER_SIZE = 1000; + public String[] cipherTests = null; + Properties props = null; + String cipherClass = null; + CipherTransformation[] transformations = null; + + // cipher + static final byte[] KEY = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + static final byte[] IV = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}; + Cipher enc, dec; + + @Before + public void setup() { + init(); + Utils.checkNotNull(cipherClass); + Utils.checkNotNull(transformations); + props = new Properties(); + props.setProperty(ConfigurationKeys.CHIMERA_CRYPTO_CIPHER_CLASSES_KEY, + cipherClass); + } + + protected abstract void init() ; + + @Test + public void cryptoTest() throws GeneralSecurityException, IOException { + for (CipherTransformation tran : transformations) { + /** uses the small data set in {@link TestData} */ + cipherTests = TestData.getTestData(tran); + for (int i = 0; i != cipherTests.length; i += 5) { + byte[] key = DatatypeConverter.parseHexBinary(cipherTests[i + 1]); + byte[] iv = DatatypeConverter.parseHexBinary(cipherTests[i + 2]); + + byte[] inputBytes = DatatypeConverter.parseHexBinary(cipherTests[i + 3]); + byte[] outputBytes = DatatypeConverter.parseHexBinary(cipherTests[i + 4]); + + ByteBuffer inputBuffer = ByteBuffer.allocateDirect(inputBytes.length); + ByteBuffer outputBuffer = ByteBuffer.allocateDirect(outputBytes.length); + inputBuffer.put(inputBytes); + inputBuffer.flip(); + outputBuffer.put(outputBytes); + outputBuffer.flip(); + + byteBufferTest(tran,key, iv, inputBuffer, outputBuffer); + byteArrayTest(tran, key, iv, inputBytes, outputBytes); + } + + /** uses randomly generated big data set */ + byteArrayTest(tran, KEY, IV); + } + } + + private void byteBufferTest(CipherTransformation transformation, byte[] key, + byte[] iv, + ByteBuffer input, ByteBuffer output) throws + GeneralSecurityException, IOException { + ByteBuffer decResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE); + ByteBuffer encResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE); + Cipher enc, dec; + + enc = getCipher(transformation); + dec = getCipher(transformation); + + try { + enc.init(Cipher.ENCRYPT_MODE, key, iv); + } catch (Exception e) { + Assert.fail("AES failed initialisation - " + e.toString()); + } + + try { + dec.init(Cipher.DECRYPT_MODE, key, iv); + } catch (Exception e) { + Assert.fail("AES failed initialisation - " + e.toString()); + } + + // + // encryption pass + // + enc.doFinal(input, encResult); + input.flip(); + encResult.flip(); + if (!output.equals(encResult)) { + byte[] b = new byte[output.remaining()]; + output.get(b); + byte[] c = new byte[encResult.remaining()]; + encResult.get(c); + Assert.fail("AES failed encryption - expected " + new String( + DatatypeConverter + .printHexBinary(b)) + " got " + new String( + DatatypeConverter.printHexBinary(c))); + } + + // + // decryption pass + // + dec.doFinal(encResult, decResult); + decResult.flip(); + + if (!input.equals(decResult)) { + byte[] inArray = new byte[input.remaining()]; + byte[] decResultArray = new byte[decResult.remaining()]; + input.get(inArray); + decResult.get(decResultArray); + Assert.fail(); + } + } + + /** test byte array whose data is planned in {@link TestData} */ + private void byteArrayTest(CipherTransformation transformation, byte[] key, + byte[] iv, byte[] input, byte[] output) throws GeneralSecurityException { + resetCipher(transformation, key, iv); + int blockSize = transformation.getAlgorithmBlockSize(); + + byte[] temp = new byte[input.length + blockSize]; + int n = enc.doFinal(input, 0, input.length, temp, 0); + byte[] cipherText = new byte[n]; + System.arraycopy(temp, 0, cipherText, 0, n); + Assert.assertArrayEquals("byte array encryption error.", output, cipherText); + + temp = new byte[cipherText.length + blockSize]; + int m = dec.doFinal(cipherText, 0, cipherText.length, temp, 0); + byte[] plainText = new byte[m]; + System.arraycopy(temp, 0, plainText, 0, m); + Assert.assertArrayEquals("byte array decryption error.", input, plainText); + } + + /** test byte array whose data is randomly generated */ + private void byteArrayTest(CipherTransformation transformation, byte[] key, + byte[] iv) throws GeneralSecurityException { + int blockSize = transformation.getAlgorithmBlockSize(); + + // AES_CBC_NOPADDING only accepts data whose size is the multiple of block size + int[] dataLenList = (transformation == CipherTransformation.AES_CBC_NOPADDING) + ? new int[] {10 * 1024} : new int[] {10 * 1024, 10 * 1024 - 3}; + for (int dataLen : dataLenList) { + byte[] plainText = new byte[dataLen]; + Random random = new SecureRandom(); + random.nextBytes(plainText); + byte[] cipherText = new byte[dataLen + blockSize]; + + // check update method with inputs whose sizes are the multiple of block size or not + int[] bufferLenList = new int[] {2 * 1024 - 128, 2 * 1024 - 125}; + for (int bufferLen : bufferLenList) { + resetCipher(transformation, key, iv); + + int offset = 0; + // encrypt (update + doFinal) the data + int cipherPos = 0; + for (int i = 0; i < dataLen / bufferLen; i ++) { + cipherPos += enc.update(plainText, offset, bufferLen, cipherText, cipherPos); + offset += bufferLen; + } + cipherPos += enc.doFinal(plainText, offset, dataLen % bufferLen, cipherText, cipherPos); + + offset = 0; + // decrypt (update + doFinal) the data + byte[] realPlainText = new byte[cipherPos + blockSize]; + int plainPos = 0; + for (int i = 0; i < cipherPos / bufferLen; i ++) { + plainPos += dec.update(cipherText, offset, bufferLen, realPlainText, plainPos); + offset += bufferLen; + } + plainPos += dec.doFinal(cipherText, offset, cipherPos % bufferLen, realPlainText, plainPos); + + // verify + Assert.assertEquals("random byte array length changes after transformation", + dataLen, plainPos); + + byte[] shrinkPlainText = new byte[plainPos]; + System.arraycopy(realPlainText, 0, shrinkPlainText, 0, plainPos); + Assert.assertArrayEquals("random byte array contents changes after transformation", + plainText, shrinkPlainText); + } + } + } + + private void resetCipher(CipherTransformation transformation, byte[] key, byte[] iv) { + enc = getCipher(transformation); + dec = getCipher(transformation); + + try { + enc.init(Cipher.ENCRYPT_MODE, key, iv); + } catch (Exception e) { + Assert.fail("AES failed initialisation - " + e.toString()); + } + + try { + dec.init(Cipher.DECRYPT_MODE, key, iv); + } catch (Exception e) { + Assert.fail("AES failed initialisation - " + e.toString()); + } + } + + private Cipher getCipher(CipherTransformation transformation) { + try { + return (Cipher) ReflectionUtils + .newInstance(ReflectionUtils.getClassByName(cipherClass), props, + transformation); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/cipher/JceCipherTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/cipher/JceCipherTest.java b/src/test/java/org/apache/commons/crypto/cipher/JceCipherTest.java new file mode 100644 index 0000000..c40aaa1 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/cipher/JceCipherTest.java @@ -0,0 +1,32 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.crypto.cipher; + +public class JceCipherTest extends AbstractCipherTest { + + @Override + public void init() { + transformations = new CipherTransformation[]{ + CipherTransformation.AES_CBC_NOPADDING, + CipherTransformation.AES_CBC_PKCS5PADDING, + CipherTransformation.AES_CTR_NOPADDING}; + cipherClass = JceCipher.class.getName(); + } + +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/cipher/OpensslCipherTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/cipher/OpensslCipherTest.java b/src/test/java/org/apache/commons/crypto/cipher/OpensslCipherTest.java new file mode 100644 index 0000000..c1ef849 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/cipher/OpensslCipherTest.java @@ -0,0 +1,165 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.crypto.cipher; + +import java.nio.ByteBuffer; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +public class OpensslCipherTest extends AbstractCipherTest { + + @Override + public void init() { + transformations = new CipherTransformation[]{ + CipherTransformation.AES_CBC_NOPADDING, + CipherTransformation.AES_CBC_PKCS5PADDING, + CipherTransformation.AES_CTR_NOPADDING}; + cipherClass = OpensslCipher.class.getName(); + } + + @Test(expected = NoSuchAlgorithmException.class, timeout=120000) + public void testInvalidAlgorithm() throws Exception { + Assume.assumeTrue(Openssl.getLoadingFailureReason() == null); + + try { + Openssl cipher = Openssl.getInstance("AES2/CTR/NoPadding"); + Assert.fail("Should specify correct algorithm."); + } catch (NoSuchAlgorithmException e) { + Assert.assertTrue(e.getMessage().contains("Doesn't support algorithm: AES2 and mode: CTR")); + throw e; + } + } + + @Test(expected = NoSuchPaddingException.class, timeout=120000) + public void testInvalidPadding() throws Exception { + Assume.assumeTrue(Openssl.getLoadingFailureReason() == null); + + try { + Openssl cipher = Openssl.getInstance("AES/CTR/NoPadding2"); + Assert.fail("Should specify correct padding."); + } catch (NoSuchPaddingException e) { + Assert.assertTrue(e.getMessage().contains("Doesn't support padding: NoPadding2")); + throw e; + } + } + + @Test(expected = NoSuchAlgorithmException.class, timeout=120000) + public void testInvalidMode() throws Exception { + try { + Assume.assumeTrue(Openssl.getLoadingFailureReason() == null); + Openssl cipher = Openssl.getInstance("AES/CTR2/NoPadding"); + Assert.fail("java.security.NoSuchAlgorithmException should be thrown."); + } catch (NoSuchAlgorithmException e) { + Assert.assertTrue(e.getMessage().contains("Doesn't support algorithm: AES and mode: CTR2")); + throw e; + } + } + + @Test(timeout=120000) + public void testUpdateArguments() throws Exception { + Assume.assumeTrue(Openssl.getLoadingFailureReason() == null); + Openssl cipher = Openssl.getInstance(CipherTransformation.AES_CTR_NOPADDING.getName()); + Assert.assertNotNull(cipher); + + cipher.init(Openssl.ENCRYPT_MODE, KEY, IV); + + // Require direct buffers + ByteBuffer input = ByteBuffer.allocate(1024); + ByteBuffer output = ByteBuffer.allocate(1024); + + try { + cipher.update(input, output); + Assert.fail("Input and output buffer should be direct buffer."); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("Direct buffers are required")); + } + + // Output buffer length should be sufficient to store output data + input = ByteBuffer.allocateDirect(1024); + output = ByteBuffer.allocateDirect(1000); + try { + cipher.update(input, output); + Assert.fail("Output buffer length should be sufficient " + + "to store output data"); + } catch (ShortBufferException e) { + Assert.assertTrue(e.getMessage().contains("Output buffer is not sufficient")); + } + } + + @Test(timeout=120000) + public void testDoFinalArguments() throws Exception { + Assume.assumeTrue(Openssl.getLoadingFailureReason() == null); + Openssl cipher = Openssl.getInstance(CipherTransformation.AES_CTR_NOPADDING.getName()); + Assert.assertNotNull(cipher); + + cipher.init(Openssl.ENCRYPT_MODE, KEY, IV); + + // Require direct buffer + ByteBuffer output = ByteBuffer.allocate(1024); + + try { + cipher.doFinal(output); + Assert.fail("Output buffer should be direct buffer."); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("Direct buffer is required")); + } + } + + @Test(expected = InvalidKeyException.class, timeout=120000) + public void testInvalidKey() throws Exception { + Assume.assumeTrue(Openssl.getLoadingFailureReason() == null); + Openssl cipher = Openssl.getInstance(CipherTransformation.AES_CTR_NOPADDING.getName()); + Assert.assertNotNull(cipher); + + final byte[] invalidKey = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11}; + try { + cipher.init(Openssl.ENCRYPT_MODE, invalidKey, IV); + Assert.fail("java.security.InvalidKeyException should be thrown."); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Invalid key length.")); + throw e; + } + } + + @Test(expected = InvalidAlgorithmParameterException.class, timeout=120000) + public void testInvalidIV() throws Exception { + Assume.assumeTrue(Openssl.getLoadingFailureReason() == null); + Openssl cipher = Openssl.getInstance(CipherTransformation.AES_CTR_NOPADDING.getName()); + Assert.assertNotNull(cipher); + + final byte[] invalidIV = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11}; + try { + cipher.init(Openssl.ENCRYPT_MODE, KEY, invalidIV); + Assert.fail("java.security.InvalidAlgorithmParameterException should be thrown."); + } catch (Exception e) { + Assert.assertTrue(e.getMessage().contains("Wrong IV length.")); + throw e; + } + } + +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/cipher/TestData.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/cipher/TestData.java b/src/test/java/org/apache/commons/crypto/cipher/TestData.java new file mode 100644 index 0000000..2f8da8f --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/cipher/TestData.java @@ -0,0 +1,160 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.cipher; + +import java.util.HashMap; +import java.util.Map; + +public class TestData { + + private static String[] CBCNoPaddingTests = { + /* + * key_len,key,iv,plainText,cipherText + */ + "128", + "2b7e151628aed2a6abf7158809cf4f3c", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "7649abac8119b246cee98e9b12e9197d", + + "128", + "2b7e151628aed2a6abf7158809cf4f3c", + "7649ABAC8119B246CEE98E9B12E9197D", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "5086cb9b507219ee95db113a917678b2", + + "192", + "603deb1015ca71be2b73aef0857d77811f352c073b6108d7", + "9CFC4E967EDB808D679F777BC6702C7D", + "30c81c46a35ce411e5fbc1191a0a52ef", + "78C57E3F543A18F472756DAC2F018523", + + "192", + "603deb1015ca71be2b73aef0857d77811f352c073b6108d7", + "39F23369A9D9BACFA530E26304231461", + "f69f2445df4f9b17ad2b417be66c3710", + "79ECA9610F0B9AAFB8C7C2D655047A41", + + "256", + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "000102030405060708090a0b0c0d0e0f", + "6bc1bee22e409f96e93d7e117393172a", + "f58c4c04d6e5f1ba779eabfb5f7bfbd6", + + "256", + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "F58C4C04D6E5F1BA779EABFB5F7BFBD6", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "9cfc4e967edb808d679f777bc6702c7d" + }; + + private static String[] CBCPKCS5PaddingTests = { + /* + * key_len,key,iv,plainText,cipherText + */ + //Test#0 for input of 6 bytes + "128", + "ac5800ac3cb59c7c14f36019e43b44fe", + "f013ce1ec901b5b60a85a986b3b72eba", + "f6cee5ff28fd", + "e8a846fd9718507371604504d4ca1ac7", + + //Test#0 for input of 15 bytes + "128", + "0784fa652e733cb699f250b0df2c4b41", + "106519760fb3ef97e1ccea073b27122d", + "6842455a2992c2e5193056a5524075", + "56a8e0c3ee3315f913693c0ca781e917", + + //Test#0 for input of 16 bytes + "128", + "04952c3fcf497a4d449c41e8730c5d9a", + "53549bf7d5553b727458c1abaf0ba167", + "c9a44f6f75e98ddbca7332167f5c45e3", + "7fa290322ca7a1a04b61a1147ff20fe66fde58510a1d0289d11c0ddf6f4decfd", + + //Test#0 for input of 32 bytes + "128", + "2ae7081caebe54909820620a44a60a0f", + "fc5e783fbe7be12f58b1f025d82ada50", + "1ba93ee6f83752df47909585b3f28e56693f89e169d3093eee85175ea3a46cd3", + "7944957a99e473e2c07eb496a83ec4e55db2fb44ebdd42bb611e0def29b23a73ac37eb0f4f5d86f090f3ddce3980425a", + + //Test#0 for input of 33 bytes + "128", + "898be9cc5004ed0fa6e117c9a3099d31", + "9dea7621945988f96491083849b068df", + "0397f4f6820b1f9386f14403be5ac16e50213bd473b4874b9bcbf5f318ee686b1d", + "e232cd6ef50047801ee681ec30f61d53cfd6b0bca02fd03c1b234baa10ea82ac9dab8b960926433a19ce6dea08677e34"}; + + private static String[] cipherCTRTests = { + /* + * key_len,key,iv,plainText,cipherText + */ + "128", + "2b7e151628aed2a6abf7158809cf4f3c", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172a", + "874d6191b620e3261bef6864990db6ce", + + "128", + "2b7e151628aed2a6abf7158809cf4f3c", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdff00", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "9806f66b7970fdff8617187bb9fffdff", + + //Test for input of 15 bytes + "128", + "2b7e151628aed2a6abf7158809cf4f3c", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdff01", + "30c81c46a35ce411e5fbc1191a0a52", + "5ae4df3edbd5d35e5b4f09020db03e", + + "256", + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "6bc1bee22e409f96e93d7e117393172a", + "601ec313775789a5b7a7f504bbf3d228", + + "256", + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdff00", + "ae2d8a571e03ac9c9eb76fac45af8e51", + "f443e3ca4d62b59aca84e990cacaf5c5", + + //Test for input of 15 bytes + "256", + "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4", + "f0f1f2f3f4f5f6f7f8f9fafbfcfdff01", + "30c81c46a35ce411e5fbc1191a0a52", + "2b0930daa23de94ce87017ba2d8498" }; + + private static Map<CipherTransformation, String[]> testData = + new HashMap<CipherTransformation, String[]>(); + + static { + testData.put(CipherTransformation.AES_CBC_NOPADDING, CBCNoPaddingTests); + testData.put(CipherTransformation.AES_CBC_PKCS5PADDING, + CBCPKCS5PaddingTests); + testData.put(CipherTransformation.AES_CTR_NOPADDING, cipherCTRTests); + } + + public static String[] getTestData(CipherTransformation transformation) { + return testData.get(transformation); + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java b/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java new file mode 100644 index 0000000..6c6f692 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/random/AbstractRandomTest.java @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.random; + +import java.io.IOException; +import java.util.Arrays; + +import org.junit.Test; + +public abstract class AbstractRandomTest { + + public abstract SecureRandom getSecureRandom() throws IOException; + + @Test(timeout=120000) + public void testRandomBytes() throws Exception { + SecureRandom random = getSecureRandom(); + // len = 16 + checkRandomBytes(random, 16); + // len = 32 + checkRandomBytes(random, 32); + // len = 128 + checkRandomBytes(random, 128); + // len = 256 + checkRandomBytes(random, 256); + random.close(); + } + + /** + * Test will timeout if secure random implementation always returns a + * constant value. + */ + private void checkRandomBytes(SecureRandom random, int len) { + byte[] bytes = new byte[len]; + byte[] bytes1 = new byte[len]; + random.nextBytes(bytes); + random.nextBytes(bytes1); + + while (Arrays.equals(bytes, bytes1)) { + random.nextBytes(bytes1); + } + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java b/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java new file mode 100644 index 0000000..a85b7f7 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/random/TestJavaSecureRandom.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.random; + +import java.io.IOException; +import java.util.Properties; + +import org.apache.commons.crypto.conf.ConfigurationKeys; +import static junit.framework.Assert.fail; + +public class TestJavaSecureRandom extends AbstractRandomTest { + + @Override + public SecureRandom getSecureRandom() throws IOException { + Properties props = new Properties(); + props.setProperty(ConfigurationKeys.CHIMERA_CRYPTO_SECURE_RANDOM_CLASSES_KEY, + JavaSecureRandom.class.getName()); + SecureRandom random = SecureRandomFactory.getSecureRandom(props); + if ( !(random instanceof JavaSecureRandom)) { + fail("The SecureRandom should be: " + JavaSecureRandom.class.getName()); + } + return random; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java b/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java new file mode 100644 index 0000000..514d547 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/random/TestOpensslSecureRandom.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.random; + +import java.io.IOException; +import java.util.Properties; + +import org.apache.commons.crypto.conf.ConfigurationKeys; +import static junit.framework.Assert.fail; + +public class TestOpensslSecureRandom extends AbstractRandomTest { + + @Override + public SecureRandom getSecureRandom() throws IOException { + Properties props = new Properties(); + props.setProperty(ConfigurationKeys.CHIMERA_CRYPTO_SECURE_RANDOM_CLASSES_KEY, + OpensslSecureRandom.class.getName()); + SecureRandom random = SecureRandomFactory.getSecureRandom(props); + if ( !(random instanceof OpensslSecureRandom)) { + fail("The SecureRandom should be: " + OpensslSecureRandom.class.getName()); + } + return random; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java b/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java new file mode 100644 index 0000000..138f766 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/random/TestOsSecureRandom.java @@ -0,0 +1,29 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.random; + +import java.io.IOException; +import java.util.Properties; + +public class TestOsSecureRandom extends AbstractRandomTest{ + + @Override + public SecureRandom getSecureRandom() throws IOException { + return new OsSecureRandom(new Properties()); + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java new file mode 100644 index 0000000..fe73f00 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/stream/AbstractCryptoStreamTest.java @@ -0,0 +1,456 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.stream; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.security.SecureRandom; +import java.util.Properties; +import java.util.Random; + +import org.apache.commons.crypto.cipher.Cipher; +import org.apache.commons.crypto.cipher.CipherTransformation; +import org.apache.commons.crypto.cipher.JceCipher; +import org.apache.commons.crypto.cipher.Openssl; +import org.apache.commons.crypto.cipher.OpensslCipher; +import org.apache.commons.crypto.utils.ReflectionUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public abstract class AbstractCryptoStreamTest { + private static final Log LOG= LogFactory.getLog(AbstractCryptoStreamTest.class); + + private final int dataLen = 20000; + private byte[] data = new byte[dataLen]; + private byte[] encData; + private Properties props = new Properties(); + protected byte[] key = new byte[16]; + private byte[] iv = new byte[16]; + private int count = 10000; + protected static int defaultBufferSize = 8192; + protected static int smallBufferSize = 1024; + + private final String jceCipherClass = JceCipher.class.getName(); + private final String opensslCipherClass = OpensslCipher.class.getName(); + protected CipherTransformation transformation; + + public abstract void setUp() throws IOException; + + @Before + public void before() throws IOException { + Random random = new SecureRandom(); + random.nextBytes(data); + random.nextBytes(key); + random.nextBytes(iv); + setUp(); + prepareData(); + } + + /** Test skip. */ + @Test(timeout=120000) + public void testSkip() throws Exception { + doSkipTest(jceCipherClass, false); + doSkipTest(opensslCipherClass, false); + + doSkipTest(jceCipherClass, true); + doSkipTest(opensslCipherClass, true); + } + + /** Test byte buffer read with different buffer size. */ + @Test(timeout=120000) + public void testByteBufferRead() throws Exception { + doByteBufferRead(jceCipherClass, false); + doByteBufferRead(opensslCipherClass, false); + + doByteBufferRead(jceCipherClass, true); + doByteBufferRead(opensslCipherClass, true); + } + + /** Test byte buffer write. */ + @Test(timeout=120000) + public void testByteBufferWrite() throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + doByteBufferWrite(jceCipherClass, baos, false); + doByteBufferWrite(opensslCipherClass, baos, false); + + doByteBufferWrite(jceCipherClass, baos, true); + doByteBufferWrite(opensslCipherClass, baos, true); + } + + private void doSkipTest(String cipherClass, boolean withChannel) throws IOException { + InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + byte[] result = new byte[dataLen]; + int n1 = readAll(in, result, 0, dataLen / 3); + + long skipped = in.skip(dataLen / 3); + int n2 = readAll(in, result, 0, dataLen); + + Assert.assertEquals(dataLen, n1 + skipped + n2); + byte[] readData = new byte[n2]; + System.arraycopy(result, 0, readData, 0, n2); + byte[] expectedData = new byte[n2]; + System.arraycopy(data, dataLen - n2, expectedData, 0, n2); + Assert.assertArrayEquals(readData, expectedData); + + try { + skipped = in.skip(-3); + Assert.fail("Skip Negative length should fail."); + } catch (IllegalArgumentException e) { + Assert.assertTrue(e.getMessage().contains("Negative skip length")); + } + + // Skip after EOF + skipped = in.skip(3); + Assert.assertEquals(skipped, 0); + + in.close(); + } + + private void doByteBufferRead(String cipherClass, boolean withChannel) throws Exception { + // Default buffer size, initial buffer position is 0 + InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + ByteBuffer buf = ByteBuffer.allocate(dataLen + 100); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Default buffer size, initial buffer position is not 0 + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + + // Small buffer size, initial buffer position is 0 + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), smallBufferSize, iv, withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Small buffer size, initial buffer position is not 0 + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), smallBufferSize, iv, withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + + // Direct buffer, default buffer size, initial buffer position is 0 + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + buf = ByteBuffer.allocateDirect(dataLen + 100); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Direct buffer, default buffer size, initial buffer position is not 0 + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + + // Direct buffer, small buffer size, initial buffer position is 0 + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), smallBufferSize, iv, withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 0); + in.close(); + + // Direct buffer, small buffer size, initial buffer position is not 0 + in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), smallBufferSize, iv, withChannel); + buf.clear(); + byteBufferReadCheck(in, buf, 11); + in.close(); + } + + private void doByteBufferWrite(String cipherClass, ByteArrayOutputStream baos, + boolean withChannel) + throws Exception { + baos.reset(); + CryptoOutputStream out = + getCryptoOutputStream(baos, getCipher(cipherClass), defaultBufferSize, + iv, withChannel); + ByteBuffer buf = ByteBuffer.allocateDirect(dataLen / 2); + buf.put(data, 0, dataLen / 2); + buf.flip(); + int n1 = out.write(buf); + + buf.clear(); + buf.put(data, n1, dataLen / 3); + buf.flip(); + int n2 = out.write(buf); + + buf.clear(); + buf.put(data, n1 + n2, dataLen - n1 - n2); + buf.flip(); + int n3 = out.write(buf); + + Assert.assertEquals(dataLen, n1 + n2 + n3); + + out.flush(); + + InputStream in = getCryptoInputStream(new ByteArrayInputStream(encData), + getCipher(cipherClass), defaultBufferSize, iv, withChannel); + buf = ByteBuffer.allocate(dataLen + 100); + byteBufferReadCheck(in, buf, 0); + in.close(); + } + + private void byteBufferReadCheck(InputStream in, ByteBuffer buf, + int bufPos) throws Exception { + buf.position(bufPos); + int n = ((ReadableByteChannel) in).read(buf); + Assert.assertEquals(bufPos + n, buf.position()); + byte[] readData = new byte[n]; + buf.rewind(); + buf.position(bufPos); + buf.get(readData); + byte[] expectedData = new byte[n]; + System.arraycopy(data, 0, expectedData, 0, n); + Assert.assertArrayEquals(readData, expectedData); + } + + private void prepareData() throws IOException { + Cipher cipher = null; + try { + cipher = (Cipher)ReflectionUtils.newInstance( + ReflectionUtils.getClassByName(jceCipherClass), props, transformation); + } catch (ClassNotFoundException cnfe) { + throw new IOException("Illegal crypto cipher!"); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream out = new CryptoOutputStream(baos, cipher, defaultBufferSize, key, iv); + out.write(data); + out.flush(); + out.close(); + encData = baos.toByteArray(); + } + + protected CryptoInputStream getCryptoInputStream(ByteArrayInputStream bais, + Cipher cipher, + int bufferSize, byte[] iv, + boolean withChannel) throws + IOException { + if (withChannel) { + return new CryptoInputStream(Channels.newChannel(bais), cipher, + bufferSize, key, iv); + } else { + return new CryptoInputStream(bais, cipher, bufferSize, key, iv); + } + } + + protected CryptoOutputStream getCryptoOutputStream(ByteArrayOutputStream baos, + Cipher cipher, + int bufferSize, byte[] iv, + boolean withChannel) throws + IOException { + if (withChannel) { + return new CryptoOutputStream(Channels.newChannel(baos), cipher, + bufferSize, key, iv); + } else { + return new CryptoOutputStream(baos, cipher, bufferSize, key, iv); + } + } + + private int readAll(InputStream in, byte[] b, int offset, int len) + throws IOException { + int n = 0; + int total = 0; + while (n != -1) { + total += n; + if (total >= len) { + break; + } + n = in.read(b, offset + total, len - total); + } + + return total; + } + + protected Cipher getCipher(String cipherClass) throws IOException { + try { + return (Cipher)ReflectionUtils.newInstance( + ReflectionUtils.getClassByName(cipherClass), props, transformation); + } catch (ClassNotFoundException cnfe) { + throw new IOException("Illegal crypto cipher!"); + } + } + + @Test + public void testReadWrite() throws Exception { + Assert.assertEquals(null, Openssl.getLoadingFailureReason()); + doReadWriteTest(0, jceCipherClass, jceCipherClass, iv); + doReadWriteTest(0, opensslCipherClass, opensslCipherClass, iv); + doReadWriteTest(count, jceCipherClass, jceCipherClass, iv); + doReadWriteTest(count, opensslCipherClass, opensslCipherClass, iv); + doReadWriteTest(count, jceCipherClass, opensslCipherClass, iv); + doReadWriteTest(count, opensslCipherClass, jceCipherClass, iv); + // Overflow test, IV: xx xx xx xx xx xx xx xx ff ff ff ff ff ff ff ff + for(int i = 0; i < 8; i++) { + iv[8 + i] = (byte) 0xff; + } + doReadWriteTest(count, jceCipherClass, jceCipherClass, iv); + doReadWriteTest(count, opensslCipherClass, opensslCipherClass, iv); + doReadWriteTest(count, jceCipherClass, opensslCipherClass, iv); + doReadWriteTest(count, opensslCipherClass, jceCipherClass, iv); + } + + private void doReadWriteTest(int count, String encCipherClass, + String decCipherClass, byte[] iv) throws IOException { + doReadWriteTestForInputStream(count, encCipherClass, decCipherClass, iv); + doReadWriteTestForReadableByteChannel(count, encCipherClass, decCipherClass, + iv); + } + + private void doReadWriteTestForInputStream(int count, String encCipherClass, + String decCipherClass, byte[] iv) throws IOException { + Cipher encCipher = getCipher(encCipherClass); + LOG.debug("Created a cipher object of type: " + encCipherClass); + + // Generate data + SecureRandom random = new SecureRandom(); + byte[] originalData = new byte[count]; + byte[] decryptedData = new byte[count]; + random.nextBytes(originalData); + LOG.debug("Generated " + count + " records"); + + // Encrypt data + ByteArrayOutputStream encryptedData = new ByteArrayOutputStream(); + CryptoOutputStream out = + getCryptoOutputStream(encryptedData, encCipher, defaultBufferSize, iv, + false); + out.write(originalData, 0, originalData.length); + out.flush(); + out.close(); + LOG.debug("Finished encrypting data"); + + Cipher decCipher = getCipher(decCipherClass); + LOG.debug("Created a cipher object of type: " + decCipherClass); + + // Decrypt data + CryptoInputStream in = getCryptoInputStream( + new ByteArrayInputStream(encryptedData.toByteArray()), decCipher, + defaultBufferSize, iv, false); + + // Check + int remainingToRead = count; + int offset = 0; + while (remainingToRead > 0) { + int n = in.read(decryptedData, offset, decryptedData.length - offset); + if (n >=0) { + remainingToRead -= n; + offset += n; + } + } + + Assert.assertArrayEquals("originalData and decryptedData not equal", + originalData, decryptedData); + + // Decrypt data byte-at-a-time + in = getCryptoInputStream( + new ByteArrayInputStream(encryptedData.toByteArray()), decCipher, + defaultBufferSize, iv, false); + + // Check + DataInputStream originalIn = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(originalData))); + int expected; + do { + expected = originalIn.read(); + Assert.assertEquals("Decrypted stream read by byte does not match", + expected, in.read()); + } while (expected != -1); + + LOG.debug("SUCCESS! Completed checking " + count + " records"); + } + + private void doReadWriteTestForReadableByteChannel(int count, + String encCipherClass, + String decCipherClass, + byte[] iv) throws IOException { + Cipher encCipher = getCipher(encCipherClass); + LOG.debug("Created a cipher object of type: " + encCipherClass); + + // Generate data + SecureRandom random = new SecureRandom(); + byte[] originalData = new byte[count]; + byte[] decryptedData = new byte[count]; + random.nextBytes(originalData); + LOG.debug("Generated " + count + " records"); + + // Encrypt data + ByteArrayOutputStream encryptedData = new ByteArrayOutputStream(); + CryptoOutputStream out = + getCryptoOutputStream(encryptedData, encCipher, defaultBufferSize, iv, + true); + out.write(originalData, 0, originalData.length); + out.flush(); + out.close(); + LOG.debug("Finished encrypting data"); + + Cipher decCipher = getCipher(decCipherClass); + LOG.debug("Created a cipher object of type: " + decCipherClass); + + // Decrypt data + CryptoInputStream in = getCryptoInputStream( + new ByteArrayInputStream(encryptedData.toByteArray()), decCipher, + defaultBufferSize, iv, true); + + // Check + int remainingToRead = count; + int offset = 0; + while (remainingToRead > 0) { + int n = in.read(decryptedData, offset, decryptedData.length - offset); + if (n >=0) { + remainingToRead -= n; + offset += n; + } + } + + Assert.assertArrayEquals("originalData and decryptedData not equal", + originalData, decryptedData); + + // Decrypt data byte-at-a-time + in = getCryptoInputStream(new ByteArrayInputStream( + encryptedData.toByteArray()),decCipher,defaultBufferSize,iv,true); + + // Check + DataInputStream originalIn = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(originalData))); + int expected; + do { + expected = originalIn.read(); + Assert.assertEquals("Decrypted stream read by byte does not match", + expected, in.read()); + } while (expected != -1); + + LOG.debug("SUCCESS! Completed checking " + count + " records"); + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java new file mode 100644 index 0000000..743a3ac --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/stream/CBCNoPaddingCryptoStreamTest.java @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.stream; + +import java.io.IOException; + +import org.apache.commons.crypto.cipher.CipherTransformation; + +public class CBCNoPaddingCryptoStreamTest extends AbstractCryptoStreamTest { + + public void setUp() throws IOException { + transformation = CipherTransformation + .AES_CBC_NOPADDING; + } + +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java new file mode 100644 index 0000000..cb65dac --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/stream/CBCPKCS5PaddingCryptoStreamTest.java @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.stream; + +import java.io.IOException; + +import org.apache.commons.crypto.cipher.CipherTransformation; + +public class CBCPKCS5PaddingCryptoStreamTest extends AbstractCryptoStreamTest { + + public void setUp() throws IOException { + transformation = CipherTransformation + .AES_CBC_PKCS5PADDING; + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java new file mode 100644 index 0000000..1a50382 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/stream/CTRCryptoStreamTest.java @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.stream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.channels.Channels; + +import org.apache.commons.crypto.cipher.Cipher; +import org.apache.commons.crypto.cipher.CipherTransformation; + +public class CTRCryptoStreamTest extends AbstractCryptoStreamTest { + + public void setUp() throws IOException { + transformation = CipherTransformation + .AES_CTR_NOPADDING; + } + + @Override + protected CTRCryptoInputStream getCryptoInputStream + (ByteArrayInputStream bais, Cipher cipher, int + bufferSize,byte[] iv, boolean withChannel) + throws IOException { + if (withChannel) { + return new CTRCryptoInputStream(Channels.newChannel(bais), cipher, + bufferSize, key, iv); + } else { + return new CTRCryptoInputStream(bais, cipher, bufferSize, key, iv); + } + } + + @Override + protected CTRCryptoOutputStream getCryptoOutputStream(ByteArrayOutputStream baos,Cipher cipher, int + bufferSize, byte[] iv, boolean withChannel) + throws IOException { + if (withChannel) { + return new CTRCryptoOutputStream(Channels.newChannel(baos), cipher, bufferSize, key, iv); + } else { + return new CTRCryptoOutputStream(baos, cipher, bufferSize, key, iv); + } + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java new file mode 100644 index 0000000..1bbf600 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/stream/CTRNoPaddingCryptoStreamTest.java @@ -0,0 +1,31 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.stream; + +import java.io.IOException; + +import org.apache.commons.crypto.cipher.CipherTransformation; + +public class CTRNoPaddingCryptoStreamTest extends AbstractCryptoStreamTest { + + public void setUp() throws IOException { + transformation = CipherTransformation + .AES_CTR_NOPADDING; + } + +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java new file mode 100644 index 0000000..5907ba8 --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/stream/PositionedCryptoInputStreamTest.java @@ -0,0 +1,381 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.commons.crypto.stream; + +import org.apache.commons.crypto.cipher.Cipher; +import org.apache.commons.crypto.cipher.CipherTransformation; +import org.apache.commons.crypto.cipher.JceCipher; +import org.apache.commons.crypto.cipher.OpensslCipher; +import org.apache.commons.crypto.stream.input.Input; +import org.apache.commons.crypto.utils.ReflectionUtils; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Properties; +import java.util.Random; + +public class PositionedCryptoInputStreamTest { + + private final int dataLen = 20000; + private byte[] testData = new byte[dataLen]; + private byte[] encData; + private Properties props = new Properties(); + private byte[] key = new byte[16]; + private byte[] iv = new byte[16]; + int bufferSize = 2048; + int bufferSizeLess = bufferSize - 1; + int bufferSizeMore = bufferSize + 1; + int length = 1024; + int lengthLess = length - 1; + int lengthMore = length + 1; + + private final String jceCipherClass = JceCipher.class.getName(); + private final String opensslCipherClass = OpensslCipher.class.getName(); + private CipherTransformation transformation = + CipherTransformation.AES_CTR_NOPADDING; + + @Before + public void before() throws IOException { + Random random = new SecureRandom(); + random.nextBytes(testData); + random.nextBytes(key); + random.nextBytes(iv); + prepareData(); + } + + private void prepareData() throws IOException { + Cipher cipher = null; + try { + cipher = (Cipher)ReflectionUtils.newInstance( + ReflectionUtils.getClassByName(jceCipherClass), + props, transformation); + } catch (ClassNotFoundException cnfe) { + throw new IOException("Illegal crypto cipher!"); + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // encryption data + OutputStream out = new CryptoOutputStream(baos, cipher, bufferSize, key, iv); + out.write(testData); + out.flush(); + out.close(); + encData = baos.toByteArray(); + } + + public void setUp() throws IOException {} + + private PositionedCryptoInputStream getCryptoInputStream(Cipher cipher, + int bufferSize) throws IOException { + return new PositionedCryptoInputStream(new PositionedInputForTest( + Arrays.copyOf(encData, encData.length)), cipher, bufferSize, key, iv, 0); + } + + @Test + public void doTest() throws Exception { + testCipher(jceCipherClass); + testCipher(opensslCipherClass); + } + + private void testCipher(String cipherClass) throws Exception { + doPositionedReadTests(cipherClass); + doReadFullyTests(cipherClass); + doSeekTests(cipherClass); + doMultipleReadTest(cipherClass); + } + + // when there are multiple positioned read actions and one read action, + // they will not interfere each other. + private void doMultipleReadTest(String cipherClass) throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream( + getCipher(cipherClass), bufferSize); + int position = 0; + while (in.available() > 0) { + ByteBuffer buf = ByteBuffer.allocate(length); + byte[] bytes1 = new byte[length]; + byte[] bytes2 = new byte[lengthLess]; + // do the read and position read + int pn1 = in.read(position, bytes1, 0, length); + int n = in.read(buf); + int pn2 = in.read(position, bytes2, 0, lengthLess); + + // verify the result + if (pn1 > 0) { + compareByteArray(testData, position, bytes1, pn1); + } + + if (pn2 > 0) { + compareByteArray(testData, position, bytes2, pn2); + } + + if (n > 0) { + compareByteArray(testData, position, buf.array(), n); + position += n; + } else { + break; + } + } + in.close(); + } + + private void doPositionedReadTests(String cipherClass) throws Exception { + // test with different bufferSize when position = 0 + testPositionedReadLoop(cipherClass, 0, length, bufferSize, dataLen); + testPositionedReadLoop(cipherClass, 0, length, bufferSizeLess, dataLen); + testPositionedReadLoop(cipherClass, 0, length, bufferSizeMore, dataLen); + // test with different position when bufferSize = 2048 + testPositionedReadLoop(cipherClass, dataLen / 2, length, bufferSize, dataLen); + testPositionedReadLoop(cipherClass, dataLen / 2 - 1, length, + bufferSizeLess, dataLen); + testPositionedReadLoop(cipherClass, dataLen / 2 + 1, length, + bufferSizeMore, dataLen); + // position = -1 or position = max length, read nothing and return -1 + testPositionedReadNone(cipherClass, -1, length, bufferSize); + testPositionedReadNone(cipherClass, dataLen, length, bufferSize); + } + + private void doReadFullyTests(String cipherClass) throws Exception { + // test with different bufferSize when position = 0 + testReadFullyLoop(cipherClass, 0, length, bufferSize, dataLen); + testReadFullyLoop(cipherClass, 0, length, bufferSizeLess, dataLen); + testReadFullyLoop(cipherClass, 0, length, bufferSizeMore, dataLen); + // test with different length when position = 0 + testReadFullyLoop(cipherClass, 0, length, bufferSize, dataLen); + testReadFullyLoop(cipherClass, 0, lengthLess, bufferSize, dataLen); + testReadFullyLoop(cipherClass, 0, lengthMore, bufferSize, dataLen); + // test read fully failed + testReadFullyFailed(cipherClass, -1, length, bufferSize); + testReadFullyFailed(cipherClass, dataLen, length, bufferSize); + testReadFullyFailed(cipherClass, dataLen - length + 1, length, bufferSize); + } + + private void doSeekTests(String cipherClass) throws Exception { + // test with different length when position = 0 + testSeekLoop(cipherClass, 0, length, bufferSize); + testSeekLoop(cipherClass, 0, lengthLess, bufferSize); + testSeekLoop(cipherClass, 0, lengthMore, bufferSize); + // there should be none data read when position = dataLen + testSeekLoop(cipherClass, dataLen, length, bufferSize); + // test exception when position = -1 + testSeekFailed(cipherClass, -1, bufferSize); + } + + private void testSeekLoop(String cipherClass, int position, int length, + int bufferSize) throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream( + getCipher(cipherClass), bufferSize); + while (in.available() > 0) { + in.seek(position); + ByteBuffer buf = ByteBuffer.allocate(length); + int n = in.read(buf); + if (n > 0) { + compareByteArray(testData, position, buf.array(), n); + position += n; + } else { + break; + } + } + in.close(); + } + + // test for the out of index position, eg, -1. + private void testSeekFailed(String cipherClass, int position, + int bufferSize) throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream( + getCipher(cipherClass), bufferSize); + try { + in.seek(position); + Assert.fail("Excepted exception for cannot seek to negative offset."); + } catch (IllegalArgumentException iae) { + } + in.close(); + } + + private void testPositionedReadLoop(String cipherClass, int position, + int length, int bufferSize, int total) throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream( + getCipher(cipherClass), bufferSize); + // do the position read until the end of data + while (position < total) { + byte[] bytes = new byte[length]; + int n = in.read(position, bytes, 0, length); + if (n >= 0) { + compareByteArray(testData, position, bytes, n); + position += n; + } else { + break; + } + } + in.close(); + } + + // test for the out of index position, eg, -1. + private void testPositionedReadNone(String cipherClass, int position, + int length, int bufferSize) throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream( + getCipher(cipherClass), bufferSize); + byte[] bytes = new byte[length]; + int n = in.read(position, bytes, 0, length); + Assert.assertEquals(n, -1); + in.close(); + } + + private void testReadFullyLoop(String cipherClass,int position, + int length, int bufferSize, int total) throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream( + getCipher(cipherClass), bufferSize); + + // do the position read full until remain < length + while (position + length <= total) { + byte[] bytes = new byte[length]; + in.readFully(position, bytes, 0, length); + compareByteArray(testData, position, bytes, length); + position += length; + } + + in.close(); + } + + // test for the End of file reached before reading fully + private void testReadFullyFailed(String cipherClass, int position, + int length, int bufferSize) throws Exception { + PositionedCryptoInputStream in = getCryptoInputStream( + getCipher(cipherClass), bufferSize); + byte[] bytes = new byte[length]; + try { + in.readFully(position, bytes, 0, length); + Assert.fail("Excepted EOFException."); + } catch (IOException ioe) { + // excepted exception + } + in.close(); + } + + // compare the data from pos with length and data2 from 0 with length + private void compareByteArray(byte[] data1, int pos, byte[] data2, int length) { + byte[] expectedData = new byte[length]; + byte[] realData = new byte[length]; + // get the expected data with the position and length + System.arraycopy(data1, pos, expectedData, 0, length); + // get the real data + System.arraycopy(data2, 0, realData, 0, length); + Assert.assertArrayEquals(expectedData, realData); + } + + private Cipher getCipher(String cipherClass) throws IOException { + try { + return (Cipher)ReflectionUtils.newInstance( + ReflectionUtils.getClassByName(cipherClass), props, transformation); + } catch (ClassNotFoundException cnfe) { + throw new IOException("Illegal crypto cipher!"); + } + } + + class PositionedInputForTest implements Input { + + byte[] data; + long pos; + long count; + + public PositionedInputForTest(byte[] data) { + this.data = data; + this.pos = 0; + this.count = data.length; + } + + @Override + public int read(ByteBuffer dst) throws IOException { + int remaining = (int)(count - pos); + if(remaining <= 0) { + return -1; + } + + int length = Math.min(dst.remaining(), remaining); + dst.put(data, (int)pos, length); + pos += length; + return length; + } + + @Override + public long skip(long n) throws IOException { + if (n <= 0) { + return 0; + } + + long remaining = count - pos; + if(remaining < n) { + n = remaining; + } + pos += n; + + return n; + } + + @Override + public int read(long position, byte[] buffer, int offset, int length) + throws IOException { + if (buffer == null) { + throw new NullPointerException(); + } else if (offset < 0 || length < 0 || length > buffer.length - offset) { + throw new IndexOutOfBoundsException(); + } + + if (position < 0 || position >= count) { + return -1; + } + + long avail = count - position; + if (length > avail) { + length = (int)avail; + } + if (length <= 0) { + return 0; + } + System.arraycopy(data, (int)position, buffer, offset, length); + return length; + } + + @Override + public void seek(long position) throws IOException { + if (pos < 0) { + throw new IOException("Negative seek offset"); + } else if (position >= 0 && position < count) { + pos = position; + } else { + // to the end of file + pos = count; + } + } + + @Override + public void close() throws IOException { + } + + @Override + public int available() throws IOException { + return (int)(count - pos); + } + } +} http://git-wip-us.apache.org/repos/asf/commons-crypto/blob/4920d272/src/test/java/org/apache/commons/crypto/utils/UtilsTest.java ---------------------------------------------------------------------- diff --git a/src/test/java/org/apache/commons/crypto/utils/UtilsTest.java b/src/test/java/org/apache/commons/crypto/utils/UtilsTest.java new file mode 100644 index 0000000..a0475be --- /dev/null +++ b/src/test/java/org/apache/commons/crypto/utils/UtilsTest.java @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.crypto.utils; + +import junit.framework.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class UtilsTest { + @Test + public void testSplitOmitEmptyLine() { + List<String> clazzNames = Utils.splitClassNames("", ","); + Assert.assertEquals(Collections.<String>emptyList(), clazzNames); + + clazzNames = Utils.splitClassNames("a,b", ","); + Assert.assertEquals(Arrays.asList("a", "b"), clazzNames); + clazzNames = Utils.splitClassNames("a,b,", ","); + Assert.assertEquals(Arrays.asList("a", "b"), clazzNames); + clazzNames = Utils.splitClassNames("a, b,", ","); + Assert.assertEquals(Arrays.asList("a", "b"), clazzNames); + } +}