blob: fea356cba0d74a6f943c219b7a2fd08b16363c3d [file]
/*
* 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
*
* https://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 static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.nio.ByteBuffer;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.IvParameterSpec;
import org.apache.commons.crypto.utils.AES;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
class OpenSslCipherTest extends AbstractCipherTest {
private ByteBuffer dummyBuffer() {
return ByteBuffer.allocateDirect(8);
}
@Override
public void init() {
assumeTrue(OpenSsl.getLoadingFailureReason() == null);
cipherClass = OPENSSL_CIPHER_CLASSNAME;
}
@Test
void testCipherLifecycle() throws Exception {
try (OpenSslCipher cipher = new OpenSslCipher(new Properties(), AES.CTR_NO_PADDING)) {
assertThrows(IllegalStateException.class, () -> cipher.update(dummyBuffer(), dummyBuffer()));
cipher.init(OpenSsl.ENCRYPT_MODE, AES.newSecretKeySpec(KEY),
new IvParameterSpec(IV));
cipher.update(dummyBuffer(), dummyBuffer());
assertThrows(InvalidKeyException.class, () -> cipher.init(OpenSsl.ENCRYPT_MODE, AES.newSecretKeySpec(new byte[1]),
new IvParameterSpec(IV)));
// Should keep working with previous init parameters.
cipher.update(dummyBuffer(), dummyBuffer());
cipher.doFinal(dummyBuffer(), dummyBuffer());
cipher.close();
assertThrows(IllegalStateException.class, () -> cipher.update(dummyBuffer(), dummyBuffer()));
cipher.init(OpenSsl.ENCRYPT_MODE, AES.newSecretKeySpec(KEY),
new IvParameterSpec(IV));
cipher.update(dummyBuffer(), dummyBuffer());
}
}
@Test
@Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
void testDoFinalArguments() throws Exception {
assumeTrue(OpenSsl.getLoadingFailureReason() == null);
final OpenSsl cipher = OpenSsl
.getInstance(AES.CTR_NO_PADDING);
assertNotNull(cipher);
cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new IvParameterSpec(IV));
// Require direct buffer
final ByteBuffer input = ByteBuffer.allocate(1024);
final ByteBuffer output = ByteBuffer.allocate(1024);
final Exception ex = assertThrows(IllegalArgumentException.class, () -> cipher.doFinal(input, output));
assertTrue(ex.getMessage().contains("Direct buffer is required"));
}
@Override
@Test
@Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
void testInvalidIV() throws Exception {
assumeTrue(OpenSsl.getLoadingFailureReason() == null);
final OpenSsl cipher = OpenSsl
.getInstance(AES.CTR_NO_PADDING);
assertNotNull(cipher);
final byte[] invalidIV = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11 };
assertThrows(InvalidAlgorithmParameterException.class,
() -> cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new IvParameterSpec(invalidIV)));
}
@Override
@Test
@Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
void testInvalidIVClass() throws Exception {
final OpenSsl cipher = OpenSsl.getInstance(AES.CTR_NO_PADDING);
assertNotNull(cipher);
assertThrows(InvalidAlgorithmParameterException.class,
() -> cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new GCMParameterSpec(IV.length, IV)));
}
@Override
@Test
@Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
void testInvalidKey() throws Exception {
assumeTrue(OpenSsl.getLoadingFailureReason() == null);
final OpenSsl cipher = OpenSsl
.getInstance(AES.CTR_NO_PADDING);
assertNotNull(cipher);
final byte[] invalidKey = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11 };
assertThrows(InvalidKeyException.class,
() -> cipher.init(OpenSsl.ENCRYPT_MODE, invalidKey, new IvParameterSpec(IV)));
}
@Test
@Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
void testInvalidMode() {
assumeTrue(OpenSsl.getLoadingFailureReason() == null);
assertThrows(NoSuchAlgorithmException.class,
() -> OpenSsl.getInstance("AES/CTR2/NoPadding"));
}
@Test
@Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
void testInvalidPadding() {
assumeTrue(OpenSsl.getLoadingFailureReason() == null);
assertThrows(NoSuchPaddingException.class,
() -> OpenSsl.getInstance("AES/CTR/NoPadding2"));
}
@Test
@Timeout(value = 120000, unit = TimeUnit.MILLISECONDS)
void testUpdateArguments() throws Exception {
assumeTrue(OpenSsl.getLoadingFailureReason() == null);
final OpenSsl cipher = OpenSsl
.getInstance(AES.CTR_NO_PADDING);
assertNotNull(cipher);
cipher.init(OpenSsl.ENCRYPT_MODE, KEY, new IvParameterSpec(IV));
// Require direct buffers
ByteBuffer input = ByteBuffer.allocate(1024);
ByteBuffer output = ByteBuffer.allocate(1024);
final ByteBuffer finalInput = input;
final ByteBuffer finalOutput = output;
Exception ex = assertThrows(IllegalArgumentException.class, () -> cipher.update(finalInput, finalOutput));
assertTrue(ex.getMessage().contains("Direct buffers are required"));
// Output buffer length should be sufficient to store output data
input = ByteBuffer.allocateDirect(1024);
output = ByteBuffer.allocateDirect(1000);
final ByteBuffer finalInput1 = input;
final ByteBuffer finalOutput1 = output;
ex = assertThrows(ShortBufferException.class, () -> cipher.update(finalInput1, finalOutput1));
assertTrue(ex.getMessage().contains("Output buffer is not sufficient"));
}
}