jmix-rs 0.3.1

Rust library for JMIX (JSON Medical Interchange) format - secure medical data exchange with cryptographic features
Documentation
# JMIX-RS

A Rust implementation of the JMIX (JSON Medical Interchange) format for secure medical data exchange.

## Features

- DICOM file processing and metadata extraction
- JSON Schema validation
- AES-256-GCM encryption with Curve25519 ECDH key exchange
- JWS digital signatures (Ed25519)
- Cryptographic assertions for sender/requester/receiver identity verification
- High-level builder API for envelope creation

## Installation

```toml
[dependencies]
jmix-rs = "0.2.0"
```

## Usage

### Basic JMIX Envelope

```rust
use jmix_rs::{builder::JmixBuilder, config::Config};

let builder = JmixBuilder::new();
let config = Config::from_file("config.json")?;
let (envelope, files) = builder.build_from_dicom("path/to/dicom", &config)?;
```

### With Security Features

```rust
// With encryption and signatures
let builder = JmixBuilder::with_complete_security()?;
let (envelope, files) = builder.build_from_dicom("path/to/dicom", &config)?;
let saved_files = builder.save_to_files(&envelope, &files, "output/")?;
```

### DICOM Processing

```rust
use jmix_rs::dicom::DicomProcessor;

let processor = DicomProcessor::new();
let metadata = processor.process_dicom_folder("path/to/dicom", None)?;
println!("Extracted {} instances", metadata.instance_count);
```

### Configuration Example

Create a configuration file:

```json
{
  "version": "1.0",
  "sender": {
    "name": "Healthcare Provider",
    "id": "org:provider.123",
    "contact": "admin@provider.com"
  },
  "patient": {
    "name": "John Doe",
    "id": "PAT12345",
    "dob": "1985-03-15"
  }
}
```

## Examples

```bash
# Basic envelope creation
cargo run --example build_jmix

# Digital signatures
cargo run --example jws_signing

# End-to-end encryption
cargo run --example envelope_encryption

# Identity verification
cargo run --example sender_assertions
```

## CLI (runbeam)

A small CLI is included to validate JMIX packages.

Build and run:

```bash
cargo run --bin runbeam -- validate ./tmp/<ENVELOPE_ID>.jmix
```

Flags:
- --validate-schema: enable JSON Schema validation (defaults to false)
- --schema-dir PATH: custom schema directory (default ../jmix/schemas)
- --verify-assertions: verify sender/requester/receiver assertions if present
- --key PATH: recipient secret key for decrypting encrypted packages (payload.enc)
- --json: output a machine-readable JSON report

Examples:

```bash
# Unencrypted package, no schema checks
cargo run --bin runbeam -- validate ./tmp/<id>.jmix

# Encrypted package: verify decryption + payload hash using secret key
cargo run --bin runbeam -- validate ./tmp/<id>.jmix --key ./tmp/keys_encrypted_test/recipient_secret.key

# With schema checks (requires schemas available)
cargo run --bin runbeam -- validate ./tmp/<id>.jmix --validate-schema --schema-dir ../jmix/schemas

# JSON output
cargo run --bin runbeam -- validate ./tmp/<id>.jmix --json
```

### Verifying assertions

To verify sender/requester/receiver assertions during validation, add `--verify-assertions`:

```bash
# Build your envelope with assertions (see examples/sender_assertions.rs for generation)
# Then validate with assertion checks enabled
cargo run --bin runbeam -- validate ./tmp/<id>.jmix --verify-assertions
```

### Decrypting an encrypted package

Extract the contents of `payload.enc` using the recipient's secret key:

```bash
cargo run --bin runbeam -- decrypt ./tmp/<id>.jmix \
  --key ./tmp/keys_encrypted_test/recipient_secret.key \
  --out ./tmp/decrypted
```

Tip: Temporary and example outputs are written under ./tmp/ by convention.

## Technical Details

### DICOM Processing

The library includes a DICOM processor that can:

- Detect DICOM files by magic number, file extension, and parsing validation
- Extract metadata: patient info, study details, series information
- Handle multiple files by merging metadata from multiple instances
- Fallback gracefully using config data when DICOM parsing fails

Example output:

```
Extracted DICOM metadata:
  Patient name: Some("Brown, Jane")
  Patient ID: Some("PID156695") 
  Study description: Some("CT Pulmonary Angiogram")
  Modalities: ["CT"]
  Series count: 1
  Instance count: 15
```

### Cryptographic Features

- **AES-256-GCM**: Authenticated encryption with 256-bit keys
- **Curve25519**: Elliptic curve Diffie-Hellman key exchange
- **Ed25519**: Elliptic curve digital signatures
- **SHA-256**: Cryptographic hashing for fingerprints and integrity
- **JWS**: JSON Web Signature standard (RFC 7515)

### Payload Hashing

JMIX-RS computes and validates a deterministic payload hash stored in `manifest.security.payload_hash` (format: `sha256:<hex>`):

