diff --git a/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java b/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java index 062a2c79..dd690230 100644 --- a/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java +++ b/commafeed-server/src/main/java/com/commafeed/CommaFeedApplication.java @@ -4,6 +4,7 @@ import jakarta.enterprise.event.Observes; import jakarta.inject.Singleton; import com.commafeed.backend.feed.FeedRefreshEngine; +import com.commafeed.backend.feed.ImageProxyUrl; import com.commafeed.backend.task.TaskScheduler; import com.commafeed.security.password.PasswordConstraintValidator; @@ -26,6 +27,10 @@ public class CommaFeedApplication { PasswordConstraintValidator.setMinimumPasswordLength(config.users().minimumPasswordLength()); + if (config.imageProxyEnabled()) { + ImageProxyUrl.generateKey(); + } + feedRefreshEngine.start(); taskScheduler.start(); } diff --git a/commafeed-server/src/main/java/com/commafeed/backend/feed/ImageProxyUrl.java b/commafeed-server/src/main/java/com/commafeed/backend/feed/ImageProxyUrl.java index 27feb785..d36cfbc1 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/feed/ImageProxyUrl.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/feed/ImageProxyUrl.java @@ -1,14 +1,15 @@ package com.commafeed.backend.feed; import java.nio.charset.StandardCharsets; -import java.security.SecureRandom; import java.util.Arrays; import java.util.Base64; import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import org.apache.commons.lang3.RandomUtils; import com.google.common.primitives.Bytes; @@ -17,28 +18,25 @@ import lombok.experimental.UtilityClass; @UtilityClass public class ImageProxyUrl { - private static final SecretKey KEY; - private static final SecureRandom SECURE_RANDOM = new SecureRandom(); private static final int GCM_IV_LENGTH = 12; private static final int GCM_TAG_LENGTH = 128; - static { - try { - KeyGenerator keyGen = KeyGenerator.getInstance("AES"); - keyGen.init(256, SECURE_RANDOM); - KEY = keyGen.generateKey(); - } catch (Exception e) { - throw new IllegalStateException("Failed to generate AES key", e); - } + private static SecretKey key; + + public static void generateKey() { + key = new SecretKeySpec(RandomUtils.secure().randomBytes(32), "AES"); } public static String encode(String url) { + if (key == null) { + throw new IllegalStateException("Key not initialized"); + } + try { - byte[] iv = new byte[GCM_IV_LENGTH]; - SECURE_RANDOM.nextBytes(iv); + byte[] iv = RandomUtils.secure().randomBytes(GCM_IV_LENGTH); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - cipher.init(Cipher.ENCRYPT_MODE, KEY, new GCMParameterSpec(GCM_TAG_LENGTH, iv)); + cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(GCM_TAG_LENGTH, iv)); byte[] encrypted = cipher.doFinal(url.getBytes(StandardCharsets.UTF_8)); byte[] combined = Bytes.concat(iv, encrypted); @@ -49,6 +47,10 @@ public class ImageProxyUrl { } public static String decode(String code) { + if (key == null) { + throw new IllegalStateException("Key not initialized"); + } + try { byte[] combined = Base64.getUrlDecoder().decode(code); @@ -56,7 +58,7 @@ public class ImageProxyUrl { byte[] encrypted = Arrays.copyOfRange(combined, GCM_IV_LENGTH, combined.length); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); - cipher.init(Cipher.DECRYPT_MODE, KEY, new GCMParameterSpec(GCM_TAG_LENGTH, iv)); + cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(GCM_TAG_LENGTH, iv)); byte[] decrypted = cipher.doFinal(encrypted); return new String(decrypted, StandardCharsets.UTF_8); diff --git a/commafeed-server/src/test/java/com/commafeed/backend/feed/ImageProxyUrlTest.java b/commafeed-server/src/test/java/com/commafeed/backend/feed/ImageProxyUrlTest.java index 1bf96dec..283e00ff 100644 --- a/commafeed-server/src/test/java/com/commafeed/backend/feed/ImageProxyUrlTest.java +++ b/commafeed-server/src/test/java/com/commafeed/backend/feed/ImageProxyUrlTest.java @@ -1,12 +1,18 @@ package com.commafeed.backend.feed; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; class ImageProxyUrlTest { + @BeforeAll + static void init() { + ImageProxyUrl.generateKey(); + } + @ParameterizedTest @ValueSource( strings = {