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 {