Skip to content

AnkaSecure Crypto CLI Architecture

CLI Version: 3.4.0 Language: Java 25 Total Commands: 35 Build Tool: Maven 3.9+

This document provides an architecture overview of the AnkaSecure Crypto CLI, including how it parses command-line arguments, authenticates with the server, logs information, and delegates cryptographic logic to the remote AnkaSecure Core API through the AnkaSecureSdk and the AnkaSecureOpenApiClient.


Table of Contents

  1. Introduction
  2. High-Level Workflow
  3. Key Components
    1. AnkaSecureCLI
    2. AnkaSecureSdk
    3. AnkaSecureOpenApiClient
    4. OpenAPI-Generated Classes
  4. Authentication Flow
  5. Configuration
  6. Error Handling
  7. Streaming vs Non-Streaming Operations
  8. Security Features
  9. Build & Distribution
  10. CLI Execution Lifecycle
  11. Related Documentation

1. Introduction

The AnkaSecure Crypto CLI is a command-line application that provides 26 subcommands for end-user cryptographic operations on data — encryption, decryption, signing, verification, combined operations, streaming, PKCS#7 conversion — plus read-only key browsing. Administrative key write/lifecycle operations are not part of this CLI; they live in the Key Management CLI (ankasecure-km) and the Admin Console. Despite offering a wide set of functionality, the CLI itself does not implement cryptographic logic directly. Instead, it:

CLI Responsibilities:

  • Parses user commands and arguments (e.g., list-keys, encrypt-file-stream, etc.)
  • Authenticates against the AnkaSecure Core API with clientId and clientSecret
  • Delegates all actual cryptographic operations to the AnkaSecure Core API via a Java SDK (AnkaSecureSdk)
  • Manages configuration, logging, and error handling
  • Provides both command-line and interactive modes

Architectural Benefits:

By separating the CLI from the core cryptographic implementation, the solution achieves:

  • Crypto-agility: Algorithm changes don't require CLI updates
  • Centralized security: HSM-protected keys on server side
  • Easy maintenance: CLI, SDK, and API evolve independently
  • Client flexibility: Same API supports CLI, SDK, and custom clients

Users invoke commands locally, while the AnkaSecure Core API performs the secure operations server-side with HSM protection.


2. High-Level Workflow

Below is a simplified depiction of how the CLI processes a command:

Example command:

AnkaSecureCLI encrypt-file --kid my-ml-kem-key --input-file plaintext.txt --output-file ciphertext.bin

Processing flow:

Step 1: Command Parsing

The CLI main class (AnkaSecureCLI) parses the command-line arguments:

  • Identifies command: encrypt-file
  • Extracts parameters: --kid my-ml-kem-key, --input-file plaintext.txt, --output-file ciphertext.bin
  • Validates required parameters are present

Step 2: Configuration Loading

Loads cli.properties or ~/.ankasecure-crypto/config.properties:

  • Server connection: openapi.scheme, openapi.host, openapi.port
  • Encrypted credentials: clientIdEnc, clientSecretEnc
  • Timeouts, proxy settings, PQC transport options

Step 3: SDK Initialization

Constructs the AnkaSecureSdk instance with loaded configuration

Step 4: Authentication

Authenticates with the server:

  • Decrypts credentials using PBKDF2 + AES-GCM
  • Calls the token endpoint: POST /api/v3/auth/token (grant_type=client_credentials)
  • Receives JWT Bearer token
  • Token cached for subsequent requests

If authentication fails, prints error and exits with code 1.

Step 5: Command Dispatch

Routes the command to its handler method:

  • Command encrypt-file → calls SDK method encryptFile(kid, input, output)
  • Command encrypt-file-stream → calls SDK method encryptFileStream(kid, input, output)

Step 6: SDK Delegation

The SDK method calls the corresponding OpenAPI client method:

  • AuthenticatedSdk.encrypt() → AnkaSecureOpenApiClient data-plane call
  • Prepares request body and headers (including Bearer token)

Step 7: REST API Call

The OpenAPI client sends HTTP request to AnkaSecure Core API:

  • Example: POST /api/v3/crypto/encrypt
  • Headers: Authorization: Bearer <jwt>, Content-Type: application/json
  • Body: the operation request (for encrypt: kid and the Base64 data)

Step 8: Response Handling

Success path:

  • Server returns 200/201 with operation result
  • CLI prints localized success message
  • Displays operation metadata (key ID, algorithm, status)
  • Exits with code 0

