anyllmplatform

package module
v0.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 17, 2026 License: Apache-2.0 Imports: 15 Imported by: 1

README

Provider Key Decrypter (Go)

Go package to decrypt provider API keys using X25519 sealed box encryption and challenge-response authentication with the ANY LLM backend.

Installation

go get github.com/mozilla-ai/any-llm-platform-client-go
CLI Installation
go install github.com/mozilla-ai/any-llm-platform-client-go/cmd/any-llm@latest

Usage

Command Line Interface

Interactive mode (prompts for provider):

export ANY_LLM_KEY='ANY.v1.<kid>.<fingerprint>-<base64_key>'
any-llm

Direct mode (specify provider as argument):

any-llm openai

With custom platform URL:

any-llm -platform-url https://api.example.com/v1 openai
Configuring the API Base URL

By default, the client connects to http://localhost:8000/api/v1. To change this:

package main

import (
    anyllmplatform "github.com/mozilla-ai/any-llm-platform-client-go"
)

func main() {
    // Create a client that talks to a different backend
    client := anyllmplatform.NewClient(
        anyllmplatform.WithPlatformURL("https://api.example.com/v1"),
    )

    // Now calls on client will use the configured base URL
}

Or set the environment variable before running the CLI:

export ANY_LLM_PLATFORM_URL="https://staging-api.example.com/v1"
any-llm openai
As a Go Library
package main

import (
    "context"
    "fmt"
    "log"

    anyllmplatform "github.com/mozilla-ai/any-llm-platform-client-go"
)

func main() {
    ctx := context.Background()

    // Create client
    client := anyllmplatform.NewClient()

    // Get decrypted provider key with metadata in one call
    anyLLMKey := "ANY.v1.12345678.abcdef01-YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoxMjM0NTY3OA=="
    result, err := client.GetDecryptedProviderKey(ctx, anyLLMKey, "openai")
    if err != nil {
        log.Fatal(err)
    }

    // Access the decrypted API key and metadata
    fmt.Printf("API Key: %s\n", result.APIKey)
    fmt.Printf("Provider Key ID: %s\n", result.ProviderKeyID)
    fmt.Printf("Project ID: %s\n", result.ProjectID)
    fmt.Printf("Provider: %s\n", result.Provider)
    fmt.Printf("Created At: %s\n", result.CreatedAt)
}
Advanced Usage (Manual Steps)

For more control over the authentication flow:

package main

import (
    "context"
    "fmt"
    "log"

    anyllmplatform "github.com/mozilla-ai/any-llm-platform-client-go"
)

func main() {
    ctx := context.Background()

    // Parse the key
    anyLLMKey := "ANY.v1...."
    keyComponents, err := anyllmplatform.ParseAnyLLMKey(anyLLMKey)
    if err != nil {
        log.Fatal(err)
    }

    // Load private key
    privateKey, err := anyllmplatform.LoadPrivateKey(keyComponents.Base64EncodedPrivateKey)
    if err != nil {
        log.Fatal(err)
    }

    // Extract public key
    publicKey, err := anyllmplatform.ExtractPublicKey(privateKey)
    if err != nil {
        log.Fatal(err)
    }

    // Authenticate with challenge-response using the client
    client := anyllmplatform.NewClient()
    challengeData, err := client.CreateChallenge(ctx, publicKey)
    if err != nil {
        log.Fatal(err)
    }

    solvedChallenge, err := client.SolveChallenge(challengeData.EncryptedChallenge, privateKey)
    if err != nil {
        log.Fatal(err)
    }

    // Request access token
    accessToken, err := client.RequestAccessToken(ctx, solvedChallenge)
    if err != nil {
        log.Fatal(err)
    }

    // Fetch and decrypt provider key
    providerKeyData, err := client.FetchProviderKey(ctx, "openai", accessToken)
    if err != nil {
        log.Fatal(err)
    }

    apiKey, err := client.DecryptProviderKeyValue(providerKeyData.EncryptedKey, privateKey)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("API Key: %s\n", apiKey)
}
Error Handling

