pymedsec 0.1.0
HIPAA/GDPR-ready medical image sanitization and encryption library with blockchain audit anchoring
License: Apache-2.0
Requires Python: >=3.8
Keywords: medical, imaging, security, hipaa, gdpr, encryption, dicom, blockchain

# PyMedSec - Medical Image Security Framework

<div align="center">

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![PyPI](https://img.shields.io/pypi/v/pymedsec.svg)](https://pypi.org/project/pymedsec/)
[![Tests](https://github.com/Faerque/pymedsec/workflows/Tests/badge.svg)](https://github.com/Faerque/pymedsec/actions)
[![Coverage](https://codecov.io/gh/Faerque/pymedsec/branch/main/graph/badge.svg)](https://codecov.io/gh/Faerque/pymedsec)
[![Documentation](https://img.shields.io/badge/docs-latest-brightgreen.svg)](https://pymedsec.readthedocs.io/)

**Enterprise-Grade Medical Image Security & Compliance Framework**

_Secure medical image processing with HIPAA/GDPR/GxP compliance, envelope encryption, PHI sanitization, and tamper-evident audit logging_

[🚀 Quick Start](#-quick-start) •
[📖 Documentation](#-documentation) •
[🏗️ Architecture](#-architecture) •
[🔧 Examples](#-examples) •
[🏥 Compliance](#-compliance)

</div>

---

## 🎯 Overview

PyMedSec is a production-ready Python framework designed for secure medical image processing in healthcare environments. It provides comprehensive tools for encryption, sanitization, and compliance management while maintaining the highest security standards for Protected Health Information (PHI).

### ✅ Production Ready Features

- **🔒 Enterprise Encryption**: AES-256-GCM envelope encryption with KMS integration
- **🧹 PHI Sanitization**: Intelligent DICOM/EXIF metadata removal and de-identification
- **📊 Audit Compliance**: Tamper-evident logging with HMAC signatures and blockchain anchoring
- **⚡ ML Integration**: Zero-copy memory decryption for secure machine learning workflows
- **🔌 Multi-Cloud KMS**: AWS KMS, HashiCorp Vault, and Azure Key Vault support
- **📋 Regulatory Compliance**: HIPAA, GDPR, CLIA, and GxP alignment with validation documentation

## �️ Architecture

PyMedSec follows a modular, security-first architecture designed for enterprise healthcare environments.

### System Architecture

```
┌─────────────────────────────────────────────────────────────────────────────────┐
│                              PyMedSec Framework                                 │
├─────────────────────┬─────────────────────┬─────────────────────┬──────────────┤
│    Public API       │   Core Security     │   Compliance        │   Audit      │
│                     │                     │                     │              │
│  ┌─────────────┐   │  ┌─────────────┐   │  ┌─────────────┐   │ ┌──────────┐ │
│  │ load_policy │   │  │ Envelope    │   │  │ PHI         │   │ │ Tamper   │ │
│  │ scrub_dicom │   │  │ Encryption  │   │  │ Sanitizer   │   │ │ Evident  │ │
│  │ encrypt_blob│   │  │ AES-256-GCM │   │  │ DICOM/EXIF  │   │ │ Logging  │ │
│  │ decrypt_blob│   │  │             │   │  │             │   │ │ HMAC     │ │
│  └─────────────┘   │  └─────────────┘   │  └─────────────┘   │ └──────────┘ │
└─────────────────────┴─────────────────────┴─────────────────────┴──────────────┘
           │                      │                      │                │
           ▼                      ▼                      ▼                ▼
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐  ┌─────────────┐
│   KMS Adapters  │    │ Crypto Provider │    │ Policy Engine   │  │ Blockchain  │
│                 │    │                 │    │                 │  │ Anchoring   │
│ ┌─────────────┐ │    │ ┌─────────────┐ │    │ ┌─────────────┐ │  │ ┌─────────┐ │
│ │  AWS KMS    │ │    │ │ Key         │ │    │ │ HIPAA       │ │  │ │Ethereum │ │
│ │  Vault      │ │    │ │ Generation  │ │    │ │ GDPR        │ │  │ │Fabric   │ │
│ │  Mock       │ │    │ │ Wrapping    │ │    │ │ GxP/CLIA    │ │  │ │Mock     │ │
│ └─────────────┘ │    │ └─────────────┘ │    │ └─────────────┘ │  │ └─────────┘ │
└─────────────────┘    └─────────────────┘    └─────────────────┘  └─────────────┘
```

### Data Flow Architecture

```
                Medical Image Processing Pipeline

┌─────────────┐   ┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐
│             │   │                 │   │                 │   │                 │
│  Raw Image  │──▶│  PHI Scrubbing  │──▶│   Encryption    │──▶│ Secure Storage  │
│  (DICOM/    │   │                 │   │                 │   │                 │
│   PNG/JPEG) │   │ • Remove PII    │   │ • Generate DEK  │   │ • Encrypted Pkg │
│             │   │ • Strip EXIF    │   │ • AES-256-GCM   │   │ • Audit Trail   │
│             │   │ • Regenerate    │   │ • Wrap with KMS │   │ • Blockchain    │
│             │   │   UIDs          │   │ • Sign Package  │   │   Anchor        │
└─────────────┘   └─────────────────┘   └─────────────────┘   └─────────────────┘
                           │                       │                       │
                           ▼                       ▼                       ▼
                  ┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐
                  │ Sanitization    │   │ Encryption      │   │ Audit Events    │
                  │ Report          │   │ Metadata        │   │                 │
                  │ • Removed Tags  │   │ • Algorithm     │   │ • Actor         │
                  │ • Pseudo PID    │   │ • Key Reference │   │ • Timestamp     │
                  │ • Hash          │   │ • IV/Nonce      │   │ • Operation     │
                  │ • Compliance    │   │ • AAD Context   │   │ • Outcome       │
                  └─────────────────┘   └─────────────────┘   └─────────────────┘
```

### ML Training Pipeline

```
               Secure Machine Learning Workflow

┌─────────────┐   ┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐
│ Encrypted   │   │ Memory-Only     │   │ Tensor          │   │ Model Training  │
│ Dataset     │──▶│ Decryption      │──▶│ Conversion      │──▶│                 │
│             │   │                 │   │                 │   │ • PyTorch       │
│ • .enc files│   │ • KMS Unwrap    │   │ • DICOM→Tensor  │   │ • TensorFlow    │
│ • Metadata  │   │ • AES Decrypt   │   │ • Preprocessing │   │ • No Disk I/O   │
│ • Audit Log │   │ • Verify HMAC   │   │ • Normalization │   │ • Auto Cleanup  │
└─────────────┘   └─────────────────┘   └─────────────────┘   └─────────────────┘
                           │                       │                       │
                           ▼                       ▼                       ▼
                  ┌─────────────────┐   ┌─────────────────┐   ┌─────────────────┐
                  │ Zero-Copy       │   │ Image Tensors   │   │ Privacy         │
                  │ Operations      │   │                 │   │ Guarantees      │
                  │                 │   │ • Shape: (H,W,C)│   │                 │
                  │ • No temp files │   │ • Dtype: float32│   │ • No PHI leaks  │
                  │ • Memory pools  │   │ • Range: [0,1]  │   │ • Secure delete │
                  │ • Automatic     │   │ • Batch ready   │   │ • Audit trail   │
                  │   cleanup       │   │                 │   │                 │
                  └─────────────────┘   └─────────────────┘   └─────────────────┘
```

## 🚀 Quick Start

### Installation

```bash
# Production installation
pip install pymedsec

# Development installation with all features
pip install pymedsec[dev,aws,vault,ocr]

# Specific feature sets
pip install pymedsec[aws]        # AWS KMS support
pip install pymedsec[vault]      # HashiCorp Vault support
pip install pymedsec[ocr]        # OCR-based redaction
pip install pymedsec[blockchain] # Blockchain anchoring
```

### 30-Second Example

```python
from pymedsec import load_policy, scrub_dicom, get_kms_client, encrypt_blob

# 1. Load HIPAA-compliant policy
policy = load_policy("hipaa_default")

# 2. Initialize KMS (use AWS KMS in production)
kms = get_kms_client("mock")  # or "aws" with proper credentials

# 3. Sanitize medical image
with open("patient_scan.dcm", "rb") as f:
    clean_data = scrub_dicom(f.read(), policy=policy, pseudo_pid="PX001")

# 4. Encrypt for secure storage
encrypted_package = encrypt_blob(
    clean_data,
    kms_client=kms,
    aad={"dataset": "study2025", "modality": "CT"}
)

# 5. Save encrypted package
with open("secure_scan.enc", "w") as f:
    f.write(encrypted_package.to_json())

print("✅ Medical image securely processed and encrypted!")
```

## 📖 API Documentation

### High-Level API (Recommended)

#### Policy Management

```python
from pymedsec import load_policy, list_policies, set_active_policy

# Load built-in policies
policy = load_policy("hipaa_default")  # or "gdpr_default", "gxp_default"

# Load custom policy
policy = load_policy("/path/to/custom_policy.yaml")

# List all available policies
policies = list_policies()

# Set global active policy
set_active_policy("hipaa_default")
```

#### KMS Integration

```python
from pymedsec import get_kms_client

# AWS KMS (production)
kms = get_kms_client("aws",
                     key_id="alias/medical-images",
                     region_name="us-east-1")

# HashiCorp Vault
kms = get_kms_client("vault",
                     vault_url="https://vault.company.com",
                     vault_path="medical/keys/imaging")

# Mock KMS (development/testing)
kms = get_kms_client("mock")
```

#### Image Processing

```python
from pymedsec import scrub_dicom, scrub_image, encrypt_blob, decrypt_blob

# DICOM sanitization with PHI removal
clean_dicom = scrub_dicom(dicom_bytes,
                          policy=policy,
                          pseudo_pid="ANON123",
                          preserve_technical=True)

# Generic image sanitization
clean_image = scrub_image(image_bytes,
                          format_hint="png",  # or "jpeg", "tiff"
                          policy=policy)

# Encryption with authenticated additional data
package = encrypt_blob(clean_data,
                       kms_client=kms,
                       aad={"study": "TRIAL001", "modality": "MRI"})

# Decryption
original_data = decrypt_blob(package, kms_client=kms)
```

#### ML Integration

```python
from pymedsec import SecureImageDataset, decrypt_to_tensor

# Create secure dataset for training
dataset = SecureImageDataset(
    data_dir="./encrypted_scans/",
    policy=policy,
    kms_client=kms,
    transform=torchvision.transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485], std=[0.229])
    ])
)

# Use with PyTorch DataLoader
dataloader = torch.utils.data.DataLoader(dataset, batch_size=32, shuffle=True)

for batch_tensors, metadata in dataloader:
    # Train your model
    outputs = model(batch_tensors)
    loss = criterion(outputs, targets)

# Direct tensor decryption (zero-copy)
tensor = decrypt_to_tensor(encrypted_package,
                          kms_client=kms,
                          format_hint="dicom")
```

### Low-Level API (Advanced Use Cases)

```python
from pymedsec.config import SecurityConfig
from pymedsec.crypto import EncryptionEngine
from pymedsec.sanitize import DicomSanitizer
from pymedsec.audit import AuditLogger

# Advanced configuration
config = SecurityConfig.load_from_file("/etc/pymedsec/config.yaml")

# Direct encryption engine
engine = EncryptionEngine(config)
encrypted_data = engine.encrypt(data, key_ref="prod-key-001")

# Advanced DICOM processing
sanitizer = DicomSanitizer(config)
result = sanitizer.sanitize(dicom_dataset)

# Audit logging
logger = AuditLogger(audit_path="/var/log/pymedsec.jsonl")
logger.log_operation("ENCRYPT", outcome="success", file_hash="sha256:abc123...")
```

## � Expected Outputs & Policy Examples

This section shows what to expect when using different policies and operations with PyMedSec.

### Policy Selection & Expected Behavior

#### HIPAA Default Policy

```python
from pymedsec import load_policy, scrub_dicom

# Load HIPAA policy
policy = load_policy("hipaa_default")
print(f"Policy: {policy.name}")
print(f"PHI Removal: {policy.sanitization.dicom.remove_private_tags}")
print(f"UID Regeneration: {policy.sanitization.dicom.regenerate_uids}")
```

**Expected Output:**

```
Policy: HIPAA Default Policy
PHI Removal: True
UID Regeneration: True
Compliance Framework: HIPAA
Retention Period: 2557 days (7 years)
```

#### GDPR Default Policy

```python
# Load GDPR policy
policy = load_policy("gdpr_default")
print(f"Data Minimization: {policy.compliance.data_minimization}")
print(f"Pseudonymization: {policy.compliance.pseudonymization_required}")
```

**Expected Output:**

```
Policy: GDPR Compliance Policy
Data Minimization: True
Pseudonymization: True
Right to Erasure: Enabled
Purpose Limitation: medical_research
```

#### GxP/Laboratory Policy

```python
# Load GxP policy for clinical trials
policy = load_policy("gxp_default")
print(f"Validation Required: {policy.compliance.validation_required}")
print(f"Audit Level: {policy.audit.detail_level}")
```

**Expected Output:**

```
Policy: GxP Clinical Laboratory Policy
Validation Required: True
Audit Level: comprehensive
21 CFR Part 11: Compliant
CLIA Standards: Aligned
```

### DICOM Sanitization Examples

#### Basic HIPAA Sanitization

```python
from pymedsec import scrub_dicom, load_policy

# Load original DICOM
with open("patient_scan.dcm", "rb") as f:
    original_dicom = f.read()

# Apply HIPAA sanitization
policy = load_policy("hipaa_default")
result = scrub_dicom(original_dicom, policy=policy, pseudo_pid="STUDY001_P001")

print(f"Original size: {len(original_dicom)} bytes")
print(f"Sanitized size: {len(result.sanitized_data)} bytes")
print(f"Tags removed: {len(result.removed_tags)}")
print(f"UIDs regenerated: {result.uids_regenerated}")
```

**Expected Output:**

```
Original size: 2,847,392 bytes
Sanitized size: 2,834,156 bytes
Tags removed: 23
UIDs regenerated: True
Pseudo Patient ID: STUDY001_P001
Compliance Hash: sha256:f4a7b2c9e8d6...
```

#### Detailed Sanitization Report

```python
# Get detailed sanitization report
result = scrub_dicom(original_dicom, policy=policy, detailed_report=True)

print("=== DICOM Sanitization Report ===")
print(f"Patient Name: {result.report.original_patient_name} → REMOVED")
print(f"Patient ID: {result.report.original_patient_id} → {result.report.pseudo_patient_id}")
print(f"Study Date: {result.report.original_study_date} → {result.report.anonymized_study_date}")
print(f"Institution: {result.report.original_institution} → REMOVED")
print("\nTechnical tags preserved:")
for tag in result.report.preserved_tags[:5]:
    print(f"  {tag}")
```

**Expected Output:**

```
=== DICOM Sanitization Report ===
Patient Name: John Doe → REMOVED
Patient ID: 12345678 → STUDY001_P001
Study Date: 2025-09-09 → 2025-01-01
Institution: General Hospital → REMOVED

Technical tags preserved:
  (0018,0050) Slice Thickness: 5.0
  (0018,0088) Spacing Between Slices: 5.0
  (0020,0032) Image Position Patient: [...]
  (0028,0030) Pixel Spacing: [0.5, 0.5]
  (0028,0010) Rows: 512
```

### Image Type Specific Examples

PyMedSec supports multiple medical image formats, each with specific metadata handling and sanitization approaches.

#### DICOM (.dcm) - Complete Example

```python
from pymedsec import scrub_dicom, load_policy

# Input: Original DICOM file
with open("mri_brain_001.dcm", "rb") as f:
    original_dicom = f.read()

policy = load_policy("hipaa_default")
result = scrub_dicom(original_dicom, policy=policy, pseudo_pid="MRI_STUDY_001")

print("=== DICOM Processing ===")
print(f"Original file size: {len(original_dicom):,} bytes")
print(f"Image dimensions: {result.metadata['Rows']}x{result.metadata['Columns']}")
print(f"Modality: {result.metadata['Modality']}")
print(f"Bits allocated: {result.metadata['BitsAllocated']}")
```

**Expected Input (DICOM Tags):**

```
(0008,0020) Study Date: '20250909'
(0008,0030) Study Time: '143015.123000'
(0008,0080) Institution Name: 'General Hospital'
(0008,0090) Referring Physician: 'Dr. Smith'
(0010,0010) Patient's Name: 'Doe^John^M'
(0010,0020) Patient ID: '12345678'
(0010,0030) Patient's Birth Date: '19851203'
(0010,0040) Patient's Sex: 'M'
(0018,0050) Slice Thickness: '5.0'
(0018,0088) Spacing Between Slices: '5.0'
(0020,000D) Study Instance UID: '1.2.840.113619.2.5.1762583153...'
(0028,0010) Rows: 512
(0028,0011) Columns: 512
(0028,0100) Bits Allocated: 16
```

**Expected Output (Sanitized):**

```
=== DICOM Processing ===
Original file size: 2,847,392 bytes
Image dimensions: 512x512
Modality: MR
Bits allocated: 16

=== Sanitization Results ===
PHI Tags Removed: 23
Technical Tags Preserved: 156
UIDs Regenerated: 4
Date Shift Applied: +67 days
Pseudo Patient ID: MRI_STUDY_001
Processing Time: 0.234 seconds

Sanitized Tags:
(0008,0020) Study Date: '20251115'  # Shifted
(0008,0030) Study Time: '000000.000000'  # Anonymized
(0008,0080) Institution Name: [REMOVED]
(0008,0090) Referring Physician: [REMOVED]
(0010,0010) Patient's Name: [REMOVED]
(0010,0020) Patient ID: 'MRI_STUDY_001'
(0010,0030) Patient's Birth Date: [REMOVED]
(0010,0040) Patient's Sex: [REMOVED]
(0018,0050) Slice Thickness: '5.0'  # Preserved
(0020,000D) Study Instance UID: '2.25.987654321...'  # Regenerated
```

#### PNG - Photographic/Microscopy Images

```python
from pymedsec import scrub_image, load_policy

# Input: PNG with EXIF metadata
with open("microscopy_sample.png", "rb") as f:
    original_png = f.read()

policy = load_policy("hipaa_default")
result = scrub_image(original_png, format_hint="png", policy=policy)

print("=== PNG Processing ===")
print(f"Original file size: {len(original_png):,} bytes")
print(f"Format: {result.format}")
print(f"Metadata found: {len(result.original_metadata)} fields")
```

**Expected Input (PNG EXIF):**

```
File: microscopy_sample.png (1,234,567 bytes)
Image Size: 2048x1536 pixels
Color Mode: RGB

EXIF Metadata:
  Make: 'Olympus'
  Model: 'BX53 Microscope'
  DateTime: '2025:09:09 14:30:15'
  Software: 'cellSens Standard 2.3'
  Artist: 'Lab Technician John Doe'
  UserComment: 'Patient ID: 12345678, Sample: Biopsy'
  GPS Info: Present (Hospital Location)
  Copyright: 'General Hospital Pathology Dept'
  ImageDescription: 'H&E stain, 40x magnification'
  XResolution: 300.0 dpi
  YResolution: 300.0 dpi
```

**Expected Output (Sanitized PNG):**

```
=== PNG Processing ===
Original file size: 1,234,567 bytes
Format: PNG
Metadata found: 12 fields

=== Sanitization Results ===
EXIF Tags Removed: 8
Technical Tags Preserved: 4
PHI References: 3 removed
Processing Time: 0.089 seconds

Sanitized Metadata:
  Make: [REMOVED]
  Model: [REMOVED]
  DateTime: [REMOVED]
  Software: [REMOVED]
  Artist: [REMOVED]
  UserComment: [REMOVED]
  GPS Info: [REMOVED]
  Copyright: [REMOVED]
  ImageDescription: [REMOVED]
  XResolution: 300.0 dpi  # Preserved (technical)
  YResolution: 300.0 dpi  # Preserved (technical)
  ColorSpace: sRGB  # Preserved (technical)

Output file size: 1,198,432 bytes (2.9% reduction)
```

#### JPEG - Clinical Photography

```python
from pymedsec import scrub_image

# Input: Clinical photograph with extensive metadata
with open("wound_documentation.jpg", "rb") as f:
    original_jpeg = f.read()

result = scrub_image(original_jpeg, format_hint="jpeg", policy=policy)
```

**Expected Input (JPEG EXIF/IPTC):**

```
File: wound_documentation.jpg (856,432 bytes)
Image Size: 4032x3024 pixels
Quality: 92%

EXIF Metadata:
  Camera Make: 'Canon'
  Camera Model: 'EOS R5'
  DateTime Original: '2025:09:09 14:30:15'
  GPS Latitude: 40.7128° N
  GPS Longitude: 74.0060° W
  Lens Model: 'RF24-105mm F4 L IS USM'
  ISO Speed: 400
  Exposure Time: 1/60
  F-Number: f/5.6

IPTC Metadata:
  Byline: 'Dr. Sarah Wilson'
  Caption: 'Post-surgical wound, day 7, patient 12345678'
  Keywords: 'wound, healing, patient care'
  Copyright Notice: 'Metropolitan Hospital 2025'
  City: 'New York'
  Country: 'USA'

XMP Metadata:
  Creator: 'Wound Care Team'
  Subject: ['medical', 'documentation', 'patient-12345678']
  Rights: 'Confidential Medical Record'
```

**Expected Output (Sanitized JPEG):**

```
=== JPEG Processing ===
Original file size: 856,432 bytes
Format: JPEG
Metadata found: 18 fields

=== Sanitization Results ===
EXIF Tags Removed: 8
IPTC Fields Removed: 6
XMP Properties Removed: 4
Technical Tags Preserved: 6
Processing Time: 0.156 seconds

Sanitized Metadata:
  Camera Make: [REMOVED]
  Camera Model: [REMOVED]
  DateTime Original: [REMOVED]
  GPS Latitude: [REMOVED]
  GPS Longitude: [REMOVED]
  Lens Model: [REMOVED]
  Byline: [REMOVED]
  Caption: [REMOVED]
  Keywords: [REMOVED]
  Copyright Notice: [REMOVED]
  Creator: [REMOVED]

  # Technical metadata preserved:
  Image Width: 4032 pixels
  Image Height: 3024 pixels
  Color Space: sRGB
  Orientation: 1 (normal)
  Resolution: 72 dpi
  Compression: JPEG (Quality 92%)

Output file size: 823,145 bytes (3.9% reduction)
```

#### TIFF - High-Resolution Pathology

```python
from pymedsec import scrub_image

# Input: High-resolution pathology slide
with open("histology_slide_001.tiff", "rb") as f:
    original_tiff = f.read()

result = scrub_image(original_tiff, format_hint="tiff", policy=policy, preserve_technical=True)
```

**Expected Input (TIFF Tags):**

```
File: histology_slide_001.tiff (45,678,234 bytes)
Image Size: 32768x24576 pixels (804 megapixels)
Bit Depth: 24-bit RGB
Compression: LZW

TIFF Tags:
  Software: 'Aperio ImageScope v12.4.6'
  DateTime: '2025:09:09 14:30:15'
  Artist: 'Pathologist Dr. Jane Smith'
  Copyright: 'Metro Pathology Lab'
  ImageDescription: 'Patient: John Doe, Case: 2025-001234, H&E 20x'
  Make: 'Aperio'
  Model: 'ScanScope AT2'
  DocumentName: 'slide_patient_12345678.svs'
  HostComputer: 'PATHOLOGY-WS-001'

  # Aperio-specific tags:
  Aperio.Filename: 'patient_12345678_slide_001'
  Aperio.Date: '09/09/2025'
  Aperio.Time: '14:30:15'
  Aperio.User: 'jsmith'
  Aperio.AppMag: '20'
  Aperio.StripeWidth: '2048'
  Aperio.ScanScope ID: 'SS1234'

  # Technical preservation tags:
  XResolution: 0.25 μm/pixel
  YResolution: 0.25 μm/pixel
  ResolutionUnit: Micrometer
  PlanarConfiguration: Chunky
  PhotometricInterpretation: RGB
```

**Expected Output (Sanitized TIFF):**

```
=== TIFF Processing ===
Original file size: 45,678,234 bytes
Format: TIFF
Image dimensions: 32768x24576 pixels
Metadata found: 23 fields

=== Sanitization Results ===
Standard TIFF Tags Removed: 8
Aperio-Specific Tags Removed: 7
Technical Tags Preserved: 8
Processing Time: 2.456 seconds

Sanitized Metadata:
  Software: [REMOVED]
  DateTime: [REMOVED]
  Artist: [REMOVED]
  Copyright: [REMOVED]
  ImageDescription: [REMOVED]
  Make: [REMOVED]
  Model: [REMOVED]
  DocumentName: [REMOVED]
  HostComputer: [REMOVED]

  # Aperio tags removed:
  Aperio.Filename: [REMOVED]
  Aperio.Date: [REMOVED]
  Aperio.Time: [REMOVED]
  Aperio.User: [REMOVED]
  Aperio.ScanScope ID: [REMOVED]

  # Technical metadata preserved:
  Image Width: 32768 pixels
  Image Height: 24576 pixels
  Bits Per Sample: 8, 8, 8
  Compression: LZW
  XResolution: 0.25 μm/pixel  # Critical for measurements
  YResolution: 0.25 μm/pixel  # Critical for measurements
  ResolutionUnit: Micrometer
  PhotometricInterpretation: RGB
  Aperio.AppMag: '20'  # Magnification preserved

Output file size: 45,456,123 bytes (0.5% reduction)
```

#### Multi-format Batch Processing

```python
from pymedsec import scrub_image
from pathlib import Path

# Process multiple image types
image_dir = Path("./medical_images/")
results = {}

for image_file in image_dir.glob("*"):
    if image_file.suffix.lower() in ['.dcm', '.png', '.jpg', '.jpeg', '.tiff', '.tif']:
        with open(image_file, "rb") as f:
            data = f.read()

        # Auto-detect format or use extension hint
        format_hint = image_file.suffix.lower().replace('.', '')
        if format_hint == 'dcm':
            result = scrub_dicom(data, policy=policy, pseudo_pid=f"BATCH_{image_file.stem}")
        else:
            result = scrub_image(data, format_hint=format_hint, policy=policy)

        results[image_file.name] = {
            'original_size': len(data),
            'sanitized_size': len(result.sanitized_data),
            'metadata_removed': len(result.removed_metadata),
            'format': result.format
        }

# Display batch results
for filename, stats in results.items():
    print(f"{filename}:")
    print(f"  Format: {stats['format']}")
    print(f"  Size: {stats['original_size']:,} → {stats['sanitized_size']:,} bytes")
    print(f"  Metadata removed: {stats['metadata_removed']} fields")
    print(f"  Reduction: {((stats['original_size'] - stats['sanitized_size']) / stats['original_size'] * 100):.1f}%")
```

**Expected Batch Output:**

```
mri_brain_001.dcm:
  Format: DICOM
  Size: 2,847,392 → 2,834,156 bytes
  Metadata removed: 23 fields
  Reduction: 0.5%

microscopy_sample.png:
  Format: PNG
  Size: 1,234,567 → 1,198,432 bytes
  Metadata removed: 8 fields
  Reduction: 2.9%

wound_documentation.jpg:
  Format: JPEG
  Size: 856,432 → 823,145 bytes
  Metadata removed: 18 fields
  Reduction: 3.9%

histology_slide_001.tiff:
  Format: TIFF
  Size: 45,678,234 → 45,456,123 bytes
  Metadata removed: 15 fields
  Reduction: 0.5%

=== Batch Summary ===
Total files processed: 4
Total original size: 50,616,625 bytes (48.3 MB)
Total sanitized size: 50,311,856 bytes (48.0 MB)
Total metadata fields removed: 64
Average processing time: 0.734 seconds/file
```

### Encryption & KMS Examples

#### AWS KMS Encryption

```python
from pymedsec import get_kms_client, encrypt_blob

# Setup AWS KMS
kms = get_kms_client("aws",
                     key_id="alias/medical-images-prod",
                     region_name="us-east-1")

# Encrypt sanitized data
encrypted_pkg = encrypt_blob(
    sanitized_data,
    kms_client=kms,
    aad={"dataset": "CLINICAL_TRIAL_2025", "modality": "CT", "site": "hospital_01"}
)

print(f"Encryption Algorithm: {encrypted_pkg.header.algorithm}")
print(f"KMS Key: {encrypted_pkg.header.kms_key_ref}")
print(f"Package Size: {len(encrypted_pkg.to_json())} bytes")
print(f"Created: {encrypted_pkg.header.created_at}")
```

**Expected Output:**

```
Encryption Algorithm: AES-256-GCM
KMS Key: arn:aws:kms:us-east-1:123456789012:alias/medical-images-prod
Package Size: 2,856,789 bytes
Created: 2025-09-09T14:30:15.123Z
Wrapped DEK: AQICAHh8sO5...
AAD Context: {"dataset": "CLINICAL_TRIAL_2025", "modality": "CT", "site": "hospital_01"}
```

#### HashiCorp Vault KMS

```python
# Setup Vault KMS
kms = get_kms_client("vault",
                     vault_url="https://vault.company.com:8200",
                     vault_path="medical/keys/imaging")

# Encrypt with Vault
encrypted_pkg = encrypt_blob(sanitized_data, kms_client=kms)
print(f"Vault Path: {kms.vault_path}")
print(f"Wrapped Key Size: {len(encrypted_pkg.crypto.wrapped_dek)} bytes")
```

**Expected Output:**

```
Vault Path: medical/keys/imaging
Vault Version: v3
Wrapped Key Size: 256 bytes
Encryption Method: transit/encrypt/imaging-key
```

### ML Integration Examples

#### Secure Dataset Loading

```python
from pymedsec import SecureImageDataset

# Create secure dataset
dataset = SecureImageDataset(
    data_dir="./encrypted_scans/",
    policy=policy,
    kms_client=kms,
    cache_size=100  # Cache 100 decrypted images
)

print(f"Dataset size: {len(dataset)} images")
print(f"Memory usage: {dataset.memory_usage_mb} MB")
print(f"Cache hit ratio: {dataset.cache_hit_ratio:.2%}")

# Load first sample
tensor, metadata = dataset[0]
print(f"Tensor shape: {tensor.shape}")
print(f"Tensor dtype: {tensor.dtype}")
print(f"Value range: [{tensor.min():.3f}, {tensor.max():.3f}]")
```

**Expected Output:**

```
Dataset size: 1,247 images
Memory usage: 234.5 MB
Cache hit ratio: 78.5%
Tensor shape: torch.Size([1, 512, 512])
Tensor dtype: torch.float32
Value range: [0.000, 1.000]
Metadata: {'study_id': 'STUDY001', 'modality': 'CT', 'slice_index': 45}
```

### Audit Logging Examples

#### Basic Audit Operations

```python
from pymedsec.audit import AuditLogger

# Initialize audit logger
logger = AuditLogger(audit_path="/var/log/pymedsec/audit.jsonl")

# Log operations
logger.log_operation("SANITIZE",
                    outcome="success",
                    file_hash="sha256:abc123...",
                    tags_removed=23,
                    policy="hipaa_default")

logger.log_operation("ENCRYPT",
                    outcome="success",
                    kms_key="alias/medical-images",
                    algorithm="AES-256-GCM")
```

**Expected Audit Log Entries:**

```jsonl
{"timestamp": "2025-09-09T14:30:15.123Z", "actor": "radiologist@hospital.com", "operation": "SANITIZE", "outcome": "success", "file_hash": "sha256:abc123...", "tags_removed": 23, "policy": "hipaa_default", "signature": "hmac_sha256:def456..."}
{"timestamp": "2025-09-09T14:30:16.456Z", "actor": "radiologist@hospital.com", "operation": "ENCRYPT", "outcome": "success", "kms_key": "alias/medical-images", "algorithm": "AES-256-GCM", "signature": "hmac_sha256:ghi789..."}
```

#### Blockchain Anchored Audit

```python
# Enable blockchain anchoring
import os
os.environ['BLOCKCHAIN_BACKEND'] = 'ethereum'
os.environ['ETHEREUM_RPC_URL'] = 'https://mainnet.infura.io/v3/YOUR_KEY'

logger = AuditLogger(audit_path="/var/log/audit_blockchain.jsonl")

# Every 1000 operations, an anchor is created
for i in range(1000):
    logger.log_operation("DECRYPT", outcome="success", access_purpose="ml_training")

# Check blockchain anchor
print(f"Last anchor hash: {logger.last_anchor_hash}")
print(f"Blockchain txn: {logger.last_blockchain_txn}")
```

**Expected Output:**

```
Last anchor hash: sha256:blockchain_anchor_abc123...
Blockchain txn: 0x1234567890abcdef...
Anchor block: 18,456,789
Gas used: 21,000
Verification status: CONFIRMED
```

### CLI Usage with Expected Outputs

#### Sanitization Command

```bash
pymedsec sanitize-cmd \
    --input patient_001.dcm \
    --output clean_001.dcm \
    --pseudo-pid STUDY001_001 \
    --policy hipaa_default \
    --verbose
```

**Expected CLI Output:**

```
🏥 PyMedSec Medical Image Sanitizer
=====================================
📁 Input: patient_001.dcm (2.85 MB)
📋 Policy: HIPAA Default Policy
🔒 Pseudo PID: STUDY001_001

📊 Sanitization Progress:
  ✅ Loaded DICOM dataset (512x512x16bit)
  ✅ Removed 23 PHI tags
  ✅ Regenerated 4 UIDs
  ✅ Preserved 156 technical tags
  ✅ Applied date shifting (+45 days)
  ⚠️  Detected burned-in annotation (handled)

💾 Output: clean_001.dcm (2.83 MB)
📈 Size reduction: 1.2%
🔐 Compliance hash: sha256:f4a7b2c9...
⏱️  Processing time: 0.234 seconds

✅ Sanitization completed successfully!
```

#### Encryption Command

```bash
pymedsec encrypt \
    --input clean_001.dcm \
    --output secure_001.enc \
    --kms-backend aws \
    --key-id alias/medical-images \
    --dataset-id CLINICAL_TRIAL_2025 \
    --verbose
```

**Expected CLI Output:**

```
🔐 PyMedSec Medical Image Encryptor
====================================
📁 Input: clean_001.dcm (2.83 MB)
🔑 KMS: AWS KMS (us-east-1)
🏷️  Key: alias/medical-images
📊 Dataset: CLINICAL_TRIAL_2025

🔒 Encryption Progress:
  ✅ Generated 256-bit data key
  ✅ Encrypted with AES-256-GCM
  ✅ Wrapped DEK with KMS
  ✅ Created tamper-evident package
  ✅ Logged to audit trail

💾 Output: secure_001.enc (2.86 MB)
🔐 Package hash: sha256:1a2b3c4d...
📜 Audit entry: 2025-09-09T14:30:15.123Z
⏱️  Processing time: 0.892 seconds

✅ Encryption completed successfully!
```

### Policy Comparison Table

| Feature              | HIPAA Default | GDPR Default | GxP Default | Custom Lab   |
| -------------------- | ------------- | ------------ | ----------- | ------------ |
| **PHI Removal**      | ✅ Complete   | ✅ Complete  | ✅ Complete | ⚠️ Selective |
| **UID Regeneration** | ✅ Yes        | ✅ Yes       | ✅ Yes      | ❌ No        |
| **Date Shifting**    | ✅ ±90 days   | ✅ ±90 days  | ❌ Preserve | ✅ ±30 days  |
| **Technical Tags**   | ✅ Preserve   | ✅ Preserve  | ✅ Preserve | ✅ Preserve  |
| **Audit Retention**  | 7 years       | 6 years      | 15 years    | 2 years      |
| **Encryption**       | AES-256-GCM   | AES-256-GCM  | AES-256-GCM | AES-256-GCM  |
| **Blockchain**       | Optional      | Optional     | Required    | Disabled     |
| **OCR Redaction**    | Strict        | Moderate     | Strict      | Disabled     |
| **Validation**       | Standard      | Standard     | Enhanced    | Minimal      |

### Error Handling Examples

#### Invalid Policy

```python
try:
    policy = load_policy("invalid_policy")
except PolicyNotFoundError as e:
    print(f"Error: {e}")
    print("Available policies:", list_policies())
```

**Expected Output:**

```
Error: Policy 'invalid_policy' not found
Available policies: ['hipaa_default', 'gdpr_default', 'gxp_default']
```

#### KMS Access Error

```python
try:
    kms = get_kms_client("aws", key_id="invalid-key")
    encrypt_blob(data, kms_client=kms)
except KMSAccessError as e:
    print(f"KMS Error: {e}")
    print("Check IAM permissions and key existence")
```

**Expected Output:**

```
KMS Error: Access denied to key 'invalid-key'
Check IAM permissions and key existence
Suggested actions:
  1. Verify key alias/ARN is correct
  2. Check IAM role has kms:Encrypt permission
  3. Ensure key is enabled and not deleted
```

## �🔧 Configuration

PyMedSec uses environment variables and YAML configuration files for flexible deployment.

### Environment Variables

| Variable                     | Description                          | Default         | Required |
| ---------------------------- | ------------------------------------ | --------------- | -------- |
| `PYMEDSEC_POLICY`            | Path to YAML policy file             | -               | ✅       |
| `PYMEDSEC_KMS_BACKEND`       | KMS backend (`aws`\|`vault`\|`mock`) | `mock`          | ✅       |
| `PYMEDSEC_KMS_KEY_REF`       | KMS key identifier                   | -               | ✅       |
| `PYMEDSEC_AUDIT_PATH`        | Audit log file path                  | `./audit.jsonl` | -        |
| `PYMEDSEC_DEBUG`             | Enable debug logging                 | `false`         | -        |
| `PYMEDSEC_NO_PLAINTEXT_DISK` | Forbid plaintext disk writes         | `false`         | -        |

### Policy Configuration

Create a YAML policy file to define security and compliance requirements:

```yaml
# /etc/pymedsec/hipaa_policy.yaml
schema_version: '1.0'
name: 'HIPAA Compliance Policy'
description: 'Enterprise HIPAA-compliant policy for medical imaging'

sanitization:
  dicom:
    remove_private_tags: true
    regenerate_uids: true
    preserve_technical_tags: true
    phi_tags_action: 'remove' # remove, replace, or pseudonymize
    burned_in_annotation_policy: 'strict' # strict, moderate, or permissive

  exif:
    strip_all_metadata: true
    preserve_orientation: false
    preserve_color_space: true

encryption:
  algorithm: 'AES-256-GCM'
  key_rotation_days: 90
  require_kms: true
  additional_authenticated_data: ['dataset_id', 'modality', 'timestamp']

audit:
  log_all_operations: true
  include_file_hashes: true
  blockchain_anchoring: false
  retention_days: 2557 # 7 years for HIPAA

compliance:
  framework: 'hipaa' # hipaa, gdpr, gxp
  purpose_limitation: 'medical_research'
  data_minimization: true
  pseudonymization_required: true
```

## 🔐 Security Model

### Envelope Encryption

PyMedSec uses industry-standard envelope encryption to protect medical images:

1. **Data Encryption Key (DEK) Generation**: Generate a random 256-bit AES key for each image
2. **Image Encryption**: Encrypt the medical image using AES-256-GCM with the DEK
3. **Key Wrapping**: Encrypt the DEK using the master key in KMS/HSM
4. **Package Creation**: Combine encrypted image + wrapped DEK + metadata in tamper-evident package

```
┌─────────────────────────────────────────────────────────────────┐
│                    Encrypted Package Structure                  │
├─────────────────────────────────────────────────────────────────┤
│ Header:                                                         │
│  ├─ version: "1.0"                                             │
│  ├─ algorithm: "AES-256-GCM"                                   │
│  ├─ kms_key_ref: "arn:aws:kms:us-east-1:123:key/abc123"       │
│  └─ created_at: "2025-09-09T10:30:00Z"                        │
├────────────────────────────