Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions jni/include/com_wolfssl_wolfcrypt_AesGcm.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions jni/jni_aesgcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,24 @@
/* #define WOLFCRYPT_JNI_DEBUG_ON */
#include <wolfcrypt_jni_debug.h>

JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmShortIvAllowed
(JNIEnv* env, jclass jcl)
{
jboolean allowed = JNI_TRUE;
(void)env;
(void)jcl;

#if defined(HAVE_FIPS) && !defined(FIPS_NO_WRAPPERS) && \
defined(FIPS_VERSION3_EQ) && defined(FIPS_VERSION3_GE)
/* FIPS returns WC_FIPS_NOT_APPROVED for GCM/GMAC IVs under 96 bits */
#if FIPS_VERSION3_EQ(5,2,4) || FIPS_VERSION3_GE(7,0,0)
allowed = JNI_FALSE;
#endif
#endif

return allowed;
}

JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_mallocNativeStruct_1internal
(JNIEnv* env, jobject this)
{
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/wolfssl/provider/jce/WolfCryptCipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -1267,6 +1267,12 @@ else if (cipherMode == CipherMode.WC_CCM) {
"AES-GCM IV is null or 0 length");
}

if (!AesGcm.shortIvAllowed() &&
gcmSpec.getIV().length < AesGcm.GCM_NONCE_MID_SZ) {
throw new InvalidAlgorithmParameterException(
"AES-GCM IV shorter than 96 bits is not FIPS approved");
}

this.iv = gcmSpec.getIV().clone();
this.gcmTagLen = tagLenToBytes("AES-GCM", gcmSpec.getTLen());
}
Expand Down
7 changes: 7 additions & 0 deletions src/main/java/com/wolfssl/provider/jce/WolfCryptMac.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import com.wolfssl.wolfcrypt.Hmac;
import com.wolfssl.wolfcrypt.AesCmac;
import com.wolfssl.wolfcrypt.AesGmac;
import com.wolfssl.wolfcrypt.AesGcm;
import com.wolfssl.wolfcrypt.Aes;

