diff --git a/jni/include/com_wolfssl_wolfcrypt_FeatureDetect.h b/jni/include/com_wolfssl_wolfcrypt_FeatureDetect.h index 4629cdf..c6d24c3 100644 --- a/jni/include/com_wolfssl_wolfcrypt_FeatureDetect.h +++ b/jni/include/com_wolfssl_wolfcrypt_FeatureDetect.h @@ -55,6 +55,14 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha384Enable JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha512Enabled (JNIEnv *, jclass); +/* + * Class: com_wolfssl_wolfcrypt_FeatureDetect + * Method: Sha3Enabled + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha3Enabled + (JNIEnv *, jclass); + /* * Class: com_wolfssl_wolfcrypt_FeatureDetect * Method: AesEnabled diff --git a/jni/include/com_wolfssl_wolfcrypt_Sha3.h b/jni/include/com_wolfssl_wolfcrypt_Sha3.h new file mode 100644 index 0000000..11f9f02 --- /dev/null +++ b/jni/include/com_wolfssl_wolfcrypt_Sha3.h @@ -0,0 +1,87 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_wolfssl_wolfcrypt_Sha3 */ + +#ifndef _Included_com_wolfssl_wolfcrypt_Sha3 +#define _Included_com_wolfssl_wolfcrypt_Sha3 +#ifdef __cplusplus +extern "C" { +#endif +#undef com_wolfssl_wolfcrypt_Sha3_NULL +#define com_wolfssl_wolfcrypt_Sha3_NULL 0LL +#undef com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_224 +#define com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_224 10L +#undef com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_256 +#define com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_256 11L +#undef com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_384 +#define com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_384 12L +#undef com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_512 +#define com_wolfssl_wolfcrypt_Sha3_TYPE_SHA3_512 13L +#undef com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_224 +#define com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_224 28L +#undef com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_256 +#define com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_256 32L +#undef com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_384 +#define com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_384 48L +#undef com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_512 +#define com_wolfssl_wolfcrypt_Sha3_DIGEST_SIZE_512 64L +/* + * Class: com_wolfssl_wolfcrypt_Sha3 + * Method: mallocNativeStruct_internal + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Sha3_mallocNativeStruct_1internal + (JNIEnv *, jobject); + +/* + * Class: com_wolfssl_wolfcrypt_Sha3 + * Method: native_init_internal + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1init_1internal + (JNIEnv *, jobject, jint); + +/* + * Class: com_wolfssl_wolfcrypt_Sha3 + * Method: native_copy_internal + * Signature: (Lcom/wolfssl/wolfcrypt/Sha3;I)V + */ +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1copy_1internal + (JNIEnv *, jobject, jobject, jint); + +/* + * Class: com_wolfssl_wolfcrypt_Sha3 + * Method: native_update_internal + * Signature: (Ljava/nio/ByteBuffer;III)V + */ +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1update_1internal__Ljava_nio_ByteBuffer_2III + (JNIEnv *, jobject, jobject, jint, jint, jint); + +/* + * Class: com_wolfssl_wolfcrypt_Sha3 + * Method: native_update_internal + * Signature: ([BIII)V + */ +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1update_1internal___3BIII + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); + +/* + * Class: com_wolfssl_wolfcrypt_Sha3 + * Method: native_final_internal + * Signature: (Ljava/nio/ByteBuffer;II)V + */ +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1final_1internal__Ljava_nio_ByteBuffer_2II + (JNIEnv *, jobject, jobject, jint, jint); + +/* + * Class: com_wolfssl_wolfcrypt_Sha3 + * Method: native_final_internal + * Signature: ([BI)V + */ +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1final_1internal___3BI + (JNIEnv *, jobject, jbyteArray, jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/jni/jni_feature_detect.c b/jni/jni_feature_detect.c index 13fbeaf..fb85cd6 100644 --- a/jni/jni_feature_detect.c +++ b/jni/jni_feature_detect.c @@ -100,6 +100,18 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha512Enable #endif } +JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_Sha3Enabled + (JNIEnv* env, jclass jcl) +{ + (void)env; + (void)jcl; +#ifdef WOLFSSL_SHA3 + return JNI_TRUE; +#else + return JNI_FALSE; +#endif +} + JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_FeatureDetect_AesEnabled (JNIEnv* env, jclass jcl) { diff --git a/jni/jni_sha.c b/jni/jni_sha.c index b9011fa..8f43444 100644 --- a/jni/jni_sha.c +++ b/jni/jni_sha.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -395,6 +396,237 @@ Java_com_wolfssl_wolfcrypt_Sha_native_1final_1internal___3B( #endif } +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1init_1internal + (JNIEnv* env, jobject this) +{ +#ifdef WOLFSSL_SHA224 + int ret = 0; + Sha224* sha = (Sha224*) getNativeStruct(env, this); + if ((*env)->ExceptionOccurred(env)) { + /* getNativeStruct may throw exception, prevent throwing another */ + return; + } + + if (sha == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wc_InitSha224(sha); + } + + if (ret != 0) { + throwWolfCryptExceptionFromError(env, ret); + } +#else + (void)env; + (void)this; + throwNotCompiledInException(env); +#endif +} + +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1copy_1internal + (JNIEnv* env, jobject this, jobject toBeCopied) +{ +#ifdef WOLFSSL_SHA224 + int ret = 0; + Sha224* sha = NULL; + Sha224* tbc = NULL; /* tbc = to be copied */ + + if (this == NULL || toBeCopied == NULL) { + throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG); + return; + } + + sha = (Sha224*) getNativeStruct(env, this); + if ((*env)->ExceptionOccurred(env)) { + /* getNativeStruct may throw exception, prevent throwing another */ + return; + } + + tbc = (Sha224*) getNativeStruct(env, toBeCopied); + if ((*env)->ExceptionOccurred(env)) { + /* getNativeStruct may throw exception, prevent throwing another */ + return; + } + + ret = wc_Sha224Copy(tbc, sha); + if (ret != 0) { + throwWolfCryptExceptionFromError(env, ret); + } +#else + (void)env; + (void)this; + (void)toBeCopied; + throwNotCompiledInException(env); +#endif +} + +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1internal__Ljava_nio_ByteBuffer_2II + (JNIEnv* env, jobject this, jobject data_buffer, jint position, jint len) +{ +#ifdef WOLFSSL_SHA224 + int ret = 0; + Sha224* sha = NULL; + byte* data = NULL; + + sha = (Sha224*) getNativeStruct(env, this); + if ((*env)->ExceptionOccurred(env)) { + /* getNativeStruct may throw exception, prevent throwing another */ + return; + } + + data = getDirectBufferAddress(env, data_buffer); + + if (sha == NULL || data == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wc_Sha224Update(sha, data + position, len); + } + + if (ret != 0) { + throwWolfCryptExceptionFromError(env, ret); + } + + LogStr("wc_Sha224Update(sha=%p, data, len) = %d\n", sha, ret); + LogStr("data[%u]: [%p]\n", (word32)len, data); + LogHex(data, 0, len); +#else + (void)env; + (void)this; + (void)data_buffer; + (void)position; + (void)len; + throwNotCompiledInException(env); +#endif +} + +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1internal___3BII + (JNIEnv* env, jobject this, jbyteArray data_buffer, jint offset, jint len) +{ +#ifdef WOLFSSL_SHA224 + int ret = 0; + Sha224* sha = NULL; + byte* data = NULL; + word32 dataSz = 0; + + sha = (Sha224*) getNativeStruct(env, this); + if ((*env)->ExceptionOccurred(env)) { + /* getNativeStruct may throw exception, prevent throwing another */ + return; + } + + data = getByteArray(env, data_buffer); + dataSz = getByteArrayLength(env, data_buffer); + + if (sha == NULL || data == NULL || + (word32)(offset + len) > dataSz) { + ret = BAD_FUNC_ARG; + } + else { + ret = wc_Sha224Update(sha, data + offset, len); + } + + if (ret != 0) { + throwWolfCryptExceptionFromError(env, ret); + } + + LogStr("wc_Sha224Update(sha=%p, data, len) = %d\n", sha, ret); + LogStr("data[%u]: [%p]\n", (word32)len, data + offset); + LogHex(data, offset, len); + + releaseByteArray(env, data_buffer, data, JNI_ABORT); +#else + (void)env; + (void)this; + (void)data_buffer; + (void)offset; + (void)len; + throwNotCompiledInException(env); +#endif +} + +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1final_1internal__Ljava_nio_ByteBuffer_2I + (JNIEnv* env, jobject this, jobject hash_buffer, jint position) +{ +#ifdef WOLFSSL_SHA224 + int ret = 0; + Sha224* sha = NULL; + byte* hash = NULL; + + sha = (Sha224*) getNativeStruct(env, this); + if ((*env)->ExceptionOccurred(env)) { + /* getNativeStruct may throw exception, prevent throwing another */ + return; + } + + hash = getDirectBufferAddress(env, hash_buffer); + + if (sha == NULL || hash == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wc_Sha224Final(sha, hash + position); + } + + if (ret != 0) { + throwWolfCryptExceptionFromError(env, ret); + } + + LogStr("wc_Sha224Final(sha=%p, hash) = %d\n", sha, ret); + LogStr("hash[%u]: [%p]\n", (word32)SHA224_DIGEST_SIZE, hash); + LogHex(hash, 0, SHA224_DIGEST_SIZE); +#else + (void)env; + (void)this; + (void)hash_buffer; + (void)position; + throwNotCompiledInException(env); +#endif +} + +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1final_1internal___3B + (JNIEnv* env, jobject this, jbyteArray hash_buffer) +{ +#ifdef WOLFSSL_SHA224 + int ret = 0; + Sha224* sha = NULL; + byte* hash = NULL; + + sha = (Sha224*) getNativeStruct(env, this); + if ((*env)->ExceptionOccurred(env)) { + /* getNativeStruct may throw exception, prevent throwing another */ + return; + } + + hash = getByteArray(env, hash_buffer); + + if (sha == NULL || hash == NULL) { + ret = BAD_FUNC_ARG; + } + else { + ret = wc_Sha224Final(sha, hash); + } + + if (ret != 0) { + throwWolfCryptExceptionFromError(env, ret); + } + + LogStr("wc_Sha224Final(sha=%p, hash) = %d\n", sha, ret); + LogStr("hash[%u]: [%p]\n", (word32)SHA224_DIGEST_SIZE, hash); + LogHex(hash, 0, SHA224_DIGEST_SIZE); + + releaseByteArray(env, hash_buffer, hash, ret); +#else + (void)env; + (void)this; + (void)hash_buffer; + + throwNotCompiledInException(env); +#endif +} + + JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha256_native_1init_1internal( JNIEnv* env, jobject this) @@ -982,22 +1214,62 @@ Java_com_wolfssl_wolfcrypt_Sha512_native_1final_1internal___3B( #endif } -JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1init_1internal +JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Sha3_mallocNativeStruct_1internal (JNIEnv* env, jobject this) { -#ifdef WOLFSSL_SHA224 - int ret = 0; - Sha224* sha = (Sha224*) getNativeStruct(env, this); - if ((*env)->ExceptionOccurred(env)) { - /* getNativeStruct may throw exception, prevent throwing another */ - return; +#ifdef WOLFSSL_SHA3 + wc_Sha3* sha = NULL; + + sha = (wc_Sha3*) XMALLOC(sizeof(wc_Sha3), NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (sha == NULL) { + throwOutOfMemoryException(env, "Failed to allocate wc_Sha3 object"); + } + else { + XMEMSET(sha, 0, sizeof(wc_Sha3)); } + LogStr("new wc_Sha3 = %p\n", sha); + + return (jlong)(uintptr_t)sha; +#else + (void)env; + (void)this; + throwNotCompiledInException(env); + return (jlong)0; +#endif +} + + +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1init_1internal + (JNIEnv* env, jobject this, jint hashType) +{ +#ifdef WOLFSSL_SHA3 + int ret = 0; + wc_Sha3* sha = NULL; + + sha = (wc_Sha3*) getNativeStruct(env, this); if (sha == NULL) { ret = BAD_FUNC_ARG; } - else { - ret = wc_InitSha224(sha); + + if (ret == 0) { + switch (hashType) { + case WC_HASH_TYPE_SHA3_224: + ret = wc_InitSha3_224(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + break; + case WC_HASH_TYPE_SHA3_256: + ret = wc_InitSha3_256(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + break; + case WC_HASH_TYPE_SHA3_384: + ret = wc_InitSha3_384(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + break; + case WC_HASH_TYPE_SHA3_512: + ret = wc_InitSha3_512(sha, NULL, DYNAMIC_TYPE_TMP_BUFFER); + break; + default: + ret = BAD_FUNC_ARG; + break; + } } if (ret != 0) { @@ -1006,55 +1278,75 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1init_1internal #else (void)env; (void)this; + (void)hashType; throwNotCompiledInException(env); #endif } -JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1copy_1internal - (JNIEnv* env, jobject this, jobject toBeCopied) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1copy_1internal + (JNIEnv* env, jobject this, jobject toBeCopied, jint hashType) { -#ifdef WOLFSSL_SHA224 +#ifdef WOLFSSL_SHA3 int ret = 0; - Sha224* sha = NULL; - Sha224* tbc = NULL; /* tbc = to be copied */ + wc_Sha3* sha = NULL; + wc_Sha3* tbc = NULL; /* tbc = to be copied */ if (this == NULL || toBeCopied == NULL) { throwWolfCryptExceptionFromError(env, BAD_FUNC_ARG); return; } - sha = (Sha224*) getNativeStruct(env, this); + sha = (wc_Sha3*) getNativeStruct(env, this); if ((*env)->ExceptionOccurred(env)) { /* getNativeStruct may throw exception, prevent throwing another */ return; } - tbc = (Sha224*) getNativeStruct(env, toBeCopied); + tbc = (wc_Sha3*) getNativeStruct(env, toBeCopied); if ((*env)->ExceptionOccurred(env)) { /* getNativeStruct may throw exception, prevent throwing another */ return; } - ret = wc_Sha224Copy(tbc, sha); + switch (hashType) { + case WC_HASH_TYPE_SHA3_224: + ret = wc_Sha3_224_Copy(tbc, sha); + break; + case WC_HASH_TYPE_SHA3_256: + ret = wc_Sha3_256_Copy(tbc, sha); + break; + case WC_HASH_TYPE_SHA3_384: + ret = wc_Sha3_384_Copy(tbc, sha); + break; + case WC_HASH_TYPE_SHA3_512: + ret = wc_Sha3_512_Copy(tbc, sha); + break; + default: + ret = BAD_FUNC_ARG; + break; + } + if (ret != 0) { throwWolfCryptExceptionFromError(env, ret); } #else (void)env; (void)this; + (void)toBeCopied; + (void)hashType; throwNotCompiledInException(env); #endif } -JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1internal__Ljava_nio_ByteBuffer_2II - (JNIEnv* env, jobject this, jobject data_buffer, jint position, jint len) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1update_1internal__Ljava_nio_ByteBuffer_2III + (JNIEnv* env, jobject this, jobject data_buffer, jint offset, jint len, jint hashType) { -#ifdef WOLFSSL_SHA224 +#ifdef WOLFSSL_SHA3 int ret = 0; - Sha224* sha = NULL; - byte* data = NULL; + byte* data = NULL; + wc_Sha3* sha = NULL; - sha = (Sha224*) getNativeStruct(env, this); + sha = (wc_Sha3*) getNativeStruct(env, this); if ((*env)->ExceptionOccurred(env)) { /* getNativeStruct may throw exception, prevent throwing another */ return; @@ -1065,37 +1357,55 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1interna if (sha == NULL || data == NULL) { ret = BAD_FUNC_ARG; } - else { - ret = wc_Sha224Update(sha, data + position, len); + + if (ret == 0) { + switch (hashType) { + case WC_HASH_TYPE_SHA3_224: + ret = wc_Sha3_224_Update(sha, data + offset, len); + break; + case WC_HASH_TYPE_SHA3_256: + ret = wc_Sha3_256_Update(sha, data + offset, len); + break; + case WC_HASH_TYPE_SHA3_384: + ret = wc_Sha3_384_Update(sha, data + offset, len); + break; + case WC_HASH_TYPE_SHA3_512: + ret = wc_Sha3_512_Update(sha, data + offset, len); + break; + default: + ret = BAD_FUNC_ARG; + break; + } } - if (ret != 0) { + if (ret < 0) { throwWolfCryptExceptionFromError(env, ret); } - LogStr("wc_Sha224Update(sha=%p, data, len) = %d\n", sha, ret); + LogStr("wc_Sha3_Update(sha=%p, data, len) = %d\n", sha, ret); LogStr("data[%u]: [%p]\n", (word32)len, data); LogHex(data, 0, len); #else (void)env; (void)this; (void)data_buffer; - (void)position; + (void)offset; (void)len; + (void)hashType; throwNotCompiledInException(env); #endif } -JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1internal___3BII - (JNIEnv* env, jobject this, jbyteArray data_buffer, jint offset, jint len) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1update_1internal___3BIII + (JNIEnv* env, jobject this, jbyteArray data_buffer, jint offset, jint len, jint hashType) { -#ifdef WOLFSSL_SHA224 +#ifdef WOLFSSL_SHA3 int ret = 0; - Sha224* sha = NULL; - byte* data = NULL; + wc_Sha3* sha = NULL; + byte* data = NULL; word32 dataSz = 0; - sha = (Sha224*) getNativeStruct(env, this); + sha = (wc_Sha3*) getNativeStruct(env, this); if ((*env)->ExceptionOccurred(env)) { /* getNativeStruct may throw exception, prevent throwing another */ return; @@ -1108,16 +1418,33 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1interna (word32)(offset + len) > dataSz) { ret = BAD_FUNC_ARG; } - else { - ret = wc_Sha224Update(sha, data + offset, len); + + if (ret == 0) { + switch(hashType) { + case WC_HASH_TYPE_SHA3_224: + ret = wc_Sha3_224_Update(sha, data + offset, len); + break; + case WC_HASH_TYPE_SHA3_256: + ret = wc_Sha3_256_Update(sha, data + offset, len); + break; + case WC_HASH_TYPE_SHA3_384: + ret = wc_Sha3_384_Update(sha, data + offset, len); + break; + case WC_HASH_TYPE_SHA3_512: + ret = wc_Sha3_512_Update(sha, data + offset, len); + break; + default: + ret = BAD_FUNC_ARG; + break; + } } - if (ret != 0) { + if (ret < 0) { throwWolfCryptExceptionFromError(env, ret); } - LogStr("wc_Sha224Update(sha=%p, data, len) = %d\n", sha, ret); - LogStr("data[%u]: [%p]\n", (word32)len, data + offset); + LogStr("wc_Sha3_Update(sha=%p, data, len) = %d\n", sha, ret); + LogStr("data[%u]: [%p]\n", (word32)len, data); LogHex(data, offset, len); releaseByteArray(env, data_buffer, data, JNI_ABORT); @@ -1127,19 +1454,20 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1interna (void)data_buffer; (void)offset; (void)len; + (void)hashType; throwNotCompiledInException(env); #endif } -JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1final_1internal__Ljava_nio_ByteBuffer_2I - (JNIEnv* env, jobject this, jobject hash_buffer, jint position) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1final_1internal__Ljava_nio_ByteBuffer_2II + (JNIEnv* env, jobject this, jobject hash_buffer, jint position, jint hashType) { -#ifdef WOLFSSL_SHA224 +#ifdef WOLFSSL_SHA3 int ret = 0; - Sha224* sha = NULL; - byte* hash = NULL; + wc_Sha3* sha = NULL; + byte* hash = NULL; - sha = (Sha224*) getNativeStruct(env, this); + sha = (wc_Sha3*) getNativeStruct(env, this); if ((*env)->ExceptionOccurred(env)) { /* getNativeStruct may throw exception, prevent throwing another */ return; @@ -1150,35 +1478,51 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1final_1internal if (sha == NULL || hash == NULL) { ret = BAD_FUNC_ARG; } - else { - ret = wc_Sha224Final(sha, hash + position); + + if (ret == 0) { + switch(hashType) { + case WC_HASH_TYPE_SHA3_224: + ret = wc_Sha3_224_Final(sha, hash + position); + break; + case WC_HASH_TYPE_SHA3_256: + ret = wc_Sha3_256_Final(sha, hash + position); + break; + case WC_HASH_TYPE_SHA3_384: + ret = wc_Sha3_384_Final(sha, hash + position); + break; + case WC_HASH_TYPE_SHA3_512: + ret = wc_Sha3_512_Final(sha, hash + position); + break; + default: + ret = BAD_FUNC_ARG; + break; + } } - if (ret != 0) { + if (ret < 0) { throwWolfCryptExceptionFromError(env, ret); } - LogStr("wc_Sha224Final(sha=%p, hash) = %d\n", sha, ret); - LogStr("hash[%u]: [%p]\n", (word32)SHA224_DIGEST_SIZE, hash); - LogHex(hash, 0, SHA224_DIGEST_SIZE); + LogStr("wc_Sha3_Final(sha=%p, hash) = %d\n", sha, ret); #else (void)env; (void)this; (void)hash_buffer; (void)position; + (void)hashType; throwNotCompiledInException(env); #endif } -JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1final_1internal___3B - (JNIEnv* env, jobject this, jbyteArray hash_buffer) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha3_native_1final_1internal___3BI + (JNIEnv* env, jobject this, jbyteArray hash_buffer, jint hashType) { -#ifdef WOLFSSL_SHA224 +#ifdef WOLFSSL_SHA3 int ret = 0; - Sha224* sha = NULL; - byte* hash = NULL; + wc_Sha3* sha = NULL; + byte* hash = NULL; - sha = (Sha224*) getNativeStruct(env, this); + sha = (wc_Sha3*) getNativeStruct(env, this); if ((*env)->ExceptionOccurred(env)) { /* getNativeStruct may throw exception, prevent throwing another */ return; @@ -1189,23 +1533,40 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1final_1internal if (sha == NULL || hash == NULL) { ret = BAD_FUNC_ARG; } - else { - ret = wc_Sha224Final(sha, hash); + + if (ret == 0) { + switch(hashType) { + case WC_HASH_TYPE_SHA3_224: + ret = wc_Sha3_224_Final(sha, hash); + break; + case WC_HASH_TYPE_SHA3_256: + ret = wc_Sha3_256_Final(sha, hash); + break; + case WC_HASH_TYPE_SHA3_384: + ret = wc_Sha3_384_Final(sha, hash); + break; + case WC_HASH_TYPE_SHA3_512: + ret = wc_Sha3_512_Final(sha, hash); + break; + default: + ret = BAD_FUNC_ARG; + break; + } } - if (ret != 0) { + if (ret < 0) { throwWolfCryptExceptionFromError(env, ret); } - LogStr("wc_Sha224Final(sha=%p, hash) = %d\n", sha, ret); - LogStr("hash[%u]: [%p]\n", (word32)SHA224_DIGEST_SIZE, hash); - LogHex(hash, 0, SHA224_DIGEST_SIZE); + LogStr("wc_Sha3_Final(sha=%p, hash) = %d\n", sha, ret); releaseByteArray(env, hash_buffer, hash, ret); #else (void)env; (void)this; (void)hash_buffer; + (void)hashType; + throwNotCompiledInException(env); #endif } diff --git a/scripts/infer.sh b/scripts/infer.sh index 9bf5fd4..0334fbe 100755 --- a/scripts/infer.sh +++ b/scripts/infer.sh @@ -57,6 +57,7 @@ infer --fail-on-issue run -- javac \ src/main/java/com/wolfssl/wolfcrypt/Sha256.java \ src/main/java/com/wolfssl/wolfcrypt/Sha384.java \ src/main/java/com/wolfssl/wolfcrypt/Sha512.java \ + src/main/java/com/wolfssl/wolfcrypt/Sha3.java \ src/main/java/com/wolfssl/wolfcrypt/WolfCrypt.java \ src/main/java/com/wolfssl/wolfcrypt/WolfCryptError.java \ src/main/java/com/wolfssl/wolfcrypt/WolfCryptException.java \ diff --git a/src/main/java/com/wolfssl/wolfcrypt/FeatureDetect.java b/src/main/java/com/wolfssl/wolfcrypt/FeatureDetect.java index 0eaa2f9..275e2cd 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/FeatureDetect.java +++ b/src/main/java/com/wolfssl/wolfcrypt/FeatureDetect.java @@ -69,6 +69,13 @@ public class FeatureDetect { */ public static native boolean Sha512Enabled(); + /** + * Tests if SHA3 is compiled into the native wolfSSL library. + * + * @return true if enabled, otherwise false if not compiled in. + */ + public static native boolean Sha3Enabled(); + /** * Tests if AES is compiled into the native wolfSSL library. * diff --git a/src/main/java/com/wolfssl/wolfcrypt/Sha3.java b/src/main/java/com/wolfssl/wolfcrypt/Sha3.java new file mode 100644 index 0000000..8a1a2d4 --- /dev/null +++ b/src/main/java/com/wolfssl/wolfcrypt/Sha3.java @@ -0,0 +1,309 @@ +/* Sha3.java + * + * Copyright (C) 2006-2025 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 2 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; + +import java.nio.ByteBuffer; + +/** + * Wrapper for the native WolfCrypt SHA3 implementation + */ +public class Sha3 extends MessageDigest implements Cloneable { + + /** SHA3-224 hash type */ + public static final int TYPE_SHA3_224 = 10; + /** SHA3-256 hash type */ + public static final int TYPE_SHA3_256 = 11; + /** SHA3-384 hash type */ + public static final int TYPE_SHA3_384 = 12; + /** SHA3-512 hash type */ + public static final int TYPE_SHA3_512 = 13; + + /** SHA3-224 digest size */ + public static final int DIGEST_SIZE_224 = 28; + /** SHA3-256 digest size */ + public static final int DIGEST_SIZE_256 = 32; + /** SHA3-384 digest size */ + public static final int DIGEST_SIZE_384 = 48; + /** SHA3-512 digest size */ + public static final int DIGEST_SIZE_512 = 64; + + /** Array to init Sha3 with, will be reset to null once initialized */ + private byte[] initialData = null; + + /** Hash type of this current object */ + private int hashType = 0; + + /** Digest size of this current object */ + private int digestSize = 0; + + /* Native JNI methods, internally reach back and grab/use pointer + * from NativeStruct.java. We wrap calls to these below in order to + * synchronize access to native pointer between threads */ + private native long mallocNativeStruct_internal() + throws OutOfMemoryError; + private native void native_init_internal(int hashType); + private native void native_copy_internal(Sha3 toBeCopied, int hashType); + private native void native_update_internal(ByteBuffer data, int offset, + int len, int hashType); + private native void native_update_internal(byte[] data, int offset, + int len, int hashType); + private native void native_final_internal(ByteBuffer hash, int offset, + int hashType); + private native void native_final_internal(byte[] hash, int hashType); + + /** + * Get the hash type of this Sha3 object + * + * @return the hash type of this Sha3 object. One of TYPE_SHA3_224, + * TYPE_SHA3_256, TYPE_SHA3_384, or TYPE_SHA3_512. + */ + public int getHashType() { + return this.hashType; + } + + /** + * Sanitize and set the hash type of this Sha3 object. + * + * @param hashType hash type of the Sha3 object + * + * @throws WolfCryptException if the hash type is invalid + */ + private void sanitizeAndSetHashType(int hashType) { + if (hashType != TYPE_SHA3_224 && hashType != TYPE_SHA3_256 && + hashType != TYPE_SHA3_384 && hashType != TYPE_SHA3_512) { + throw new WolfCryptException( + "Invalid hash type: " + hashType + ". " + + "Must be one of TYPE_SHA3_224, TYPE_SHA3_256, " + + "TYPE_SHA3_384, or TYPE_SHA3_512."); + } + this.hashType = hashType; + + switch (hashType) { + case TYPE_SHA3_224: + this.digestSize = DIGEST_SIZE_224; + break; + case TYPE_SHA3_256: + this.digestSize = DIGEST_SIZE_256; + break; + case TYPE_SHA3_384: + this.digestSize = DIGEST_SIZE_384; + break; + case TYPE_SHA3_512: + this.digestSize = DIGEST_SIZE_512; + break; + } + } + + /** + * Malloc native JNI Sha3 structure + * + * @return native allocated pointer + * + * @throws OutOfMemoryError when malloc fails with memory error + */ + protected long mallocNativeStruct() + throws OutOfMemoryError { + + synchronized (pointerLock) { + return mallocNativeStruct_internal(); + } + } + + /** + * Initialize Sha3 object + * + * @throws WolfCryptException if native operation fails + */ + protected void native_init() + throws WolfCryptException { + + synchronized (pointerLock) { + native_init_internal(this.hashType); + + /* Check if we need to init with passed in data */ + if (this.initialData != null) { + update(this.initialData); + this.initialData = null; + } + } + } + + /** + * Copy existing native wc_Sha3 struct (Sha3 object) into this one. + * Copies structure state using wc_Sha3_XXX_Copy(). + * + * @param toBeCopied initialized Sha3 object to be copied. + * + * @throws WolfCryptException if native operation fails + */ + protected void native_copy(Sha3 toBeCopied) + throws WolfCryptException { + + synchronized (pointerLock) { + native_copy_internal(toBeCopied, toBeCopied.getHashType()); + } + } + + /** + * Native SHA-3 update + * + * @param data input data + * @param offset offset into input data + * @param len length of input data + * + * @throws WolfCryptException if native operation fails + */ + protected void native_update(ByteBuffer data, int offset, int len) + throws WolfCryptException { + + synchronized (pointerLock) { + native_update_internal(data, offset, len, this.hashType); + } + } + + /** + * Native SHA-3 update + * + * @param data input data + * @param offset offset into input data + * @param len length of input data + * + * @throws WolfCryptException if native operation fails + */ + protected void native_update(byte[] data, int offset, int len) + throws WolfCryptException { + + synchronized (pointerLock) { + native_update_internal(data, offset, len, this.hashType); + } + } + + /** + * Native SHA-3 final, calculate final digest + * + * @param hash output buffer to place digest + * @param offset offset into output buffer to write digest + * + * @throws WolfCryptException if native operation fails + */ + protected void native_final(ByteBuffer hash, int offset) + throws WolfCryptException { + + synchronized (pointerLock) { + native_final_internal(hash, offset, this.hashType); + } + } + + /** + * Native SHA-3 final, calculate final digest + * + * @param hash output buffer to place digest + * + * @throws WolfCryptException if native operation fails + */ + protected void native_final(byte[] hash) + throws WolfCryptException { + + synchronized (pointerLock) { + native_final_internal(hash, this.hashType); + } + } + + /** + * Create new Sha3 object. + * + * @param hashType SHA3 hash type: one of TYPE_SHA3_224, TYPE_SHA3_256, + * TYPE_SHA3_384, or TYPE_SHA3_512. + * + * @throws WolfCryptException if SHA-3 has not been compiled into native + * wolfCrypt library. + */ + public Sha3(int hashType) { + if (!FeatureDetect.Sha3Enabled()) { + throw new WolfCryptException( + WolfCryptError.NOT_COMPILED_IN.getCode()); + } + /* Internal state is initialized on first use */ + sanitizeAndSetHashType(hashType); + } + + /** + * Create new Sha3 object by making a copy of the one given. + * + * @param sha3 Initialized/created Sha3 object to be copied + * + * @throws WolfCryptException to indicate this constructor has been + * deprecated, along with instructions on what API to call + * + * @deprecated This constructor has been deprecated to avoid storage + * of a second Sha3 object inside this Sha3 object, and to + * avoid potential incomplete object creation issues between + * subclass/superclasses. Please refactor existing code to + * call Sha3.clone() to get a copy of an existing Sha3 + * object. + */ + @Deprecated + public Sha3(Sha3 sha3) { + throw new WolfCryptException( + "Constructor deprecated, use Sha3.clone() to duplicate " + + "Sha3 object"); + } + + /** + * Create new Sha3 object. + * + * @param data input data to hash + * @param hashType hash type of the Sha3 object + * + * @throws WolfCryptException if SHA-3 has not been compiled into native + * wolfCrypt library. + */ + public Sha3(byte[] data, int hashType) { + if (!FeatureDetect.Sha3Enabled()) { + throw new WolfCryptException( + WolfCryptError.NOT_COMPILED_IN.getCode()); + } + /* Internal state is initialized on first use */ + this.initialData = data.clone(); + sanitizeAndSetHashType(hashType); + } + + /** + * Get SHA3 digest size + * + * @return SHA3 digest size + */ + public int digestSize() { + return this.digestSize; + } + + @Override + public Object clone() { + + Sha3 shaCopy = new Sha3(this.hashType); + /* Initialize NativeStruct, since is done on first use */ + shaCopy.checkStateAndInitialize(); + shaCopy.native_copy(this); + + return shaCopy; + } +} diff --git a/src/test/java/com/wolfssl/wolfcrypt/test/Sha3Test.java b/src/test/java/com/wolfssl/wolfcrypt/test/Sha3Test.java new file mode 100644 index 0000000..1d1c05d --- /dev/null +++ b/src/test/java/com/wolfssl/wolfcrypt/test/Sha3Test.java @@ -0,0 +1,377 @@ +/* Sha3Test.java + * + * Copyright (C) 2006-2025 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 2 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.LinkedBlockingQueue; + +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.Sha3; +import com.wolfssl.wolfcrypt.NativeStruct; +import com.wolfssl.wolfcrypt.WolfCryptException; +import com.wolfssl.wolfcrypt.WolfCryptError; + +public class Sha3Test { + private ByteBuffer data = ByteBuffer.allocateDirect(32); + private ByteBuffer result = ByteBuffer.allocateDirect(Sha3.DIGEST_SIZE_512); + private ByteBuffer expected = ByteBuffer.allocateDirect(Sha3.DIGEST_SIZE_512); + + @Rule + public TestRule watcher = new TestWatcher() { + protected void starting(Description desc) { + System.out.println("\t" + desc.getMethodName()); + } + }; + + @BeforeClass + public static void checkSha3IsAvailable() { + try { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_256); + System.out.println("JNI Sha3 Class"); + } catch (WolfCryptException e) { + if (e.getError() == WolfCryptError.NOT_COMPILED_IN) { + System.out.println("Sha3Test skipped: " + e.getError()); + Assume.assumeTrue(false); + } + } + } + + @Test + public void constructorShouldNotInitializeNativeStruct() { + assertEquals(NativeStruct.NULL, + new Sha3(Sha3.TYPE_SHA3_256).getNativeStruct()); + } + + @Test + public void sha3_256HashShouldMatchUsingByteArray() { + /* Test vectors from NIST FIPS 202 - SHA-3 Standard */ + String[] dataVector = new String[] { + "", /* empty string */ + "616263", /* "abc" */ + /* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */ + "6162636462636465636465666465666765666768666768696768696A68696A6B" + + "696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071" + }; + + String[] hashVector = new String[] { + /* NIST FIPS 202 A.1 - SHA3-256 Empty Test Vector */ + "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", + /* NIST FIPS 202 A.1 - SHA3-256 abc Test Vector */ + "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", + /* NIST FIPS 202 A.1 - SHA3-256 Long Test Vector */ + "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376" + }; + + for (int i = 0; i < dataVector.length; i++) { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_256); + byte[] data = Util.h2b(dataVector[i]); + byte[] expected = Util.h2b(hashVector[i]); + + sha.update(data); + byte[] result = sha.digest(); + + assertArrayEquals(expected, result); + } + } + + @Test + public void sha3_224HashShouldMatchUsingByteArray() { + /* Test vectors from NIST FIPS 202 - SHA-3 Standard */ + String[] dataVector = new String[] { + "", /* empty string */ + "616263", /* "abc" */ + /* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */ + "6162636462636465636465666465666765666768666768696768696A68696A6B" + + "696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071" + }; + + String[] hashVector = new String[] { + /* NIST FIPS 202 A.1 - SHA3-224 Empty Test Vector */ + "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7", + /* NIST FIPS 202 A.1 - SHA3-224 abc Test Vector */ + "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf", + /* NIST FIPS 202 A.1 - SHA3-224 Long Test Vector */ + "8a24108b154ada21c9fd5574494479ba5c7e7ab76ef264ead0fcce33" + }; + + for (int i = 0; i < dataVector.length; i++) { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_224); + byte[] data = Util.h2b(dataVector[i]); + byte[] expected = Util.h2b(hashVector[i]); + + sha.update(data); + byte[] result = sha.digest(); + + assertArrayEquals(expected, result); + } + } + + @Test + public void sha3_384HashShouldMatchUsingByteArray() { + /* Test vectors from NIST FIPS 202 - SHA-3 Standard */ + String[] dataVector = new String[] { + "", /* empty string */ + "616263", /* "abc" */ + /* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */ + "6162636462636465636465666465666765666768666768696768696A68696A6B" + + "696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071" + }; + + String[] hashVector = new String[] { + /* NIST FIPS 202 A.1 - SHA3-384 Empty Test Vector */ + "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2a" + + "c3713831264adb47fb6bd1e058d5f004", + /* NIST FIPS 202 A.1 - SHA3-384 abc Test Vector */ + "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b2" + + "98d88cea927ac7f539f1edf228376d25", + /* NIST FIPS 202 A.1 - SHA3-384 Long Test Vector */ + "991c665755eb3a4b6bbdfb75c78a492e8c56a22c5c4d7e429bfdbc32b9d4ad5a" + + "a04a1f076e62fea19eef51acd0657c22" + }; + + for (int i = 0; i < dataVector.length; i++) { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_384); + byte[] data = Util.h2b(dataVector[i]); + byte[] expected = Util.h2b(hashVector[i]); + + sha.update(data); + byte[] result = sha.digest(); + + assertArrayEquals(expected, result); + } + } + + @Test + public void sha3_512HashShouldMatchUsingByteArray() { + /* Test vectors from NIST FIPS 202 - SHA-3 Standard */ + String[] dataVector = new String[] { + "", /* empty string */ + "616263", /* "abc" */ + /* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */ + "6162636462636465636465666465666765666768666768696768696A68696A6B" + + "696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071" + }; + + String[] hashVector = new String[] { + /* NIST FIPS 202 A.1 - SHA3-512 Empty Test Vector */ + "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a6" + + "15b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26", + /* NIST FIPS 202 A.1 - SHA3-512 abc Test Vector */ + "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e" + + "10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0", + /* NIST FIPS 202 A.1 - SHA3-512 Long Test Vector */ + "04a371e84ecfb5b8b77cb48610fca8182dd457ce6f326a0fd3d7ec2f1e91636d" + + "ee691fbe0c985302ba1b0d8dc78c086346b533b49c030d99a27daf1139d6e75e" + }; + + for (int i = 0; i < dataVector.length; i++) { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_512); + byte[] data = Util.h2b(dataVector[i]); + byte[] expected = Util.h2b(hashVector[i]); + + sha.update(data); + byte[] result = sha.digest(); + + assertArrayEquals(expected, result); + } + } + + @Test + public void reuseObject() { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_256); + byte[] data = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 }; + byte[] data2 = new byte[] { 0x05, 0x06, 0x07, 0x08, 0x09 }; + + sha.update(data); + byte[] result = sha.digest(); + + /* test reusing existing object after a call to digest() */ + sha.update(data2); + byte[] result2 = sha.digest(); + + assertNotNull(result); + assertNotNull(result2); + assertFalse(Arrays.equals(result, result2)); + + sha.releaseNativeStruct(); + } + + @Test + public void copyObject() { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_256); + byte[] data = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 }; + + sha.update(data); + + /* test making copy of Sha3, should retain same state */ + Sha3 shaCopy = (Sha3)sha.clone(); + + byte[] result = sha.digest(); + byte[] result2 = shaCopy.digest(); + + assertArrayEquals(result, result2); + + sha.releaseNativeStruct(); + shaCopy.releaseNativeStruct(); + } + + @Test + public void threadedHashTest() throws InterruptedException { + int numThreads = 100; + ExecutorService service = Executors.newFixedThreadPool(numThreads); + final CountDownLatch latch = new CountDownLatch(numThreads); + final LinkedBlockingQueue 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() { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_256); + + /* 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 */ + latch.await(); + + /* compare all digests, all should be the same across threads */ + Iterator 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(); + } + } + } + + @Test + public void blockSizeEdgeCases() { + /* Test vectors for block size edge cases */ + int[] sizes = { + 136, /* SHA3-224 block size */ + 104, /* SHA3-256 block size */ + 72, /* SHA3-384 block size */ + 72 /* SHA3-512 block size */ + }; + int[] types = { + Sha3.TYPE_SHA3_224, + Sha3.TYPE_SHA3_256, + Sha3.TYPE_SHA3_384, + Sha3.TYPE_SHA3_512 + }; + + for (int i = 0; i < sizes.length; i++) { + /* Test exactly block size */ + byte[] blockData = new byte[sizes[i]]; + Arrays.fill(blockData, (byte)0x61); /* fill with 'a' */ + + Sha3 sha = new Sha3(types[i]); + sha.update(blockData); + byte[] result1 = sha.digest(); + + /* Test one byte less than block size */ + byte[] underData = new byte[sizes[i] - 1]; + Arrays.fill(underData, (byte)0x61); + + sha = new Sha3(types[i]); + sha.update(underData); + byte[] result2 = sha.digest(); + + /* Test one byte more than block size */ + byte[] overData = new byte[sizes[i] + 1]; + Arrays.fill(overData, (byte)0x61); + + sha = new Sha3(types[i]); + sha.update(overData); + byte[] result3 = sha.digest(); + + /* Results should all be different */ + assertFalse(Arrays.equals(result1, result2)); + assertFalse(Arrays.equals(result2, result3)); + assertFalse(Arrays.equals(result1, result3)); + } + } + + @Test + public void streamingUpdates() { + /* Test streaming updates with known test vector */ + String input = + "6162636462636465636465666465666765666768666768696768696A68696A6B" + + "696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F7071"; + String expected = + "41c0dba2a9d6240849100376a8235e2c82e1b9998a999e21db32dd97496d3376"; + + byte[] data = Util.h2b(input); + + /* Test different chunk sizes */ + int[] chunks = {1, 3, 7, 13, 17, 32, 64}; + + for (int chunkSize : chunks) { + Sha3 sha = new Sha3(Sha3.TYPE_SHA3_256); + + /* Update in chunks */ + for (int i = 0; i < data.length; i += chunkSize) { + int len = Math.min(chunkSize, data.length - i); + sha.update(data, i, len); + } + + byte[] result = sha.digest(); + assertArrayEquals(Util.h2b(expected), result); + } + } +} + diff --git a/src/test/java/com/wolfssl/wolfcrypt/test/WolfCryptTestSuite.java b/src/test/java/com/wolfssl/wolfcrypt/test/WolfCryptTestSuite.java index 4430d9b..e89abae 100644 --- a/src/test/java/com/wolfssl/wolfcrypt/test/WolfCryptTestSuite.java +++ b/src/test/java/com/wolfssl/wolfcrypt/test/WolfCryptTestSuite.java @@ -37,6 +37,7 @@ import org.junit.runners.Suite.SuiteClasses; Sha256Test.class, Sha384Test.class, Sha512Test.class, + Sha3Test.class, HmacTest.class, RngTest.class, RsaTest.class,