diff --git a/README_JCE.md b/README_JCE.md index 309887f..89a9941 100644 --- a/README_JCE.md +++ b/README_JCE.md @@ -92,6 +92,10 @@ The JCE provider currently supports the following algorithms: SHA-256 SHA-384 SHA-512 + SHA3-224 + SHA3-256 + SHA3-384 + SHA3-512 SecureRandom Class DEFAULT (maps to HashDRBG) @@ -112,6 +116,10 @@ The JCE provider currently supports the following algorithms: HmacSHA256 HmacSHA384 HmacSHA512 + HmacSHA3-224 + HmacSHA3-256 + HmacSHA3-384 + HmacSHA3-512 Signature Class MD5withRSA @@ -120,11 +128,19 @@ The JCE provider currently supports the following algorithms: SHA256withRSA SHA384withRSA SHA512withRSA + SHA3-224withRSA + SHA3-256withRSA + SHA3-384withRSA + SHA3-512withRSA SHA1withECDSA SHA224withECDSA SHA256withECDSA SHA384withECDSA SHA512withECDSA + SHA3-224withECDSA + SHA3-256withECDSA + SHA3-384withECDSA + SHA3-512withECDSA KeyAgreement Class DiffieHellman 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_Hmac.h b/jni/include/com_wolfssl_wolfcrypt_Hmac.h index a992d9f..34db274 100644 --- a/jni/include/com_wolfssl_wolfcrypt_Hmac.h +++ b/jni/include/com_wolfssl_wolfcrypt_Hmac.h @@ -113,6 +113,38 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha512 JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeBlake2b (JNIEnv *, jclass); +/* + * Class: com_wolfssl_wolfcrypt_Hmac + * Method: getCodeSha3_224 + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1224 + (JNIEnv *, jclass); + +/* + * Class: com_wolfssl_wolfcrypt_Hmac + * Method: getCodeSha3_256 + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1256 + (JNIEnv *, jclass); + +/* + * Class: com_wolfssl_wolfcrypt_Hmac + * Method: getCodeSha3_384 + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1384 + (JNIEnv *, jclass); + +/* + * Class: com_wolfssl_wolfcrypt_Hmac + * Method: getCodeSha3_512 + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1512 + (JNIEnv *, jclass); + /* * Class: com_wolfssl_wolfcrypt_Hmac * Method: mallocNativeStruct 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_hmac.c b/jni/jni_hmac.c index edc66bf..dba7d6c 100644 --- a/jni/jni_hmac.c +++ b/jni/jni_hmac.c @@ -65,7 +65,9 @@ static WC_INLINE int GetHashSizeByType(int type) { if (!(type == WC_MD5 || type == WC_SHA || type == WC_SHA224 - || type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512)) { + || type == WC_SHA256 || type == WC_SHA384 || type == WC_SHA512 + || type == WC_SHA3_224 || type == WC_SHA3_256 || type == WC_SHA3_384 + || type == WC_SHA3_512)) { return BAD_FUNC_ARG; } @@ -100,14 +102,27 @@ static WC_INLINE int GetHashSizeByType(int type) return SHA512_DIGEST_SIZE; #endif + #if defined(WOLFSSL_SHA3) + case WC_SHA3_224: + return WC_SHA3_224_DIGEST_SIZE; + + case WC_SHA3_256: + return WC_SHA3_256_DIGEST_SIZE; + + case WC_SHA3_384: + return WC_SHA3_384_DIGEST_SIZE; + + case WC_SHA3_512: + return WC_SHA3_512_DIGEST_SIZE; + #endif + default: return BAD_FUNC_ARG; } } -JNIEXPORT jlong JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_mallocNativeStruct( - JNIEnv* env, jobject this) +JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Hmac_mallocNativeStruct + (JNIEnv* env, jobject this) { #ifndef NO_HMAC Hmac* hmac = NULL; @@ -131,9 +146,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_mallocNativeStruct( #endif } -JNIEXPORT void JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacSetKey( - JNIEnv* env, jobject this, jint type, jbyteArray key_object) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacSetKey + (JNIEnv* env, jobject this, jint type, jbyteArray key_object) { #ifndef NO_HMAC int ret = 0; @@ -165,9 +179,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacSetKey( #endif } -JNIEXPORT void JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate__B( - JNIEnv* env, jobject this, jbyte data) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate__B + (JNIEnv* env, jobject this, jbyte data) { #ifndef NO_HMAC int ret = 0; @@ -191,9 +204,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate__B( #endif } -JNIEXPORT void JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate___3BII( - JNIEnv* env, jobject this, jbyteArray data_object, jint offset, jint length) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate___3BII + (JNIEnv* env, jobject this, jbyteArray data_object, jint offset, jint length) { #ifndef NO_HMAC int ret = 0; @@ -225,9 +237,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate___3BII( #endif } -JNIEXPORT void JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate__Ljava_nio_ByteBuffer_2II( - JNIEnv* env, jobject this, jobject data_object, jint offset, jint length) +JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate__Ljava_nio_ByteBuffer_2II + (JNIEnv* env, jobject this, jobject data_object, jint offset, jint length) { #ifndef NO_HMAC int ret = 0; @@ -257,9 +268,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacUpdate__Ljava_nio_ByteBuffer_2II( #endif } -JNIEXPORT jbyteArray JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacFinal( - JNIEnv* env, jobject this) +JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacFinal + (JNIEnv* env, jobject this) { jbyteArray result = NULL; @@ -308,9 +318,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacFinal( return result; } -JNIEXPORT jint JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacSizeByType( - JNIEnv* env, jobject this, jint type) +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacSizeByType + (JNIEnv* env, jobject this, jint type) { jint result = 0; @@ -330,9 +339,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_wc_1HmacSizeByType( return result; } -JNIEXPORT jint JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_getCodeMd5( - JNIEnv* env, jobject this) +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeMd5 + (JNIEnv* env, jobject this) { #ifndef NO_MD5 jint result = WC_MD5; @@ -344,9 +352,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_getCodeMd5( #endif } -JNIEXPORT jint JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha( - JNIEnv* env, jobject this) +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha + (JNIEnv* env, jobject this) { #ifndef NO_SHA jint result = WC_SHA; @@ -358,9 +365,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha( #endif } -JNIEXPORT jint JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha224( - JNIEnv* env, jobject this) +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha224 + (JNIEnv* env, jobject this) { #ifdef WOLFSSL_SHA224 jint result = WC_SHA224; @@ -372,9 +378,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha224( #endif } -JNIEXPORT jint JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha256( - JNIEnv* env, jobject this) +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha256 + (JNIEnv* env, jobject this) { #ifndef NO_SHA256 jint result = WC_SHA256; @@ -386,9 +391,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha256( #endif } -JNIEXPORT jint JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha384( - JNIEnv* env, jobject this) +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha384 + (JNIEnv* env, jobject this) { #ifdef WOLFSSL_SHA384 jint result = WC_SHA384; @@ -400,9 +404,8 @@ Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha384( #endif } -JNIEXPORT jint JNICALL -Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha512( - JNIEnv* env, jobject this) +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha512 + (JNIEnv* env, jobject this) { #ifdef WOLFSSL_SHA512 jint result = WC_SHA512; @@ -414,3 +417,55 @@ Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha512( #endif } +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1224 + (JNIEnv* env, jclass this) +{ +#ifdef WOLFSSL_SHA3 + jint result = WC_SHA3_224; + LogStr("WC_SHA3_224 = %d\n", result); + return result; +#else + /* not compiled in */ + return (jint) -1; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1256 + (JNIEnv* env, jclass this) +{ +#ifdef WOLFSSL_SHA3 + jint result = WC_SHA3_256; + LogStr("WC_SHA3_256 = %d\n", result); + return result; +#else + /* not compiled in */ + return (jint) -1; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1384 + (JNIEnv* env, jclass this) +{ +#ifdef WOLFSSL_SHA3 + jint result = WC_SHA3_384; + LogStr("WC_SHA3_384 = %d\n", result); + return result; +#else + /* not compiled in */ + return (jint) -1; +#endif +} + +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Hmac_getCodeSha3_1512 + (JNIEnv* env, jclass this) +{ +#ifdef WOLFSSL_SHA3 + jint result = WC_SHA3_512; + LogStr("WC_SHA3_512 = %d\n", result); + return result; +#else + /* not compiled in */ + return (jint) -1; +#endif +} + diff --git a/jni/jni_sha.c b/jni/jni_sha.c index b9011fa..b995d81 100644 --- a/jni/jni_sha.c +++ b/jni/jni_sha.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -308,7 +309,7 @@ Java_com_wolfssl_wolfcrypt_Sha_native_1update_1internal___3BII( data = getByteArray(env, data_buffer); dataSz = getByteArrayLength(env, data_buffer); - if (sha == NULL || data == NULL || + if (sha == NULL || data == NULL || offset < 0 || len < 0 || (word32)(offset + len) > dataSz) { ret = BAD_FUNC_ARG; } @@ -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 || offset < 0 || len < 0 || + (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) @@ -503,7 +735,7 @@ Java_com_wolfssl_wolfcrypt_Sha256_native_1update_1internal___3BII( data = getByteArray(env, data_buffer); dataSz = getByteArrayLength(env, data_buffer); - if (sha == NULL || data == NULL || + if (sha == NULL || data == NULL || offset < 0 || len < 0 || (word32)(offset + len) > dataSz) { ret = BAD_FUNC_ARG; } @@ -698,7 +930,7 @@ Java_com_wolfssl_wolfcrypt_Sha384_native_1update_1internal___3BII( data = getByteArray(env, data_buffer); dataSz = getByteArrayLength(env, data_buffer); - if (sha == NULL || data == NULL || + if (sha == NULL || data == NULL || offset < 0 || len < 0 || (word32)(offset + len) > dataSz) { ret = BAD_FUNC_ARG; } @@ -894,7 +1126,7 @@ Java_com_wolfssl_wolfcrypt_Sha512_native_1update_1internal___3BII( data = getByteArray(env, data_buffer); dataSz = getByteArrayLength(env, data_buffer); - if (sha == NULL || data == NULL || + if (sha == NULL || data == NULL || offset < 0 || len < 0 || (word32)(offset + len) > dataSz) { ret = BAD_FUNC_ARG; } @@ -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; @@ -1104,20 +1414,37 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Sha224_native_1update_1interna data = getByteArray(env, data_buffer); dataSz = getByteArrayLength(env, data_buffer); - if (sha == NULL || data == NULL || + if (sha == NULL || data == NULL || offset < 0 || len < 0 || (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/provider/jce/WolfCryptMac.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptMac.java index 98fff82..c9acf66 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptMac.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptMac.java @@ -35,6 +35,7 @@ import com.wolfssl.wolfcrypt.Sha224; import com.wolfssl.wolfcrypt.Sha256; import com.wolfssl.wolfcrypt.Sha384; import com.wolfssl.wolfcrypt.Sha512; +import com.wolfssl.wolfcrypt.Sha3; import com.wolfssl.wolfcrypt.Hmac; /** @@ -48,7 +49,11 @@ public class WolfCryptMac extends MacSpi { WC_HMAC_SHA224, WC_HMAC_SHA256, WC_HMAC_SHA384, - WC_HMAC_SHA512 + WC_HMAC_SHA512, + WC_HMAC_SHA3_224, + WC_HMAC_SHA3_256, + WC_HMAC_SHA3_384, + WC_HMAC_SHA3_512 } private Hmac hmac = null; @@ -94,6 +99,26 @@ public class WolfCryptMac extends MacSpi { this.nativeHmacType = Hmac.SHA512; break; + case WC_HMAC_SHA3_224: + this.digestSize = Sha3.DIGEST_SIZE_224; + this.nativeHmacType = Hmac.SHA3_224; + break; + + case WC_HMAC_SHA3_256: + this.digestSize = Sha3.DIGEST_SIZE_256; + this.nativeHmacType = Hmac.SHA3_256; + break; + + case WC_HMAC_SHA3_384: + this.digestSize = Sha3.DIGEST_SIZE_384; + this.nativeHmacType = Hmac.SHA3_384; + break; + + case WC_HMAC_SHA3_512: + this.digestSize = Sha3.DIGEST_SIZE_512; + this.nativeHmacType = Hmac.SHA3_512; + break; + default: throw new NoSuchAlgorithmException( "Unsupported HMAC type"); @@ -178,6 +203,12 @@ public class WolfCryptMac extends MacSpi { return "SHA384"; case WC_HMAC_SHA512: return "SHA512"; + case WC_HMAC_SHA3_224: + return "SHA3-224"; + case WC_HMAC_SHA3_256: + return "SHA3-256"; + case WC_HMAC_SHA3_384: + return "SHA3-384"; default: return "None"; } @@ -287,5 +318,64 @@ public class WolfCryptMac extends MacSpi { super(HmacType.WC_HMAC_SHA512); } } -} + /** + * wolfJCE HMAC-SHA3-224 class + */ + public static final class wcHmacSHA3_224 extends WolfCryptMac { + /** + * Create new wcHmacSHA3_224 object + * + * @throws NoSuchAlgorithmException if HMAC-SHA3-224 is not available at + * native wolfCrypt level. + */ + public wcHmacSHA3_224() throws NoSuchAlgorithmException { + super(HmacType.WC_HMAC_SHA3_224); + } + } + + /** + * wolfJCE HMAC-SHA3-256 class + */ + public static final class wcHmacSHA3_256 extends WolfCryptMac { + /** + * Create new wcHmacSHA3_256 object + * + * @throws NoSuchAlgorithmException if HMAC-SHA3-256 is not available at + * native wolfCrypt level. + */ + public wcHmacSHA3_256() throws NoSuchAlgorithmException { + super(HmacType.WC_HMAC_SHA3_256); + } + } + + /** + * wolfJCE HMAC-SHA3-384 class + */ + public static final class wcHmacSHA3_384 extends WolfCryptMac { + /** + * Create new wcHmacSHA3_384 object + * + * @throws NoSuchAlgorithmException if HMAC-SHA3-384 is not available at + * native wolfCrypt level. + */ + public wcHmacSHA3_384() throws NoSuchAlgorithmException { + super(HmacType.WC_HMAC_SHA3_384); + } + } + + /** + * wolfJCE HMAC-SHA3-512 class + */ + public static final class wcHmacSHA3_512 extends WolfCryptMac { + /** + * Create new wcHmacSHA3_512 object + * + * @throws NoSuchAlgorithmException if HMAC-SHA3-512 is not available at + * native wolfCrypt level. + */ + public wcHmacSHA3_512() throws NoSuchAlgorithmException { + super(HmacType.WC_HMAC_SHA3_512); + } + } +} diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptMessageDigestSha3.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptMessageDigestSha3.java new file mode 100644 index 0000000..9c234c6 --- /dev/null +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptMessageDigestSha3.java @@ -0,0 +1,199 @@ +/* WolfCryptMessageDigestSha3.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.provider.jce; + +import java.security.MessageDigestSpi; +import java.security.NoSuchAlgorithmException; +import javax.crypto.ShortBufferException; + +import com.wolfssl.wolfcrypt.Sha3; +import com.wolfssl.wolfcrypt.WolfCryptException; + +/** + * wolfCrypt JCE SHA-3 MessageDigest wrapper + */ +public class WolfCryptMessageDigestSha3 + extends MessageDigestSpi implements Cloneable { + + /* internal reference to wolfCrypt JNI Sha object */ + private Sha3 sha; + + /** + * Create new WolfCryptMessageDigestSha3 object + * + * @param hashType hash type to be used with this MessageDigest + * @throws NoSuchAlgorithmException if digest type is not + * available in native wolfCrypt library + */ + public WolfCryptMessageDigestSha3(int hashType) + throws NoSuchAlgorithmException { + + try { + sha = new Sha3(hashType); + sha.init(); + + } catch (WolfCryptException e) { + throw new NoSuchAlgorithmException(e.getMessage()); + } + } + + /** + * Create new WolfCryptMessageDigestSha3 based on existing Sha3 object. + * Existing object should already be initialized. + * + * @param sha initialized Sha3 object to be used with this MessageDigest + */ + private WolfCryptMessageDigestSha3(Sha3 sha) { + this.sha = sha; + } + + @Override + protected byte[] engineDigest() { + + byte[] digest = new byte[sha.digestSize()]; + + try { + this.sha.digest(digest); + + } catch (ShortBufferException e) { + throw new RuntimeException(e.getMessage()); + } + + log("generated final digest, len: " + digest.length); + + return digest; + } + + @Override + protected void engineReset() { + + this.sha.init(); + + log("engine reset"); + } + + @Override + protected void engineUpdate(byte input) { + + byte[] tmp = new byte[1]; + tmp[0] = input; + + this.sha.update(tmp, 1); + + log("update with single byte"); + } + + @Override + protected void engineUpdate(byte[] input, int offset, int len) { + + this.sha.update(input, offset, len); + + log("update, offset: " + offset + ", len: " + len); + } + + @Override + protected int engineGetDigestLength() { + return this.sha.digestSize(); + } + + private void log(String msg) { + WolfCryptDebug.print("[MessageDigest, SHA-3] " + msg); + } + + @Override + public Object clone() { + Sha3 shaCopy = (Sha3)this.sha.clone(); + return new WolfCryptMessageDigestSha3(shaCopy); + } + + @SuppressWarnings("deprecation") + @Override + protected void finalize() throws Throwable { + try { + if (this.sha != null) + this.sha.releaseNativeStruct(); + } finally { + super.finalize(); + } + } + + /** + * wolfJCE SHA1wECDSA message digest class + */ + public static final class wcSHA3_224 extends WolfCryptMessageDigestSha3 { + /** + * Create new wcSHA3_224 object + * + * @throws NoSuchAlgorithmException if digest type is not + * available in native wolfCrypt library + */ + public wcSHA3_224() throws NoSuchAlgorithmException { + super(Sha3.TYPE_SHA3_224); + } + } + + /** + * wolfJCE SHA3-256 message digest class + */ + public static final class wcSHA3_256 extends WolfCryptMessageDigestSha3 { + /** + * Create new wcSHA3_256 object + * + * @throws NoSuchAlgorithmException if digest type is not + * available in native wolfCrypt library + */ + public wcSHA3_256() throws NoSuchAlgorithmException { + super(Sha3.TYPE_SHA3_256); + } + } + + /** + * wolfJCE SHA3-384 message digest class + */ + public static final class wcSHA3_384 extends WolfCryptMessageDigestSha3 { + /** + * Create new wcSHA3_384 object + * + * @throws NoSuchAlgorithmException if digest type is not + * available in native wolfCrypt library + */ + public wcSHA3_384() throws NoSuchAlgorithmException { + super(Sha3.TYPE_SHA3_384); + } + } + + /** + * wolfJCE SHA3-512 message digest class + */ + public static final class wcSHA3_512 extends WolfCryptMessageDigestSha3 { + /** + * Create new wcSHA3_512 object + * + * @throws NoSuchAlgorithmException if digest type is not + * available in native wolfCrypt library + */ + public wcSHA3_512() throws NoSuchAlgorithmException { + super(Sha3.TYPE_SHA3_512); + } + } +} + diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java index 3e758ab..1bb3e37 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java @@ -94,6 +94,16 @@ public final class WolfCryptProvider extends Provider { put("MessageDigest.SHA-512", "com.wolfssl.provider.jce.WolfCryptMessageDigestSha512"); } + if (FeatureDetect.Sha3Enabled()) { + put("MessageDigest.SHA3-224", + "com.wolfssl.provider.jce.WolfCryptMessageDigestSha3$wcSHA3_224"); + put("MessageDigest.SHA3-256", + "com.wolfssl.provider.jce.WolfCryptMessageDigestSha3$wcSHA3_256"); + put("MessageDigest.SHA3-384", + "com.wolfssl.provider.jce.WolfCryptMessageDigestSha3$wcSHA3_384"); + put("MessageDigest.SHA3-512", + "com.wolfssl.provider.jce.WolfCryptMessageDigestSha3$wcSHA3_512"); + } /* SecureRandom */ /* TODO: May need to add "SHA1PRNG" alias, other JCA consumemrs may @@ -138,6 +148,25 @@ public final class WolfCryptProvider extends Provider { put("Signature.SHA512withECDSA", "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA512wECDSA"); } + if (FeatureDetect.Sha3Enabled()) { + put("Signature.SHA3-224withRSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_224wRSA"); + put("Signature.SHA3-256withRSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_256wRSA"); + put("Signature.SHA3-384withRSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_384wRSA"); + put("Signature.SHA3-512withRSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_512wRSA"); + + put("Signature.SHA3-224withECDSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_224wECDSA"); + put("Signature.SHA3-256withECDSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_256wECDSA"); + put("Signature.SHA3-384withECDSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_384wECDSA"); + put("Signature.SHA3-512withECDSA", + "com.wolfssl.provider.jce.WolfCryptSignature$wcSHA3_512wECDSA"); + } /* Mac */ if (FeatureDetect.HmacMd5Enabled()) { @@ -164,6 +193,22 @@ public final class WolfCryptProvider extends Provider { put("Mac.HmacSHA512", "com.wolfssl.provider.jce.WolfCryptMac$wcHmacSHA512"); } + if (FeatureDetect.HmacSha3_224Enabled()) { + put("Mac.HmacSHA3-224", + "com.wolfssl.provider.jce.WolfCryptMac$wcHmacSHA3_224"); + } + if (FeatureDetect.HmacSha3_256Enabled()) { + put("Mac.HmacSHA3-256", + "com.wolfssl.provider.jce.WolfCryptMac$wcHmacSHA3_256"); + } + if (FeatureDetect.HmacSha3_384Enabled()) { + put("Mac.HmacSHA3-384", + "com.wolfssl.provider.jce.WolfCryptMac$wcHmacSHA3_384"); + } + if (FeatureDetect.HmacSha3_512Enabled()) { + put("Mac.HmacSHA3-512", + "com.wolfssl.provider.jce.WolfCryptMac$wcHmacSHA3_512"); + } /* Cipher */ if (FeatureDetect.AesCbcEnabled()) { diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java index b557d4a..4973d21 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptSignature.java @@ -43,6 +43,7 @@ import com.wolfssl.wolfcrypt.Sha224; import com.wolfssl.wolfcrypt.Sha256; import com.wolfssl.wolfcrypt.Sha384; import com.wolfssl.wolfcrypt.Sha512; +import com.wolfssl.wolfcrypt.Sha3; import com.wolfssl.wolfcrypt.Rsa; import com.wolfssl.wolfcrypt.Ecc; import com.wolfssl.wolfcrypt.Rng; @@ -64,7 +65,11 @@ public class WolfCryptSignature extends SignatureSpi { WC_SHA224, WC_SHA256, WC_SHA384, - WC_SHA512 + WC_SHA512, + WC_SHA3_224, + WC_SHA3_256, + WC_SHA3_384, + WC_SHA3_512 } /* internal hash type sums (asn.h) */ @@ -74,6 +79,10 @@ public class WolfCryptSignature extends SignatureSpi { private int SHA256h = 414; private int SHA384h = 415; private int SHA512h = 416; + private int SHA3_224h = 420; + private int SHA3_256h = 421; + private int SHA3_384h = 422; + private int SHA3_512h = 423; /* internal key objects */ private Rsa rsa = null; @@ -86,6 +95,7 @@ public class WolfCryptSignature extends SignatureSpi { private Sha256 sha256 = null; private Sha384 sha384 = null; private Sha512 sha512 = null; + private Sha3 sha3 = null; private KeyType keyType; /* active key type, from KeyType */ private DigestType digestType; /* active digest type, from DigestType */ @@ -155,6 +165,30 @@ public class WolfCryptSignature extends SignatureSpi { this.internalHashSum = SHA512h; break; + case WC_SHA3_224: + this.sha3 = new Sha3(Sha3.TYPE_SHA3_224); + this.digestSz = Sha3.DIGEST_SIZE_224; + this.internalHashSum = SHA3_224h; + break; + + case WC_SHA3_256: + this.sha3 = new Sha3(Sha3.TYPE_SHA3_256); + this.digestSz = Sha3.DIGEST_SIZE_256; + this.internalHashSum = SHA3_256h; + break; + + case WC_SHA3_384: + this.sha3 = new Sha3(Sha3.TYPE_SHA3_384); + this.digestSz = Sha3.DIGEST_SIZE_384; + this.internalHashSum = SHA3_384h; + break; + + case WC_SHA3_512: + this.sha3 = new Sha3(Sha3.TYPE_SHA3_512); + this.digestSz = Sha3.DIGEST_SIZE_512; + this.internalHashSum = SHA3_512h; + break; + default: throw new NoSuchAlgorithmException( "Unsupported signature algorithm digest type"); @@ -280,6 +314,13 @@ public class WolfCryptSignature extends SignatureSpi { case WC_SHA512: this.sha512.init(); break; + + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.init(); + break; } log("init sign with PrivateKey"); @@ -350,6 +391,12 @@ public class WolfCryptSignature extends SignatureSpi { case WC_SHA512: this.sha512.init(); break; + + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.init(); } log("init verify with PublicKey"); @@ -399,8 +446,14 @@ public class WolfCryptSignature extends SignatureSpi { case WC_SHA512: this.sha512.digest(digest); break; - } + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.digest(digest); + break; + } } catch (ShortBufferException e) { throw new SignatureException(e.getMessage()); } @@ -489,6 +542,12 @@ public class WolfCryptSignature extends SignatureSpi { case WC_SHA512: this.sha512.update(b, off, len); break; + + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.update(b, off, len); } log("update, offset: " + off + ", len: " + len); @@ -531,6 +590,13 @@ public class WolfCryptSignature extends SignatureSpi { case WC_SHA512: this.sha512.digest(digest); break; + + case WC_SHA3_224: + case WC_SHA3_256: + case WC_SHA3_384: + case WC_SHA3_512: + this.sha3.digest(digest); + break; } } catch (ShortBufferException e) { @@ -619,6 +685,14 @@ public class WolfCryptSignature extends SignatureSpi { return "SHA384"; case WC_SHA512: return "SHA512"; + case WC_SHA3_224: + return "SHA3-224"; + case WC_SHA3_256: + return "SHA3-256"; + case WC_SHA3_384: + return "SHA3-384"; + case WC_SHA3_512: + return "SHA3-512"; default: return "None"; } @@ -652,6 +726,9 @@ public class WolfCryptSignature extends SignatureSpi { if (this.sha512 != null) this.sha512.releaseNativeStruct(); + if (this.sha3 != null) + this.sha3.releaseNativeStruct(); + /* free native key objects */ if (this.rsa != null) this.rsa.releaseNativeStruct(); @@ -763,6 +840,66 @@ public class WolfCryptSignature extends SignatureSpi { } } + /** + * wolfJCE SHA3-224wRSA signature class + */ + public static final class wcSHA3_224wRSA extends WolfCryptSignature { + /** + * Create new wcSHA3_224wRSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_224wRSA() throws NoSuchAlgorithmException { + super(KeyType.WC_RSA, DigestType.WC_SHA3_224); + } + } + + /** + * wolfJCE SHA3-256wRSA signature class + */ + public static final class wcSHA3_256wRSA extends WolfCryptSignature { + /** + * Create new wcSHA3_256wRSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_256wRSA() throws NoSuchAlgorithmException { + super(KeyType.WC_RSA, DigestType.WC_SHA3_256); + } + } + + /** + * wolfJCE SHA3-384wRSA signature class + */ + public static final class wcSHA3_384wRSA extends WolfCryptSignature { + /** + * Create new wcSHA3_384wRSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_384wRSA() throws NoSuchAlgorithmException { + super(KeyType.WC_RSA, DigestType.WC_SHA3_384); + } + } + + /** + * wolfJCE SHA3-512wRSA signature class + */ + public static final class wcSHA3_512wRSA extends WolfCryptSignature { + /** + * Create new wcSHA3_512wRSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_512wRSA() throws NoSuchAlgorithmException { + super(KeyType.WC_RSA, DigestType.WC_SHA3_512); + } + } + /** * wolfJCE SHA1wECDSA signature class */ @@ -837,5 +974,64 @@ public class WolfCryptSignature extends SignatureSpi { super(KeyType.WC_ECDSA, DigestType.WC_SHA512); } } -} + /** + * wolfJCE SHA3-224wECDSA signature class + */ + public static final class wcSHA3_224wECDSA extends WolfCryptSignature { + /** + * Create new wcSHA3_224wECDSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_224wECDSA() throws NoSuchAlgorithmException { + super(KeyType.WC_ECDSA, DigestType.WC_SHA3_224); + } + } + + /** + * wolfJCE SHA3-256wECDSA signature class + */ + public static final class wcSHA3_256wECDSA extends WolfCryptSignature { + /** + * Create new wcSHA3_256wECDSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_256wECDSA() throws NoSuchAlgorithmException { + super(KeyType.WC_ECDSA, DigestType.WC_SHA3_256); + } + } + + /** + * wolfJCE SHA3-384wECDSA signature class + */ + public static final class wcSHA3_384wECDSA extends WolfCryptSignature { + /** + * Create new wcSHA3_384wECDSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_384wECDSA() throws NoSuchAlgorithmException { + super(KeyType.WC_ECDSA, DigestType.WC_SHA3_384); + } + } + + /** + * wolfJCE SHA3-512wECDSA signature class + */ + public static final class wcSHA3_512wECDSA extends WolfCryptSignature { + /** + * Create new wcSHA3_512wECDSA object + * + * @throws NoSuchAlgorithmException if signature type is not + * available in native wolfCrypt library + */ + public wcSHA3_512wECDSA() throws NoSuchAlgorithmException { + super(KeyType.WC_ECDSA, DigestType.WC_SHA3_512); + } + } +} 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/Hmac.java b/src/main/java/com/wolfssl/wolfcrypt/Hmac.java index e5b2abf..846d084 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/Hmac.java +++ b/src/main/java/com/wolfssl/wolfcrypt/Hmac.java @@ -29,7 +29,8 @@ import java.nio.ByteBuffer; public class Hmac extends NativeStruct { private enum hashType { - typeMD5, typeSHA, typeSHA224, typeSHA256, typeSHA384, typeSHA512; + typeMD5, typeSHA, typeSHA224, typeSHA256, typeSHA384, typeSHA512, + typeSHA3_224, typeSHA3_256, typeSHA3_384, typeSHA3_512; } /* types may be -1 if not compiled in at native level */ @@ -45,6 +46,14 @@ public class Hmac extends NativeStruct { public static final int SHA384 = getHashCode(hashType.typeSHA384); /** HMAC-SHA2-512 type */ public static final int SHA512 = getHashCode(hashType.typeSHA512); + /** HMAC-SHA3-224 type */ + public static final int SHA3_224 = getHashCode(hashType.typeSHA3_224); + /** HMAC-SHA3-256 type */ + public static final int SHA3_256 = getHashCode(hashType.typeSHA3_256); + /** HMAC-SHA3-384 type */ + public static final int SHA3_384 = getHashCode(hashType.typeSHA3_384); + /** HMAC-SHA3-512 type */ + public static final int SHA3_512 = getHashCode(hashType.typeSHA3_512); private WolfCryptState state = WolfCryptState.UNINITIALIZED; private int type = -1; @@ -102,6 +111,10 @@ public class Hmac extends NativeStruct { private native static int getCodeSha384(); private native static int getCodeSha512(); private native static int getCodeBlake2b(); + private native static int getCodeSha3_224(); + private native static int getCodeSha3_256(); + private native static int getCodeSha3_384(); + private native static int getCodeSha3_512(); /** * Malloc native JNI Hmac structure @@ -333,6 +346,18 @@ public class Hmac extends NativeStruct { else if (type == SHA512) { return "HmacSHA512"; } + else if (type == SHA3_224) { + return "HmacSHA3-224"; + } + else if (type == SHA3_256) { + return "HmacSHA3-256"; + } + else if (type == SHA3_384) { + return "HmacSHA3-384"; + } + else if (type == SHA3_512) { + return "HmacSHA3-512"; + } else { return ""; } @@ -373,6 +398,14 @@ public class Hmac extends NativeStruct { return getCodeSha384(); case typeSHA512: return getCodeSha512(); + case typeSHA3_224: + return getCodeSha3_224(); + case typeSHA3_256: + return getCodeSha3_256(); + case typeSHA3_384: + return getCodeSha3_384(); + case typeSHA3_512: + return getCodeSha3_512(); default: return WolfCrypt.FAILURE; } 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/provider/jce/test/WolfCryptMacTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptMacTest.java index 65eb5c5..f4652f0 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptMacTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptMacTest.java @@ -49,6 +49,7 @@ import java.security.InvalidKeyException; import com.wolfssl.wolfcrypt.Fips; import com.wolfssl.provider.jce.WolfCryptProvider; +import com.wolfssl.wolfcrypt.test.Util; public class WolfCryptMacTest { @@ -58,7 +59,11 @@ public class WolfCryptMacTest { "HmacSHA224", "HmacSHA256", "HmacSHA384", - "HmacSHA512" + "HmacSHA512", + "HmacSHA3-224", + "HmacSHA3-256", + "HmacSHA3-384", + "HmacSHA3-512" }; private static ArrayList enabledAlgos = @@ -71,6 +76,10 @@ public class WolfCryptMacTest { 28, 32, 48, + 64, + 28, + 32, + 48, 64 }; @@ -88,8 +97,6 @@ public class WolfCryptMacTest { public static void testProviderInstallationAtRuntime() throws NoSuchProviderException { - Mac mac; - System.out.println("JCE WolfCryptMac Class"); /* install wolfJCE provider at runtime */ @@ -102,7 +109,7 @@ public class WolfCryptMacTest { * compiled out */ for (int i = 0; i < wolfJCEAlgos.length; i++) { try { - mac = Mac.getInstance(wolfJCEAlgos[i], "wolfJCE"); + Mac mac = Mac.getInstance(wolfJCEAlgos[i], "wolfJCE"); assertNotNull(mac); enabledAlgos.add(wolfJCEAlgos[i]); enabledAlgoLengths.add(wolfJCEMacLengths[i]); @@ -116,17 +123,15 @@ public class WolfCryptMacTest { public void testGetMacFromProvider() throws NoSuchProviderException, NoSuchAlgorithmException { - Mac mac; - /* try to get all available options we expect to have */ for (int i = 0; i < enabledAlgos.size(); i++) { - mac = Mac.getInstance(enabledAlgos.get(i), "wolfJCE"); + Mac mac = Mac.getInstance(enabledAlgos.get(i), "wolfJCE"); assertNotNull(mac); } /* getting a garbage algorithm should throw an exception */ try { - mac = Mac.getInstance("NotValid", "wolfJCE"); + Mac.getInstance("NotValid", "wolfJCE"); fail("Mac.getInstance should throw NoSuchAlgorithmException " + "when given bad algorithm value"); @@ -820,7 +825,8 @@ public class WolfCryptMacTest { new SecretKeySpec(vectors[i].getKey(), "SHA512"); try { - Mac mac = Mac.getInstance("HmacSHA512", "wolfJCE"); + Mac mac = + Mac.getInstance("HmacSHA512", "wolfJCE"); mac.init(keyspec); mac.update(vectors[i].getInput()); @@ -836,6 +842,201 @@ public class WolfCryptMacTest { } } + /** + * Shared SHA-3 test key and data vectors. + */ + static final String[] sha3KeyVector = new String[] { + "4A656665", /* Jefe */ + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + }; + static final String[] sha3DataVector = new String[] { + /* what do ya want for nothing? */ + "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + /* Hi There */ + "4869205468657265", + "dddddddddddddddddddd" + + "dddddddddddddddddddd" + + "dddddddddddddddddddd" + + "dddddddddddddddddddd" + + "dddddddddddddddddddd", + /* Big Key Input */ + "426967204b657920496e707574" + }; + + @Test + public void testMacSha3_224SingleUpdate() + throws InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException { + + String[] hashVector = new String[] { + "7fdb8dd88bd2f60d1b798634ad386811" + + "c2cfc85bfaf5d52bbace5e66", + "3b16546bbc7be2706a031dcafd56373d" + + "9884367641d8c59af3c860f7", + "676cfc7d16153638780390692be142d2" + + "df7ce924b909c0c08dbfdc1a", + "29e05e46c4a45e4674bfd72d1ad866db" + + "2d0d104e2bfaad537d15698b" + }; + + if (!enabledAlgos.contains("HmacSHA3-224")) { + return; + } + + Mac mac = Mac.getInstance("HmacSHA3-224", "wolfJCE"); + + for (int i = 0; i < hashVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + SecretKeySpec key = new SecretKeySpec( + Util.h2b(sha3KeyVector[i]), "HmacSHA3-224"); + mac.init(key); + mac.update(Util.h2b(sha3DataVector[i])); + byte[] result = mac.doFinal(); + + assertArrayEquals(Util.h2b(hashVector[i]), result); + } + } + + @Test + public void testMacSha3_256SingleUpdate() + throws InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException { + + String[] hashVector = new String[] { + "c7d4072e788877ae3596bbb0da73b887" + + "c9171f93095b294ae857fbe2645e1ba5", + "ba85192310dffa96e2a3a40e69774351" + + "140bb7185e1202cdcc917589f95e16bb", + "84ec79124a27107865cedd8bd82da996" + + "5e5ed8c37b0ac98005a7f39ed58a4207", + "b55b8d64b69c21d0bf205ca2f7b9b14e" + + "8821612c66c391ae6c95168583e6f49b" + }; + + if (!enabledAlgos.contains("HmacSHA3-256")) { + return; + } + + Mac mac = Mac.getInstance("HmacSHA3-256", "wolfJCE"); + + for (int i = 0; i < hashVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + SecretKeySpec key = new SecretKeySpec( + Util.h2b(sha3KeyVector[i]), "HmacSHA3-256"); + mac.init(key); + mac.update(Util.h2b(sha3DataVector[i])); + byte[] result = mac.doFinal(); + + assertArrayEquals(Util.h2b(hashVector[i]), result); + } + } + + @Test + public void testMacSha3_384SingleUpdate() + throws InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException { + + String[] hashVector = new String[] { + "f1101f8cbf9766fd6764d2ed61903f21" + + "ca9b18f57cf3e1a23ca13508a93243ce" + + "48c045dc007f26a21b3f5e0e9df4c20a", + "68d2dcf7fd4ddd0a2240c8a437305f61" + + "fb7334cfb5d0226e1bc27dc10a2e723a" + + "20d370b47743130e26ac7e3d532886bd", + "275cd0e661bb8b151c64d288f1f782fb" + + "91a8abd56858d72babb2d476f0458373" + + "b41b6ab5bf174bec422e53fc3135ac6e", + "aa91b3a62f56a1be8c3e7438db58d9d3" + + "34dea0606d8d46e0eca9f6063514e6ed" + + "83e67c77246c11b59082b575da7b832d" + }; + + if (!enabledAlgos.contains("HmacSHA3-384")) { + return; + } + + Mac mac = Mac.getInstance("HmacSHA3-384", "wolfJCE"); + + for (int i = 0; i < hashVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + SecretKeySpec key = new SecretKeySpec( + Util.h2b(sha3KeyVector[i]), "HmacSHA3-384"); + mac.init(key); + mac.update(Util.h2b(sha3DataVector[i])); + byte[] result = mac.doFinal(); + + assertArrayEquals(Util.h2b(hashVector[i]), result); + } + } + + @Test + public void testMacSha3_512SingleUpdate() + throws InvalidKeyException, NoSuchAlgorithmException, + NoSuchProviderException { + + String[] hashVector = new String[] { + "5a4bfeab6166427c7a3647b747292b83" + + "84537cdb89afb3bf5665e4c5e709350b" + + "287baec921fd7ca0ee7a0c31d022a95e" + + "1fc92ba9d77df883960275beb4e62024", + "eb3fbd4b2eaab8f5c504bd3a41465aac" + + "ec15770a7cabac531e482f860b5ec7ba" + + "47ccb2c6f2afce8f88d22b6dc61380f2" + + "3a668fd3888bb80537c0a0b86407689e", + "309e99f9ec075ec6c6d475eda1180687" + + "fcf1531195802a99b5677449a8625182" + + "851cb332afb6a89c411325fbcbcd42af" + + "cb7b6e5aab7ea42c660f97fd8584bf03", + "1cc3a9244a4a3fbdc72000169b794703" + + "78752cb5f12e627cbeef4e8f0b112b32" + + "a0eec9d04d64640b37f4dd66f78bb3ad" + + "52526b6512de0d7cc08b60016c37d7a8" + }; + + if (!enabledAlgos.contains("HmacSHA3-512")) { + return; + } + + Mac mac = Mac.getInstance("HmacSHA3-512", "wolfJCE"); + + for (int i = 0; i < hashVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + SecretKeySpec key = new SecretKeySpec( + Util.h2b(sha3KeyVector[i]), "HmacSHA3-512"); + mac.init(key); + mac.update(Util.h2b(sha3DataVector[i])); + byte[] result = mac.doFinal(); + + assertArrayEquals(Util.h2b(hashVector[i]), result); + } + } + private void threadRunnerMacTest(String hmacAlgo, String digest, HmacVector vector) throws InterruptedException { @@ -1140,6 +1341,50 @@ public class WolfCryptMacTest { if (enabledAlgos.contains("HmacSHA512")) { threadRunnerMacTest("HmacSHA512", "SHA512", sha512Vector); } + + + if (enabledAlgos.contains("HmacSHA3-224")) { + HmacVector sha3_224Vector = new HmacVector( + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + Util.h2b("4869205468657265"), + Util.h2b("3b16546bbc7be2706a031dcafd56373d" + + "9884367641d8c59af3c860f7") + ); + threadRunnerMacTest("HmacSHA3-224", "SHA3-224", sha3_224Vector); + } + + if (enabledAlgos.contains("HmacSHA3-256")) { + HmacVector sha3_256Vector = new HmacVector( + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + Util.h2b("4869205468657265"), + Util.h2b("ba85192310dffa96e2a3a40e69774351" + + "140bb7185e1202cdcc917589f95e16bb") + ); + threadRunnerMacTest("HmacSHA3-256", "SHA3-256", sha3_256Vector); + } + + if (enabledAlgos.contains("HmacSHA3-384")) { + HmacVector sha3_384Vector = new HmacVector( + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + Util.h2b("4869205468657265"), + Util.h2b("68d2dcf7fd4ddd0a2240c8a437305f61" + + "fb7334cfb5d0226e1bc27dc10a2e723a" + + "20d370b47743130e26ac7e3d532886bd") + ); + threadRunnerMacTest("HmacSHA3-384", "SHA3-384", sha3_384Vector); + } + + if (enabledAlgos.contains("HmacSHA3-512")) { + HmacVector sha3_512Vector = new HmacVector( + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + Util.h2b("4869205468657265"), + Util.h2b("eb3fbd4b2eaab8f5c504bd3a41465aac" + + "ec15770a7cabac531e482f860b5ec7ba" + + "47ccb2c6f2afce8f88d22b6dc61380f2" + + "3a668fd3888bb80537c0a0b86407689e") + ); + threadRunnerMacTest("HmacSHA3-512", "SHA3-512", sha3_512Vector); + } } private class HmacVector { diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptMessageDigestSha3Test.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptMessageDigestSha3Test.java new file mode 100644 index 0000000..113dd01 --- /dev/null +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptMessageDigestSha3Test.java @@ -0,0 +1,654 @@ +/* WolfCryptMessageDigestSha3Test.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.provider.jce.test; + +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.rules.TestRule; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; +import org.junit.Test; +import org.junit.Assume; +import org.junit.BeforeClass; + +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 java.security.Security; +import java.security.Provider; +import java.security.MessageDigest; +import java.security.NoSuchProviderException; +import java.security.NoSuchAlgorithmException; + +import com.wolfssl.wolfcrypt.Sha3; +import com.wolfssl.provider.jce.WolfCryptProvider; +import com.wolfssl.wolfcrypt.FeatureDetect; + +public class WolfCryptMessageDigestSha3Test { + + @Rule + public TestRule watcher = new TestWatcher() { + protected void starting(Description description) { + System.out.println("\t" + description.getMethodName()); + } + }; + + @BeforeClass + public static void testProviderInstallationAtRuntime() + throws NoSuchProviderException { + + System.out.println("JCE WolfCryptMessageDigestSha3 Class"); + + /* Install wolfJCE provider at runtime */ + Security.insertProviderAt(new WolfCryptProvider(), 1); + + Provider p = Security.getProvider("wolfJCE"); + assertNotNull(p); + + try { + MessageDigest.getInstance("SHA3-256", "wolfJCE"); + + } catch (NoSuchAlgorithmException e) { + /* If algo is compiled out, skip tests */ + if (FeatureDetect.Sha3Enabled() == false) { + System.out.println("wolfJCE SHA3 Test skipped"); + Assume.assumeTrue(false); + } + } + } + + @Test + public void testSha3_224SingleUpdate() + throws NoSuchProviderException, NoSuchAlgorithmException { + + DigestVector vectors[] = new DigestVector[] { + /* NIST FIPS 202 test vector */ + new DigestVector( + new String("abc").getBytes(), + new byte[] { + (byte)0xe6, (byte)0x42, (byte)0x82, (byte)0x4c, + (byte)0x3f, (byte)0x8c, (byte)0xf2, (byte)0x4a, + (byte)0xd0, (byte)0x92, (byte)0x34, (byte)0xee, + (byte)0x7d, (byte)0x3c, (byte)0x76, (byte)0x6f, + (byte)0xc9, (byte)0xa3, (byte)0xa5, (byte)0x16, + (byte)0x8d, (byte)0x0c, (byte)0x94, (byte)0xad, + (byte)0x73, (byte)0xb4, (byte)0x6f, (byte)0xdf + } + ), + }; + + byte[] output; + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-224", "wolfJCE"); + + for (int i = 0; i < vectors.length; i++) { + sha3.update(vectors[i].getInput()); + output = sha3.digest(); + assertEquals(vectors[i].getOutput().length, output.length); + assertArrayEquals(vectors[i].getOutput(), output); + } + } + + @Test + public void testSha3_256SingleUpdate() + throws NoSuchProviderException, NoSuchAlgorithmException { + + DigestVector vectors[] = new DigestVector[] { + /* NIST FIPS 202 test vector */ + new DigestVector( + new String("abc").getBytes(), + new byte[] { + (byte)0x3a, (byte)0x98, (byte)0x5d, (byte)0xa7, + (byte)0x4f, (byte)0xe2, (byte)0x25, (byte)0xb2, + (byte)0x04, (byte)0x5c, (byte)0x17, (byte)0x2d, + (byte)0x6b, (byte)0xd3, (byte)0x90, (byte)0xbd, + (byte)0x85, (byte)0x5f, (byte)0x08, (byte)0x6e, + (byte)0x3e, (byte)0x9d, (byte)0x52, (byte)0x5b, + (byte)0x46, (byte)0xbf, (byte)0xe2, (byte)0x45, + (byte)0x11, (byte)0x43, (byte)0x15, (byte)0x32 + } + ), + }; + + byte[] output; + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE"); + + for (int i = 0; i < vectors.length; i++) { + sha3.update(vectors[i].getInput()); + output = sha3.digest(); + assertEquals(vectors[i].getOutput().length, output.length); + assertArrayEquals(vectors[i].getOutput(), output); + } + } + + @Test + public void testSha3_384SingleUpdate() + throws NoSuchProviderException, NoSuchAlgorithmException { + + DigestVector vectors[] = new DigestVector[] { + /* NIST FIPS 202 test vector */ + new DigestVector( + new String("abc").getBytes(), + new byte[] { + (byte)0xec, (byte)0x01, (byte)0x49, (byte)0x82, + (byte)0x88, (byte)0x51, (byte)0x6f, (byte)0xc9, + (byte)0x26, (byte)0x45, (byte)0x9f, (byte)0x58, + (byte)0xe2, (byte)0xc6, (byte)0xad, (byte)0x8d, + (byte)0xf9, (byte)0xb4, (byte)0x73, (byte)0xcb, + (byte)0x0f, (byte)0xc0, (byte)0x8c, (byte)0x25, + (byte)0x96, (byte)0xda, (byte)0x7c, (byte)0xf0, + (byte)0xe4, (byte)0x9b, (byte)0xe4, (byte)0xb2, + (byte)0x98, (byte)0xd8, (byte)0x8c, (byte)0xea, + (byte)0x92, (byte)0x7a, (byte)0xc7, (byte)0xf5, + (byte)0x39, (byte)0xf1, (byte)0xed, (byte)0xf2, + (byte)0x28, (byte)0x37, (byte)0x6d, (byte)0x25 + } + ), + }; + + byte[] output; + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-384", "wolfJCE"); + + for (int i = 0; i < vectors.length; i++) { + sha3.update(vectors[i].getInput()); + output = sha3.digest(); + assertEquals(vectors[i].getOutput().length, output.length); + assertArrayEquals(vectors[i].getOutput(), output); + } + } + + @Test + public void testSha3_512SingleUpdate() + throws NoSuchProviderException, NoSuchAlgorithmException { + + DigestVector vectors[] = new DigestVector[] { + /* NIST FIPS 202 test vector */ + new DigestVector( + new String("abc").getBytes(), + new byte[] { + (byte)0xb7, (byte)0x51, (byte)0x85, (byte)0x0b, + (byte)0x1a, (byte)0x57, (byte)0x16, (byte)0x8a, + (byte)0x56, (byte)0x93, (byte)0xcd, (byte)0x92, + (byte)0x4b, (byte)0x6b, (byte)0x09, (byte)0x6e, + (byte)0x08, (byte)0xf6, (byte)0x21, (byte)0x82, + (byte)0x74, (byte)0x44, (byte)0xf7, (byte)0x0d, + (byte)0x88, (byte)0x4f, (byte)0x5d, (byte)0x02, + (byte)0x40, (byte)0xd2, (byte)0x71, (byte)0x2e, + (byte)0x10, (byte)0xe1, (byte)0x16, (byte)0xe9, + (byte)0x19, (byte)0x2a, (byte)0xf3, (byte)0xc9, + (byte)0x1a, (byte)0x7e, (byte)0xc5, (byte)0x76, + (byte)0x47, (byte)0xe3, (byte)0x93, (byte)0x40, + (byte)0x57, (byte)0x34, (byte)0x0b, (byte)0x4c, + (byte)0xf4, (byte)0x08, (byte)0xd5, (byte)0xa5, + (byte)0x65, (byte)0x92, (byte)0xf8, (byte)0x27, + (byte)0x4e, (byte)0xec, (byte)0x53, (byte)0xf0 + } + ), + }; + + byte[] output; + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-512", "wolfJCE"); + + for (int i = 0; i < vectors.length; i++) { + sha3.update(vectors[i].getInput()); + output = sha3.digest(); + assertEquals(vectors[i].getOutput().length, output.length); + assertArrayEquals(vectors[i].getOutput(), output); + } + } + + @Test + public void testSha3Reset() + throws NoSuchProviderException, NoSuchAlgorithmException { + + String input = "abc"; + byte[] inArray = input.getBytes(); + final byte expected[] = new byte[] { + (byte)0x3a, (byte)0x98, (byte)0x5d, (byte)0xa7, + (byte)0x4f, (byte)0xe2, (byte)0x25, (byte)0xb2, + (byte)0x04, (byte)0x5c, (byte)0x17, (byte)0x2d, + (byte)0x6b, (byte)0xd3, (byte)0x90, (byte)0xbd, + (byte)0x85, (byte)0x5f, (byte)0x08, (byte)0x6e, + (byte)0x3e, (byte)0x9d, (byte)0x52, (byte)0x5b, + (byte)0x46, (byte)0xbf, (byte)0xe2, (byte)0x45, + (byte)0x11, (byte)0x43, (byte)0x15, (byte)0x32 + }; + + byte[] output; + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE"); + + for (int i = 0; i < inArray.length; i++) { + sha3.update(inArray[i]); + } + + sha3.reset(); + + for (int i = 0; i < inArray.length; i++) { + sha3.update(inArray[i]); + } + output = sha3.digest(); + assertEquals(expected.length, output.length); + assertArrayEquals(expected, output); + } + + @Test + public void testSha3Clone() + throws NoSuchProviderException, NoSuchAlgorithmException, + CloneNotSupportedException { + + String input = "abc"; + byte[] inArray = input.getBytes(); + final byte expected[] = new byte[] { + (byte)0x3a, (byte)0x98, (byte)0x5d, (byte)0xa7, + (byte)0x4f, (byte)0xe2, (byte)0x25, (byte)0xb2, + (byte)0x04, (byte)0x5c, (byte)0x17, (byte)0x2d, + (byte)0x6b, (byte)0xd3, (byte)0x90, (byte)0xbd, + (byte)0x85, (byte)0x5f, (byte)0x08, (byte)0x6e, + (byte)0x3e, (byte)0x9d, (byte)0x52, (byte)0x5b, + (byte)0x46, (byte)0xbf, (byte)0xe2, (byte)0x45, + (byte)0x11, (byte)0x43, (byte)0x15, (byte)0x32 + }; + + byte[] output; + byte[] output2; + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE"); + + for (int i = 0; i < inArray.length; i++) { + sha3.update(inArray[i]); + } + + /* Try to clone existing MessageDigest, should copy over same state */ + MessageDigest sha3Copy = (MessageDigest)sha3.clone(); + + output = sha3.digest(); + output2 = sha3Copy.digest(); + + assertEquals(expected.length, output.length); + assertEquals(expected.length, output2.length); + + assertArrayEquals(expected, output); + assertArrayEquals(expected, output2); + } + + @Test + public void testSha3GetDigestLength() + throws NoSuchProviderException, NoSuchAlgorithmException { + + MessageDigest sha3_224 = + MessageDigest.getInstance("SHA3-224", "wolfJCE"); + assertEquals(Sha3.DIGEST_SIZE_224, sha3_224.getDigestLength()); + + MessageDigest sha3_256 = + MessageDigest.getInstance("SHA3-256", "wolfJCE"); + assertEquals(Sha3.DIGEST_SIZE_256, sha3_256.getDigestLength()); + + MessageDigest sha3_384 = + MessageDigest.getInstance("SHA3-384", "wolfJCE"); + assertEquals(Sha3.DIGEST_SIZE_384, sha3_384.getDigestLength()); + + MessageDigest sha3_512 = + MessageDigest.getInstance("SHA3-512", "wolfJCE"); + assertEquals(Sha3.DIGEST_SIZE_512, sha3_512.getDigestLength()); + } + + @Test + public void testSha3Threaded() + throws NoSuchProviderException, NoSuchAlgorithmException, + 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() { + + MessageDigest sha3 = null; + + try { + sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE"); + } catch (NoSuchAlgorithmException | + NoSuchProviderException e) { + /* Add empty array on failure, will error out below */ + results.add(new byte[] {0}); + } + + /* Process/update in 1024-byte chunks */ + for (int j = 0; j < rand10kBuf.length; j+= 1024) { + sha3.update(rand10kBuf, j, 1024); + } + + /* Get final hash */ + byte[] hash = sha3.digest(); + results.add(hash.clone()); + + 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 testSha3EmptyInput() + throws NoSuchProviderException, NoSuchAlgorithmException { + + /* NIST FIPS 202 test vectors for empty input */ + byte[] empty224 = new byte[] { + (byte)0x6b, (byte)0x4e, (byte)0x03, (byte)0x42, + (byte)0x36, (byte)0x67, (byte)0xdb, (byte)0xb7, + (byte)0x3b, (byte)0x6e, (byte)0x15, (byte)0x45, + (byte)0x4f, (byte)0x0e, (byte)0xb1, (byte)0xab, + (byte)0xd4, (byte)0x59, (byte)0x7f, (byte)0x9a, + (byte)0x1b, (byte)0x07, (byte)0x8e, (byte)0x3f, + (byte)0x5b, (byte)0x5a, (byte)0x6b, (byte)0xc7 + }; + + byte[] empty256 = new byte[] { + (byte)0xa7, (byte)0xff, (byte)0xc6, (byte)0xf8, + (byte)0xbf, (byte)0x1e, (byte)0xd7, (byte)0x66, + (byte)0x51, (byte)0xc1, (byte)0x47, (byte)0x56, + (byte)0xa0, (byte)0x61, (byte)0xd6, (byte)0x62, + (byte)0xf5, (byte)0x80, (byte)0xff, (byte)0x4d, + (byte)0xe4, (byte)0x3b, (byte)0x49, (byte)0xfa, + (byte)0x82, (byte)0xd8, (byte)0x0a, (byte)0x4b, + (byte)0x80, (byte)0xf8, (byte)0x43, (byte)0x4a + }; + + byte[] empty384 = new byte[] { + (byte)0x0c, (byte)0x63, (byte)0xa7, (byte)0x5b, + (byte)0x84, (byte)0x5e, (byte)0x4f, (byte)0x7d, + (byte)0x01, (byte)0x10, (byte)0x7d, (byte)0x85, + (byte)0x2e, (byte)0x4c, (byte)0x24, (byte)0x85, + (byte)0xc5, (byte)0x1a, (byte)0x50, (byte)0xaa, + (byte)0xaa, (byte)0x94, (byte)0xfc, (byte)0x61, + (byte)0x99, (byte)0x5e, (byte)0x71, (byte)0xbb, + (byte)0xee, (byte)0x98, (byte)0x3a, (byte)0x2a, + (byte)0xc3, (byte)0x71, (byte)0x38, (byte)0x31, + (byte)0x26, (byte)0x4a, (byte)0xdb, (byte)0x47, + (byte)0xfb, (byte)0x6b, (byte)0xd1, (byte)0xe0, + (byte)0x58, (byte)0xd5, (byte)0xf0, (byte)0x04 + }; + + byte[] empty512 = new byte[] { + (byte)0xa6, (byte)0x9f, (byte)0x73, (byte)0xcc, + (byte)0xa2, (byte)0x3a, (byte)0x9a, (byte)0xc5, + (byte)0xc8, (byte)0xb5, (byte)0x67, (byte)0xdc, + (byte)0x18, (byte)0x5a, (byte)0x75, (byte)0x6e, + (byte)0x97, (byte)0xc9, (byte)0x82, (byte)0x16, + (byte)0x4f, (byte)0xe2, (byte)0x58, (byte)0x59, + (byte)0xe0, (byte)0xd1, (byte)0xdc, (byte)0xc1, + (byte)0x47, (byte)0x5c, (byte)0x80, (byte)0xa6, + (byte)0x15, (byte)0xb2, (byte)0x12, (byte)0x3a, + (byte)0xf1, (byte)0xf5, (byte)0xf9, (byte)0x4c, + (byte)0x11, (byte)0xe3, (byte)0xe9, (byte)0x40, + (byte)0x2c, (byte)0x3a, (byte)0xc5, (byte)0x58, + (byte)0xf5, (byte)0x00, (byte)0x19, (byte)0x9d, + (byte)0x95, (byte)0xb6, (byte)0xd3, (byte)0xe3, + (byte)0x01, (byte)0x75, (byte)0x85, (byte)0x86, + (byte)0x28, (byte)0x1d, (byte)0xcd, (byte)0x26 + }; + + byte[] output; + + /* Test SHA3-224 empty input */ + MessageDigest sha3 = MessageDigest.getInstance("SHA3-224", "wolfJCE"); + output = sha3.digest(); + assertEquals(empty224.length, output.length); + assertArrayEquals(empty224, output); + + /* Test SHA3-256 empty input */ + sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE"); + output = sha3.digest(); + assertEquals(empty256.length, output.length); + assertArrayEquals(empty256, output); + + /* Test SHA3-384 empty input */ + sha3 = MessageDigest.getInstance("SHA3-384", "wolfJCE"); + output = sha3.digest(); + assertEquals(empty384.length, output.length); + assertArrayEquals(empty384, output); + + /* Test SHA3-512 empty input */ + sha3 = MessageDigest.getInstance("SHA3-512", "wolfJCE"); + output = sha3.digest(); + assertEquals(empty512.length, output.length); + assertArrayEquals(empty512, output); + } + + @Test + public void testSha3ByteByByteUpdate() + throws NoSuchProviderException, NoSuchAlgorithmException { + + String input = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + byte[] inArray = input.getBytes(); + final byte expected[] = new byte[] { + /* NIST FIPS 202 test vector for above input with SHA3-256 */ + (byte)0x41, (byte)0xc0, (byte)0xdb, (byte)0xa2, + (byte)0xa9, (byte)0xd6, (byte)0x24, (byte)0x08, + (byte)0x49, (byte)0x10, (byte)0x03, (byte)0x76, + (byte)0xa8, (byte)0x23, (byte)0x5e, (byte)0x2c, + (byte)0x82, (byte)0xe1, (byte)0xb9, (byte)0x99, + (byte)0x8a, (byte)0x99, (byte)0x9e, (byte)0x21, + (byte)0xdb, (byte)0x32, (byte)0xdd, (byte)0x97, + (byte)0x49, (byte)0x6d, (byte)0x33, (byte)0x76 + }; + + byte[] output; + byte[] output2; + + MessageDigest sha3 = + MessageDigest.getInstance("SHA3-256", "wolfJCE"); + MessageDigest sha3Bulk = + MessageDigest.getInstance("SHA3-256", "wolfJCE"); + + /* Update one byte at a time */ + for (int i = 0; i < inArray.length; i++) { + sha3.update(inArray[i]); + } + + /* Update all at once */ + sha3Bulk.update(inArray); + + output = sha3.digest(); + output2 = sha3Bulk.digest(); + + /* Both methods should produce same digest */ + assertEquals(expected.length, output.length); + assertEquals(expected.length, output2.length); + assertArrayEquals(expected, output); + assertArrayEquals(expected, output2); + assertArrayEquals(output, output2); + } + + @Test + public void testSha3LargeInput() + throws NoSuchProviderException, NoSuchAlgorithmException { + + /* Test with 1MB of random data */ + byte[] largeInput = new byte[1024 * 1024]; + new Random().nextBytes(largeInput); + + MessageDigest sha3_224 = + MessageDigest.getInstance("SHA3-224", "wolfJCE"); + MessageDigest sha3_256 = + MessageDigest.getInstance("SHA3-256", "wolfJCE"); + MessageDigest sha3_384 = + MessageDigest.getInstance("SHA3-384", "wolfJCE"); + MessageDigest sha3_512 = + MessageDigest.getInstance("SHA3-512", "wolfJCE"); + + /* Hash same input with all SHA-3 variants */ + byte[] hash224 = sha3_224.digest(largeInput); + byte[] hash256 = sha3_256.digest(largeInput); + byte[] hash384 = sha3_384.digest(largeInput); + byte[] hash512 = sha3_512.digest(largeInput); + + /* Verify expected digest sizes */ + assertEquals(Sha3.DIGEST_SIZE_224, hash224.length); + assertEquals(Sha3.DIGEST_SIZE_256, hash256.length); + assertEquals(Sha3.DIGEST_SIZE_384, hash384.length); + assertEquals(Sha3.DIGEST_SIZE_512, hash512.length); + + /* Verify digests are different */ + assertFalse(Arrays.equals(hash224, hash256)); + assertFalse(Arrays.equals(hash224, hash384)); + assertFalse(Arrays.equals(hash224, hash512)); + assertFalse(Arrays.equals(hash256, hash384)); + assertFalse(Arrays.equals(hash256, hash512)); + assertFalse(Arrays.equals(hash384, hash512)); + } + + @Test + public void testSha3Interop() + throws NoSuchProviderException, NoSuchAlgorithmException { + + String input = "Bozeman, MT"; + String input2 = "wolfSSL is an Open Source Internet security " + + "company, focused primarily on SSL/TLS and " + + "cryptography. Main products include the wolfSSL " + + "embedded SSL/TLS library, wolfCrypt cryptography " + + "library, wolfMQTT, and wolfSSH. Products are " + + "dual licensed under both GPLv2 and a commercial" + + "license."; + + byte[] wolfOutput; + byte[] interopOutput; + + /* Get SUN SHA3 implementation */ + MessageDigest sunSha3 = null; + try { + sunSha3 = MessageDigest.getInstance("SHA3-256", "SUN"); + Provider provider = sunSha3.getProvider(); + if (!provider.getName().equals("SUN")) { + /* Skip test if SUN SHA3-256 provider name mismatch */ + return; + } + } catch (NoSuchAlgorithmException e) { + /* Skip test if SUN SHA3-256 provider available */ + return; + } + + MessageDigest wolfSha3 = + MessageDigest.getInstance("SHA3-256", "wolfJCE"); + + /* short message */ + sunSha3.update(input.getBytes()); + interopOutput = sunSha3.digest(); + + wolfSha3.update(input.getBytes()); + wolfOutput = wolfSha3.digest(); + + assertArrayEquals(wolfOutput, interopOutput); + + /* long message */ + sunSha3.update(input2.getBytes()); + interopOutput = sunSha3.digest(); + + wolfSha3.update(input2.getBytes()); + wolfOutput = wolfSha3.digest(); + + assertArrayEquals(wolfOutput, interopOutput); + } + + @Test + public void testSha3DigestAfterDigest() + throws NoSuchProviderException, NoSuchAlgorithmException { + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE"); + sha3.update((byte)0x00); + sha3.digest(); + + /* Try to digest again without update, should return empty hash */ + byte[] emptyHash = sha3.digest(); + byte[] expectedEmptyHash = new byte[] { + (byte)0xa7, (byte)0xff, (byte)0xc6, (byte)0xf8, + (byte)0xbf, (byte)0x1e, (byte)0xd7, (byte)0x66, + (byte)0x51, (byte)0xc1, (byte)0x47, (byte)0x56, + (byte)0xa0, (byte)0x61, (byte)0xd6, (byte)0x62, + (byte)0xf5, (byte)0x80, (byte)0xff, (byte)0x4d, + (byte)0xe4, (byte)0x3b, (byte)0x49, (byte)0xfa, + (byte)0x82, (byte)0xd8, (byte)0x0a, (byte)0x4b, + (byte)0x80, (byte)0xf8, (byte)0x43, (byte)0x4a + }; + assertArrayEquals(expectedEmptyHash, emptyHash); + } + + @Test + public void testSha3UpdateAfterDigest() + throws NoSuchProviderException, NoSuchAlgorithmException { + + MessageDigest sha3 = MessageDigest.getInstance("SHA3-256", "wolfJCE"); + sha3.update((byte)0x00); + sha3.digest(); + + /* Try to update after digest, should implicitly reset */ + sha3.update((byte)0x00); + byte[] output = sha3.digest(); + + /* Verify we get expected output for single 0x00 byte */ + byte[] expected = new byte[] { + (byte)0x5d, (byte)0x53, (byte)0x46, (byte)0x9f, + (byte)0x20, (byte)0xfe, (byte)0xf4, (byte)0xf8, + (byte)0xea, (byte)0xb5, (byte)0x2b, (byte)0x88, + (byte)0x04, (byte)0x4e, (byte)0xde, (byte)0x69, + (byte)0xc7, (byte)0x7a, (byte)0x6a, (byte)0x68, + (byte)0xa6, (byte)0x07, (byte)0x28, (byte)0x60, + (byte)0x9f, (byte)0xc4, (byte)0xa6, (byte)0x5f, + (byte)0xf5, (byte)0x31, (byte)0xe7, (byte)0xd0 + }; + assertArrayEquals(expected, output); + } +} diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java index f4df715..2108d04 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptSignatureTest.java @@ -62,11 +62,19 @@ public class WolfCryptSignatureTest { "SHA256withRSA", "SHA384withRSA", "SHA512withRSA", + "SHA3-224withRSA", + "SHA3-256withRSA", + "SHA3-384withRSA", + "SHA3-512withRSA", "SHA1withECDSA", "SHA224withECDSA", "SHA256withECDSA", "SHA384withECDSA", - "SHA512withECDSA" + "SHA512withECDSA", + "SHA3-224withECDSA", + "SHA3-256withECDSA", + "SHA3-384withECDSA", + "SHA3-512withECDSA" }; private static ArrayList enabledAlgos = diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfJCETestSuite.java b/src/test/java/com/wolfssl/provider/jce/test/WolfJCETestSuite.java index 11be273..f626101 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfJCETestSuite.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfJCETestSuite.java @@ -33,6 +33,7 @@ import org.junit.runners.Suite.SuiteClasses; WolfCryptMessageDigestSha256Test.class, WolfCryptMessageDigestSha384Test.class, WolfCryptMessageDigestSha512Test.class, + WolfCryptMessageDigestSha3Test.class, WolfCryptRandomTest.class, WolfCryptSecretKeyFactoryTest.class, WolfCryptSignatureTest.class, diff --git a/src/test/java/com/wolfssl/wolfcrypt/test/HmacTest.java b/src/test/java/com/wolfssl/wolfcrypt/test/HmacTest.java index 695fe3c..f89603e 100644 --- a/src/test/java/com/wolfssl/wolfcrypt/test/HmacTest.java +++ b/src/test/java/com/wolfssl/wolfcrypt/test/HmacTest.java @@ -40,6 +40,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; +import com.wolfssl.wolfcrypt.Fips; import com.wolfssl.wolfcrypt.Hmac; import com.wolfssl.wolfcrypt.NativeStruct; import com.wolfssl.wolfcrypt.WolfCryptError; @@ -274,6 +275,197 @@ public class HmacTest { } } + static final String[] sha3KeyVector = new String[] { + "4A656665", /* Jefe */ + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + + "0102030405060708010203040506070801020304050607080102030405060708" + }; + static final String[] sha3DataVector = new String[] { + /* what do ya want for nothing? */ + "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + /* Hi There */ + "4869205468657265", + "dddddddddddddddddddd" + + "dddddddddddddddddddd" + + "dddddddddddddddddddd" + + "dddddddddddddddddddd" + + "dddddddddddddddddddd", + /* Big Key Input */ + "426967204b657920496e707574" + }; + + @Test + public void sha3_224HmacShouldMatch() { + String[] hashVector = new String[] { + "7fdb8dd88bd2f60d1b798634ad386811c2cfc85bfaf5d52bbace5e66", + "3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7", + "676cfc7d16153638780390692be142d2df7ce924b909c0c08dbfdc1a", + "29e05e46c4a45e4674bfd72d1ad866db2d0d104e2bfaad537d15698b" + }; + + for (int i = 0; i < sha3DataVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + try { + Hmac hmac = new Hmac(); + + byte[] key = Util.h2b(sha3KeyVector[i]); + byte[] data = Util.h2b(sha3DataVector[i]); + byte[] expected = Util.h2b(hashVector[i]); + + hmac.setKey(Hmac.SHA3_224, key); + hmac.update(data); + + assertArrayEquals(expected, hmac.doFinal()); + + hmac.reset(); + assertArrayEquals(expected, hmac.doFinal(data)); + + } catch (WolfCryptException e) { + if (e.getError() == WolfCryptError.NOT_COMPILED_IN) { + System.out.println("Hmac SHA3-224 test skipped: " + + e.getError()); + } else { + throw e; + } + } + } + } + + @Test + public void sha3_256HmacShouldMatch() { + String[] hashVector = new String[] { + "c7d4072e788877ae3596bbb0da73b887c9171f93095b294ae857fbe2645e1ba5", + "ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb", + "84ec79124a27107865cedd8bd82da9965e5ed8c37b0ac98005a7f39ed58a4207", + "b55b8d64b69c21d0bf205ca2f7b9b14e8821612c66c391ae6c95168583e6f49b" + }; + + for (int i = 0; i < sha3DataVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + try { + Hmac hmac = new Hmac(); + + byte[] key = Util.h2b(sha3KeyVector[i]); + byte[] expected = Util.h2b(hashVector[i]); + byte[] data = Util.h2b(sha3DataVector[i]); + + hmac.setKey(Hmac.SHA3_256, key); + hmac.update(data); + + assertArrayEquals(expected, hmac.doFinal()); + + hmac.reset(); + assertArrayEquals(expected, hmac.doFinal(data)); + + } catch (WolfCryptException e) { + if (e.getError() == WolfCryptError.NOT_COMPILED_IN) { + System.out.println("Hmac SHA3-256 test skipped: " + + e.getError()); + } else { + throw e; + } + } + } + } + + @Test + public void sha3_384HmacShouldMatch() { + String[] hashVector = new String[] { + "f1101f8cbf9766fd6764d2ed61903f21ca9b18f57cf3e1a23ca13508a93243ce48c045dc007f26a21b3f5e0e9df4c20a", + "68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd", + "275cd0e661bb8b151c64d288f1f782fb91a8abd56858d72babb2d476f0458373b41b6ab5bf174bec422e53fc3135ac6e", + "aa91b3a62f56a1be8c3e7438db58d9d334dea0606d8d46e0eca9f6063514e6ed83e67c77246c11b59082b575da7b832d" + }; + + for (int i = 0; i < sha3DataVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + try { + Hmac hmac = new Hmac(); + + byte[] key = Util.h2b(sha3KeyVector[i]); + byte[] data = Util.h2b(sha3DataVector[i]); + byte[] expected = Util.h2b(hashVector[i]); + + hmac.setKey(Hmac.SHA3_384, key); + hmac.update(data); + + assertArrayEquals(expected, hmac.doFinal()); + + hmac.reset(); + assertArrayEquals(expected, hmac.doFinal(data)); + + } catch (WolfCryptException e) { + if (e.getError() == WolfCryptError.NOT_COMPILED_IN) { + System.out.println("Hmac SHA3-384 test skipped: " + + e.getError()); + } else { + throw e; + } + } + } + } + + @Test + public void sha3_512HmacShouldMatch() { + String[] hashVector = new String[] { + "5a4bfeab6166427c7a3647b747292b8384537cdb89afb3bf5665e4c5e709350b287baec921fd7ca0ee7a0c31d022a95e1fc92ba9d77df883960275beb4e62024", + "eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e", + "309e99f9ec075ec6c6d475eda1180687fcf1531195802a99b5677449a8625182851cb332afb6a89c411325fbcbcd42afcb7b6e5aab7ea42c660f97fd8584bf03", + "1cc3a9244a4a3fbdc72000169b79470378752cb5f12e627cbeef4e8f0b112b32a0eec9d04d64640b37f4dd66f78bb3ad52526b6512de0d7cc08b60016c37d7a8" + }; + + for (int i = 0; i < sha3DataVector.length; i++) { + + if ((i == 0) && Fips.enabled) { + /* FIPS doesn't allow short key lengths */ + continue; + } + + try { + Hmac hmac = new Hmac(); + + byte[] expected = Util.h2b(hashVector[i]); + byte[] data = Util.h2b(sha3DataVector[i]); + + hmac.setKey(Hmac.SHA3_512, Util.h2b(sha3KeyVector[i])); + hmac.update(data); + + assertArrayEquals(expected, hmac.doFinal()); + + hmac.reset(); + assertArrayEquals(expected, hmac.doFinal(data)); + + } catch (WolfCryptException e) { + if (e.getError() == WolfCryptError.NOT_COMPILED_IN) { + System.out.println("Hmac SHA3-512 test skipped: " + + e.getError()); + } else { + throw e; + } + } + } + } + private void threadRunnerHmacTest(int hmacType, byte[] inKey, byte[] inData, byte[] inExpected) throws InterruptedException { @@ -421,5 +613,42 @@ public class HmacTest { "952ac4b7da7131f0") ); } + + if (Hmac.SHA3_224 != -1) { + threadRunnerHmacTest(Hmac.SHA3_224, + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), /* key */ + Util.h2b("4869205468657265"), /* data */ + Util.h2b("3b16546bbc7be2706a031dcafd56373d" + + "9884367641d8c59af3c860f7") + ); + } + if (Hmac.SHA3_256 != -1) { + threadRunnerHmacTest(Hmac.SHA3_256, + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), /* key */ + Util.h2b("4869205468657265"), /* data */ + Util.h2b("ba85192310dffa96e2a3a40e697743" + + "51140bb7185e1202cdcc917589f95e" + + "16bb") + ); + } + if (Hmac.SHA3_384 != -1) { + threadRunnerHmacTest(Hmac.SHA3_384, + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), /* key */ + Util.h2b("4869205468657265"), /* data */ + Util.h2b("68d2dcf7fd4ddd0a2240c8a437305f61" + + "fb7334cfb5d0226e1bc27dc10a2e723a" + + "20d370b47743130e26ac7e3d532886bd") + ); + } + if (Hmac.SHA3_512 != -1) { + threadRunnerHmacTest(Hmac.SHA3_512, + Util.h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), /* key */ + Util.h2b("4869205468657265"), /* data */ + Util.h2b("eb3fbd4b2eaab8f5c504bd3a41465aac" + + "ec15770a7cabac531e482f860b5ec7ba" + + "47ccb2c6f2afce8f88d22b6dc61380f2" + + "3a668fd3888bb80537c0a0b86407689e") + ); + } } } 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,