From 1929fe30cfa769bf4deba89928653da028cb72e5 Mon Sep 17 00:00:00 2001
From: Brian Campbell <brian.d.campbell@gmail.com>
Date: Wed, 1 Feb 2023 17:24:15 -0700
Subject: [PATCH] PBES2 - disallow iteration count < 1000 (Issue #203) and salt
 < 8 bytes. Also increased the default iteration count

---
 .../Pbes2HmacShaWithAesKeyWrapAlgorithm.java  | 14 +++++++++-
 ...es2HmacShaWithAesKeyWrapAlgorithmTest.java | 26 +++++++++++++++++--
 2 files changed, 37 insertions(+), 3 deletions(-)

Index: jose4j-0.5.1/src/main/java/org/jose4j/jwe/Pbes2HmacShaWithAesKeyWrapAlgorithm.java
===================================================================
--- jose4j-0.5.1.orig/src/main/java/org/jose4j/jwe/Pbes2HmacShaWithAesKeyWrapAlgorithm.java
+++ jose4j-0.5.1/src/main/java/org/jose4j/jwe/Pbes2HmacShaWithAesKeyWrapAlgorithm.java
@@ -48,7 +48,7 @@ public class Pbes2HmacShaWithAesKeyWrapA
 
     // RFC 2898 and JWA both recommend a minimum iteration count of 1000 and mandate at least 8 bytes of salt
     // so we'll go with defaults that somewhat exceed those requirements/recommendations
-    private long defaultIterationCount = 8192L;
+    private long defaultIterationCount = 8192L * 8;
     private int defaultSaltByteLength = 12;
 
     public Pbes2HmacShaWithAesKeyWrapAlgorithm(String alg, String hmacAlg, AesKeyWrapManagementAlgorithm keyWrapAlg)
@@ -78,6 +78,12 @@ public class Pbes2HmacShaWithAesKeyWrapA
             headers.setObjectHeaderValue(HeaderParameterNames.PBES2_ITERATION_COUNT, iterationCount);
         }
 
+        if (iterationCount < 1000)
+        {
+            throw new JoseException("iteration count ("+HeaderParameterNames.PBES2_ITERATION_COUNT+"="+
+                    iterationCount+") cannot be less than 1000 (and should probably be considerably more)");
+        }
+
         String saltInputString = headers.getStringHeaderValue(HeaderParameterNames.PBES2_SALT_INPUT);
         byte[] saltInput;
         Base64Url base64Url = new Base64Url();
@@ -92,6 +98,12 @@ public class Pbes2HmacShaWithAesKeyWrapA
             saltInput = base64Url.base64UrlDecode(saltInputString);
         }
 
+
+        if (saltInput.length < 8)
+        {
+            throw new JoseException("A p2s salt input value containing 8 or more octets MUST be used.");
+        }
+
         return deriveKey(managementKey, iterationCount, saltInput, providerContext);
     }
 
Index: jose4j-0.5.1/src/test/java/org/jose4j/jwe/Pbes2HmacShaWithAesKeyWrapAlgorithmTest.java
===================================================================
--- jose4j-0.5.1.orig/src/test/java/org/jose4j/jwe/Pbes2HmacShaWithAesKeyWrapAlgorithmTest.java
+++ jose4j-0.5.1/src/test/java/org/jose4j/jwe/Pbes2HmacShaWithAesKeyWrapAlgorithmTest.java
@@ -32,8 +32,7 @@ import static org.hamcrest.CoreMatchers.
 import static org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers.*;
 import static org.jose4j.jwe.KeyManagementAlgorithmIdentifiers.PBES2_HS256_A128KW;
 import static org.jose4j.jwe.KeyManagementAlgorithmIdentifiers.PBES2_HS384_A192KW;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
 
 /**
  */
@@ -183,4 +182,27 @@ public class Pbes2HmacShaWithAesKeyWrapA
     }
 
 
+    @Test (expected = JoseException.class)
+    public void testTooSmallIterationCountRejected() throws JoseException
+    {
+        JsonWebEncryption encryptingJwe  = new JsonWebEncryption();
+        encryptingJwe.setHeader(HeaderParameterNames.PBES2_ITERATION_COUNT, 918L);
+        encryptingJwe.setAlgorithmHeaderValue(PBES2_HS256_A128KW);
+        encryptingJwe.setEncryptionMethodHeaderParameter(AES_128_CBC_HMAC_SHA_256);
+        encryptingJwe.setPayload("some text");
+        encryptingJwe.setKey(new PbkdfKey("super secret word"));
+        encryptingJwe.getCompactSerialization();
+    }
+
+    @Test (expected = JoseException.class)
+    public void testTooLittleSaltRejected() throws JoseException
+    {
+        JsonWebEncryption encryptingJwe  = new JsonWebEncryption();
+        encryptingJwe.setHeader(HeaderParameterNames.PBES2_SALT_INPUT, "bWVo");
+        encryptingJwe.setAlgorithmHeaderValue(PBES2_HS256_A128KW);
+        encryptingJwe.setEncryptionMethodHeaderParameter(AES_128_CBC_HMAC_SHA_256);
+        encryptingJwe.setPayload("some text");
+        encryptingJwe.setKey(new PbkdfKey("super secret word"));
+        encryptingJwe.getCompactSerialization();
+    }
 }