- Unencrypted packages: The hash is computed over the contents of `payload/` as follows:
  - Recursively list files under `payload/`
  - Sort by path relative to `payload/` (Unicode codepoint order)
  - For each file: update the SHA-256 hasher with `relative/path` (UTF-8), then a single newline byte (`\n`), then the file's raw bytes
  - The final digest is emitted as `sha256:<hex>`

- Encrypted packages: The payload is first assembled as a `payload.tar` and then encrypted to `payload.enc` using AES-256-GCM with ECDH (Curve25519) and HKDF-SHA256. The payload hash is computed as the SHA-256 over the plaintext `payload.tar` bytes prior to encryption and saved in the manifest. This makes the hash independent of IVs/ephemeral keys and stable across encryptions.

During validation:
- Unencrypted: the validator recomputes the directory hash and compares it to the manifest value.
- Encrypted: when a recipient secret key is provided, the validator decrypts `payload.enc`, hashes the plaintext TAR, and compares.

### Schema Validation

The validation system supports:

- Configurable schema path (default: `../jmix/schemas`)
- Lazy loading of schemas on demand
- Comprehensive validation for manifest, metadata, audit, and files
- Detailed error reporting with schema path and validation failures

To enable schema validation:

1. Ensure schema files exist in `../jmix/schemas/` (or configure a custom directory)
2. Configure schema discovery (precedence):
   - CLI flag `--schema-dir <PATH>`
   - Environment variable `JMIX_SCHEMA_DIR=/absolute/or/relative/path`
   - Default `../jmix/schemas`
3. Run validation tests:
   ```bash
   JMIX_SCHEMA_DIR=../jmix/schemas \
   cargo test test_validate_sample_files_with_schemas -- --ignored
   ```

CLI examples:
```bash
# Use a specific schema directory
cargo run --bin runbeam -- validate ./tmp/<id>.jmix --validate-schema --schema-dir ../jmix/schemas

# Or via environment variable (no flag needed)
JMIX_SCHEMA_DIR=../jmix/schemas \
  cargo run --bin runbeam -- validate ./tmp/<id>.jmix --validate-schema
```

### Error Handling

```rust
use jmix_rs::error::{JmixError, ValidationError, DicomError, EncryptionError};

match result {
    Ok(envelope) => println!("Success: Secure envelope created"),
    Err(JmixError::Validation(e)) => eprintln!("Schema validation error: {}", e),
    Err(JmixError::Dicom(e)) => eprintln!("DICOM processing error: {}", e),
    Err(JmixError::Encryption(e)) => eprintln!("Encryption error: {}", e),
    Err(JmixError::Jws(e)) => eprintln!("Signing error: {}", e),
    Err(JmixError::Assertion(e)) => eprintln!("Assertion error: {}", e),
    Err(e) => eprintln!("Other error: {}", e),
}
```

## Testing

```bash
# Run all tests (50+ tests)
cargo test

# Run with output
cargo test -- --nocapture

# Test specific modules
cargo test encryption
cargo test jws
cargo test assertion
```

### Test Coverage

- **Unit tests (32)**: DICOM, encryption, JWS, assertions, builder, types
- **Integration tests (11)**: End-to-end security, DICOM processing, envelope structure
- **Sample validation tests (7)**: JSON sample consistency, config conversion

## Project Structure

```
src/
├── lib.rs                  # Library root
├── config.rs               # Configuration types
├── types.rs                # JMIX core types
├── builder.rs              # High-level builder API
├── validation.rs           # JSON Schema validation
├── dicom.rs                # DICOM file processing
├── encryption.rs           # AES-256-GCM encryption (ECDH+HKDF)
├── jws.rs                  # JWS digital signatures
├── assertion.rs            # Ed25519 identity assertions
├── package_validation.rs   # Package-level validation API (hash, schema, assertions, decrypt)
├── bin/
│   └── runbeam.rs          # CLI: runbeam validate
└── error.rs                # Error handling

examples/
├── build_jmix.rs       # Basic envelope creation
├── jws_signing.rs      # Digital signature example
├── envelope_encryption.rs    # End-to-end encryption
└── sender_assertions.rs      # Identity verification

samples/
├── study_1/            # Real DICOM files (15 files, 3 series)
├── sample_config.json  # Configuration example
├── sample_manifest.json
├── sample_metadata.json
├── sample_audit.json
└── sample_files.json
```

## Sample Data

The library includes real sample data for testing:

- **DICOM files**: CT study with 15 instances across 3 series
- **JSON samples**: Complete configuration and manifest examples
- **Test data**: Used in integration tests and examples

## Development

```bash
# Build and test
cargo build
cargo test

# Run examples
cargo build --examples

# Code quality
cargo clippy
cargo fmt

# Generate documentation
cargo doc --open
```

## License

This project matches the licensing of the original PHP implementation.