All errors can be checked using Go's errors.Is and errors.As:

import "errors"

result, err := client.GetDecryptedProviderKey(ctx, anyLLMKey, "openai")
if err != nil {
    switch {
    case errors.Is(err, anyllmplatform.ErrChallengeCreation):
        // Handle challenge creation errors
    case errors.Is(err, anyllmplatform.ErrProviderKeyFetch):
        // Handle provider key fetch errors
    case errors.Is(err, anyllmplatform.ErrInvalidKey):
        // Handle invalid key format errors
    case errors.Is(err, anyllmplatform.ErrDecryption):
        // Handle decryption errors
    default:
        // Handle other errors
    }
}

// Get more details with type assertions
var challengeErr *anyllmplatform.ChallengeCreationError
if errors.As(err, &challengeErr) {
    fmt.Printf("Challenge failed with status %d: %s\n", challengeErr.StatusCode, challengeErr.Message)
}

How It Works

  1. The library extracts the X25519 private key from your ANY_LLM_KEY
  2. Derives the public key and sends it to create an authentication challenge
  3. The backend returns an encrypted challenge
  4. Decrypts the challenge UUID using your private key
  5. Uses the solved challenge to authenticate and fetch the encrypted provider key
  6. Decrypts the provider API key using your private key

Requirements

  • Go 1.23+
  • golang.org/x/crypto (for X25519 and XChaCha20-Poly1305)

ANY_LLM_KEY Format

ANY.v1.<kid>.<fingerprint>-<base64_32byte_private_key>

Generate your ANY_LLM_KEY from the project page in the web UI.

Security Notes

  • The private key from your ANY_LLM_KEY is highly sensitive and should never be logged or transmitted over insecure channels
  • This package uses X25519 sealed box encryption with XChaCha20-Poly1305 for strong cryptographic guarantees

Development

Run tests:

go test -v ./...

Run tests with race detection:

go test -v -race ./...

Run linting:

golangci-lint run ./...

Build:

go build ./...

Comparison with Python Version

This is the official Go port of any-llm-platform-client. Key differences:

Feature Python Go
Async support async/await Goroutines + context
Error handling Exceptions error return values
Type hints Type annotations Static types
HTTP client httpx net/http
Crypto library PyNaCl golang.org/x/crypto

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

Documentation

Overview

Package anyllmplatform provides a client for the ANY LLM platform API.

Security Notes

This package implements X25519 sealed box encryption for secure key exchange. The cryptographic primitives used are:

  • X25519 (Curve25519) for Elliptic Curve Diffie-Hellman key agreement
  • XChaCha20-Poly1305 for authenticated encryption (AEAD)
  • SHA-512 for deterministic nonce derivation

The sealed box format follows the NaCl/libsodium convention and provides:

  • Forward secrecy through ephemeral keypairs
  • Authenticated encryption preventing tampering
  • Deterministic nonces preventing nonce reuse attacks

Private keys should be handled with care and never logged or exposed.

Index

Constants

View Source
const (
	// DefaultPlatformURL is the default URL for the ANY LLM platform API.
	DefaultPlatformURL = "http://localhost:8000/api/v1"
	// TokenValidityDuration is the validity duration for access tokens (23 hours for safety margin).
	TokenValidityDuration = 23 * time.Hour
)
View Source
const (
	// X25519KeySize is the size of an X25519 key in bytes (256 bits).
	// This provides approximately 128 bits of security.
	X25519KeySize = 32

	// XChaCha20NonceSize is the size of an XChaCha20 nonce in bytes (192 bits).
	// The extended nonce size eliminates practical nonce collision concerns.
	XChaCha20NonceSize = 24
)

Variables

View Source
var (
	// ErrChallengeCreation indicates authentication challenge creation failed.
	ErrChallengeCreation = errors.New("challenge creation failed")

	// ErrProviderKeyFetch indicates fetching a provider API key failed.
	ErrProviderKeyFetch = errors.New("provider key fetch failed")

	// ErrInvalidKey indicates the ANY_LLM_KEY format is invalid.
	ErrInvalidKey = errors.New("invalid ANY_LLM_KEY format")

	// ErrDecryption indicates a decryption operation failed.
	ErrDecryption = errors.New("decryption failed")

	// ErrAuthentication indicates an authentication failure.
	ErrAuthentication = errors.New("authentication failed")
)

