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  
19  package org.apache.commons.crypto.cipher;
20  
21  import static org.junit.jupiter.api.Assertions.assertNotNull;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  import static org.junit.jupiter.api.Assumptions.assumeTrue;
25  
26  import java.nio.ByteBuffer;
27  import java.security.InvalidAlgorithmParameterException;
28  import java.security.InvalidKeyException;
29  import java.security.NoSuchAlgorithmException;
30  import java.util.Properties;
31  import java.util.concurrent.TimeUnit;
32  
33  import javax.crypto.NoSuchPaddingException;
34  import javax.crypto.ShortBufferException;
35  import javax.crypto.spec.GCMParameterSpec;
36  import javax.crypto.spec.IvParameterSpec;
37  
38  import org.apache.commons.crypto.utils.AES;
39  import org.junit.jupiter.api.Test;
40  import org.junit.jupiter.api.Timeout;
41  
42  
43  public class OpenSslCipherTest extends AbstractCipherTest {
44  
45      private ByteBuffer dummyBuffer() {
46          return ByteBuffer.allocateDirect(8);
47      }
48  
49      @Override
50      public void init() {
51          assumeTrue(OpenSsl.getLoadingFailureReason() == null);
52          transformations = new String[] {
53                  AES.CBC_NO_PADDING,
54                  AES.CBC_PKCS5_PADDING,
55                  AES.CTR_NO_PADDING};
56          cipherClass = OPENSSL_CIPHER_CLASSNAME;
57      }
58  
59      @Test
60      public void testCipherLifecycle() throws Exception {
61          try (OpenSslCipher cipher = new OpenSslCipher(new Properties(), AES.CTR_NO_PADDING)) {
62  
63              assertThrows(IllegalStateException.class, () -> cipher.update(dummyBuffer(), dummyBuffer()));
64              cipher.init(OpenSsl.ENCRYPT_MODE, AES.newSecretKeySpec(KEY),
65                  new IvParameterSpec(IV));
66              cipher.update(dummyBuffer(), dummyBuffer());
67  
68              assertThrows(InvalidKeyException.class, () -> cipher.init(OpenSsl.ENCRYPT_MODE, AES.newSecretKeySpec(new byte[1]),
69                      new IvParameterSpec(IV)));
70              // Should keep working with previous init parameters.
71              cipher.update(dummyBuffer(), dummyBuffer());
72              cipher.doFinal(dummyBuffer(), dummyBuffer());
73              cipher.close();
74  
75              assertThrows(IllegalStateException.class, () -> cipher.update(dummyBuffer(), dummyBuffer()));
76              cipher.init(OpenSsl.ENCRYPT_MODE, AES.newSecretKeySpec(KEY),
77                  new IvParameterSpec(IV));
78              cipher.update(dummyBuffer(), dummyBuffer());
79          }
80      }
81  
82      @Test
83      @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
84      public void testDoFinalArguments() throws Exception {
85          assumeTrue(OpenSsl.getLoadingFailureReason() == null);
86          final OpenSsl cipher = OpenSsl
87                  .getInstance(AES.CTR_NO_PADDING);
88          assertNotNull(cipher);
89  
90          cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new IvParameterSpec(IV));
91  
92          // Require direct buffer
93          final ByteBuffer input = ByteBuffer.allocate(1024);
94          final ByteBuffer output = ByteBuffer.allocate(1024);
95  
96          final Exception ex = assertThrows(IllegalArgumentException.class, () -> cipher.doFinal(input, output));
97          assertTrue(ex.getMessage().contains("Direct buffer is required"));
98      }
99  
100     @Override
101     @Test
102     @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
103     public void testInvalidIV() throws Exception {
104         assumeTrue(OpenSsl.getLoadingFailureReason() == null);
105         final OpenSsl cipher = OpenSsl
106                 .getInstance(AES.CTR_NO_PADDING);
107         assertNotNull(cipher);
108 
109         final byte[] invalidIV = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
110                 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11 };
111 
112         assertThrows(InvalidAlgorithmParameterException.class,
113                 () -> cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new IvParameterSpec(invalidIV)));
114     }
115 
116     @Override
117     @Test
118     @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
119     public void testInvalidIVClass() throws Exception {
120         final OpenSsl cipher = OpenSsl.getInstance(AES.CTR_NO_PADDING);
121         assertNotNull(cipher);
122 
123 
124         assertThrows(InvalidAlgorithmParameterException.class,
125                 () ->  cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new GCMParameterSpec(IV.length, IV)));
126     }
127 
128     @Override
129     @Test
130     @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
131     public void testInvalidKey() throws Exception {
132         assumeTrue(OpenSsl.getLoadingFailureReason() == null);
133         final OpenSsl cipher = OpenSsl
134                 .getInstance(AES.CTR_NO_PADDING);
135         assertNotNull(cipher);
136 
137         final byte[] invalidKey = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
138                 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11 };
139 
140         assertThrows(InvalidKeyException.class,
141                 () -> cipher.init(OpenSsl.ENCRYPT_MODE, invalidKey, new IvParameterSpec(IV)));
142     }
143 
144     @Test
145     @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
146     public void testInvalidMode() {
147         assumeTrue(OpenSsl.getLoadingFailureReason() == null);
148         assertThrows(NoSuchAlgorithmException.class,
149                 () -> OpenSsl.getInstance("AES/CTR2/NoPadding"));
150     }
151 
152     @Test
153     @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
154     public void testInvalidPadding() {
155         assumeTrue(OpenSsl.getLoadingFailureReason() == null);
156         assertThrows(NoSuchPaddingException.class,
157                 () -> OpenSsl.getInstance("AES/CTR/NoPadding2"));
158     }
159 
160     @Test
161     @Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
162     public void testUpdateArguments() throws Exception {
163         assumeTrue(OpenSsl.getLoadingFailureReason() == null);
164         final OpenSsl cipher = OpenSsl
165                 .getInstance(AES.CTR_NO_PADDING);
166         assertNotNull(cipher);
167 
168         cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new IvParameterSpec(IV));
169 
170         // Require direct buffers
171         ByteBuffer input = ByteBuffer.allocate(1024);
172         ByteBuffer output = ByteBuffer.allocate(1024);
173 
174         final ByteBuffer finalInput = input;
175         final ByteBuffer finalOutput = output;
176         Exception ex = assertThrows(IllegalArgumentException.class, () -> cipher.update(finalInput, finalOutput));
177         assertTrue(ex.getMessage().contains("Direct buffers are required"));
178 
179         // Output buffer length should be sufficient to store output data
180         input = ByteBuffer.allocateDirect(1024);
181         output = ByteBuffer.allocateDirect(1000);
182         final ByteBuffer finalInput1 = input;
183         final ByteBuffer finalOutput1 = output;
184         ex = assertThrows(ShortBufferException.class, () -> cipher.update(finalInput1, finalOutput1));
185         assertTrue(ex.getMessage().contains("Output buffer is not sufficient"));
186 
187     }
188 
189 }