This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git


The following commit(s) were added to refs/heads/master by this push:
     new b1f77e8da WSS-729 Switch default JasyptPasswordEncryptor algorithm to 
PBEWithHmacSHA512AndAES_256 (#683)
b1f77e8da is described below

commit b1f77e8da6ad2a9a37fc587747f46093201c298e
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Thu Sep 10 06:58:58 2026 +0100

    WSS-729 Switch default JasyptPasswordEncryptor algorithm to 
PBEWithHmacSHA512AndAES_256 (#683)
---
 .../common/crypto/JasyptPasswordEncryptor.java     | 61 ++++++++++++++++++----
 .../wss4j/common/crypto/PasswordEncryptorTest.java | 37 +++++++++++++
 .../wss4j/dom/message/PasswordEncryptorTest.java   | 14 +++++
 .../wss4j/stax/test/PasswordEncryptorTest.java     | 14 +++++
 4 files changed, 115 insertions(+), 11 deletions(-)

diff --git 
a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/JasyptPasswordEncryptor.java
 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/JasyptPasswordEncryptor.java
index 68ed78aa4..557276ee0 100644
--- 
a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/JasyptPasswordEncryptor.java
+++ 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/JasyptPasswordEncryptor.java
@@ -34,13 +34,32 @@ import org.jasypt.salt.RandomSaltGenerator;
 
 /**
  * An implementation of PasswordEncryptor that relies on Jasypt's 
StandardPBEStringEncryptor to
- * encrypt and decrypt passwords. The default algorithm that is used is 
"PBEWithMD5AndTripleDES".
+ * encrypt and decrypt passwords. The default algorithm that is used is
+ * "PBEWithHmacSHA512AndAES_256". Values encrypted under the previous non-FIPS 
default
+ * ("PBEWithMD5AndTripleDES") can still be decrypted by setting the
+ * "org.apache.wss4j.crypto.jasypt.useLegacyDefaultAlgorithm" system property 
to "true", or by
+ * passing that algorithm to the constructor explicitly - but the legacy 
algorithm (an MD5-based
+ * PKCS#5 v1.5 KDF with 3DES) is weak against offline dictionary attack and 
values should be
+ * re-encrypted under the current default.
  */
 public class JasyptPasswordEncryptor implements PasswordEncryptor {
 
-    public static final String DEFAULT_ALGORITHM = 
-        FIPSUtils.isFIPSEnabled() 
-            ? "PBEWithHmacSHA512AndAES_256" : "PBEWithMD5AndTripleDES";
+    /**
+     * The default algorithm prior to WSS4J adopting 
"PBEWithHmacSHA512AndAES_256"
+     * universally (it was previously only the default when FIPS mode was 
enabled).
+     */
+    public static final String LEGACY_DEFAULT_ALGORITHM = 
"PBEWithMD5AndTripleDES";
+
+    /**
+     * System property to restore {@link #LEGACY_DEFAULT_ALGORITHM} as the 
default
+     * algorithm (ignored in FIPS mode), for compatibility with values 
encrypted under
+     * previous releases. The property is read each time an instance is 
constructed
+     * without an explicit algorithm, not once at class-loading time.
+     */
+    public static final String USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY =
+        "org.apache.wss4j.crypto.jasypt.useLegacyDefaultAlgorithm";
+
+    public static final String DEFAULT_ALGORITHM = 
"PBEWithHmacSHA512AndAES_256";
 
     private static final org.slf4j.Logger LOG =
         org.slf4j.LoggerFactory.getLogger(JasyptPasswordEncryptor.class);
@@ -49,31 +68,51 @@ public class JasyptPasswordEncryptor implements 
PasswordEncryptor {
     private CallbackHandler callbackHandler;
 
     public JasyptPasswordEncryptor(String password) {
-        this(password, DEFAULT_ALGORITHM);
+        this(password, defaultAlgorithm());
     }
 
     public JasyptPasswordEncryptor(String password, String algorithm) {
         passwordEncryptor = new StandardPBEStringEncryptor();
         passwordEncryptor.setPassword(password);
         passwordEncryptor.setAlgorithm(algorithm);
-        if (FIPSUtils.isFIPSEnabled()) {
-            passwordEncryptor.setSaltGenerator(new 
RandomSaltGenerator("PKCS11"));
-            passwordEncryptor.setIvGenerator(new RandomIvGenerator("PKCS11"));
-        }
+        configureGenerators(algorithm);
     }
 
     public JasyptPasswordEncryptor(CallbackHandler callbackHandler) {
-        this(callbackHandler, DEFAULT_ALGORITHM);
+        this(callbackHandler, defaultAlgorithm());
     }
 
     public JasyptPasswordEncryptor(CallbackHandler callbackHandler, String 
algorithm) {
         passwordEncryptor = new StandardPBEStringEncryptor();
         passwordEncryptor.setAlgorithm(algorithm);
+        configureGenerators(algorithm);
+        this.callbackHandler = callbackHandler;
+    }
+
+    /**
+     * Resolve the algorithm to use when none is given explicitly, honoring
+     * {@link #USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY} at construction time 
(outside FIPS mode).
+     */
+    private static String defaultAlgorithm() {
+        if (!FIPSUtils.isFIPSEnabled()
+            && 
Boolean.parseBoolean(System.getProperty(USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY, 
"false"))) {
+            return LEGACY_DEFAULT_ALGORITHM;
+        }
+        return DEFAULT_ALGORITHM;
+    }
+
+    private void configureGenerators(String algorithm) {
         if (FIPSUtils.isFIPSEnabled()) {
             passwordEncryptor.setSaltGenerator(new 
RandomSaltGenerator("PKCS11"));
             passwordEncryptor.setIvGenerator(new RandomIvGenerator("PKCS11"));
+        } else if (requiresIv(algorithm)) {
+            // AES-based PBE algorithms need an explicit IV generator with 
Jasypt
+            passwordEncryptor.setIvGenerator(new RandomIvGenerator());
         }
-        this.callbackHandler = callbackHandler;
+    }
+
+    private static boolean requiresIv(String algorithm) {
+        return algorithm != null && 
algorithm.toUpperCase(java.util.Locale.ROOT).contains("AES");
     }
 
     /**
diff --git 
a/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/PasswordEncryptorTest.java
 
b/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/PasswordEncryptorTest.java
index ead1899ac..310c737af 100644
--- 
a/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/PasswordEncryptorTest.java
+++ 
b/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/PasswordEncryptorTest.java
@@ -40,4 +40,41 @@ public class PasswordEncryptorTest {
         assertEquals(decryptedPassword, "password");
     }
 
+    @Test
+    public void testJasyptDefaultAlgorithm() throws Exception {
+        // The strong algorithm is the default on both the FIPS and non-FIPS 
paths, and
+        // round-trips without needing any pre-encrypted fixture
+        assertEquals(JasyptPasswordEncryptor.DEFAULT_ALGORITHM, 
"PBEWithHmacSHA512AndAES_256");
+
+        PasswordEncryptor passwordEncryptor =
+            new JasyptPasswordEncryptor("master-password");
+        String encryptedPassword = passwordEncryptor.encrypt("password");
+        assertNotEquals(encryptedPassword, "password");
+        String decryptedPassword = 
passwordEncryptor.decrypt(encryptedPassword);
+        assertEquals(decryptedPassword, "password");
+    }
+
+    @Test
+    public void testJasyptLegacyDefaultAlgorithmOptIn() throws Exception {
+        // A value encrypted under the previous default algorithm...
+        PasswordEncryptor legacyEncryptor =
+            new JasyptPasswordEncryptor("master-password",
+                                        
JasyptPasswordEncryptor.LEGACY_DEFAULT_ALGORITHM);
+        String legacyEncryptedPassword = legacyEncryptor.encrypt("password");
+        assertNotEquals(legacyEncryptedPassword, "password");
+
+        // ...can still be decrypted with the default constructor by opting in 
via the system
+        // property. The class is already loaded at this point, so this also 
checks that the
+        // property is honored at construction time rather than at 
class-loading time.
+        try {
+            
System.setProperty(JasyptPasswordEncryptor.USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY,
 "true");
+            PasswordEncryptor passwordEncryptor =
+                new JasyptPasswordEncryptor("master-password");
+            String decryptedPassword = 
passwordEncryptor.decrypt(legacyEncryptedPassword);
+            assertEquals(decryptedPassword, "password");
+        } finally {
+            
System.clearProperty(JasyptPasswordEncryptor.USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY);
+        }
+    }
+
 }
\ No newline at end of file
diff --git 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/PasswordEncryptorTest.java
 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/PasswordEncryptorTest.java
index cf068c397..b4b6b5fcc 100644
--- 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/PasswordEncryptorTest.java
+++ 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/PasswordEncryptorTest.java
@@ -45,6 +45,8 @@ import org.apache.wss4j.dom.handler.RequestData;
 import org.apache.wss4j.dom.handler.WSHandlerConstants;
 import org.apache.wss4j.dom.handler.WSHandlerResult;
 
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.w3c.dom.Document;
 
@@ -65,6 +67,18 @@ public class PasswordEncryptorTest {
         new JasyptPasswordEncryptor("this-is-a-secret");
     private Crypto crypto;
 
+    // The ENC() value in crypto_enc.properties was encrypted under the 
previous default
+    // algorithm (PBEWithMD5AndTripleDES), so opt in to the legacy default for 
this class
+    @BeforeAll
+    public static void setUpLegacyDefaultAlgorithm() {
+        
System.setProperty(JasyptPasswordEncryptor.USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY,
 "true");
+    }
+
+    @AfterAll
+    public static void tearDownLegacyDefaultAlgorithm() {
+        
System.clearProperty(JasyptPasswordEncryptor.USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY);
+    }
+
     public PasswordEncryptorTest() throws Exception {
         WSSConfig.init();
         Properties properties =
diff --git 
a/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/PasswordEncryptorTest.java
 
b/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/PasswordEncryptorTest.java
index c55bce821..5820dcd82 100644
--- 
a/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/PasswordEncryptorTest.java
+++ 
b/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/PasswordEncryptorTest.java
@@ -41,6 +41,8 @@ import org.apache.wss4j.stax.setup.OutboundWSSec;
 import org.apache.wss4j.stax.setup.WSSec;
 import org.apache.wss4j.stax.test.utils.XmlReaderToWriter;
 import org.apache.xml.security.stax.securityEvent.SecurityEvent;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -58,6 +60,18 @@ import static org.junit.jupiter.api.Assertions.fail;
  */
 public class PasswordEncryptorTest extends AbstractTestBase {
 
+    // The ENC() value in transmitter-crypto-enc.properties was encrypted 
under the previous
+    // default algorithm (PBEWithMD5AndTripleDES), so opt in to the legacy 
default for this class
+    @BeforeAll
+    public static void setUpLegacyDefaultAlgorithm() {
+        
System.setProperty(JasyptPasswordEncryptor.USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY,
 "true");
+    }
+
+    @AfterAll
+    public static void tearDownLegacyDefaultAlgorithm() {
+        
System.clearProperty(JasyptPasswordEncryptor.USE_LEGACY_DEFAULT_ALGORITHM_PROPERTY);
+    }
+
     @Test
     public void testSignatureCryptoPropertiesOutbound() throws Exception {
 

Reply via email to