Sentinel errors for common error conditions.

Functions

func DecryptData

func DecryptData(encryptedDataBase64 string, privateKey []byte) (string, error)

DecryptData decrypts data using X25519 sealed box format.

The sealed box format is:

  • First 32 bytes: ephemeral public key
  • Remaining bytes: XChaCha20-Poly1305 ciphertext with 16-byte auth tag

The shared secret is computed using X25519 ECDH, and the nonce is derived deterministically from SHA512(ephemeral_public_key || recipient_public_key)[:24].

Security properties:

  • Forward secrecy: Compromising the recipient's private key does not compromise past messages encrypted with ephemeral keypairs.
  • Authenticated encryption: The Poly1305 MAC ensures message integrity and prevents tampering.
  • Nonce uniqueness: Deterministic derivation from public keys guarantees unique nonces for each sender-recipient pair.

func ExtractPublicKey

func ExtractPublicKey(privateKey []byte) (string, error)

ExtractPublicKey derives the public key from an X25519 private key.

Returns the base64-encoded public key.

func LoadPrivateKey

func LoadPrivateKey(base64PrivateKey string) ([]byte, error)

LoadPrivateKey loads an X25519 private key from a base64-encoded string.

Returns the 32-byte private key or an error if decoding fails or the key is invalid.

Types

type ChallengeCreationError

type ChallengeCreationError struct {
	StatusCode int
	Message    string
}

ChallengeCreationError represents an error during authentication challenge creation.

func (*ChallengeCreationError) Error

func (e *ChallengeCreationError) Error() string

func (*ChallengeCreationError) Is

func (e *ChallengeCreationError) Is(target error) bool

Is implements errors.Is for ChallengeCreationError.

func (*ChallengeCreationError) Unwrap

func (e *ChallengeCreationError) Unwrap() error

type Client

type Client struct {
	// PlatformURL is the base URL for the ANY LLM platform API.
	PlatformURL string
	// HTTPClient is the HTTP client to use for requests.
	HTTPClient *http.Client
	// contains filtered or unexported fields
}

Client is the HTTP client for communicating with the ANY LLM backend.

func NewClient

func NewClient(opts ...Option) *Client

NewClient creates a new Client with the given options.

func (*Client) CreateChallenge

func (c *Client) CreateChallenge(ctx context.Context, publicKey string) (*challengeResponse, error)

CreateChallenge creates an authentication challenge using the provided public key.

func (*Client) DecryptProviderKeyValue

func (c *Client) DecryptProviderKeyValue(encryptedKey string, privateKey []byte) (string, error)

DecryptProviderKeyValue decrypts the provider API key.

func (*Client) FetchProviderKey

func (c *Client) FetchProviderKey(ctx context.Context, provider, accessToken string) (*providerKeyResponse, error)

FetchProviderKey fetches the encrypted provider API key from the server.

func (*Client) GetAccessToken

func (c *Client) GetAccessToken(ctx context.Context, anyLLMKey string) (string, error)

GetAccessToken returns a valid access token, refreshing if necessary. This is useful for making authenticated requests to the platform API.

func (*Client) GetDecryptedProviderKey

func (c *Client) GetDecryptedProviderKey(ctx context.Context, anyLLMKey, provider string) (*DecryptedProviderKey, error)

GetDecryptedProviderKey gets a decrypted provider API key using the complete authentication flow.

func (*Client) GetPublicKey

func (c *Client) GetPublicKey(anyLLMKey string) (string, error)

GetPublicKey extracts the public key from an ANY_LLM_KEY.

func (*Client) GetSolvedChallenge

func (c *Client) GetSolvedChallenge(ctx context.Context, anyLLMKey string) (uuid.UUID, error)

GetSolvedChallenge gets a solved authentication challenge from an ANY_LLM_KEY.

