wolfcrypt-jni/src/test/java/com/wolfssl/wolfcrypt/test/Sha224Test.java

262 lines
8.2 KiB
Java

/* Sha224Test.java
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
package com.wolfssl.wolfcrypt.test;
import static org.junit.Assert.*;
import java.nio.ByteBuffer;
import java.util.Random;
import java.util.Arrays;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.LinkedBlockingQueue;
import javax.crypto.ShortBufferException;
import org.junit.Test;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
import com.wolfssl.wolfcrypt.Sha224;
import com.wolfssl.wolfcrypt.NativeStruct;
import com.wolfssl.wolfcrypt.WolfCryptException;
import com.wolfssl.wolfcrypt.WolfCryptError;
import com.wolfssl.wolfcrypt.test.TimedTestWatcher;
public class Sha224Test {
private ByteBuffer data = ByteBuffer.allocateDirect(64);
private ByteBuffer result = ByteBuffer.allocateDirect(Sha224.DIGEST_SIZE);
private ByteBuffer expected = ByteBuffer.allocateDirect(Sha224.DIGEST_SIZE);
static String[] dataVector = new String[] {
"",
"abc",
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
};
static String[] hashVector = new String[] {
"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f",
"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7",
"75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525"
};
@Rule(order = Integer.MIN_VALUE)
public TestRule testWatcher = TimedTestWatcher.create();
@BeforeClass
public static void checkSha224IsAvailable() {
try {
Sha224 sha = new Sha224();
System.out.println("JNI Sha224 Class");
} catch (WolfCryptException e) {
if (e.getError() == WolfCryptError.NOT_COMPILED_IN) {
System.out.println("Sha224Test skipped: " + e.getError());
Assume.assumeTrue(false);
}
}
}
@Test
public void constructorShouldNotInitializeNativeStruct() {
assertEquals(NativeStruct.NULL, new Sha224().getNativeStruct());
}
@Test
public void updateWithWrappedOffsetAndLenShouldThrow() {
Sha224 sha = new Sha224();
byte[] data = new byte[8];
/* offset + len wraps int arithmetic, update must reject it */
try {
sha.update(data, 1, Integer.MAX_VALUE);
fail("update() should have thrown for wrapped offset + len");
} catch (IllegalStateException e) {
/* init failure is not the bounds rejection */
throw e;
} catch (RuntimeException e) {
/* expected */
}
}
@Test
public void hashShouldMatchUsingByteBuffer() throws ShortBufferException {
for (int i = 0; i < dataVector.length; i++) {
Sha224 sha = new Sha224();
byte[] input = dataVector[i].getBytes();
data.put(input).rewind();
expected.put(Util.h2b(hashVector[i])).rewind();
sha.update(data, input.length);
sha.digest(result);
data.rewind();
result.rewind();
assertEquals(expected, result);
}
}
@Test
public void hashShouldMatchUsingByteArray() {
for (int i = 0; i < dataVector.length; i++) {
Sha224 sha = new Sha224();
byte[] data = dataVector[i].getBytes();
byte[] expected = Util.h2b(hashVector[i]);
sha.update(data);
byte[] result = sha.digest();
assertArrayEquals(expected, result);
}
}
@Test
public void releaseAndReInitObject() {
Sha224 sha = new Sha224();
byte[] data = dataVector[0].getBytes();
byte[] expected = Util.h2b(hashVector[0]);
byte[] result = null;
sha.update(data);
result = sha.digest();
assertArrayEquals(expected, result);
sha.releaseNativeStruct();
/* test re-initializing object */
sha = new Sha224();
result = null;
sha.update(data);
result = sha.digest();
sha.releaseNativeStruct();
}
@Test
public void reuseObject() {
Sha224 sha = new Sha224();
byte[] data = dataVector[0].getBytes();
byte[] data2 = dataVector[1].getBytes();
byte[] expected = Util.h2b(hashVector[0]);
byte[] expected2 = Util.h2b(hashVector[1]);
byte[] result = null;
byte[] result2 = null;
sha.update(data);
result = sha.digest();
assertArrayEquals(expected, result);
/* test reusing existing object after a call to digest() */
sha.update(data2);
result2 = sha.digest();
assertArrayEquals(expected2, result2);
sha.releaseNativeStruct();
}
@Test
public void copyObject() {
Sha224 sha = null;
Sha224 shaCopy = null;
byte[] data = dataVector[0].getBytes();
byte[] expected = Util.h2b(hashVector[0]);
byte[] result = null;
byte[] result2 = null;
sha = new Sha224();
sha.update(data);
/* test making copy of Sha224, should retain same state */
shaCopy = (Sha224)sha.clone();
result = sha.digest();
result2 = shaCopy.digest();
assertArrayEquals(expected, result);
assertArrayEquals(expected, result2);
sha.releaseNativeStruct();
shaCopy.releaseNativeStruct();
}
@Test
public void threadedHashTest() throws InterruptedException {
/* Use fewer threads in CI environments to avoid resource limits */
int numThreads = System.getenv("CI") != null ? 20 : 100;
ExecutorService service = Executors.newFixedThreadPool(numThreads);
final CountDownLatch latch = new CountDownLatch(numThreads);
final LinkedBlockingQueue<byte[]> results = new LinkedBlockingQueue<>();
final byte[] rand10kBuf = new byte[10240];
/* fill large input buffer with random bytes */
new Random().nextBytes(rand10kBuf);
/* generate hash over input data concurrently across numThreads */
for (int i = 0; i < numThreads; i++) {
service.submit(new Runnable() {
@Override public void run() {
Sha224 sha = new Sha224();
/* process/update in 1024-byte chunks */
for (int j = 0; j < rand10kBuf.length; j+= 1024) {
sha.update(rand10kBuf, j, 1024);
}
/* get final hash */
byte[] hash = sha.digest();
results.add(hash.clone());
sha.releaseNativeStruct();
latch.countDown();
}
});
}
/* wait for all threads to complete */
assertTrue("timed out waiting for threads to finish",
latch.await(120, TimeUnit.SECONDS));
service.shutdown();
/* compare all digests, all should be the same across threads */
Iterator<byte[]> listIterator = results.iterator();
byte[] current = listIterator.next();
while (listIterator.hasNext()) {
byte[] next = listIterator.next();
if (!Arrays.equals(current, next)) {
fail("Found two non-identical digests in thread test");
}
if (listIterator.hasNext()) {
current = listIterator.next();
}
}
}
}