No description
Find a file
2026-05-01 19:09:38 +02:00
.idea Fix test error 2026-04-29 17:08:10 +02:00
src Wrap more byte arrays in SecureBuffers where possible 2026-05-01 19:09:38 +02:00
.gitignore Add tests 2026-04-21 18:00:31 +02:00
AGENTS.md Add README and SecureBuffer memory locking 2026-04-29 19:13:48 +02:00
dependency-reduced-pom.xml Do proper class isolation 2026-04-30 16:48:32 +02:00
pom.xml Do proper class isolation 2026-04-30 16:48:32 +02:00
README.md Add README and SecureBuffer memory locking 2026-04-29 19:13:48 +02:00

NOMYO Secure Java Chat Client

OpenAI-compatible secure chat client with end-to-end encryption for NOMYO Inference Endpoints

🔒 All prompts and responses are automatically encrypted and decrypted

🔑 Uses hybrid encryption (AES-256-GCM + RSA-OAEP with 4096-bit keys)

🔄 Drop-in replacement for OpenAI's ChatCompletion API (Java)

🚀 Quick Start

0. Try It Now (Demo Credentials)

No account needed — use these public demo credentials to test immediately:

API key NOMYO_AI_E2EE_INFERENCE
Model Qwen/Qwen3-0.6B

Note: The demo endpoint uses a fixed 256-token context window and is intended for evaluation only.

1. Installation

via Maven (recommended):

<dependency>
    <groupId>com.nomyo</groupId>
    <artifactId>nomyo-java</artifactId>
    <version>1.0.0</version>
</dependency>

via Gradle:

implementation 'com.nomyo:nomyo-java:1.0.0'

2. Use the client (same API as OpenAI)

import com.nomyo.client.SecureChatCompletion;
import com.nomyo.client.Constants;
import java.util.List;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        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());
    }
}

🔐 Security Features

Hybrid Encryption

  • Payload encryption: AES-256-GCM (authenticated encryption)
  • Key exchange: RSA-OAEP with SHA-256
  • Key size: 4096-bit RSA keys
  • All communication: End-to-end encrypted

Key Management

  • Automatic key generation: Keys are automatically generated on first use
  • Automatic key loading: Existing keys are loaded automatically from client_keys/ directory
  • No manual intervention required: The library handles key management automatically
  • Keys kept in memory: Active session keys are stored in memory for performance
  • Optional persistence: Keys can be saved to client_keys/ directory for reuse across sessions
  • Password protection: Optional password encryption for private keys (recommended for production)
  • Secure permissions: Private keys stored with restricted permissions (600 - owner-only access)

Secure Memory Protection

Ephemeral AES Keys

  • Per-request encryption keys: A unique AES-256 key is generated for each request
  • Automatic rotation: AES keys are never reused - a fresh key is created for every encryption operation
  • Forward secrecy: Compromise of one AES key only affects that single request
  • Secure generation: AES keys are generated using cryptographically secure random number generation
  • Automatic cleanup: AES keys are zeroed from memory immediately after use
  • Automatic protection: Plaintext payloads are automatically protected during encryption
  • Prevents memory swapping: Sensitive data cannot be swapped to disk
  • Guaranteed zeroing: Memory is zeroed after encryption completes
  • Fallback mechanism: Graceful degradation if SecureMemory module unavailable

🔄 OpenAI Compatibility

The SecureChatCompletion class provides exact API compatibility with OpenAI's ChatCompletion.create() method.

Supported Parameters

All standard OpenAI parameters are supported:

  • model: Model identifier
  • messages: List of message objects (List<Map<String, Object>>)
  • temperature: Sampling temperature (0-2)
  • max_tokens: Maximum tokens to generate
  • top_p: Nucleus sampling
  • frequency_penalty: Frequency penalty
  • presence_penalty: Presence penalty
  • stop: Stop sequences
  • n: Number of completions
  • tools: Tool definitions
  • tool_choice: Tool selection strategy
  • user: User identifier
  • And more...

Response Format

Responses follow the OpenAI format exactly, with an additional _metadata field for debugging and security information.

{
    "id": "chatcmpl-123",
    "object": "chat.completion",
    "created": 1234567890,
    "model": "Qwen/Qwen3-0.6B",
    "choices": [
        {
            "index": 0,
            "message": {
                "role": "assistant",
                "content": "Hello! I'm doing well, thank you for asking.",
                "tool_calls": [...]  // if tools were used
            },
            "finish_reason": "stop"
        }
    ],
    "usage": {
        "prompt_tokens": 10,
        "completion_tokens": 20,
        "total_tokens": 30
    },
    "_metadata": {
        "payload_id": "openai-compat-abc123",  // Unique identifier for this request
        "processed_at": 1765250382,  // Timestamp when server processed the request
        "is_encrypted": true,  // Indicates this response was decrypted
        "encryption_algorithm": "hybrid-aes256-rsa4096",  // Encryption method used
        "response_status": "success"  // Status of the decryption/processing
    }
}

The _metadata field contains security-related information about the encrypted communication and is automatically added to all responses.

🛠️ Usage Examples

Basic Chat

