Do proper class isolation

This commit is contained in:
Oracle 2026-04-30 16:48:32 +02:00
parent 4a1e3c915d
commit dd8a863cb3
Signed by: Oracle
SSH key fingerprint: SHA256:x4/RtnjUyuHkdvmwNDsWSfcfF1V5PNr3OpriZqOvCX8
9 changed files with 117 additions and 46 deletions

View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>ai.nomyo</groupId>
<artifactId>nomyo4J</artifactId>
<version>1.0</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.44</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.0</version>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<outputFile>${project.build.directory}/${project.build.finalName}.jar</outputFile>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.44</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.12.1</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>junit-jupiter-api</artifactId>
<groupId>org.junit.jupiter</groupId>
</exclusion>
<exclusion>
<artifactId>junit-jupiter-params</artifactId>
<groupId>org.junit.jupiter</groupId>
</exclusion>
<exclusion>
<artifactId>junit-jupiter-engine</artifactId>
<groupId>org.junit.jupiter</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>local-repository</id>
<url>http://gamingvm.home.lan:8080/snapshots</url>
</repository>
</distributionManagement>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>25</maven.compiler.target>
<maven.compiler.source>25</maven.compiler.source>
</properties>
</project>

24
pom.xml
View file

@ -36,6 +36,13 @@
</dependency> </dependency>
</dependencies> </dependencies>
<distributionManagement>
<repository>
<id>local-repository</id>
<url>http://gamingvm.home.lan:8080/snapshots</url>
</repository>
</distributionManagement>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
@ -57,6 +64,23 @@
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>3.5.0</version> <version>3.5.0</version>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<outputFile>${project.build.directory}/${project.build.finalName}.jar</outputFile>
<minimizeJar>true</minimizeJar>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>

View file