Error path:

  • Server returns 4xx/5xx error
  • SDK throws AnkaSecureSdkException
  • CLI catches exception, logs to devLogger
  • Prints user-friendly error message (localized)
  • Exits with appropriate error code (1-3)

Step 9: Exit

CLI terminates with exit code indicating success or failure type.


3. Key Components

3.1 AnkaSecureCLI (Main Entry Point)

Location: co.ankatech.ankasecure.core.cli.AnkaSecureCLI

Entry Point: main(String[] args)

Responsibilities:

Configuration Management:

  • Reads configuration from cli.properties or ~/.ankasecure-crypto/config.properties
  • Loads server connection details: scheme, host, port, timeouts
  • Decrypts stored credentials using PBKDF2 + AES-GCM

Command Routing:

  • Parses command-line arguments to identify command and parameters
  • Routes to appropriate command handler (35 commands total)
  • Validates required parameters before execution

Authentication:

  • Authenticates with server using decrypted clientId and clientSecret
  • Manages JWT Bearer token lifecycle
  • Handles token refresh when expired

Error Handling:

  • Catches SDK exceptions and maps to user-friendly messages
  • Logs detailed errors to devLogger for troubleshooting
  • Manages exit codes:
  • 0: Success
  • 1: Invalid arguments
  • 2: Not found (key doesn't exist)
  • 3: Execution error (HTTP errors, I/O exceptions)

Mode Support:

  • Command-line mode: Direct command execution
  • Interactive mode: Menu-driven interface (launch with -i or --interactive)

Key Principle: No cryptographic logic resides here; all operations delegated to AnkaSecureSdk.

3.2 AnkaSecureSdk (Client Bridge)

Location: co.ankatech.ankasecure.sdk.AnkaSecureSdk

Purpose: Main client-facing bridge to the remote AnkaSecure Core API

High-Level Operations:

  • Key Management: Generate, import, export, list, remove, revoke, patch, rotate keys
  • Encryption/Decryption: File encryption with symmetric or asymmetric keys (non-streaming and streaming)
  • Digital Signatures: Sign and verify files with classical or post-quantum algorithms
  • Key Rotation: Re-encrypt and re-sign operations for algorithm transitions
  • Migration: Import PKCS#12 bundles, analyze and convert PKCS#7/CMS files
  • Interoperability: Encrypt/verify with external public keys (not stored in keystore)
  • License Management: Retrieve usage and entitlement information

Implementation Pattern:

The SDK provides high-level methods that abstract the REST API complexity:

  • Method encrypt(kid, plaintext) → calls OpenAPI client → POST /api/v3/crypto/encrypt. Key provisioning is NOT on this path: the SDK is data-plane only, and creating a key is an Admin API operation reached through ankasecure-km or the Admin Console.
  • Method encryptFileStream(kid, input, output) → calls OpenAPI client → POST /api/v3/crypto/stream/encrypt

Exception Handling:

Catches low-level exceptions (ApiException, IOException) and rethrows as unified AnkaSecureSdkException with clean error messages and correlation IDs.


3.3 AnkaSecureOpenApiClient (HTTP Client)

Location: co.ankatech.ankasecure.openapi.client.AnkaSecureOpenApiClient

Purpose: HTTP client layer that orchestrates REST API calls

Responsibilities:

HTTP Configuration:

  • Configures OkHttp client with timeouts, proxy, SSL trust settings
  • Applies properties from configuration file
  • Manages connection pooling and keep-alive

Authentication:

  • Adds Authorization: Bearer <jwt> header to all requests
  • Manages token lifecycle and expiration
  • Supports token refresh when expired

Request/Response Handling:

  • Prepares request bodies (JSON serialization)
  • Adds required headers (Content-Type, Accept, X-Correlation-ID)
  • Handles multipart form-data for streaming operations
  • Parses response bodies (JSON deserialization)

Streaming Support:

  • Sets up streaming endpoints for large files
  • Uses multipart form-data: metadata (JSON) + file stream (binary)
  • Optional progress bar display for uploads (openapi.enableProgressBar=true)
  • Memory-efficient: reads files in chunks (64 KB default)

PQC Transport Layer:

  • Optional quantum-resistant transport encryption
  • Encrypts request/response payloads with ML-KEM + AES-GCM
  • Manages PQC sessions with Redis-backed state
  • See PQC Transport Layer for details

3.4 OpenAPI-Generated Classes

Location: co.ankatech.secure.client.* (generated code)

Packages:

  • co.ankatech.secure.client.api - API interfaces (KeyManagementApi, SecureApi, StreamingApi, etc.)
  • co.ankatech.secure.client.model - Model classes (EncryptRequest, EncryptResponse, KeyMetadata, etc.)
  • co.ankatech.secure.client.invoker - ApiClient, configuration, exceptions

Generation Process:

Uses Maven plugin openapi-generator-maven-plugin with AnkaSecureAPI.json specification:

<plugin>
    <groupId>org.openapitools</groupId>
    <artifactId>openapi-generator-maven-plugin</artifactId>
    <configuration>
        <inputSpec>${project.basedir}/AnkaSecureAPI.json</inputSpec>
        <generatorName>java</generatorName>
        <library>okhttp-gson</library>
    </configuration>
</plugin>

Responsibilities:

  • Type-safe API: Java interfaces for all REST endpoints
  • Model classes: Request/response DTOs with validation
  • Serialization: JSON ↔ Java object mapping (Gson)
  • Exception handling: Typed ApiException with HTTP status codes

Note: These classes are auto-generated and should not be manually edited. See Maven OpenAPI Generator for regeneration instructions.


4. Authentication Flow

The CLI authenticates once at startup and reuses the JWT token for all subsequent operations.

Authentication Process:

Step 1: Load Credentials

The CLI reads encrypted credentials from configuration:

  • client.uuid - Installation-specific identifier
  • client.salt - Random salt for key derivation
  • clientIdEnc - Encrypted client ID (Base64)
  • clientSecretEnc - Encrypted client secret (Base64)

Step 2: Decrypt Credentials

Derives decryption key using PBKDF2-HMAC-SHA256 (150,000 iterations):

  • Input: client.uuid (password) + client.salt
  • Output: 256-bit AES key

Decrypts credentials using AES-GCM:

  • Ciphertext format: <IV:12 bytes><Ciphertext><AuthTag:16 bytes>
  • Result: Plaintext clientId and clientSecret

Step 3: Call Authentication Endpoint

SDK calls authentication API:

  • Endpoint: POST /api/v3/auth/token
  • Body (application/x-www-form-urlencoded): grant_type=client_credentials, client_id, client_secret
  • Response: { access_token, token_type, expires_in } (no refresh_token is issued for client_credentials)

Step 4: Store Token

JWT Bearer token cached in SDK for subsequent requests:

  • Added to all API calls: Authorization: Bearer <jwt>
  • Token lifetime: ~1 hour (configurable)
  • Refresh token: ~7 days (for long-running processes)

Step 5: Execute Operations

All subsequent cryptographic operations reuse the authenticated SDK instance. No re-authentication required unless token expires.

Security Note: Credentials never sent in plaintext over network. Encryption at rest (config file) and in transit (TLS + optional PQC transport).

Credential Storage

The CLI uses AES-256-GCM encryption for secure credential storage:

flowchart LR
    subgraph Init["init Command"]
        UUID["Generate UUID"]
        Salt["Generate Salt"]
        PBKDF2["PBKDF2-HMAC-SHA256<br/>150,000 iterations"]
        AES["AES-256-GCM"]
    end

    subgraph Storage["cli.properties"]
        Props["client.uuid<br/>client.salt<br/>clientIdEnc<br/>clientSecretEnc"]
    end

    UUID --> PBKDF2
    Salt --> PBKDF2
    PBKDF2 -->|256-bit key| AES
    AES --> Props

Runtime Authentication

sequenceDiagram
    participant CLI
    participant SDK as AnkaSecureSdk
    participant Auth as Auth API

    CLI->>CLI: Load cli.properties
    CLI->>CLI: Derive AES key (PBKDF2)
    CLI->>CLI: Decrypt credentials
    CLI->>SDK: authenticateApplication(clientId, secret)
    SDK->>Auth: POST /api/v3/auth/token
    Auth-->>SDK: {accessToken, refreshToken}
    SDK->>SDK: Store tokens in memory
    Note over SDK: Subsequent calls use Bearer token

5. Configuration

Server Connection

# API Server
openapi.scheme=https
openapi.host=dev.ankatech.co
openapi.port=443
openapi.insecureSkipTlsVerify=false      # Set true for self-signed certs

# Timeouts
openapi.connectTimeoutMs=10000
openapi.readTimeoutMs=30000
openapi.writeTimeoutMs=30000

Proxy Support

# Optional proxy configuration
openapi.proxyHost=proxy.company.com
openapi.proxyPort=8080
openapi.proxyUser=username
openapi.proxyPassword=password

Logging Configuration

# Logging configuration
user.log.level=INFO
user.log.filename=AnkaSecureCLI.log
user.log.maxFileSize=5MB
openapi.debugging=false                   # Enable HTTP debug logs

Dual-Logger System

The CLI uses two separate loggers for different audiences:

User Logger (co.ankatech.cli.user):

  • Purpose: User-facing messages
  • Level: INFO, WARN, ERROR
  • Output: Console + rolling file (user.log)
  • Examples:
  • "✓ Key generated successfully"
  • "⚠ Warning: Key will expire in 30 days"
  • "✗ Error: Key not found"

Dev Logger (co.ankatech.cli.dev):

  • Purpose: Technical troubleshooting and debugging
  • Level: DEBUG, TRACE
  • Output: Rolling file only (dev.log)
  • Examples:
  • "SDK initialized with config: {...}"
  • "HTTP POST /api/v3/crypto/encrypt → 200 OK"
  • "Stack trace: AnkaSecureSdkException at line 145..."

Configuration: Managed via logback.xml in the CLI JAR.


Internationalization (i18n)

Resource Bundles:

The CLI uses Java ResourceBundle for all user-visible text:

  • messages.properties (English) - Default
  • messages_es.properties (Spanish)

Message Loading:

All user-facing text loaded from bundles:

  • Success messages: MSG.getString("encryptFileSuccess")
  • Error messages: MSG.getString("keyNotFound")
  • HTTP status: MSG.getString("http.401.unauthorized")

Locale Detection:

  • Automatically detects system locale (Locale.getDefault())
  • Falls back to English if bundle not available
  • Manual override: -Duser.language=es

Supported Languages:

  • English (en) - Default
  • Spanish (es) - Complete translation

See Internationalization Guide for complete details.


6. Error Handling

Exit Codes

Code Meaning
0 Success
1 Invalid arguments
2 Command not found
3 Execution error

HTTP Status Mapping

HTTP Status CLI Behavior
400 Bad Request error with context
401 Authentication failed
403 Insufficient permissions
404 Resource not found
409 Conflict (key exists)
422 Validation error
5xx Server error

Internationalization

All user-facing messages support i18n:

  • messages.properties (English - default)
  • messages_es.properties (Spanish)

7. Streaming vs Non-Streaming Operations

The CLI provides two modes for file operations to handle different file sizes efficiently.

Non-Streaming Mode

Commands: encrypt-file, decrypt-file, sign-file, verify-signature, reencrypt-file, resign-file

Characteristics:

  • File size limit: < 100 MB recommended
  • Memory usage: Loads entire file into memory
  • Encoding: Base64-encoded JSON payloads
  • HTTP method: Single POST request
  • Speed: Faster for small files (less overhead)

Process:

  1. Read entire file into byte array
  2. Base64-encode file content
  3. Send as JSON body, for example encrypt: { "kid": "...", "data": "BASE64..." }
  4. Receive JSON response, for example encrypt: { "jweToken": { ...JWE General JSON... }, "keyRequested": "...", ... }
  5. Write the result to the output file (decrypt returns decryptedData, which is Base64-decoded first)

Streaming Mode

Commands: encrypt-file-stream, decrypt-file-stream, sign-file-stream, verify-signature-stream, reencrypt-file-stream, resign-file-stream

Characteristics:

  • File size limit: none in the API (tested up to 500 GB); a proxy in front of the deployment may cap uploads; see Behind a buffering proxy
  • Memory usage: O(1) constant ~500 MB regardless of file size
  • Encoding: Binary chunks with JSON metadata
  • HTTP method: Multipart POST (header + file stream)
  • Progress: Optional progress bar display

Process:

  1. Prepare JSON header with operation metadata
  2. Open file input stream
  3. Create multipart request:
    • Part 1: header (application/json) - Operation metadata
    • Part 2: file (application/octet-stream) - File stream
  4. Upload in chunks (default 64 KB)
  5. Server processes stream and returns detached result
  6. Write output stream to file

Performance:

  • Small files (< 10 MB): Non-streaming faster (less overhead)
  • Large files (> 100 MB): Streaming required (memory efficient)
  • Huge files (> 1 GB): Streaming only option

8. Security Features

Credential Protection

Feature Implementation
Encryption AES-256-GCM with 128-bit auth tag
Key Derivation PBKDF2-HMAC-SHA256, 150,000 iterations
Salt 128-bit random per credential
IV 96-bit random per encryption

Code Protection

Feature Implementation
JAR Signing Timestamped code signature, on BOTH the thin jar and the runnable fat jar
Obfuscation ProGuard runs on the thin jar only. The fat jar that ships is shaded before ProGuard runs, so the CLI classes inside it are NOT obfuscated
SDK Readable in full. The data-plane SDK is not obfuscated: every class keeps its source name, so a CLI stack trace names real types

Best Practices

  1. Protect cli.properties with OS file permissions (chmod 600)
  2. Use separate credentials per environment
  3. Enable TLS verification in production (insecureSkipTlsVerify=false)
  4. Rotate application credentials regularly

9. Build & Distribution

Build Pipeline

flowchart LR
    Compile["Java 25<br/>Compile"] --> JAR["Thin JAR"]
    JAR --> Shade["Maven Shade<br/>Fat JAR (runnable)"]
    JAR --> Obfuscate["ProGuard<br/>thin JAR only"]
    Shade --> SignFat["JAR Signing<br/>fat"]
    Obfuscate --> SignThin["JAR Signing<br/>thin"]
    SignFat --> Package["Install4J<br/>Installers"]

Artifacts

Artifact Description
AnkaSecureCLI-3.0.0.jar Regular JAR
AnkaSecureCLI-3.0.0-fat.jar Fat JAR with every dependency but Bouncy Castle
lib/bcprov-jdk18on.jar, lib/bcutil-jdk18on.jar, lib/bcpkix-jdk18on.jar Bouncy Castle, unmodified and signed, loaded by the fat JAR's Class-Path
Windows Installer .exe with bundled JRE 25
macOS Installer .dmg with bundled JRE 25
Linux Installer .sh with bundled JRE 25

Dependencies

Dependency Version Purpose
AnkaSecure SDK 3.0.0 Core SDK library
Picocli 4.7.7 CLI framework
OkHttp (transitive) HTTP client
Bouncy Castle (transitive) PQC cryptography
Jackson 2 (com.fasterxml.jackson) (transitive) JSON processing. The CLI resolves Jackson 2 only — the platform runs two Jackson majors side by side, and the Jackson 3 (tools.jackson) half is confined to three server-side mappers the CLI never links. See The Jackson Major Split*
Logback 1.5.25 Logging

10. CLI Execution Lifecycle

Detailed execution flow from launch to exit:

Phase 1: Startup (0-100ms)

  1. JVM launches with main(String[] args)
  2. Parse global flags (--help, --version, --interactive)
  3. Initialize logging framework (Logback)
  4. Load configuration from file or prompt if missing

Phase 2: Configuration (100-200ms)

  1. Read cli.properties or ~/.ankasecure-crypto/config.properties
  2. Decrypt credentials using PBKDF2 + AES-GCM (150,000 iterations)
  3. Validate required properties present
  4. Initialize SDK with configuration

Phase 3: Authentication (200-500ms)

  1. Call the token endpoint: POST /api/v3/auth/token (grant_type=client_credentials)
  2. Receive JWT Bearer token
  3. Cache token in SDK for reuse
  4. Set up HTTP headers for subsequent requests

Phase 4: Command Execution (variable)

  1. Parse command-specific arguments
  2. Validate required parameters
  3. Call SDK method (e.g., encrypt(), encryptFileStream())
  4. SDK calls OpenAPI client
  5. OpenAPI client sends HTTP request
  6. Server processes and returns response

Phase 5: Response Processing (50-100ms)

  1. Parse JSON response or stream output
  2. Validate response structure
  3. Extract operation metadata
  4. Print localized success message
  5. Log details to dev logger

Phase 6: Cleanup and Exit (0-50ms)

  1. Close open file streams
  2. Flush log buffers
  3. Exit with appropriate code (0-3)

Total execution time:

  • Simple operations (list-keys): ~500ms
  • Key generation: ~1-2 seconds
  • Small file encryption: ~1-3 seconds
  • Large file streaming (100 GB): Minutes to hours (depends on file size and network)

CLI Documentation

User Guides:

Technical Documentation:


SDK Documentation

The CLI is built on the AnkaSecure SDK:


Core API Documentation

The CLI calls the AnkaSecure Core API:

  • Core API Overview* - REST API architecture
  • Core API Endpoints* - HTTP endpoint reference
  • Streaming Operations* - Large-file handling

Security & Algorithms


Last Updated: December 2025
CLI Version: 3.0.0 Java Version: 25


© 2025 ANKATech Solutions Inc. All rights reserved.

* restricted content — see higher-tier documentation