import com.nomyo.client.SecureChatCompletion;
import com.nomyo.client.Constants;
import java.util.List;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        SecureChatCompletion client = new SecureChatCompletion(
            Constants.DEFAULT_BASE_URL, 
            "NOMYO_AI_E2EE_INFERENCE"
        );

        List<Map<String, Object>> messages = List.of(
            Map.of("role", "system", "content", "You are a helpful assistant."),
            Map.of("role", "user", "content", "What is the capital of France?")
        );

        Map<String, Object> kwargs = Map.of("security_tier", "standard", "temperature", 0.7);

        var response = client.create(
            "Qwen/Qwen3-0.6B",
            messages,
            kwargs
        );

        // Extract content safely
        System.out.println(response.get("choices").get(0).get("message").get("content"));
    }
}

With Tools

import com.nomyo.client.SecureChatCompletion;
import com.nomyo.client.Constants;
import java.util.List;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        SecureChatCompletion client = new SecureChatCompletion(
            Constants.DEFAULT_BASE_URL, 
            "NOMYO_AI_E2EE_INFERENCE"
        );

        List<Map<String, Object>> messages = List.of(
            Map.of("role", "user", "content", "What's the weather in Paris?")
        );

        Map<String, Object> tools = Map.of(
            "type", "function",
            "function", Map.of(
                "name", "get_weather",
                "description", "Get weather information",
                "parameters", Map.of(
                    "type", "object",
                    "properties", Map.of(
                        "location", Map.of("type", "string")
                    ),
                    "required", List.of("location")
                )
            )
        );

        Map<String, Object> kwargs = Map.of("security_tier", "standard", "temperature", 0.7);

        var response = client.create(
            "Qwen/Qwen3-0.6B",
            messages,
            kwargs
        );

        System.out.println(response.get("choices").get(0).get("message").get("content"));
    }
}

📦 Dependencies

  • Maven Coordinates: com.nomyo:nomyo-java
  • Java Version: Java 11+ (Required for HTTP Client and crypto primitives)
  • JSON Processing: Jackson Databind (for Map/JSON handling)
  • HTTP Client: Apache HttpClient or Java NIO (Included in core)
  • Crypto: BouncyCastle or JDK Crypto (Included in core)

🔧 Configuration

Custom Base URL

SecureChatCompletion client = new SecureChatCompletion("https://NOMYO-Pro-Router:12434", "YOUR_API_KEY");

API Key Authentication

// Initialize with API key (recommended for production)
SecureChatCompletion client = new SecureChatCompletion(
    "https://api.nomyo.ai",
    "your-api-key-here"
);

// Or pass API key in the create() method if supported by extension
// Map<String, Object> kwargs = Map.of("security_tier", "standard", "api_key", "your-api-key-here");

Secure Memory Configuration

The library enables secure memory protection by default.

// Enable secure memory protection (default)
SecureChatCompletion client = new SecureChatCompletion("https://api.nomyo.ai", "YOUR_API_KEY");

// Disable secure memory (not recommended, for testing only)
// Requires passing specific config flag if available in version
SecureChatCompletion client = new SecureChatCompletion("https://api.nomyo.ai", "YOUR_API_KEY");

Key Management

Keys are automatically generated on first use.

Generate Keys Manually

import com.nomyo.client.SecureCompletionClient;

public class KeyManager {
    public static void main(String[] args) {
        SecureCompletionClient client = new SecureCompletionClient();
        client.generateKeys(true, "client_keys", "your-password");
    }
}

Load Existing Keys

import com.nomyo.client.SecureCompletionClient;

public class KeyManager {
    public static void main(String[] args) {
        SecureCompletionClient client = new SecureCompletionClient();
        client.loadKeys("client_keys/private_key.pem", "client_keys/public_key.pem", "your-password");
    }
}

📚 API Reference

SecureChatCompletion

Constructor

SecureChatCompletion(
    String base_url,
    String api_key
)

Parameters:

  • base_url: Base URL of the NOMYO Router (must use HTTPS for production)
  • api_key: Optional API key for bearer authentication

Methods

  • create(String model, List<Map<String, Object>> messages, Map<String, Object> kwargs): Create a chat completion

SecureCompletionClient

Constructor

SecureCompletionClient(
    String router_url
)

Methods

  • generateKeys(boolean saveToFile, String keyDir, String password): Generate RSA key pair
  • loadKeys(String private_key_path, String public_key_path, String password): Load keys from files
  • fetchServerPublicKey(): Fetch server's public key
  • encryptPayload(Map<String, Object> payload): Encrypt a payload
  • decryptResponse(Map<String, Object> encrypted_response, String payload_id): Decrypt a response
  • sendSecureRequest(Map<String, Object> payload, String payload_id): Send encrypted request and receive decrypted response

📝 Notes

Security Best Practices

  • Always use password protection for private keys in production
  • Keep private keys secure (permissions set to 600)
  • Never share your private key
  • Verify server's public key fingerprint before first use

Performance

  • Key generation takes ~1-2 seconds (one-time operation)
  • Encryption/decryption adds minimal overhead (~10-20ms per request)

Compatibility

  • Works with any OpenAI-compatible code
  • No changes needed to existing OpenAI client code
  • Simply replace openai.ChatCompletion.create() with SecureChatCompletion.create()

🤝 Contributing

Contributions are welcome! Please open issues or pull requests on the project repository.

📄 License

See LICENSE file for licensing information.

📞 Support

For questions or issues, please refer to the project documentation or open an issue.