This is an automated email from the ASF dual-hosted git repository.
enapps-enorman pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-discovery-base.git
The following commit(s) were added to refs/heads/master by this push:
new e4c70d5 SLING-13223 Improve TopologyRequestValidator encryption (#21)
e4c70d5 is described below
commit e4c70d56889bcf2522b3fb49ea5f3a33417e9254
Author: Eric Norman <[email protected]>
AuthorDate: Fri May 29 13:40:53 2026 -0700
SLING-13223 Improve TopologyRequestValidator encryption (#21)
---
pom.xml | 14 ++-
.../connectors/ping/TopologyRequestValidator.java | 103 +++++++++------------
2 files changed, 57 insertions(+), 60 deletions(-)
diff --git a/pom.xml b/pom.xml
index 8cd16e7..937f9ed 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,6 +42,8 @@
<properties>
<jackrabbit.version>2.14.3</jackrabbit.version>
+ <surefire.maxmem>-Xmx2048m</surefire.maxmem>
+ <surefire.argline>${surefire.maxmem}</surefire.argline>
</properties>
<build>
@@ -51,7 +53,7 @@
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
- <argLine>-Xmx2048m</argLine>
+ <argLine>${surefire.argline}</argLine>
<excludedGroups>${sling.excluded.surefire.groups}</excludedGroups>
</configuration>
</plugin>
@@ -285,4 +287,14 @@
</dependency>
</dependencies>
+ <profiles>
+ <!-- override to pass the extra jacoco arguments to surefire-->
+ <profile>
+ <id>jacoco-report</id>
+ <properties>
+ <surefire.argline>${surefire.maxmem}
${jacoco.command}</surefire.argline>
+ </properties>
+ </profile>
+ </profiles>
+
</project>
diff --git
a/src/main/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidator.java
b/src/main/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidator.java
index a5f9545..c1a0e38 100644
---
a/src/main/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidator.java
+++
b/src/main/java/org/apache/sling/discovery/base/connectors/ping/TopologyRequestValidator.java
@@ -21,7 +21,7 @@ import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
-import java.security.AlgorithmParameters;
+import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -29,7 +29,6 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
-import java.security.spec.InvalidParameterSpecException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
import java.util.Collections;
@@ -45,7 +44,7 @@ import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import jakarta.json.Json;
@@ -83,6 +82,16 @@ public class TopologyRequestValidator {
*/
private static final int MINKEYS = 3;
+ /**
+ * GCM authentication tag length in bits.
+ */
+ private static final int GCM_TAG_LENGTH = 128;
+
+ /**
+ * GCM nonce length in bytes.
+ */
+ private static final int GCM_NONCE_LENGTH = 12;
+
/**
* true if trust information should be in request headers.
*/
@@ -153,24 +162,9 @@ public class TopologyRequestValidator {
StringWriter writer = new StringWriter();
Json.createGenerator(writer).write(json.build()).close();
return writer.toString();
- } catch (InvalidKeyException e) {
- e.printStackTrace();
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (IllegalBlockSizeException e) {
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (BadPaddingException e) {
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (UnsupportedEncodingException e) {
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (NoSuchAlgorithmException e) {
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (NoSuchPaddingException e) {
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (JsonException e) {
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (InvalidKeySpecException e) {
- throw new IOException("Unable to Encrypt Message " +
e.getMessage());
- } catch (InvalidParameterSpecException e) {
+ } catch (InvalidKeyException | IllegalBlockSizeException |
BadPaddingException | NoSuchAlgorithmException
+ | NoSuchPaddingException | JsonException |
InvalidKeySpecException
+ | InvalidAlgorithmParameterException e) {
throw new IOException("Unable to Encrypt Message " +
e.getMessage());
}
@@ -227,22 +221,10 @@ public class TopologyRequestValidator {
if (json.containsKey("payload")) {
return decrypt(json.getJsonArray("payload"));
}
- } catch (JsonException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
- } catch (InvalidKeyException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
- } catch (IllegalBlockSizeException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
- } catch (BadPaddingException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
- } catch (NoSuchAlgorithmException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
- } catch (NoSuchPaddingException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
- } catch (InvalidAlgorithmParameterException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
- } catch (InvalidKeySpecException e) {
- throw new IOException("Encrypted Message is in the
correct json format");
+ } catch (JsonException | InvalidKeyException |
IllegalBlockSizeException | BadPaddingException
+ | NoSuchAlgorithmException |
NoSuchPaddingException | InvalidAlgorithmParameterException
+ | InvalidKeySpecException e) {
+ throw new IOException("Encrypted Message is not in the
correct json format");
}
}
@@ -419,9 +401,9 @@ public class TopologyRequestValidator {
}
/**
- * Decrypt the body.
+ * Decrypt the body using AES/GCM mode with authenticated encryption.
*
- * @param jsonArray the encrypted payload
+ * @param jsonArray the encrypted payload (nonce, ciphertext, authTag)
* @return the decrypted payload.
* @throws IllegalBlockSizeException
* @throws BadPaddingException
@@ -433,18 +415,21 @@ public class TopologyRequestValidator {
* @throws InvalidAlgorithmParameterException
*/
private String decrypt(JsonArray jsonArray) throws
IllegalBlockSizeException,
- BadPaddingException, UnsupportedEncodingException,
InvalidKeyException,
- NoSuchAlgorithmException, NoSuchPaddingException,
InvalidAlgorithmParameterException, InvalidKeySpecException {
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- cipher.init(Cipher.DECRYPT_MODE,
getCipherKey(Base64.decodeBase64(jsonArray.get(0).toString().getBytes("UTF-8"))),
new
IvParameterSpec(Base64.decodeBase64(jsonArray.get(1).toString().getBytes("UTF-8"))));
- return new
String(cipher.doFinal(Base64.decodeBase64(jsonArray.get(2).toString().getBytes("UTF-8"))));
+ BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
+ NoSuchPaddingException, InvalidAlgorithmParameterException,
InvalidKeySpecException {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ byte[] nonce =
Base64.decodeBase64(jsonArray.get(0).toString().getBytes(StandardCharsets.UTF_8));
+ byte[] ciphertext =
Base64.decodeBase64(jsonArray.get(1).toString().getBytes(StandardCharsets.UTF_8));
+ GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
+ cipher.init(Cipher.DECRYPT_MODE, getCipherKey(nonce), spec);
+ return new String(cipher.doFinal(ciphertext), StandardCharsets.UTF_8);
}
/**
- * Encrypt a payload with the numbed key/
+ * Encrypt a payload with AES/GCM mode with authenticated encryption.
*
* @param payload the payload.
- * @return an encrypted version.
+ * @return an encrypted version (nonce, ciphertext).
* @throws IllegalBlockSizeException
* @throws BadPaddingException
* @throws UnsupportedEncodingException
@@ -452,20 +437,20 @@ public class TopologyRequestValidator {
* @throws NoSuchAlgorithmException
* @throws NoSuchPaddingException
* @throws InvalidKeySpecException
- * @throws InvalidParameterSpecException
+ * @throws InvalidAlgorithmParameterException
*/
private List<String> encrypt(String payload) throws
IllegalBlockSizeException,
- BadPaddingException, UnsupportedEncodingException,
InvalidKeyException,
- NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeySpecException, InvalidParameterSpecException {
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
- byte[] salt = new byte[9];
- random.nextBytes(salt);
- cipher.init(Cipher.ENCRYPT_MODE, getCipherKey(salt));
- AlgorithmParameters params = cipher.getParameters();
- List<String> encrypted = new ArrayList<String>();
- encrypted.add(new String(Base64.encodeBase64(salt)));
- encrypted.add(new
String(Base64.encodeBase64(params.getParameterSpec(IvParameterSpec.class).getIV())));
- encrypted.add(new
String(Base64.encodeBase64(cipher.doFinal(payload.getBytes("UTF-8")))));
+ BadPaddingException, InvalidKeyException, NoSuchAlgorithmException,
+ NoSuchPaddingException, InvalidKeySpecException,
InvalidAlgorithmParameterException {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ byte[] nonce = new byte[GCM_NONCE_LENGTH];
+ random.nextBytes(nonce);
+ GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, nonce);
+ cipher.init(Cipher.ENCRYPT_MODE, getCipherKey(nonce), spec);
+ byte[] ciphertext =
cipher.doFinal(payload.getBytes(StandardCharsets.UTF_8));
+ List<String> encrypted = new ArrayList<>();
+ encrypted.add(new String(Base64.encodeBase64(nonce),
StandardCharsets.UTF_8));
+ encrypted.add(new String(Base64.encodeBase64(ciphertext),
StandardCharsets.UTF_8));
return encrypted;
}
@@ -480,7 +465,7 @@ public class TopologyRequestValidator {
// The NIST guidelines suggest the iteration count to be at least 10000
// Using longer hashes (SHA-256 and higher) increases the attacker's
costs
SecretKeyFactory factory =
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
- KeySpec spec = new PBEKeySpec(sharedKey.toCharArray(), salt, 10000,
128);
+ KeySpec spec = new PBEKeySpec(sharedKey.toCharArray(), salt, 10000,
256);
SecretKey tmp = factory.generateSecret(spec);
return new SecretKeySpec(tmp.getEncoded(), "AES");
}