diff --git a/README_JCE.md b/README_JCE.md index 48513c3b..df96c16e 100644 --- a/README_JCE.md +++ b/README_JCE.md @@ -99,7 +99,7 @@ The JCE provider currently supports the following algorithms: SecureRandom Class DEFAULT (maps to HashDRBG) - HashDRBG + HashDRBG (aliased also as: Hash_DRBG, DRBG) Cipher Class AES/CBC/NoPadding diff --git a/jni/include/com_wolfssl_wolfcrypt_Rng.h b/jni/include/com_wolfssl_wolfcrypt_Rng.h index b707f513..a063950a 100644 --- a/jni/include/com_wolfssl_wolfcrypt_Rng.h +++ b/jni/include/com_wolfssl_wolfcrypt_Rng.h @@ -49,6 +49,14 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rng_rngGenerateBlock__Ljava_ni JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rng_rngGenerateBlock___3BII (JNIEnv *, jobject, jbyteArray, jint, jint); +/* + * Class: com_wolfssl_wolfcrypt_Rng + * Method: getRNG_MAX_BLOCK_LEN + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Rng_getRNG_1MAX_1BLOCK_1LEN + (JNIEnv *, jclass); + #ifdef __cplusplus } #endif diff --git a/jni/jni_rng.c b/jni/jni_rng.c index 15fa8f14..bbf7c886 100644 --- a/jni/jni_rng.c +++ b/jni/jni_rng.c @@ -132,12 +132,17 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rng_rngGenerateBlock__Ljava_ni buffer = getDirectBufferAddress(env, buffer_buffer); - ret = (!rng || !buffer) - ? BAD_FUNC_ARG - : wc_RNG_GenerateBlock(rng, buffer + position, size); + if (rng == NULL || buffer == NULL) { + ret = BAD_FUNC_ARG; + } - if (ret != 0) + if (ret == 0) { + ret = wc_RNG_GenerateBlock(rng, buffer + position, size); + } + + if (ret != 0) { throwWolfCryptExceptionFromError(env, ret); + } LogStr("wc_RNG_GenerateBlock(rng=%p, buffer, size) = %d\n", rng, ret); LogStr("output[%u]: [%p]\n", (word32)size, buffer); @@ -155,6 +160,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rng_rngGenerateBlock___3BII( int ret = 0; RNG* rng = NULL; byte* buffer = NULL; + word32 bufferSz = 0; rng = (RNG*) getNativeStruct(env, this); if ((*env)->ExceptionOccurred(env)) { @@ -163,12 +169,20 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rng_rngGenerateBlock___3BII( } buffer = getByteArray(env, buffer_buffer); + bufferSz = getByteArrayLength(env, buffer_buffer); - ret = (!rng || !buffer) - ? BAD_FUNC_ARG - : wc_RNG_GenerateBlock(rng, buffer + offset, length); - if (ret != 0) + if (rng == NULL || buffer == NULL || (offset + length) > bufferSz || + offset < 0 || length < 0) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + ret = wc_RNG_GenerateBlock(rng, buffer + offset, length); + } + + if (ret != 0) { throwWolfCryptExceptionFromError(env, ret); + } LogStr("wc_RNG_GenerateBlock(rng=%p, buffer, length) = %d\n", rng, ret); LogStr("output[%u]: [%p]\n", (word32)length, buffer); @@ -180,3 +194,9 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rng_rngGenerateBlock___3BII( #endif } +JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Rng_getRNG_1MAX_1BLOCK_1LEN + (JNIEnv* env, jclass jcl) +{ + return RNG_MAX_BLOCK_LEN; +} + diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java index efea99e6..238737a2 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptProvider.java @@ -117,6 +117,10 @@ private void registerServices() { "com.wolfssl.provider.jce.WolfCryptRandom"); put("SecureRandom.HashDRBG", "com.wolfssl.provider.jce.WolfCryptRandom"); + put("SecureRandom.Hash_DRBG", + "com.wolfssl.provider.jce.WolfCryptRandom"); + put("SecureRandom.DRBG", + "com.wolfssl.provider.jce.WolfCryptRandom"); /* Signature */ if (FeatureDetect.Md5Enabled()) { diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java index 805e1ff1..1a56a8de 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptRandom.java @@ -52,7 +52,22 @@ public WolfCryptRandom() { } @Override - protected synchronized byte[] engineGenerateSeed(int numBytes) { + protected synchronized byte[] engineGenerateSeed(int numBytes) + throws IllegalArgumentException { + + if (numBytes == 0) { + return new byte[0]; + } + + if (numBytes < 0) { + throw new IllegalArgumentException("numBytes must be non-negative"); + } + + if (numBytes > Rng.RNG_MAX_BLOCK_LEN) { + throw new IllegalArgumentException( + "numBytes too large. wolfCrypt max is " + + Rng.RNG_MAX_BLOCK_LEN); + } return rng.generateBlock(numBytes); } diff --git a/src/main/java/com/wolfssl/wolfcrypt/Rng.java b/src/main/java/com/wolfssl/wolfcrypt/Rng.java index ab6855fd..829b3f6f 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/Rng.java +++ b/src/main/java/com/wolfssl/wolfcrypt/Rng.java @@ -28,6 +28,10 @@ */ public class Rng extends NativeStruct { + /* Maximum generate block length for wolfCrypt */ + public static int RNG_MAX_BLOCK_LEN = + Rng.getRNG_MAX_BLOCK_LEN(); + /** * Malloc native JNI Rng structure * @@ -45,6 +49,7 @@ public class Rng extends NativeStruct { private native void rngGenerateBlock(ByteBuffer buffer, int offset, int length); private native void rngGenerateBlock(byte[] buffer, int offset, int length); + private static native int getRNG_MAX_BLOCK_LEN(); /* Lock to prevent concurrent access to native WC_RNG */ private final Object rngLock = new Object(); @@ -98,6 +103,7 @@ public synchronized void free() { * ByteBuffer is not direct. */ public synchronized void generateBlock(ByteBuffer buffer) { + init(); if (buffer.isDirect() == false) { @@ -120,7 +126,9 @@ public synchronized void generateBlock(ByteBuffer buffer) { * * @throws WolfCryptException if native operation fails */ - public synchronized void generateBlock(byte[] buffer, int offset, int length) { + public synchronized void generateBlock(byte[] buffer, int offset, + int length) { + init(); synchronized (rngLock) { diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptRandomTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptRandomTest.java index f3ceea17..2a7e264a 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptRandomTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptRandomTest.java @@ -79,6 +79,14 @@ public void testGetRandomFromProvider() /* DEFAULT */ rand = SecureRandom.getInstance("DEFAULT", "wolfJCE"); assertNotNull(rand); + + /* Hash_DRBG alias */ + rand = SecureRandom.getInstance("Hash_DRBG", "wolfJCE"); + assertNotNull(rand); + + /* DRBG alias */ + rand = SecureRandom.getInstance("DRBG", "wolfJCE"); + assertNotNull(rand); } @Test @@ -279,5 +287,63 @@ public void testSetSeed() rand.setSeed(seed); } + @Test + public void testGenerateSeedWithNegativeArgument() + throws NoSuchProviderException, NoSuchAlgorithmException { + + SecureRandom rand = SecureRandom.getInstance("HashDRBG", "wolfJCE"); + + try { + rand.generateSeed(-1); + fail("Expected IllegalArgumentException for negative seed length"); + + } catch (IllegalArgumentException e) { + /* Expected exception */ + } + } + + @Test + public void testGenerateSeedWithTooLargeArgument() + throws NoSuchProviderException, NoSuchAlgorithmException { + + SecureRandom rand = SecureRandom.getInstance("HashDRBG", "wolfJCE"); + + /* Get the maximum block length from Rng class */ + int maxLen = com.wolfssl.wolfcrypt.Rng.RNG_MAX_BLOCK_LEN; + + try { + rand.generateSeed(maxLen + 1); + fail("Expected IllegalArgumentException for too large length"); + } catch (IllegalArgumentException e) { + /* Expected exception */ + } + } + + @Test + public void testGenerateSeedWithValidMaxArgument() + throws NoSuchProviderException, NoSuchAlgorithmException { + + SecureRandom rand = SecureRandom.getInstance("HashDRBG", "wolfJCE"); + + /* Get the maximum block length from Rng class */ + int maxLen = com.wolfssl.wolfcrypt.Rng.RNG_MAX_BLOCK_LEN; + + /* This should succeed */ + byte[] seed = rand.generateSeed(maxLen); + assertNotNull(seed); + assertEquals(maxLen, seed.length); + } + + @Test + public void testGenerateSeedWithZeroArgument() + throws NoSuchProviderException, NoSuchAlgorithmException { + + SecureRandom rand = SecureRandom.getInstance("HashDRBG", "wolfJCE"); + + /* Zero length should be valid */ + byte[] seed = rand.generateSeed(0); + assertNotNull(seed); + assertEquals(0, seed.length); + } }