/**
Expand Down Expand Up @@ -256,6 +257,12 @@ protected void engineInit(Key key, AlgorithmParameterSpec params)
" bits, got " + gmacTagBits);
}

if (!AesGcm.shortIvAllowed() &&
gcmSpec.getIV().length < AesGcm.GCM_NONCE_MID_SZ) {
throw new InvalidAlgorithmParameterException(
"AES-GMAC IV shorter than 96 bits not FIPS approved");
}

this.aesGmac.setKey(encodedKey);
this.gmacIv = gcmSpec.getIV();
/* Convert bits to bytes */
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/wolfssl/wolfcrypt/AesGcm.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
*/
public class AesGcm extends NativeStruct {

/** 96-bit AES-GCM IV size in bytes, native GCM_NONCE_MID_SZ */
public static final int GCM_NONCE_MID_SZ = 12;

private WolfCryptState state = WolfCryptState.UNINITIALIZED;

/* Size of IV generated by setIV(), 0 until setIV() is called */
Expand All @@ -49,6 +52,24 @@ private native byte[] wc_AesGcmDecrypt(byte[] input, byte[] iv,
private native byte[] wc_AesGcmSetIV(int ivSz, byte[] ivFixed, Rng rng);
private native byte[] wc_AesGcmEncrypt_ex(byte[] input, byte[] ivOut,
byte[] authTagOut, byte[] authIn);
private static native boolean wc_AesGcmShortIvAllowed();

/**
* Checks if short AES-GCM and GMAC IVs (under 96 bits) are allowed.
* wolfCrypt FIPS v5.2.4 and v7+ mark them as not FIPS approved.
*
* @return true if IVs shorter than 96 bits are allowed
*/
public static boolean shortIvAllowed() {

if (Fips.enabled) {
if (!wc_AesGcmShortIvAllowed()) {
return false;
}
}

return true;
}

/**
* Create a new AesGcm object.
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/com/wolfssl/wolfcrypt/WolfCryptError.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ public enum WolfCryptError {
/** No error found */
NO_ERROR_FOUND (-1),

/** FIPS 140-3 service indicator, operation is not FIPS approved */
WC_FIPS_NOT_APPROVED (1),

/* error codes match <wolfssl>/wolfssl/wolfcrypt/error-crypt.h */

/** errors -97 - -1008 */
Expand Down Expand Up @@ -834,8 +837,12 @@ public int getCode() {
* @return String description of current error
*/
public String getDescription() {
if (this == WolfCryptError.NO_ERROR_FOUND)
if (this == WolfCryptError.NO_ERROR_FOUND) {
return "No error code found in JNI WolfCryptError enum";
}
if (this == WolfCryptError.WC_FIPS_NOT_APPROVED) {
return "Operation is not FIPS approved";
}
return wc_GetErrorString(this.code);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
import com.wolfssl.wolfcrypt.FeatureDetect;
import com.wolfssl.wolfcrypt.test.Util;
import com.wolfssl.wolfcrypt.Aes;
import com.wolfssl.wolfcrypt.AesGcm;
import com.wolfssl.wolfcrypt.AesXts;
import com.wolfssl.wolfcrypt.Fips;
import com.wolfssl.wolfcrypt.test.Util;
Expand Down Expand Up @@ -10240,6 +10241,42 @@ public void nextBytes(byte[] bytes) {
}
}

/**
* AES-GCM IV shorter than 96 bits is rejected at init() where FIPS
* v5.2.4 and v7+ mark it not approved, and works otherwise.
*/
@Test
public void testAesGcmShortIv() throws Exception {

if (!enabledJCEAlgos.contains("AES/GCM/NoPadding") ||
!FeatureDetect.Aes128Enabled()) {
return;
}

byte[] pt = "AES-GCM short IV".getBytes();
SecretKeySpec key = new SecretKeySpec(new byte[16], "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, new byte[8]);
Cipher c = Cipher.getInstance("AES/GCM/NoPadding", jceProvider);

if (AesGcm.shortIvAllowed()) {
c.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] ct = c.doFinal(pt);
c.init(Cipher.DECRYPT_MODE, key, spec);
assertArrayEquals(pt, c.doFinal(ct));
}
else {
for (int mode : new int[] {Cipher.ENCRYPT_MODE,
Cipher.DECRYPT_MODE}) {
try {
c.init(mode, key, spec);
fail("AES-GCM init with 8-byte IV should throw");
} catch (InvalidAlgorithmParameterException e) {
/* expected */
}
}
}
}

/**
* Ciphertext from a wolfJCE AES/GCM/NoPadding encrypt init without
* parameters decrypts with the interop provider using getIV().
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/com/wolfssl/provider/jce/test/WolfCryptMacTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import java.security.InvalidAlgorithmParameterException;

import com.wolfssl.wolfcrypt.Fips;
import com.wolfssl.wolfcrypt.AesGcm;
import com.wolfssl.provider.jce.WolfCryptProvider;
import com.wolfssl.wolfcrypt.test.Util;
import com.wolfssl.wolfcrypt.test.TimedTestWatcher;
Expand Down Expand Up @@ -2194,6 +2195,33 @@ public void testAesGmacRejectsInvalidTagLength()
assertEquals(16, mac.getMacLength());
}

@Test
public void testAesGmacShortIv()
throws InvalidKeyException, NoSuchAlgorithmException,
NoSuchProviderException, InvalidAlgorithmParameterException {

if (!enabledAlgos.contains("AESGMAC")) {
return;
}

Mac mac = Mac.getInstance("AESGMAC", "wolfJCE");
SecretKeySpec keyspec = new SecretKeySpec(new byte[16], "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, new byte[8]);

if (AesGcm.shortIvAllowed()) {
mac.init(keyspec, spec);
assertEquals(16, mac.doFinal().length);
}
else {
try {
mac.init(keyspec, spec);
fail("AES-GMAC init with 8-byte IV should throw");
} catch (InvalidAlgorithmParameterException e) {
/* expected */
}
}
}

@Test
public void testAesGmacRejectedInitPreservesState()
throws InvalidKeyException, NoSuchAlgorithmException,
Expand Down
7 changes: 7 additions & 0 deletions src/test/java/com/wolfssl/wolfcrypt/test/WolfCryptTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,13 @@ public void testGetDigestSize() {
}
}

@Test
public void testFipsNotApprovedError() {
WolfCryptException e = new WolfCryptException(1);
assertEquals(WolfCryptError.WC_FIPS_NOT_APPROVED, e.getError());
assertEquals("Operation is not FIPS approved", e.getMessage());
}

@Test
public void testToHexStringBasic() throws Exception {

Expand Down
Loading