func (*Client) RefreshAccessToken

func (c *Client) RefreshAccessToken(ctx context.Context, anyLLMKey string) (string, error)

RefreshAccessToken refreshes the access token using the ANY_LLM_KEY.

func (*Client) RequestAccessToken

func (c *Client) RequestAccessToken(ctx context.Context, solvedChallenge uuid.UUID) (string, error)

RequestAccessToken requests an access token by submitting the solved challenge.

func (*Client) SolveChallenge

func (c *Client) SolveChallenge(encryptedChallenge string, privateKey []byte) (uuid.UUID, error)

SolveChallenge decrypts and solves the authentication challenge.

type DecryptedProviderKey

type DecryptedProviderKey struct {
	// APIKey is the decrypted API key for the provider.
	APIKey string
	// ProviderKeyID is the unique identifier for the provider key.
	ProviderKeyID uuid.UUID
	// ProjectID is the unique identifier for the project.
	ProjectID uuid.UUID
	// Provider is the provider name (e.g., "openai", "anthropic").
	Provider string
	// CreatedAt is when the provider key was created.
	CreatedAt time.Time
	// UpdatedAt is when the provider key was last updated (may be zero).
	UpdatedAt time.Time
}

DecryptedProviderKey contains the decrypted provider key and metadata.

type DecryptionError

type DecryptionError struct {
	Message string
}

DecryptionError represents a decryption failure.

func (*DecryptionError) Error

func (e *DecryptionError) Error() string

func (*DecryptionError) Is

func (e *DecryptionError) Is(target error) bool

Is implements errors.Is for DecryptionError.

func (*DecryptionError) Unwrap

func (e *DecryptionError) Unwrap() error

type InvalidKeyError

type InvalidKeyError struct {
	Message string
}

InvalidKeyError represents an error when parsing an ANY_LLM_KEY.

func (*InvalidKeyError) Error

func (e *InvalidKeyError) Error() string

func (*InvalidKeyError) Is

func (e *InvalidKeyError) Is(target error) bool

Is implements errors.Is for InvalidKeyError.

func (*InvalidKeyError) Unwrap

func (e *InvalidKeyError) Unwrap() error

type KeyComponents

type KeyComponents struct {
	// KeyID is the unique key identifier.
	KeyID string
	// PublicKeyFingerprint is the fingerprint of the public key.
	PublicKeyFingerprint string
	// Base64EncodedPrivateKey is the base64-encoded X25519 private key.
	Base64EncodedPrivateKey string
}

KeyComponents represents the parsed components of an ANY_LLM_KEY.

func ParseAnyLLMKey

func ParseAnyLLMKey(anyLLMKey string) (*KeyComponents, error)

ParseAnyLLMKey parses an ANY_LLM_KEY string into its components.

The expected format is: ANY.v1.<key_id>.<fingerprint>-<base64_key>

Returns an error if the key format is invalid.

type Option

type Option func(*Client)

Option is a functional option for configuring the Client.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient sets a custom HTTP client.

func WithPlatformURL

func WithPlatformURL(url string) Option

WithPlatformURL sets a custom platform URL.

type ProviderKeyFetchError

type ProviderKeyFetchError struct {
	StatusCode int
	Provider   string
	Message    string
}

ProviderKeyFetchError represents an error when fetching a provider API key.

func (*ProviderKeyFetchError) Error

func (e *ProviderKeyFetchError) Error() string

func (*ProviderKeyFetchError) Is

func (e *ProviderKeyFetchError) Is(target error) bool

Is implements errors.Is for ProviderKeyFetchError.

func (*ProviderKeyFetchError) Unwrap

func (e *ProviderKeyFetchError) Unwrap() error

Directories

Path Synopsis
cmd
any-llm command
examples
basic command
Package main demonstrates basic usage of the any-llm-platform-client-go library.
Package main demonstrates basic usage of the any-llm-platform-client-go library.
internal
testutil
Package testutil provides test utilities and fixtures for the any-llm-platform-client-go package.
Package testutil provides test utilities and fixtures for the any-llm-platform-client-go package.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL