1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.crypto.cipher;
19
20 import java.io.IOException;
21 import java.nio.ByteBuffer;
22 import java.security.GeneralSecurityException;
23 import java.security.SecureRandom;
24 import java.util.Properties;
25 import java.util.Random;
26 import javax.xml.bind.DatatypeConverter;
27
28 import org.apache.commons.crypto.conf.ConfigurationKeys;
29 import org.apache.commons.crypto.utils.ReflectionUtils;
30 import org.apache.commons.crypto.utils.Utils;
31 import org.junit.Assert;
32 import org.junit.Before;
33 import org.junit.Test;
34
35 public abstract class AbstractCipherTest {
36
37
38 public static final int BYTEBUFFER_SIZE = 1000;
39 public String[] cipherTests = null;
40 Properties props = null;
41 String cipherClass = null;
42 CipherTransformation[] transformations = null;
43
44
45 static final byte[] KEY = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
46 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
47 static final byte[] IV = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
48 0x07, 0x08, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
49 Cipher enc, dec;
50
51 @Before
52 public void setup() {
53 init();
54 Utils.checkNotNull(cipherClass);
55 Utils.checkNotNull(transformations);
56 props = new Properties();
57 props.setProperty(ConfigurationKeys.COMMONS_CRYPTO_CIPHER_CLASSES_KEY,
58 cipherClass);
59 }
60
61 protected abstract void init() ;
62
63 @Test
64 public void cryptoTest() throws GeneralSecurityException, IOException {
65 for (CipherTransformation tran : transformations) {
66
67 cipherTests = TestData.getTestData(tran);
68 for (int i = 0; i != cipherTests.length; i += 5) {
69 byte[] key = DatatypeConverter.parseHexBinary(cipherTests[i + 1]);
70 byte[] iv = DatatypeConverter.parseHexBinary(cipherTests[i + 2]);
71
72 byte[] inputBytes = DatatypeConverter.parseHexBinary(cipherTests[i + 3]);
73 byte[] outputBytes = DatatypeConverter.parseHexBinary(cipherTests[i + 4]);
74
75 ByteBuffer inputBuffer = ByteBuffer.allocateDirect(inputBytes.length);
76 ByteBuffer outputBuffer = ByteBuffer.allocateDirect(outputBytes.length);
77 inputBuffer.put(inputBytes);
78 inputBuffer.flip();
79 outputBuffer.put(outputBytes);
80 outputBuffer.flip();
81
82 byteBufferTest(tran,key, iv, inputBuffer, outputBuffer);
83 byteArrayTest(tran, key, iv, inputBytes, outputBytes);
84 }
85
86
87 byteArrayTest(tran, KEY, IV);
88 }
89 }
90
91 private void byteBufferTest(CipherTransformation transformation, byte[] key,
92 byte[] iv,
93 ByteBuffer input, ByteBuffer output) throws
94 GeneralSecurityException, IOException {
95 ByteBuffer decResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE);
96 ByteBuffer encResult = ByteBuffer.allocateDirect(BYTEBUFFER_SIZE);
97 Cipher enc, dec;
98
99 enc = getCipher(transformation);
100 dec = getCipher(transformation);
101
102 try {
103 enc.init(Cipher.ENCRYPT_MODE, key, iv);
104 } catch (Exception e) {
105 Assert.fail("AES failed initialisation - " + e.toString());
106 }
107
108 try {
109 dec.init(Cipher.DECRYPT_MODE, key, iv);
110 } catch (Exception e) {
111 Assert.fail("AES failed initialisation - " + e.toString());
112 }
113
114
115
116
117 enc.doFinal(input, encResult);
118 input.flip();
119 encResult.flip();
120 if (!output.equals(encResult)) {
121 byte[] b = new byte[output.remaining()];
122 output.get(b);
123 byte[] c = new byte[encResult.remaining()];
124 encResult.get(c);
125 Assert.fail("AES failed encryption - expected " + new String(
126 DatatypeConverter
127 .printHexBinary(b)) + " got " + new String(
128 DatatypeConverter.printHexBinary(c)));
129 }
130
131
132
133
134 dec.doFinal(encResult, decResult);
135 decResult.flip();
136
137 if (!input.equals(decResult)) {
138 byte[] inArray = new byte[input.remaining()];
139 byte[] decResultArray = new byte[decResult.remaining()];
140 input.get(inArray);
141 decResult.get(decResultArray);
142 Assert.fail();
143 }
144 }
145
146
147 private void byteArrayTest(CipherTransformation transformation, byte[] key,
148 byte[] iv, byte[] input, byte[] output) throws GeneralSecurityException {
149 resetCipher(transformation, key, iv);
150 int blockSize = transformation.getAlgorithmBlockSize();
151
152 byte[] temp = new byte[input.length + blockSize];
153 int n = enc.doFinal(input, 0, input.length, temp, 0);
154 byte[] cipherText = new byte[n];
155 System.arraycopy(temp, 0, cipherText, 0, n);
156 Assert.assertArrayEquals("byte array encryption error.", output, cipherText);
157
158 temp = new byte[cipherText.length + blockSize];
159 int m = dec.doFinal(cipherText, 0, cipherText.length, temp, 0);
160 byte[] plainText = new byte[m];
161 System.arraycopy(temp, 0, plainText, 0, m);
162 Assert.assertArrayEquals("byte array decryption error.", input, plainText);
163 }
164
165
166 private void byteArrayTest(CipherTransformation transformation, byte[] key,
167 byte[] iv) throws GeneralSecurityException {
168 int blockSize = transformation.getAlgorithmBlockSize();
169
170
171 int[] dataLenList = (transformation == CipherTransformation.AES_CBC_NOPADDING)
172 ? new int[] {10 * 1024} : new int[] {10 * 1024, 10 * 1024 - 3};
173 for (int dataLen : dataLenList) {
174 byte[] plainText = new byte[dataLen];
175 Random random = new SecureRandom();
176 random.nextBytes(plainText);
177 byte[] cipherText = new byte[dataLen + blockSize];
178
179
180 int[] bufferLenList = new int[] {2 * 1024 - 128, 2 * 1024 - 125};
181 for (int bufferLen : bufferLenList) {
182 resetCipher(transformation, key, iv);
183
184 int offset = 0;
185
186 int cipherPos = 0;
187 for (int i = 0; i < dataLen / bufferLen; i ++) {
188 cipherPos += enc.update(plainText, offset, bufferLen, cipherText, cipherPos);
189 offset += bufferLen;
190 }
191 cipherPos += enc.doFinal(plainText, offset, dataLen % bufferLen, cipherText, cipherPos);
192
193 offset = 0;
194
195 byte[] realPlainText = new byte[cipherPos + blockSize];
196 int plainPos = 0;
197 for (int i = 0; i < cipherPos / bufferLen; i ++) {
198 plainPos += dec.update(cipherText, offset, bufferLen, realPlainText, plainPos);
199 offset += bufferLen;
200 }
201 plainPos += dec.doFinal(cipherText, offset, cipherPos % bufferLen, realPlainText, plainPos);
202
203
204 Assert.assertEquals("random byte array length changes after transformation",
205 dataLen, plainPos);
206
207 byte[] shrinkPlainText = new byte[plainPos];
208 System.arraycopy(realPlainText, 0, shrinkPlainText, 0, plainPos);
209 Assert.assertArrayEquals("random byte array contents changes after transformation",
210 plainText, shrinkPlainText);
211 }
212 }
213 }
214
215 private void resetCipher(CipherTransformation transformation, byte[] key, byte[] iv) {
216 enc = getCipher(transformation);
217 dec = getCipher(transformation);
218
219 try {
220 enc.init(Cipher.ENCRYPT_MODE, key, iv);
221 } catch (Exception e) {
222 Assert.fail("AES failed initialisation - " + e.toString());
223 }
224
225 try {
226 dec.init(Cipher.DECRYPT_MODE, key, iv);
227 } catch (Exception e) {
228 Assert.fail("AES failed initialisation - " + e.toString());
229 }
230 }
231
232 private Cipher getCipher(CipherTransformation transformation) {
233 try {
234 return (Cipher) ReflectionUtils
235 .newInstance(ReflectionUtils.getClassByName(cipherClass), props,
236 transformation);
237 } catch (ClassNotFoundException e) {
238 throw new RuntimeException(e);
239 }
240
241 }
242 }