View Javadoc
1    /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.commons.crypto.stream;
19  
20  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotNull;
23  import static org.junit.jupiter.api.Assertions.assertThrows;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.IOException;
28  import java.nio.ByteBuffer;
29  import java.nio.channels.Channels;
30  import java.security.spec.AlgorithmParameterSpec;
31  import java.util.Properties;
32  import java.util.concurrent.TimeUnit;
33  
34  import javax.crypto.ShortBufferException;
35  import javax.crypto.spec.IvParameterSpec;
36  
37  import org.apache.commons.crypto.cipher.AbstractCipherTest;
38  import org.apache.commons.crypto.cipher.CryptoCipher;
39  import org.apache.commons.crypto.stream.input.ChannelInput;
40  import org.apache.commons.crypto.stream.input.StreamInput;
41  import org.apache.commons.crypto.stream.output.ChannelOutput;
42  import org.apache.commons.crypto.utils.AES;
43  import org.junit.jupiter.api.Test;
44  import org.junit.jupiter.api.Timeout;
45  
46  public class CtrCryptoStreamTest extends AbstractCipherStreamTest {
47  
48      protected void doDecryptTest(final String cipherClass, final boolean withChannel)
49              throws IOException {
50  
51          final CtrCryptoInputStream in = newCryptoInputStream(new ByteArrayInputStream(encData),
52                  getCipher(cipherClass), defaultBufferSize, iv, withChannel);
53  
54          final ByteBuffer buf = ByteBuffer.allocateDirect(dataLen);
55          buf.put(encData);
56          buf.rewind();
57          in.decrypt(buf, 0, dataLen);
58          final byte[] readData = new byte[dataLen];
59          final byte[] expectedData = new byte[dataLen];
60          buf.get(readData);
61          System.arraycopy(data, 0, expectedData, 0, dataLen);
62          assertArrayEquals(readData, expectedData);
63          final Exception ex = assertThrows(IOException.class, () -> in.decryptBuffer(buf));
64          assertEquals(ex.getCause().getClass(), ShortBufferException.class);
65  
66      }
67  
68      @Override
69      protected void doFieldGetterTest(final String cipherClass, final ByteArrayOutputStream baos,
70              final boolean withChannel) throws Exception {
71          assumeJniPresence(cipherClass);
72  
73          final StreamInput streamInput = new StreamInput(new ByteArrayInputStream(encData), 0);
74          Exception ex = assertThrows(UnsupportedOperationException.class, () -> streamInput.seek(0));
75          assertEquals(ex.getMessage(), "Seek is not supported by this implementation");
76  
77          ex = assertThrows(UnsupportedOperationException.class, () -> streamInput.read(0, new byte[0], 0, 0));
78          assertEquals(ex.getMessage(), "Positioned read is not supported by this implementation");
79  
80          assertEquals(streamInput.available(), encData.length);
81  
82          final ChannelInput channelInput = new ChannelInput(Channels.newChannel(new ByteArrayInputStream(encData)));
83          ex = assertThrows(UnsupportedOperationException.class, () -> channelInput.seek(0));
84          assertEquals(ex.getMessage(), "Seek is not supported by this implementation");
85  
86          ex = assertThrows(UnsupportedOperationException.class, () -> channelInput.read(0, new byte[0], 0, 0));
87          assertEquals(ex.getMessage(), "Positioned read is not supported by this implementation");
88          assertEquals(channelInput.available(), 0);
89  
90          final CtrCryptoInputStream in = new CtrCryptoInputStream(channelInput, getCipher(cipherClass),
91                  defaultBufferSize, key, iv);
92  
93          final Properties props = new Properties();
94          final String bufferSize = "4096";
95          props.put(CryptoInputStream.STREAM_BUFFER_SIZE_KEY, bufferSize);
96          in.setStreamOffset(smallBufferSize);
97  
98          assertEquals(CryptoInputStream.getBufferSize(props), Integer.parseInt(bufferSize));
99          assertEquals(smallBufferSize, in.getStreamOffset());
100         assertEquals(in.getBufferSize(), 8192);
101         assertEquals(in.getCipher().getClass(), Class.forName(cipherClass));
102         assertEquals(in.getKey().getAlgorithm(), AES.ALGORITHM);
103         assertEquals(in.getParams().getClass(), IvParameterSpec.class);
104         assertNotNull(in.getInput());
105 
106         in.close();
107 
108         final CtrCryptoOutputStream out = new CtrCryptoOutputStream(new ChannelOutput(
109                 Channels.newChannel(baos)), getCipher(cipherClass),
110                 Integer.parseInt(bufferSize), key, iv);
111         out.setStreamOffset(smallBufferSize);
112         assertEquals(out.getStreamOffset(), smallBufferSize);
113 
114         out.close();
115     }
116 
117     @Override
118     protected CtrCryptoInputStream newCryptoInputStream(
119             final ByteArrayInputStream bais, final CryptoCipher cipher, final int bufferSize,
120             final byte[] iv, final boolean withChannel) throws IOException {
121         if (withChannel) {
122             return new CtrCryptoInputStream(Channels.newChannel(bais), cipher,
123                     bufferSize, key, iv);
124         }
125         return new CtrCryptoInputStream(bais, cipher, bufferSize, key, iv);
126     }
127 
128     @Override
129     protected CryptoInputStream newCryptoInputStream(final String transformation, final Properties props,
130             final ByteArrayInputStream bais, final byte[] key, final AlgorithmParameterSpec params,
131             final boolean withChannel) throws IOException {
132         if (withChannel) {
133             return new CtrCryptoInputStream(props, Channels.newChannel(bais), key,
134                     ((IvParameterSpec)params).getIV());
135         }
136         return new CtrCryptoInputStream(props, bais, key, ((IvParameterSpec)params).getIV());
137     }
138 
139     @Override
140     protected CtrCryptoOutputStream newCryptoOutputStream(
141             final ByteArrayOutputStream baos, final CryptoCipher cipher, final int bufferSize,
142             final byte[] iv, final boolean withChannel) throws IOException {
143         if (withChannel) {
144             return new CtrCryptoOutputStream(Channels.newChannel(baos), cipher,
145                     bufferSize, key, iv);
146         }
147         return new CtrCryptoOutputStream(baos, cipher, bufferSize, key, iv);
148     }
149 
150     @Override
151     protected CtrCryptoOutputStream newCryptoOutputStream(final String transformation,
152             final Properties props, final ByteArrayOutputStream baos, final byte[] key,
153             final AlgorithmParameterSpec params, final boolean withChannel) throws IOException {
154         if (withChannel) {
155             return new CtrCryptoOutputStream(props, Channels.newChannel(baos), key,
156                     ((IvParameterSpec)params).getIV());
157         }
158         return new CtrCryptoOutputStream(props, baos, key, ((IvParameterSpec)params).getIV());
159     }
160 
161     @Override
162     public void setUp() {
163         transformation = AES.CTR_NO_PADDING;
164     }
165 
166     @Test
167     @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
168     public void testDecrypt() throws Exception {
169         doDecryptTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, false);
170         doDecryptTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, false);
171 
172         doDecryptTest(AbstractCipherTest.JCE_CIPHER_CLASSNAME, true);
173         doDecryptTest(AbstractCipherTest.OPENSSL_CIPHER_CLASSNAME, true);
174     }
175 }