@ -5,7 +5,7 @@ import java.util.Set;
/** /**
* Protocol, crypto, and configuration constants. Immutable used for downgrade detection. * Protocol, crypto, and configuration constants. Immutable used for downgrade detection.
*/ */
public final class Constants { final class Constants {
// Protocol Constants // Protocol Constants

View file

@ -11,7 +11,7 @@ import lombok.Setter;
*/ */
@Setter @Setter
@Getter @Getter
public class EncryptedRequest { class EncryptedRequest {
private static final Gson GSON = new GsonBuilder().create(); private static final Gson GSON = new GsonBuilder().create();

View file

@ -1,31 +0,0 @@
package ai.nomyo;
import java.security.SecureRandom;
import java.util.List;
import java.util.Map;
/**
* Entry point loads RSA keys and validates key length.
*/
public class Main {
static void main() {
SecureChatCompletion secureChatCompletion = new SecureChatCompletion(Constants.DEFAULT_BASE_URL, "NOMYO_AI_E2EE_INFERENCE");
List<Map<String, Object>> messages = List.of(
Map.of("role", "user", "content", "Hello! How are you today?")
);
Map<String, Object> kwargs = Map.of(
"security_tier", "standard",
"temperature", 0.7
);
var response = secureChatCompletion.create(
"Qwen/Qwen3-0.6B",
messages,
kwargs);
System.out.println(response.toString());
}
}

View file

@ -1,6 +1,5 @@
package ai.nomyo.util; package ai.nomyo;
import ai.nomyo.SecureMemory;
import ai.nomyo.SecureMemory.SecureBuffer; import ai.nomyo.SecureMemory.SecureBuffer;
import ai.nomyo.errors.SecurityError; import ai.nomyo.errors.SecurityError;
@ -13,7 +12,6 @@ import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.*; import java.security.*;
import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidKeySpecException;

View file

@ -2,7 +2,6 @@ package ai.nomyo;
import ai.nomyo.errors.*; import ai.nomyo.errors.*;
import ai.nomyo.util.PEMConverter; import ai.nomyo.util.PEMConverter;
import ai.nomyo.util.Pass2Key;
import ai.nomyo.SecureMemory.SecureBuffer; import ai.nomyo.SecureMemory.SecureBuffer;
import lombok.Getter; import lombok.Getter;
@ -40,7 +39,7 @@ import java.util.concurrent.locks.ReentrantLock;
/** /**
* Low-level client: key management, hybrid encryption, HTTP with retry, response decryption. Used by {@link SecureChatCompletion}. * Low-level client: key management, hybrid encryption, HTTP with retry, response decryption. Used by {@link SecureChatCompletion}.
*/ */
public class SecureCompletionClient { class SecureCompletionClient {
/** /**
* NOMYO router base URL (trailing slash stripped). * NOMYO router base URL (trailing slash stripped).
@ -405,9 +404,10 @@ public class SecureCompletionClient {
throw new RuntimeException(new SecurityError("RSA-OAEP key wrapping failed: " + e.getMessage(), e)); throw new RuntimeException(new SecurityError("RSA-OAEP key wrapping failed: " + e.getMessage(), e));
} }
String encryptedAESKeyB64 = Base64.getEncoder().encodeToString(encryptedAESKey);
try (SecureBuffer secureEncryptedAESKey = SecureMemory.secureByteArray(encryptedAESKey)) { try (SecureBuffer secureEncryptedAESKey = SecureMemory.secureByteArray(encryptedAESKey)) {
Arrays.fill(encryptedAESKey, (byte) 0);
byte[] tag = Arrays.copyOfRange(ciphertext, ciphertext.length - Constants.GCM_TAG_SIZE, ciphertext.length); byte[] tag = Arrays.copyOfRange(ciphertext, ciphertext.length - Constants.GCM_TAG_SIZE, ciphertext.length);
byte[] actualCiphertext = Arrays.copyOf(ciphertext, ciphertext.length - Constants.GCM_TAG_SIZE); byte[] actualCiphertext = Arrays.copyOf(ciphertext, ciphertext.length - Constants.GCM_TAG_SIZE);
@ -416,13 +416,11 @@ public class SecureCompletionClient {
request.setVersion(Constants.PROTOCOL_VERSION); request.setVersion(Constants.PROTOCOL_VERSION);
request.setAlgorithm(Constants.HYBRID_ALGORITHM); request.setAlgorithm(Constants.HYBRID_ALGORITHM);
request.setEncryptedPayload(new EncryptedRequest.EncryptedPayload(Base64.getEncoder().encodeToString(actualCiphertext), encryptedAESKeyB64, Base64.getEncoder().encodeToString(tag))); request.setEncryptedPayload(new EncryptedRequest.EncryptedPayload(Base64.getEncoder().encodeToString(actualCiphertext), Base64.getEncoder().encodeToString(secureNonce.getAsByteArray()), Base64.getEncoder().encodeToString(tag)));
request.setEncryptedAESKey(encryptedAESKeyB64); request.setEncryptedAESKey(Base64.getEncoder().encodeToString(secureEncryptedAESKey.getAsByteArray()));
request.setKeyAlgorithm(Constants.KEY_WRAP_ALGORITHM); request.setKeyAlgorithm(Constants.KEY_WRAP_ALGORITHM);
request.setPayloadAlgorithm(Constants.PAYLOAD_ALGORITHM); request.setPayloadAlgorithm(Constants.PAYLOAD_ALGORITHM);
Arrays.fill(encryptedAESKey, (byte) 0);
return request.toJson().getBytes(StandardCharsets.UTF_8); return request.toJson().getBytes(StandardCharsets.UTF_8);
} }
} }

View file

@ -12,7 +12,7 @@ import java.util.Map;
* Cross-platform memory locking and secure zeroing for sensitive cryptographic buffers. Fails gracefully if unavailable. * Cross-platform memory locking and secure zeroing for sensitive cryptographic buffers. Fails gracefully if unavailable.
*/ */
@SuppressWarnings("SameReturnValue") @SuppressWarnings("SameReturnValue")
public final class SecureMemory { final class SecureMemory {
@Getter @Getter
private static final boolean HAS_MEMORY_LOCKING; private static final boolean HAS_MEMORY_LOCKING;

View file

@ -1,7 +1,6 @@
package ai.nomyo; package ai.nomyo;
import ai.nomyo.errors.SecurityError; import ai.nomyo.errors.SecurityError;
import ai.nomyo.util.Pass2Key;
import org.junit.jupiter.api.*; import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.api.parallel.Execution; import org.junit.jupiter.api.parallel.Execution;