Project Index
Crypto Evaluation & Readiness for Infrastructure Adaptation (Post-Quantum)
Overview
Post-Quantum Cryptography Scanner implementing Malaysia's NCII SCAD Framework. Author: Yusri (yusri@dysfunktion.tech)| Version: 1.0 | Last Updated: 2026-07-22 |
Quick Links
- Quick Start - Get started in 5 minutes
- User Manual - Complete feature documentation
- API Reference - REST API endpoints
- Report Exports - PDF, Excel, CBOM, CSV, and JSON exports
- Deployment Guide - Production deployment
- Admin Guide - Administration tasks
Project Details
- Status: ✅ Deployed and Live
- URL: https://pqcs.dysfunktion.tech
- Platform: cPanel Shared Hosting
- Stack: Python 3.11, FastAPI, SQLite
Key Features
- 7 Cryptographic Collectors (TLS, SSH, VPN, DB, OS, App Config, Cert Store)
- SCAD Risk Scoring Framework (7 criteria)
- HNDL Risk Calculator (Mosca's Inequality)
- Certificate Chain Analysis
- MySEAL Compliance
- Web Dashboard + CLI
Last Updated: 2026-07-22
Current Release Highlights
- Enterprise demo-data generation for up to 500 devices across vendors, device archetypes, collector detections, and HNDL severities.
- Paginated Device Inventory and Device Risk Assessment tables for large datasets.
- Persistent backend report queue with progress, recovery, downloads, and deletion.
- WeasyPrint PDF reports and populated PQC Excel template exports.
- Generated Reports at
/report-exports, with export actions unified under Export to on/report.
Getting Started
1. First Time Setup (5 minutes)
# Install dependencies
pip install -e .
# Create admin user
ceria --verbose dashboard
# Then access http://localhost:8080/login
# Click "Register" to create first admin user (auto-assigned)
2. Run Your First Scan (5 minutes)
# Option A: CLI
ceria scan 192.168.1.0/24 --name "My First Scan"
# Option B: Web Dashboard
# 1. Open http://localhost:8080
# 2. Login
# 3. Go to "Scan" page
# 4. Enter target: 192.168.1.0/24
# 5. Click "Start Scan"
3. View Results (2 minutes)
# CLI
ceria report --session 1 --format table
# Web
# Go to "Scan Detail" → Expand devices
4. Key Actions to Take
Set Device Priorities
- Go to Inventory
- Click on high-risk device
- Select Tier: Critical / High / Medium / Low
- Set Data Retention Years for HNDL calculation
Load Enterprise Demo Data
ceria demo-data --count 500 --snapshots 4 --seed 20260722
This creates a timestamped SQLite backup before loading deterministic data for all supported vendors, device types, collector detections, risk priorities, and HNDL severities.
Export Reports
- Open
/report. - Select Export to and choose PDF, PQC Excel, CBOM, CSV, or JSON.
- Follow backend progress in the on-page status panel.
- Open
/report-exportsto download or delete completed files.
Common Commands Cheat Sheet
| Task | Command |
| Start dashboard | ceria dashboard |
| Scan network | ceria scan 192.168.1.0/24 |
| View sessions | ceria sessions |
| Generate demo data | ceria demo-data --count 500 |
| Export CSV from CLI | ceria report --session 1 --format csv --output out.csv |
Web Dashboard URLs
| Page | URL |
| Dashboard | / |
| Start Scan | /scan |
| Scan Results | /scan/{id} |
| All Devices | /inventory |
| Device Detail | /inventory/{id} |
| Certificates | /certificates |
| Risk Report | /report |
| Generated Reports | /report-exports |
| Settings | /settings |
Need Help?
See MANUAL.md for complete documentation.
Installation
Requirements
- Python 3.10+
- nmap (system package)
- OpenSSL libraries
Local Installation
# Clone repository
git clone <repo-url>
cd pqc
# Install with pip
pip install -e .
# Or install development dependencies
pip install -e ".[dev]"
# Verify installation
ceria --version
Environment Setup
Create .env file:
# Required
SECRET_KEY=your-secure-secret-key-here
DATABASE_URL=sqlite:///ceria.db
# Optional
DASHBOARD_HOST=0.0.0.0
DASHBOARD_PORT=8080
NCII_SECTOR=digital
# SSH Credentials (for remote collectors)
SSH_USERNAME=admin
SSH_PASSWORD=your-ssh-password
SSH_KEY_PATH=/path/to/private/key
# Database Scan Credentials
DB_SCAN_USERNAME=db_user
DB_SCAN_PASSWORD=db_password
NCII Sectors
Available sectors: defense, finance, healthcare, telecom, energy, transport, water, waste, gov, broadcast, digital
→ Next: Quick Start
Report Generation Dependencies
Install the project with its declared dependencies to enable all exports. WeasyPrint generates PDFs, while openpyxl populates the official PQC Excel workbook. The application account must be able to write to outputs/reports.
Overview
What is CERIA?
CERIA discovers cryptographic assets across your network infrastructure and prioritizes them for Post-Quantum Cryptography (PQC) migration.
Main dashboard showing network-wide PQC readiness
Why PQC Migration?
Quantum computers will break current cryptographic algorithms:
- RSA (all key sizes)
- ECDSA/ECDH (all curves)
- DSA/DSS
- Diffie-Hellman
The Threat Timeline
| Year | Milestone |
| 2024-2029 | PQC standards finalized (NIST) |
| 2030 | Malaysia NCII: Symmetric crypto migration deadline |
| 2035 | Malaysia NCII: Asymmetric crypto migration deadline |
| 2035+ | Cryptographically relevant quantum computer expected |
Key Features
1. Automated Discovery
Configure network scans with multiple collectors
2. Risk-Based Prioritization
SCAD framework ranks devices by migration urgency
3. Certificate Management
Track all certificates with PQC readiness status
4. Compliance Reporting
Generate reports for:- MySEAL (Malaysia)
- MyKriptografi NCII
- NACSA standards
Who Should Use CERIA?
- CISOs - Strategic PQC migration planning
- Security Engineers - Technical asset discovery
- Compliance Officers - Regulatory reporting
- System Administrators - Device inventory management
Supported Platforms
| Platform | Status |
| Web Dashboard | ✅ Full support |
| CLI | ✅ Full support |
| Linux | ✅ Primary |
| macOS | ✅ Supported |
| Windows (WSL) | ✅ Supported |
| cPanel Hosting | ✅ Documented |
Next: Architecture
Enterprise Dataset and Reporting
CERIA supports demo assessments with up to 500 devices. Inventory and risk tables paginate these datasets, while export jobs run in the backend and remain available from Generated Reports.
Architecture
System Overview
CERIA Architecture Diagram
Data Flow
1. Network Discovery
Target Range → nmap scan → Live hosts → Port detection → Device records
2. Cryptographic Collection
Device + Open Ports → Collector selection → Asset scanning → Crypto assets
3. Risk Analysis
Crypto assets → SCAD scoring → HNDL calculation → Priority ranking
4. Reporting
Prioritized assets → Visualization → Export (PDF/CSV/CBOM)
Collector Types
Example: Device showing multiple crypto asset types
| Collector | Port | Protocol | Credential Required |
| TLS/SSL | 443 | HTTPS | No |
| SSH | 22 | SSH | Optional |
| VPN | 500/4500 | IKE/IPSec | No |
| Database | 5432/3306 | Various | Yes |
| OS Crypto | - | SSH | Yes |
| App Config | - | SSH | Yes |
| Cert Store | - | SSH | Yes |
Database Schema
Core Tables
devices- Network devices discoveredcrypto_assets- Cryptographic findingscertificates- X.509 certificatesrisk_scores- Calculated risk scoresscan_sessions- Scan metadatausers- Authentication
Relationships
ScanSession (1) ──▶ (N) Device (1) ──▶ (N) CryptoAsset
──▶ (N) Certificate
──▶ (1) RiskScore
Next: Scanning Features
Report Export Pipeline
/report Export to -> POST /api/v1/reports/exports -> persistent ReportExport job
-> background worker -> WeasyPrint / openpyxl / CSV / JSON / CycloneDX
-> unique file in outputs/reports -> download or delete from /report-exports
Queued and processing jobs continue when users navigate away. Startup recovery resumes queued work and safely marks interrupted jobs.
User Manual
A comprehensive guide for the Post-Quantum Cryptography Scanner implementing Malaysia's NCII (National Critical Information Infrastructure) SCAD Framework.
Table of Contents
- Overview
- Architecture
- Installation & Setup
- CLI Usage
- Web Dashboard
- Scanning Features
- Cryptographic Collectors
- Risk Scoring (SCAD Framework)
- HNDL Risk Calculator
- Certificate Management
- Compliance & Reporting
- Migration Planning
- API Reference
- Troubleshooting
Overview
PQC Scanner discovers cryptographic assets across your network and prioritizes them for Post-Quantum Cryptography (PQC) migration based on the 7-criterion SCAD Framework.
Key Features
- 7 Cryptographic Collectors: TLS/SSL, SSH, VPN, Database, OS Crypto, App Config, Certificate Stores
- SCAD Risk Scoring: 7-criterion framework for PQC migration prioritization
- HNDL Risk Calculator: Mosca's Inequality implementation for quantum exposure risk
- Certificate Chain Analysis: Full chain PQC assessment with CA roadmap tracking
- Vendor Readiness Tracking: Cisco, Juniper, Fortinet, AWS, Azure, and more
- MySEAL/MyKriptografi Compliance: Malaysia NCII compliance reporting
- Web Dashboard: Real-time scanning, visualization, and reporting
- CLI Interface: Full command-line access for automation
Technology Stack
- Backend: Python 3.11, FastAPI, SQLAlchemy, SQLite
- Frontend: Jinja2 templates, Tailwind CSS, Chart.js, G6 v5 (AntV)
- CLI: Click-based interface
- Scanning: python-nmap, sslyze, paramiko, cryptography
Architecture
Scanner Pipeline:
Network Discovery (nmap) → Port Detection → Collector Execution → Risk Scoring → DB Storage
├── Network Discovery
│ └── nmap host discovery, OS fingerprinting, port scanning
│
├── Cryptographic Collectors
│ ├── TLS/SSL (sslyze + banner fallback)
│ ├── SSH (ssh-audit + nmap scripts)
│ ├── VPN (IKE probes)
│ ├── Database (TDE check)
│ ├── OS Crypto (certificate stores)
│ ├── App Config (configuration files)
│ └── Certificate Store (system stores)
│
├── Risk Analysis
│ ├── SCAD 7-criterion scoring
│ ├── HNDL risk calculation
│ ├── Certificate chain analysis
│ └── Vendor readiness assessment
│
└── Reports & Compliance
├── MySEAL compliance checking
├── Migration recommendations
├── CBOM export (CycloneDX)
├── PDF/CSV/JSON reports
└── G6 dependency graphs
Installation & Setup
Requirements
- Python 3.10+
- nmap (system package)
- OpenSSL libraries
Installation
# Clone repository
git clone <repo-url>
cd pqc
# Install with pip
pip install -e .
# Or install development dependencies
pip install -e ".[dev]"
# Verify installation
pqcs --version
Configuration
Environment Variables (.env file)
# Required
SECRET_KEY=your-secure-secret-key-here
DATABASE_URL=sqlite:///pqcs.db
# Optional
DASHBOARD_HOST=0.0.0.0
DASHBOARD_PORT=8080
NCII_SECTOR=digital
# SSH Credentials (for remote collectors)
SSH_USERNAME=admin
SSH_PASSWORD=your-ssh-password
SSH_KEY_PATH=/path/to/private/key
# Database Scan Credentials
DB_SCAN_USERNAME=db_user
DB_SCAN_PASSWORD=db_password
NCII Sectors
Available sectors: defense, finance, healthcare, telecom, energy, transport, water, waste, gov, broadcast, digital
CLI Usage
Global Options
pqcs [OPTIONS] COMMAND [ARGS]...
Options:
--db-url TEXT Database URL (env: DATABASE_URL)
--verbose, -v Enable debug logging
--version Show version
--help Show help
Commands
1. Scan Network
# Basic scan
ceria scan 192.168.1.0/24
# Named scan
ceria scan 192.168.1.0/24 --name "Production Network Scan"
# Specific collectors only
ceria scan 192.168.1.0/24 --collectors tls,ssh,vpn
# All available collectors
ceria scan 192.168.1.0/24 --collectors tls,ssh,vpn,db,os_crypto,app_config,cert_store
Available Collectors:
tls- TLS/SSL certificates and cipher suitesssh- SSH algorithms and host keysvpn- VPN/IKE configurationdb- Database encryption (TDE)os_crypto- OS certificate storesapp_config- Application crypto configscert_store- Certificate stores
2. Network Discovery
# Discover hosts without full crypto scan
ceria discover 192.168.1.0/24 --ports 22,443,8443
3. Generate Reports
# Table format (console)
ceria report --session 1 --format table
# Filter by priority
ceria report --session 1 --priority CRITICAL --format table
# Export to CSV
ceria report --session 1 --format csv --output report.csv
# Export to JSON
ceria report --session 1 --format json --output report.json
# Export to PDF
ceria report --session 1 --format pdf --output report.pdf
# Export CBOM (CycloneDX)
ceria report --session 1 --format cbom --output cbom.json
4. List Sessions
ceria sessions
5. Launch Dashboard
# Default port 8080
ceria dashboard
# Custom port
ceria dashboard --port 3000 --host 127.0.0.1
Web Dashboard
Access
http://localhost:8080 (local)
https://pqcs.dysfunktion.tech (deployed)
Pages
| Page | URL | Description |
| Login | /login | JWT authentication |
| Dashboard | / | Summary, device table, charts, topology |
| Scan Control | /scan | Configure and run network scans |
| Scan Detail | /scan/{id} | Full scan results with expandable devices |
| Inventory | /inventory | Paginated devices with filters and sorting |
| Device Detail | /inventory/{id} | Device tiering, migration tracking, HNDL |
| Port Detail | /inventory/{device_id}/ports/{port} | Port-specific crypto details |
| Certificates | /certificates | Certificate store with PQC assessment |
| Cert Detail | /certificates/{id} | Chain analysis, PEM viewer, CA roadmap |
| HNDL Detail | /hndl | Harvest Now Decrypt Later risk analysis |
| Report | /report | Paginated risk assessment, visualizations, and Export to menu |
| Generated Reports | /report-exports | Export queue progress, downloads, type tabs, and deletion |
| Settings | /settings | Credentials, ports, scoring weights, scheduling |
| Profile | /profile | User management, password change |
| Asset Detail | /asset | Individual crypto asset deep dive |
Enterprise Demo Data
ceria demo-data --count 500 --snapshots 4 --seed 20260722
The command backs up SQLite before creating a deterministic enterprise dataset. It covers all supported vendors, infrastructure archetypes, collector detection types, priority bands, and varied HNDL outcomes. Use --append to retain existing scan-domain data.
Queued Report Exports
See Report Exports for the complete workflow and screenshots.
The /report Export to dropdown queues PDF, PQC Excel, CBOM, CSV, or JSON generation. Progress comes from the backend worker. Completed exports receive timestamped UUID-based filenames.
The /report-exports page lists all jobs with tabs by type. Active jobs show progress; completed jobs can be downloaded or deleted. PDF generation uses WeasyPrint, and PQC Excel generation populates the official workbook while preserving template formatting and reference content.
Scanning Features
Network Discovery
Uses nmap for:
- Host discovery (ping sweep)
- OS fingerprinting
- Port scanning
- Service version detection
Scanning Modes
1. Quick Scan
- Basic nmap scan
- TLS/SSH banner grabbing
- Certificate extraction
2. Deep Scan
- Full sslyze analysis
- SSH algorithm enumeration (ssh-audit)
- IKE probing for VPNs
- Certificate chain extraction
3. Credential-based Scan
Requires SSH credentials for:- OS crypto store analysis
- Application config extraction
- Certificate store enumeration
Port Coverage
Default ports scanned:
SSH: 22, 2222
TLS/HTTPS: 443, 8443, 4443, 993, 995, 990, 636, 3269, 8080, 9090
VPN: 500, 4500, 1194, 1723
Database: 5432, 1433, 3306, 1521, 27017, 6379, 9042
Mail: 143, 993, 110, 995, 25, 465, 587
LDAP/Kerberos: 389, 636, 88, 3268, 3269
RDP/VNC: 3389, 5900, 5901
SMB: 135, 139, 445
DNS: 53
Docker/K8s: 2375, 2376, 6443, 10250, 10255
Monitoring: 9090, 3000, 9100
MQTT: 1883, 8883
Redis/Memcached: 6379, 11211
Elasticsearch: 9200, 9300
RabbitMQ: 5672, 15672
Zookeeper: 2181
Cassandra: 9042, 9160
MongoDB: 27017, 27018
Add custom ports in Settings page (supports ranges like 9000-9010).
Cryptographic Collectors
1. TLS/SSL Collector
Scans for:- TLS versions (1.0, 1.1, 1.2, 1.3)
- Cipher suites (quantum-vulnerable vs PQC-ready)
- Certificate chains
- Weak signatures (MD5, SHA-1)
- Hybrid certificates (PQC + Traditional)
{
"port": 443,
"tls_version": "TLSv1.2",
"cipher_suite": "ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"certificate_info": {...},
"chain_analysis": {...},
"confidence": 0.95
}
2. SSH Collector
Scans for:- Key algorithms (RSA, ECDSA, Ed25519)
- KEX algorithms
- MAC algorithms
- Weak curves (secp192, secp224)
- Deprecated algorithms (ssh-rsa, diffie-hellman-group1-sha1)
- Banner analysis: 0.8
- Full ssh-audit: 0.95
- Weak curve detection: 0.9
3. VPN Collector
Scans for:- IKE version (v1, v2)
- Transform proposals
- DH groups
- Authentication methods
4. Database Collector
Scans for:- Transparent Data Encryption (TDE) status
- Connection encryption
- SSL/TLS configuration
5. OS Crypto Collector
Scans for:- System certificate stores
- Trusted root CAs
- Installed certificates
- Key stores
6. App Config Collector
Scans for:- Crypto config files (OpenSSL, Java keystores)
- Algorithm configurations
- Protocol settings
7. Certificate Store Collector
Scans for:- Certificate files (.pem, .crt, .p12)
- Trust stores
- Private key files
Risk Scoring (SCAD Framework)
The SCAD (System Cryptographic Asset Demand) Framework uses 7 criteria with adjustable weights (must sum to 100%):
Criteria Descriptions
| Criterion | Weight | Description |
| Data Lifespan | 20% | How long data must remain confidential |
| Algorithm Vulnerability | 25% | Known vulnerabilities in current algorithms |
| Key Size | 15% | RSA key size or ECC curve strength |
| System Criticality | 15% | Importance to business operations |
| Legacy Status | 10% | End-of-life systems harder to migrate |
| Third Party Dependency | 10% | External dependencies affecting migration |
| NCII Sector | 5% | Malaysia NCII sector classification |
Priority Levels
| Score Range | Priority | Action |
| 80-100 | CRITICAL | Immediate migration required |
| 60-79 | HIGH | Plan migration within 6 months |
| 40-59 | MEDIUM | Plan migration within 12 months |
| 20-39 | LOW | Plan migration within 24 months |
| 0-19 | MINIMAL | Track for future migration |
Adjusting Weights
- Go to Settings page
- Modify criterion weights (must sum to 100%)
- Click Save
- Re-run scan to apply new weights
HNDL Risk Calculator
Harvest Now, Decrypt Later (HNDL)
Implements Mosca's Inequality: X + Y > Z
Where:
- X = Years data must remain secret (Data Lifespan)
- Y = Years to migrate to PQC (Migration Time)
- Z = Years until quantum computers break current crypto (Q-Day estimate)
Risk Levels
| X+Y vs Z | Risk Level | Color |
| X+Y >> Z | CRITICAL | Red |
| X+Y > Z | HIGH | Orange |
| X+Y ≈ Z | MODERATE | Yellow |
| X+Y < Z | LOW | Green |
| X+Y << Z | MINIMAL | Blue |
Setting Data Retention
- Go to Inventory → Select Device
- Click Edit on tiering section
- Set Data Retention (Years)
- Save changes
HNDL risk auto-recalculates.
Certificate Management
Certificate Discovery
Automatically extracts and stores:
- Leaf certificates
- Intermediate CAs
- Root CAs
- Chain relationships
Certificate Analysis
For each certificate:
- PQC Status: Ready / Vulnerable / Transitioning
- Algorithm: RSA, ECDSA, Ed25519, ML-DSA, etc.
- Key Size: 2048, 4096, P-256, P-384, etc.
- Signature: SHA-256, SHA-384, SHA-1 (weak)
- Expiry: Days remaining
- CA Roadmap: Vendor's PQC transition plan
Chain Analysis
Root CA (PQC Status)
↓ trusts
Intermediate CA (PQC Status, Hybrid?)
↓ issues
Leaf Certificate (PQC Status, Algorithm)
Chain risk based on weakest link.
CA Roadmap Database
Tracks vendor PQC readiness:
- DigiCert
- Let's Encrypt
- Sectigo
- GlobalSign
- Entrust
- AWS ACM
- Azure Key Vault
- Google Trust Services
Download Certificates
From certificate detail page:
- PEM format: Full chain
- Individual: Leaf only
Compliance & Reporting
MySEAL Compliance
Malaysia's MySEAL (Malaysia Security Evaluation and Assurance Lab) approved algorithms.
Checks:- Approved encryption algorithms
- Approved signature algorithms
- Key size compliance
- Random number generation
- Compliance status per device
- Non-compliant algorithms list
- Recommendations for compliance
MyKriptografi NCII
Malaysia NCII (National Critical Information Infrastructure) requirements.
PQC Transition Timeline:- 2030: Symmetric crypto migration
- 2035: Asymmetric crypto migration
Schedule Re-Scans
- Go to Settings
- Under Automatic Re-Scan:
- Enable scheduled scans
- Select frequency: Daily, Weekly, Monthly, Quarterly
- Set scan time
- Save settings
Drift Detection
Compares scan results over time:
- Algorithm changes
- Cipher suite changes
- Certificate changes
- New vulnerabilities
Alerts for:
- Cryptographic Drift: Algorithm/cipher changes
- Expiry Warnings: Certificate expiring <30 days
- New Vulnerabilities: CVE detection
Migration Planning
Migration Advisor
File:pqcs/analysis/migration_advisor.py
Analyzes crypto patterns and provides step-by-step migration plans for:
Patterns Supported
| Pattern | Description |
rsa-2048-tls | TLS using RSA-2048 certificates |
rsa-4096-tls | TLS using RSA-4096 certificates |
ecdsa-p256-tls | TLS using ECDSA P-256 |
ssh-rsa-deprecated | SSH using deprecated ssh-rsa |
ssh-ecdsa | SSH using ECDSA host keys |
vpn-ikev2-rsa | VPN IKEv2 with RSA authentication |
db-tde-rsa | Database TDE using RSA |
java-keystore-rsa | Java keystore with RSA certs |
openssl-server-rsa | OpenSSL server config |
Migration Plan Structure
For each pattern:
- Current State: What was detected
- Target State: PQC-ready replacement
- Migration Steps: Numbered procedures
- Caveats: Known issues or blockers
- Rollback: How to revert if needed
- Resources: Official docs and guides
Critical Path Analysis
File:pqcs/analysis/dependency_graph.py
Identifies migration order:
1. Root CAs (highest priority)
2. Intermediate CAs
3. Leaf certificates
4. Device configurations
Dependencies visualized as G6 graph with risk-based coloring.
API Reference
Authentication Endpoints
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "admin",
"password": "password"
}
Response:
{
"status": "ok",
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": 1,
"username": "admin",
"role": "admin"
}
}
Scan Endpoints
# Start scan
POST /api/v1/scans/start
Authorization: Bearer <token>
Content-Type: application/json
{
"target_range": "192.168.1.0/24",
"session_name": "Test Scan",
"collectors": ["tls", "ssh"]
}
# Get scan status
GET /api/v1/scans/{session_id}/status
# Get scan results
GET /api/v1/scans/{session_id}/results
# Get scan log
GET /api/v1/scans/{session_id}/log
Device Endpoints
# List devices
GET /api/v1/devices
# Get device details
GET /api/v1/devices/{device_id}
# Update device tiering
PUT /api/v1/devices/{device_id}/tiering
Content-Type: application/json
{
"tier": "critical",
"data_retention_years": 10,
"criticality": "high"
}
# Get device assets
GET /api/v1/devices/{device_id}/assets
# Get score history
GET /api/v1/devices/{device_id}/score-history
Certificate Endpoints
# List certificates
GET /api/v1/certificates
# Get certificate details
GET /api/v1/certificates/{cert_id}
# Download certificate
GET /api/v1/certificates/{cert_id}/download
# Get certificate chain
GET /api/v1/certificates/{cert_id}/chain
Visualization Endpoints
# Network topology (G6 format)
GET /api/v1/devices/network-topology
# Risk heatmap data
GET /api/v1/devices/risk-heatmap
# Expiry timeline
GET /api/v1/devices/expiry-timeline
# Certificate chain graph
GET /api/v1/certificates/graph
Settings Endpoints
# Get settings
GET /api/v1/settings
# Update settings
PUT /api/v1/settings
Content-Type: application/json
{
"scan_rate_limit": "10",
"default_scan_timeout": "300"
}
# Get scoring weights
GET /api/v1/scoring/weights
# Update weights
PUT /api/v1/scoring/weights
Content-Type: application/json
{
"data_lifespan": "20",
"algorithm_vulnerability": "25",
"key_size": "15",
"system_criticality": "15",
"legacy_status": "10",
"third_party_dependency": "10",
"ncii_sector": "5"
}
Troubleshooting
Common Issues
1. Port Permission Denied (macOS/Linux)
# macOS
sudo ceria dashboard --port 80
# Linux (CAP_NET_BIND_SERVICE)
sudo setcap cap_net_bind_service=+ep $(which python)
2. Nmap Not Found
# Install nmap
# Ubuntu/Debian
sudo apt-get install nmap
# macOS
brew install nmap
# Windows
choco install nmap
3. Database Connection Issues
# Check database permissions
ls -la pqcs.db
chmod 644 pqcs.db
# Or use absolute path
DATABASE_URL=sqlite:////home/user/db/pqcs.db ceria dashboard
4. SSH Connection Failures
- Verify SSH credentials in Settings
- Check SSH host key is known (
~/.ssh/known_hosts) - Verify firewall allows SSH (port 22)
- Check SSH user has sudo/admin rights for collectors
5. Certificate Parsing Errors
Some certificates may fail to parse due to:
- Non-standard formats
- Corrupted PEM data
- Unusual extensions
These are logged but don't stop the scan.
Log Locations
| Platform | Log Location |
| Local | Console output (use --verbose) |
| cPanel | /home2/yusricom/logs/passenger.log |
| systemd | journalctl -u pqcs |
Debug Mode
# Enable debug logging
pqcs --verbose dashboard
# Or set environment variable
export LOG_LEVEL=DEBUG
ceria dashboard
Security Considerations
Credential Storage
- SSH passwords stored encrypted in database
- SSH keys can be used instead of passwords
- API tokens (JWT) expire after 24 hours
Network Security
- Scanner uses standard ports only
- No exploitable services exposed
- All scan data stored locally
Data Protection
- Database contains sensitive crypto info
- Use strong SECRET_KEY
- Restrict database file permissions
- Enable HTTPS for web dashboard
Advanced Topics
Custom Collectors
Create new collectors by extending BaseCollector:
from pqcs.scanner.collectors.base import BaseCollector
class MyCollector(BaseCollector):
asset_type = "myprotocol"
def collect(self, device: Device) -> list[dict]:
assets = []
# Your scanning logic here
if self._port_is_open(device, 1234):
assets.append({
"port": 1234,
"asset_type": "myprotocol",
"protocol_version": "1.0",
"algorithm": "RSA-2048",
})
return assets
Custom Scoring
Modify criteria.py to add new algorithm checks.
API Integration
Use the REST API to integrate with external systems:
import requests
# Login
r = requests.post("https://pqcs/api/v1/auth/login", json={
"username": "admin",
"password": "password"
})
token = r.json()["token"]
# Start scan
requests.post("/api/v1/scans/start",
headers={"Authorization": f"Bearer {token}"},
json={"target_range": "10.0.0.0/24"}
)
Development
Running Tests
pytest tests/
pytest tests/ -v # verbose
pytest tests/test_scoring.py # specific test
Code Style
# Lint
ruff check pqcs/
# Format
ruff format pqcs/
# Type check
mypy pqcs/
Project Structure
pqcs/
├── __init__.py
├── __main__.py # Entry point
├── cli.py # CLI commands
├── config.py # Configuration
├── db.py # Database models
├── web/ # Web dashboard
│ ├── app.py # FastAPI app
│ ├── routes.py # API routes
│ ├── middleware.py # Auth & rate limiting
│ └── templates/ # HTML templates
├── scanner/ # Scanning engine
│ ├── engine.py # Orchestrator
│ ├── network_discovery.py
│ ├── runner.py # Web scan runner
│ └── collectors/ # Crypto collectors
├── scoring/ # Risk scoring
│ ├── engine.py
│ ├── criteria.py # Algorithm DB
│ └── hndl_calculator.py
├── analysis/ # Analysis tools
│ ├── migration_advisor.py
│ └── dependency_graph.py
├── compliance/ # Compliance checking
│ └── myseal.py
└── reporting/ # Export formats
├── csv_export.py
├── json_export.py
├── pdf_export.py
└── template_export.py
License
MIT License - See LICENSE file
Support
For issues, feature requests, or questions:
- Check troubleshooting section above
- Review AGENTS.md for development context
- Open an issue in the repository
Version: 0.1.0 Last Updated: 2026-07-22
Web Dashboard
Access
http://localhost:8080 (local)
https://pqcs.dysfunktion.tech (deployed)
Pages
Public Pages
| Page | URL | Description | Screenshot |
| Login | /login | JWT authentication | ![]() |
Protected Pages
| Page | URL | Description |
| Dashboard | / | Summary, device table, charts, topology |
| Scan Control | /scan | Configure and run network scans |
| Scan Detail | /scan/{id} | Full scan results with expandable devices |
| Inventory | /inventory | All devices with filters and sorting |
| Device Detail | /inventory/{id} | Device tiering, migration tracking, HNDL |
| Certificates | /certificates | Certificate store with PQC assessment |
| HNDL Detail | /hndl | Harvest Now Decrypt Later risk analysis |
| Report | /report | Visualization: heatmap, timeline, expiry charts |
| Settings | /settings | Credentials, ports, scoring weights, scheduling |
| Profile | /profile | User management, password change |
Dashboard Overview
The main dashboard provides a comprehensive view of your network's PQC readiness:
Main dashboard with device summary, risk distribution, and PQC readiness gauge
Scan Configuration
Configure and start network scans from the Scan Control page:
Scan configuration - select collectors, set target range, and start scanning
Device Management
View all discovered devices in the Inventory:
Device inventory with filtering, sorting, and risk scores
Device Detail View
Deep dive into individual device analysis:
Device detail showing HNDL risk, crypto assets, and score breakdown
Individual cryptographic assets per device
Certificate Management
Browse discovered certificates with PQC status:
Certificate store with PQC assessment and expiry tracking
Reports & Visualization
View risk heatmaps and compliance reports:
Risk heatmap, certificate expiry timeline, and PQC readiness charts
Detailed analytics and reporting visualizations
HNDL Risk Analysis
Access Mosca's Inequality calculator:
Harvest Now Decrypt Later risk analysis dashboard
Settings & Configuration
Configure scanning parameters and scoring weights:
Application settings with SSH credentials, custom ports, and auto-scan scheduling
SCAD risk scoring weights configuration
Risk Priority Dashboard
Monitor critical devices requiring immediate attention:
Risk priority cards highlighting CRITICAL and HIGH priority devices
Navigation
Use the sidebar menu to navigate between pages. The dashboard shows:
- Total devices scanned
- Risk distribution (CRITICAL, HIGH, MEDIUM, LOW, MINIMAL)
- PQC readiness gauge
- Recent scan activity
- Network topology graph
Screenshots
See detailed screenshots in Screenshots Gallery
Quick preview:
- Dashboard - Main dashboard
- Scan Control - Scan configuration
- Device Inventory - Device list
- HNDL Risk Analysis - HNDL calculator
Large Inventory Navigation
Device Inventory and Device Risk Assessment paginate large device collections. Use the previous/next controls and page-size selector instead of loading every device into one table.
Exporting Reports
See complete export guide for formats, queue behavior, downloads, deletion, and troubleshooting.
On /report, select Export to and choose PDF, PQC Excel, CBOM, CSV, or JSON. CERIA queues the job and displays backend progress. Completion exposes a direct download link and success message.
Open Generated Reports at /report-exports to view all jobs. Tabs filter by type, active jobs show progress, and completed or failed jobs can be deleted.
Report Exports
Overview
CERIA generates reports through a persistent backend queue. Export requests continue if you leave the page, and completed files remain available from Generated Reports until they are deleted.
Open the Export Menu
- Open
/report. - Select Export to in the report header.
- Choose the required format.
The report page immediately queues the export and shows live backend progress. A successful job displays its unique filename and a download action.
Export Formats
| Format | Contents | Recommended use |
| Visual executive assessment generated with WeasyPrint | Management review and formal reporting | |
| PQC Excel | Official workbook template populated with project, inventory, discovery, and risk data | Structured assessment and migration planning |
| CBOM | CycloneDX cryptographic bill of materials | Tool integration and machine-readable inventory |
| CSV | Device risk register | Spreadsheet analysis and filtering |
| JSON | Detailed devices, scores, assets, and certificate data | API integration and complete data exchange |
Generated Reports
Open /report-exports or select Generated Reports from the report page.
The page provides:
- Tabs for all exports, PDF, PQC Excel, CBOM, CSV, and JSON.
- Live progress for queued and processing jobs.
- Success and failure status messages.
- Unique timestamp and UUID-based filenames.
- Download actions for completed reports.
- Delete actions for completed or failed jobs.
Active jobs cannot be deleted. CERIA returns a conflict response until generation completes or fails.
Job Lifecycle
Queued -> Processing -> Completed
-> Failed
Job metadata is stored in the database. Files are written safely through a temporary .part file and moved into place only when complete. On startup, CERIA recovers queued jobs and reconciles interrupted work.
API Workflow
Queue an export:
POST /api/v1/reports/exports
Content-Type: application/json
{"export_type": "pdf"}
Monitor and manage it:
GET /api/v1/reports/exports
GET /api/v1/reports/exports/{job_id}
GET /api/v1/reports/exports/{job_id}/download
DELETE /api/v1/reports/exports/{job_id}
PDF Export
PDF generation uses WeasyPrint and a dedicated print layout. The report contains the current assessment details, visual summaries, risk information, migration context, and device-level findings without requiring browser rendering.
PQC Excel Export
PQC Excel generation uses docs/PQC Template.xlsx and preserves the template structure and formatting. The operational sheets are populated with:
- Project and assessment information.
- Enterprise asset inventory.
- Cryptographic discovery results.
- Device risk assessment data.
Troubleshooting
- Confirm the application account can write to
outputs/reports. - Confirm WeasyPrint and its required platform libraries are installed for PDF generation.
- Confirm
docs/PQC Template.xlsxexists for PQC Excel generation. - Review the failure message shown in Generated Reports.
- Restart CERIA to recover jobs that remain queued after an interrupted shutdown.
CLI Usage
Global Options
ceria [OPTIONS] COMMAND [ARGS]...
Options:
--db-url TEXT Database URL (env: DATABASE_URL)
--verbose, -v Enable debug logging
--version Show version
--help Show help
Commands
CLI dashboard view when running ceria dashboard
1. Scan Network
# Basic scan
ceria scan 192.168.1.0/24
# Named scan
ceria scan 192.168.1.0/24 --name "Production Network Scan"
# Specific collectors only
ceria scan 192.168.1.0/24 --collectors tls,ssh,vpn
# All available collectors
ceria scan 192.168.1.0/24 --collectors tls,ssh,vpn,db,os_crypto,app_config,cert_store
Available Collectors:
tls- TLS/SSL certificates and cipher suitesssh- SSH algorithms and host keysvpn- VPN/IKE configurationdb- Database encryption (TDE)os_crypto- OS certificate storesapp_config- Application crypto configscert_store- Certificate stores
Sample scan output in terminal:
[2026-07-22 10:00:01] INFO: Starting scan: My First Scan
[2026-07-22 10:00:05] INFO: Port scan: Found 24 hosts
[2026-07-22 10:00:12] INFO: TLS collector: 15 certificates collected
[2026-07-22 10:00:18] INFO: SSH collector: 8 SSH servers found
[2026-07-22 10:00:25] INFO: Cert collector: 22 certificates discovered
[2026-07-22 10:00:30] INFO: Scan completed in 29.4s
2. Network Discovery
# Discover hosts without full crypto scan
ceria discover 192.168.1.0/24 --ports 22,443,8443
3. Generate Reports
# Table format (console)
ceria report --session 1 --format table
# Filter by priority
ceria report --session 1 --priority CRITICAL --format table
# Export to CSV
ceria report --session 1 --format csv --output report.csv
# Export to JSON
ceria report --session 1 --format json --output report.json
# Export to PDF
ceria report --session 1 --format pdf --output report.pdf
# Export CBOM (CycloneDX)
ceria report --session 1 --format cbom --output cbom.json
Sample table output:
IP Address | Hostname | Priority | Algorithms
--------------+-------------+-----------+------------------
192.168.1.10 | web-server | CRITICAL | RSA-1024
192.168.1.20 | mail-server | HIGH | RSA-2048, SHA-1
192.168.1.30 | db-server | MEDIUM | RSA-2048
4. List Sessions
ceria sessions
Output:
ID | Name | Status | Devices | Started
----+-------------------------+------------+---------+-------------------
1 | My First Scan | completed | 24 | 2026-07-22 10:00
2 | Production Network Scan | running | 12 | 2026-07-22 11:30
5. Launch Dashboard
# Default port 8080
ceria dashboard
# Custom port
ceria dashboard --port 3000 --host 127.0.0.1
Opens web interface at http://localhost:8080 (or your specified port).
Enterprise Demo Data
ceria demo-data --count 500 --snapshots 4 --seed 20260722
This creates a timestamped SQLite backup before replacing scan-domain records. Use --append to retain scan data, --backup-dir to choose the backup location, and --seed to reproduce a dataset.
Scanning Features
Network Discovery
CERIA uses nmap for initial host discovery:
Discovery Methods
- ARP scan (local network)
- ICMP echo (ping sweep)
- TCP SYN (port probing)
- OS fingerprinting
Port Scanning
Default ports include:
- SSH: 22, 2222
- TLS/HTTPS: 443, 8443, 8080
- VPN: 500, 4500, 1194
- Database: 5432, 1433, 3306
- Mail: 993, 995, 465
- Plus 50+ more
Custom Ports
Add custom ports in Settings:
Format: ports or ranges
Example: 9000,9001,9002-9010,10000
Configure custom ports in Settings
Scanning Modes
Quick Scan
- Basic nmap discovery
- TLS/SSH banner analysis
- Certificate extraction
- Duration: 2-5 minutes
Deep Scan
- Full sslyze analysis
- SSH algorithm enumeration
- IKE probing
- Certificate chain extraction
- Duration: 10-30 minutes
Credential-Based Scan
Requires SSH credentials for:- OS certificate store enumeration
- Application config extraction
- System crypto settings
Scan results showing discovered devices
Scan Scheduling
Automated Re-scans
- Go to Settings
- Enable Automatic Re-scan
- Select frequency:
- Daily - Every day
- Weekly - Selected day
- Monthly - Selected date
- Quarterly - Every 3 months
Drift Detection
Compares scan results over time:
- Algorithm changes
- Certificate updates
- New vulnerabilities
- Configuration drift
Alerts for significant changes.
Scan Performance
Network Size Recommendations
| Network Size | Timeout | Concurrent Hosts |
| /24 (254) | 5 min | 50 |
| /23 (510) | 10 min | 50 |
| /22 (1,022) | 20 min | 50 |
| /16 (65k) | 60 min | 25 |
Tune via Settings page.
See also: Cryptographic Collectors
Demonstration Coverage
The generator creates network infrastructure, security appliances, servers, endpoints, cloud services, databases, operational technology, storage, identity, and communications devices. Findings cover all supported vendors and collector detection types, including vulnerable, transitional, and PQC-ready algorithms.
Risk Scoring
The SCAD (System Cryptographic Asset Demand) Framework uses 7 criteria with adjustable weights (must sum to 100%).
Dashboard View
Risk priority distribution on main dashboard
Configuring Weights
Adjust SCAD framework weights in Settings page
Criteria Descriptions
| Criterion | Weight | Description |
| Algorithm Vulnerability | 25% | Known vulnerabilities in current algorithms |
| Data Lifespan | 20% | How long data must remain confidential |
| Key Size | 15% | RSA key size or ECC curve strength |
| System Criticality | 15% | Importance to business operations |
| Legacy Status | 10% | End-of-life systems harder to migrate |
| Third Party Dependency | 10% | External dependencies affecting migration |
| NCII Sector | 5% | Malaysia NCII sector classification |
Priority Levels
| Score Range | Priority | Action |
| 80-100 | CRITICAL | Immediate migration required |
| 60-79 | HIGH | Plan migration within 6 months |
| 40-59 | MEDIUM | Plan migration within 12 months |
| 20-39 | LOW | Plan migration within 24 months |
| 0-19 | MINIMAL | Track for future migration |
Adjusting Weights
- Go to Settings page
- Modify criterion weights (must sum to 100%)
- Click Save
- Re-run scan to apply new weights
Industry-Specific Configurations
Financial Services
Algorithm Vulnerability: 30%
Data Lifespan: 25%
System Criticality: 20%
Key Size: 10%
Legacy Status: 5%
Third Party: 5%
NCII Sector: 5%
Healthcare
Data Lifespan: 35%
Algorithm Vulnerability: 25%
System Criticality: 15%
Key Size: 10%
Legacy Status: 5%
Third Party: 5%
NCII Sector: 5%
See Screenshots Gallery for more views.
Demo Risk Distribution
Demo datasets distribute SCAD scores and priorities across the supported range. HNDL values come from varied retention, migration, and quantum-timeline inputs, so devices do not receive identical severity scores.
HNDL Calculator
HNDL Overview Dashboard
Harvest Now Decrypt Later summary on dashboard
Mosca's Inequality
Implements Mosca's Inequality: X + Y > Z
Where:
- X = Years data must remain secret (Data Lifespan)
- Y = Years to migrate to PQC (Migration Time)
- Z = Years until quantum computers break current crypto (Q-Day estimate)
Device-Level HNDL Analysis
Mosca's Inequality calculation per device with X+Y vs Z breakdown
Risk Levels
| X+Y vs Z | Risk Level | Recommended Action |
| X+Y >> Z | CRITICAL | Immediate migration |
| X+Y > Z | HIGH | Begin migration now |
| X+Y ≈ Z | MODERATE | Plan within 6 months |
| X+Y < Z | LOW | Plan within 12 months |
| X+Y << Z | MINIMAL | Track and monitor |
Setting Data Retention
- Go to Inventory → Select Device
- Click Edit on tiering section
- Set Data Retention (Years)
- Save changes
HNDL risk auto-recalculates when you update the value.
Examples
Critical Risk Example
Data Retention: 15 years (medical records)
Migration Time: 2 years
Quantum Timeline: 10 years (2035 estimate)
X + Y = 17 > Z = 10
Result: CRITICAL - Data needs protection beyond quantum capability
Low Risk Example
Data Retention: 1 year (temporary cache)
Migration Time: 2 years
Quantum Timeline: 10 years
X + Y = 3 < Z = 10
Result: MINIMAL - Data expires before quantum threat
See Screenshots Gallery for more visuals.
HNDL in Demo Assessments
Seeded datasets include CRITICAL, HIGH, MODERATE, LOW, and MINIMAL HNDL outcomes. Each device retains its own input values and calculated years until exposure.
Certificate Management
Certificate Discovery
Automatically extracts and stores X.509 certificates from:
- TLS handshake (port 443, 8443, etc.)
- Certificate files (.pem, .crt, .cer)
- System certificate stores
Certificate inventory with PQC status
Certificate Analysis
For each certificate, CERIA analyzes:
Basic Properties
- Subject/Issuer DN
- Serial number
- Validity period
- Days until expiry
Algorithm Assessment
| Algorithm | PQC Status |
| RSA-2048+ | ⚠️ Vulnerable |
| ECDSA P-256 | ⚠️ Vulnerable |
| ECDSA P-384 | ⚠️ Vulnerable |
| Ed25519 | ✅ PQC Ready |
| Ed448 | ✅ PQC Ready |
| ML-DSA | ✅ PQC Ready |
| ML-KEM | ✅ PQC Ready |
Signature Analysis
- SHA-256 ✅ Good
- SHA-384 ✅ Good
- SHA-1 ⚠️ Weak (deprecated)
- MD5 ❌ Broken (rejected)
Chain Analysis
Root CA (ISRG Root X1)
└── Intermediate (R3)
└── Leaf (example.com)
Each level assessed for:
- PQC readiness status
- Hybrid certificate detection
- CA roadmap alignment
Certificate chain detail view
CA Roadmap Database
Tracks vendor PQC transition plans:
| CA Vendor | Current Status | PQC ETA |
| DigiCert | Transitioning | 2025 |
| Let's Encrypt | Transitioning | 2025 |
| Sectigo | Transitioning | 2025 |
| GlobalSign | Planning | 2026 |
| AWS ACM | Ready | Available |
| Azure KV | Ready | Available |
Certificate Actions
Download
- PEM format - Full chain
- Individual - Single certificate
- Chain - CA bundle
Expiry Alerts
Automatic warnings for certificates expiring within:- 90 days (notice)
- 60 days (warning)
- 30 days (critical)
PQC Assessment Report
Generates report showing:- Certificates by PQC status
- Expiry timeline
- Migration priority
- Replacement recommendations
See Screenshots Gallery for certificate views
Compliance
MySEAL Compliance
MySEAL (Malaysia Security Evaluation and Assurance Lab) approved algorithms for government and critical infrastructure.MySEAL Approved Algorithms
Encryption
- AES-128, AES-192, AES-256 (GCM, CBC)
- ChaCha20-Poly1305
Digital Signatures
- RSA-2048+ (transitional)
- ECDSA P-256+ (transitional)
- Ed25519, Ed448 (recommended)
- ML-DSA (PQC-ready)
Key Exchange
- ECDH (transitional)
- X25519, X448 (recommended)
- ML-KEM (PQC-ready)
MySEAL Compliance Check
CERIA checks devices against MySEAL approved algorithms and flags non-compliant crypto.
MyKriptografi NCII Framework
Malaysia's National Critical Information Infrastructure (NCII) requirements for Post-Quantum Cryptography.
PQC Transition Timeline
| Phase | Deadline | Requirements |
| Phase 1 | 2030 | Symmetric crypto migration |
| Phase 2 | 2035 | Asymmetric crypto migration |
NCII Sectors
Priority weighting based on sector:
| Sector | Weight |
| Defense | Critical |
| Finance | Critical |
| Healthcare | Critical |
| Telecom | High |
| Energy | High |
| Government | High |
| Digital Services | Medium |
Compliance Report
Generated report includes:
- Overall compliance percentage
- Non-compliant algorithm list
- Priority remediation list
- Timeline recommendations
Compliance visualization in Reports
NACSA Alignment
National Cyber Security Agency (NACSA) guidelines:
- Crypto Inventory ✅ - Automated discovery
- Risk Assessment ✅ - SCAD scoring
- Migration Plan ✅ - Priority-based roadmap
- Progress Tracking ✅ - Scheduled re-scans
Export Formats
CBOM (CycloneDX)
Cryptographic Bill of Materials in standard format for:- Vendor assessment
- Audit trails
- Compliance documentation
NACSA XML (Future)
Direct NACSA reporting format support planned.See also: Risk Scoring for compliance weighting
PQC Excel Assessment Export
The PQC Excel export populates the official workbook without replacing template formatting or references. Its first four operational sheets cover project details, asset inventory, cryptographic discovery, and risk assessment.
Migration Planning
Migration Advisor
CERIA analyzes crypto patterns and generates step-by-step migration plans.
Detected Patterns
Common cryptographic configurations requiring migration:
| Pattern | Current State | Target State |
| rsa-2048-tls | RSA-2048 TLS | ML-KEM/ML-DSA or X25519/Ed25519 |
| rsa-4096-tls | RSA-4096 TLS | PQC algorithms |
| ecdsa-p256-tls | ECDSA P-256 | ML-DSA-65 or Ed25519 |
| ssh-rsa-deprecated | ssh-rsa | rsa-sha2-512 or Ed25519 |
| ssh-ecdsa | ECDSA host keys | Ed25519 host keys |
| vpn-ikev2-rsa | IKEv2 with RSA | IKEv2 with ECDSA or PQC |
Device showing detected crypto patterns
Migration Plan Structure
Each migration plan includes:
1. Current State
- What is currently deployed
- Why it's vulnerable
- Risk assessment
2. Target State
- Recommended replacement
- Algorithm rationale
- Compatibility considerations
3. Migration Steps
Numbered procedures:1. Generate new key pair
2. Create CSR with new algorithm
3. Obtain PQC-ready certificate
4. Configure service to use new cert
5. Test connectivity
6. Schedule cutover
4. Caveats & Risks
Known issues:- Larger certificate sizes
- Increased handshake latency
- Client compatibility concerns
5. Rollback Procedure
How to revert if issues occur.6. Resources
- Official documentation links
- Vendor guides
- NIST recommendations
Dependency Graph
Visualize migration dependencies:
Root CA must migrate first
→ Intermediate CAs
→ Leaf certificates
→ Device configurations
Migration critical path visualization
Critical Path Analysis
Identifies the order in which to migrate:
- Root CAs (blocks everything)
- Intermediate CAs (blocks leaf certs)
- High-risk devices (SCAD priority)
- Remaining devices (by tier)
Migration Tracking
Per-device migration status:
| Status | Meaning |
| Not Started | No action taken |
| In Planning | Migration designed |
| Testing | In test environment |
| Scheduled | Production date set |
| Complete | Migrated to PQC |
| Blocked | Dependency pending |
Update status in device detail page.
Migration Timeline
Recommended timeline based on HNDL risk:
| HNDL Risk | Migration Window |
| CRITICAL | Immediate - 3 months |
| HIGH | 3 - 6 months |
| MEDIUM | 6 - 12 months |
| LOW | 12 - 24 months |
| MINIMAL | Track only |
See HNDL Calculator for risk assessment
Exporting Migration Evidence
Use PDF for the executive assessment, PQC Excel for the migration workbook, CBOM for machine-readable cryptographic inventory, CSV for risk-register analysis, and JSON for complete device and asset details.
API Reference
Authentication
All API endpoints require a JWT token except for /api/v1/auth/login and /api/v1/auth/register.
Login
POST /api/v1/auth/login
Content-Type: application/json
{
"username": "string",
"password": "string"
}
Response:
{
"status": "ok",
"token": "eyJhbGciOiJIUzI1NiIs...",
"user": {
"id": 1,
"username": "admin",
"role": "admin"
}
}
Error Responses:
401- Invalid credentials403- Account disabled
Get Current User
GET /api/v1/auth/me
Authorization: Bearer <token>
Scans
Start New Scan
POST /api/v1/scans/start
Authorization: Bearer <token>
Content-Type: application/json
{
"target_range": "192.168.1.0/24",
"session_name": "Production Scan",
"collectors": ["tls", "ssh", "vpn"]
}
Parameters:
| Field | Type | Required | Description |
| target_range | string | Yes | Network CIDR or IP |
| session_name | string | No | Scan name |
| collectors | array | No | [tls, ssh, vpn, db, os_crypto, app_config, cert_store] |
{
"status": "ok",
"session_id": 1
}
Get Scan Status
GET /api/v1/scans/{session_id}/status
Authorization: Bearer <token>
Response:
{
"session_id": 1,
"status": "running",
"progress": {
"phase": "collecting",
"current_device": "5 of 10",
"collector": "tls"
},
"log": [
{"time": "10:00:01", "level": "info", "message": "Starting scan..."},
{"time": "10:00:15", "level": "info", "message": "Found 10 hosts"}
]
}
Stop Scan
POST /api/v1/scans/{session_id}/stop
Authorization: Bearer <token>
Get Scan Results
GET /api/v1/scans/{session_id}/results
Authorization: Bearer <token>
List All Scan Sessions
GET /api/v1/scans
Authorization: Bearer <token>
Devices
List All Devices
GET /api/v1/devices
Authorization: Bearer <token>
Query Parameters:
scan_session_id- Filter by scantier- Filter by tier (critical, high, medium, low)page- Page number (default: 1)page_size- Items per page (default: 50)
{
"items": [
{
"id": 1,
"ip_address": "192.168.1.10",
"hostname": "server01",
"os_fingerprint": "Linux 5.4",
"tier": "critical",
"open_ports": [{"port": 22, "service": "ssh"}, {"port": 443, "service": "https"}],
"risk_score": {
"overall": 85.5,
"priority_label": "CRITICAL"
},
"hndl": {
"risk_level": "HIGH",
"years_until_exposure": 3.5
}
}
],
"total": 42,
"page": 1,
"page_size": 50
}
Get Device Details
GET /api/v1/devices/{device_id}
Authorization: Bearer <token>
Update Device Tiering
PUT /api/v1/devices/{device_id}/tiering
Authorization: Bearer <token>
Content-Type: application/json
{
"tier": "critical",
"data_retention_years": 10,
"system_criticality": "high",
"migration_notes": "Business critical payment gateway"
}
Fields:
| Field | Type | Description |
| tier | enum | critical, high, medium, low |
| data_retention_years | int | Years data must remain confidential |
| system_criticality | enum | high, medium, low |
| legacy_status | enum | eol_soon, maintained, modern |
| migration_notes | string | Free text notes |
Get Device Assets
GET /api/v1/devices/{device_id}/assets
Authorization: Bearer <token>
Get Device Score History
GET /api/v1/devices/{device_id}/score-history
Authorization: Bearer <token>
Certificates
List Certificates
GET /api/v1/certificates
Authorization: Bearer <token>
Query Parameters:
device_id- Filter by deviceis_expired- true/falsepqc_status- ready, vulnerable, hybrid
Get Certificate Details
GET /api/v1/certificates/{cert_id}
Authorization: Bearer <token>
Response:
{
"id": 1,
"subject": "CN=example.com",
"issuer": "CN=Let's Encrypt R3",
"serial_number": "00:01:02:...",
"valid_from": "2024-01-01T00:00:00",
"valid_until": "2024-12-31T23:59:59",
"days_remaining": 180,
"algorithm": "ECDSA P-256",
"signature_hash": "SHA256",
"pqc_status": "vulnerable",
"is_hybrid": false,
"has_weak_signature": false,
"chain_analysis": {
"root_ca": "ISRG Root X1",
"root_pqc_status": "transitioning",
"intermediate_ca": "R3",
"intermediate_pqc_status": "transitioning",
"chain_trust": "trusted",
"chain_risk_score": 25
},
"pem_data": "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWg..."
}
Download Certificate
GET /api/v1/certificates/{cert_id}/download
Authorization: Bearer <token>
Response: PEM-encoded certificate file
Get Certificate Chain
GET /api/v1/certificates/{cert_id}/chain
Authorization: Bearer <token>
Risk Scoring
Get Scoring Weights
GET /api/v1/scoring/weights
Authorization: Bearer <token>
Response:
{
"data_lifespan": 20,
"algorithm_vulnerability": 25,
"key_size": 15,
"system_criticality": 15,
"legacy_status": 10,
"third_party_dependency": 10,
"ncii_sector": 5,
"total": 100
}
Update Scoring Weights
PUT /api/v1/scoring/weights
Authorization: Bearer <token>
Content-Type: application/json
{
"data_lifespan": 25,
"algorithm_vulnerability": 20,
"key_size": 15,
"system_criticality": 15,
"legacy_status": 10,
"third_party_dependency": 10,
"ncii_sector": 5
}
Note: Weights must sum to exactly 100.
HNDL (Harvest Now Decrypt Later)
Get HNDL Risk Calculation
POST /api/v1/hndl/calculate
Authorization: Bearer <token>
Content-Type: application/json
{
"data_retention_years": 10,
"migration_years": 2
}
Response:
{
"hndl_risk_level": "HIGH",
"years_until_exposure": 12,
"risk_factors": {
"data_retention": 10,
"migration_time": 2,
"quantum_timeline": 10,
"mosca_inequality": "X + Y > Z (CRITICAL)"
},
"recommendations": [
"Immediate migration recommended",
"Current algorithms will be broken before data expires"
]
}
Compliance
MySEAL Compliance Check
GET /api/v1/compliance/myseal
Authorization: Bearer <token>
MyKriptografi NCII Report
GET /api/v1/compliance/ncii-report
Authorization: Bearer <token>
Migration
Get Migration Recommendation
GET /api/v1/devices/{device_id}/migration
Authorization: Bearer <token>
Response:
{
"detected_patterns": ["rsa-2048-tls", "ssh-rsa-deprecated"],
"recommendations": [
{
"pattern": "rsa-2048-tls",
"current_state": "RSA-2048 for TLS authentication",
"target_state": "ML-KEM/ML-DSA or X25519/Ed25519",
"migration_steps": [
"1. Generate new PQC key pair",
"2. Install hybrid certificate",
"3. Update TLS configuration"
],
"caveats": ["Hybrid certificates may increase handshake size"],
"resources": ["https://csrc.nist.gov/pqc-standardization"]
}
]
}
Analytics & Visualization
Network Topology
GET /api/v1/analytics/topology
Authorization: Bearer <token>
Response: G6 graph format
{
"nodes": [
{"id": "device_1", "type": "device", "label": "192.168.1.10", "risk": 85},
{"id": "cert_1", "type": "certificate", "label": "CN=example.com"}
],
"edges": [
{"source": "device_1", "target": "cert_1", "type": "uses"}
]
}
Risk Heatmap Data
GET /api/v1/analytics/risk-heatmap
Authorization: Bearer <token>
Certificate Expiry Timeline
GET /api/v1/analytics/expiry-timeline
Authorization: Bearer <token>
PQC Readiness Gauge
GET /api/v1/analytics/pqc-readiness
Authorization: Bearer <token>
{
"total_devices": 100,
"ready": 15,
"transitioning": 35,
"vulnerable": 50,
"percentage_ready": 15
}
Settings
Get All Settings
GET /api/v1/settings
Authorization: Bearer <token>
Update Setting
PUT /api/v1/settings/{key}
Authorization: Bearer <token>
Content-Type: application/json
{
"value": "new_value"
}
Common Settings
| Key | Description | Default |
scan_rate_limit | Max concurrent scans per minute | 5 |
default_scan_timeout | Scan timeout in seconds | 300 |
nmap_args | Default nmap arguments | -sV -O -sS |
ssh_username | SSH username for collectors | "" |
target_range | Default scan target | 192.168.1.0/24 |
Export
Exports are asynchronous. Queue a job, poll its status, then use its download_url when it reaches completed.
pdf, pqc_excel, cbom, csv, json.
List Export Types
GET /api/v1/reports/exports/types
Authorization: Bearer <token>
Queue Export
POST /api/v1/reports/exports
Authorization: Bearer <token>
Content-Type: application/json
{"export_type": "pdf"}
Returns 202 Accepted with the persistent job record.
List and Filter Exports
GET /api/v1/reports/exports
GET /api/v1/reports/exports?export_type=pqc_excel
Authorization: Bearer <token>
Read Export Status
GET /api/v1/reports/exports/{job_id}
Authorization: Bearer <token>
Statuses are queued, processing, completed, and failed. Responses include progress, unique filename, timestamps, errors, and a download URL when ready.
Download Export
GET /api/v1/reports/exports/{job_id}/download
Authorization: Bearer <token>
Delete Export
DELETE /api/v1/reports/exports/{job_id}
Authorization: Bearer <token>
Queued or processing jobs return 409 Conflict and cannot be deleted.
User Management
Register User (Admin only)
POST /api/v1/auth/register
Authorization: Bearer <token>
Content-Type: application/json
{
"username": "newuser",
"password": "securepassword",
"role": "user"
}
List Users (Admin only)
GET /api/v1/auth/users
Authorization: Bearer <token>
Update User (Admin only)
PUT /api/v1/auth/users/{user_id}
Authorization: Bearer <token>
Content-Type: application/json
{
"role": "admin",
"is_active": true
}
Delete User (Admin only)
DELETE /api/v1/auth/users/{user_id}
Authorization: Bearer <token>
Change Password
POST /api/v1/auth/change-password
Authorization: Bearer <token>
Content-Type: application/json
{
"current_password": "oldpass",
"new_password": "newpass"
}
Error Codes
| Code | Meaning | Description |
| 400 | Bad Request | Invalid JSON or parameters |
| 401 | Unauthorized | Invalid or missing token |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource already exists |
| 422 | Unprocessable Entity | Validation error |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
Python Example
import requests
BASE_URL = "https://pqcs.dysfunktion.tech/api/v1"
# Login
resp = requests.post(f"{BASE_URL}/auth/login", json={
"username": "admin",
"password": "password"
})
token = resp.json()["token"]
headers = {"Authorization": f"Bearer {token}"}
# Start scan
resp = requests.post(
f"{BASE_URL}/scans/start",
headers=headers,
json={"target_range": "10.0.0.0/24"}
)
session_id = resp.json()["session_id"]
# Wait for scan to complete
import time
while True:
status = requests.get(
f"{BASE_URL}/scans/{session_id}/status",
headers=headers
).json()
if status["status"] == "completed":
break
time.sleep(5)
# Get results
results = requests.get(
f"{BASE_URL}/scans/{session_id}/results",
headers=headers
).json()
# Export PDF
pdf = requests.get(
f"{BASE_URL}/export/{session_id}?format=pdf",
headers=headers
)
with open("report.pdf", "wb") as f:
f.write(pdf.content)
cURL Examples
Full Scan Workflow
# 1. Login
TOKEN=$(curl -s -X POST https://pqcs/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"pass"}' | jq -r '.token')
# 2. Start scan
curl -X POST https://pqcs/api/v1/scans/start \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"target_range":"192.168.1.0/24"}'
# 3. Get devices
curl https://pqcs/api/v1/devices \
-H "Authorization: Bearer $TOKEN" | jq
# 4. Export CSV
curl "https://pqcs/api/v1/export/1?format=csv" \
-H "Authorization: Bearer $TOKEN" \
-o report.csv
Last Updated: 2026-07-22
Administration Guide
Guide for administrators managing PQC Scanner in production environments.
Table of Contents
- User Management
- Scan Management
- Database Administration
- Configuration Management
- Risk Scoring Configuration
- Monitoring & Alerts
- Maintenance Tasks
- Backup & Recovery
- Troubleshooting
User Management
Creating Users
Via Web Interface
- Login as admin
- Go to Profile page (
/profile) - Click User Management
- Click Add User
- Fill in:
- Username
- Password (must be 8+ chars)
- Role (admin/user/viewer)
- Save
Via CLI
# Interactive
pqcs user create
# Or programmatic (custom script)
python << 'EOF'
import bcrypt
from pqcs.db import init_db, User
from pqcs.config import AppConfig
config = AppConfig()
db = init_db(config.database.url)
pw_hash = bcrypt.hashpw(b"newpassword", bcrypt.gensalt())
user = User(
username="newuser",
password_hash=pw_hash.decode(),
role="user",
is_active=True
)
db.add(user)
db.commit()
print(f"Created user: {user.username}")
EOF
User Roles
| Role | Permissions |
| admin | Full access: scans, reports, settings, user management |
| user | Can run scans, view reports, modify device data |
| viewer | Read-only: view scans, reports, cannot modify data |
Disabling Users
- Go to Profile → User Management
- Find user
- Toggle Active switch to OFF
- User can no longer login
Password Reset
# Via CLI
python << 'EOF'
import bcrypt
from pqcs.db import init_db, User
from pqcs.config import AppConfig
config = AppConfig()
db = init_db(config.database.url)
user = db.query(User).filter_by(username="user_to_reset").first()
if user:
new_pw = bcrypt.hashpw(b"temppassword123", bcrypt.gensalt())
user.password_hash = new_pw.decode()
db.commit()
print("Password reset to: temppassword123")
print("User must change on next login")
EOF
Scan Management
Scheduling Scans
Via Web Settings
- Go to Settings page
- Scroll to Automatic Re-scan
- Enable scheduled scans
- Select frequency:
- Daily: Every day at set time
- Weekly: Selected day of week
- Monthly: Selected day of month
- Quarterly: Every 3 months
- Set scan time (24h format)
- Save settings
Via CLI
from pqcs.scheduler.scan_scheduler import ScanScheduler
from pqcs.config import AppConfig
config = AppConfig()
scheduler = ScanScheduler(config)
# Schedule daily scan
job = scheduler.schedule_scan(
target_range="192.168.1.0/24",
schedule_type="daily",
name="Daily Network Scan"
)
# List scheduled jobs
jobs = scheduler.list_scheduled_scans()
for job in jobs:
print(f"{job['id']}: {job['name']} - {job['schedule']}")
# Cancel schedule
scheduler.cancel_schedule(job_id=1)
Managing Running Scans
Check Scan Status
# Via CLI
ceria sessions
# Get specific scan status
curl http://localhost:8080/api/v1/scans/1/status \
-H "Authorization: Bearer <token>"
Stop Running Scan
- Go to Scan Detail page
- Click Stop Scan button
- Or via API:
curl -X POST http://localhost:8080/api/v1/scans/1/stop \
-H "Authorization: Bearer <token>"
Delete Old Scans
# Via CLI script
python << 'EOF'
from pqcs.db import init_db, ScanSession
from pqcs.config import AppConfig
from datetime import datetime, timedelta
config = AppConfig()
db = init_db(config.database.url)
# Delete scans older than 90 days
cutoff = datetime.utcnow() - timedelta(days=90)
old_scans = db.query(ScanSession).filter(ScanSession.finished_at < cutoff).all()
for scan in old_scans:
print(f"Deleting scan {scan.id}: {scan.name}")
db.delete(scan)
db.commit()
print(f"Deleted {len(old_scans)} old scans")
EOF
Scan Optimization
Custom Ports
- Go to Settings
- Edit Custom Ports
- Add ports (comma-separated or ranges):
- Save
9000,9001,9002-9010,10000
Scan Timeouts
| Network Size | Recommended Timeout |
| /24 (254 hosts) | 300 seconds |
| /23 (510 hosts) | 600 seconds |
| /22 (1022 hosts) | 1200 seconds |
| /16 (65534 hosts) | 3600 seconds |
Database Administration
Database Schema
Key tables:
users- Authentication and rolesscan_sessions- Scan metadatadevices- Discovered network devicescrypto_assets- Cryptographic findingscertificates- X.509 certificatesrisk_scores- Calculated risk scoressettings- Application configuration
Direct Database Access
# SQLite CLI
sqlite3 /var/lib/pqcs/pqcs.db
# Common queries
.tables
.schema devices
SELECT COUNT(*) FROM devices;
SELECT * FROM scan_sessions ORDER BY started_at DESC LIMIT 5;
.quit
Database Maintenance
Vacuum (SQLite)
# Reclaim space after deletions
sqlite3 /var/lib/pqcs/pqcs.db "VACUUM;"
Analyze (performance)
# Update query planner statistics
sqlite3 /var/lib/pqcs/pqcs.db "ANALYZE;"
Check Integrity
sqlite3 /var/lib/pqcs/pqcs.db "PRAGMA integrity_check;"
Migration to PostgreSQL (Advanced)
# Install PostgreSQL adapter
pip install psycopg2-binary
# Export SQLite
sqlite3 pqcs.db .dump > dump.sql
# Import to PostgreSQL
psql -U postgres -d pqcs < dump.sql
# Update DATABASE_URL
export DATABASE_URL="postgresql://user:pass@localhost/pqcs"
Configuration Management
Settings Storage
Settings stored in database table settings:
settings = {
"scan_rate_limit": "5",
"default_scan_timeout": "300",
"nmap_args": "-sV -O -sS",
"ssh_username": "",
"ssh_password": "",
"custom_ports": "",
}
Updating Settings
Via API
# Update single setting
curl -X PUT http://localhost:8080/api/v1/settings/scan_rate_limit \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"value": "10"}'
# Get all settings
curl http://localhost:8080/api/v1/settings \
-H "Authorization: Bearer <token>"
Via Python
from pqcs.db import init_db, Setting
from pqcs.config import AppConfig
config = AppConfig()
db = init_db(config.database.url)
# Update setting
setting = db.query(Setting).filter_by(key="scan_rate_limit").first()
if setting:
setting.value = "10"
else:
setting = Setting(key="scan_rate_limit", value="10")
db.add(setting)
db.commit()
Environment Variables Priority
Priority order (highest first):
- Environment variables (
.env) - Database settings
- Default values in code
Risk Scoring Configuration
Understanding SCAD Weights
Default weights (must sum to 100%):
| Criterion | Default | When to Increase |
| Algorithm Vulnerability | 25% | Known CVEs, weak algorithms |
| Data Lifespan | 20% | Long-term sensitive data |
| Key Size | 15% | Large RSA keys (>2048) |
| System Criticality | 15% | Business-critical systems |
| Legacy Status | 10% | EOL systems |
| Third Party Dependency | 10% | Vendor-managed crypto |
| NCII Sector | 5% | Regulated industries |
Adjusting for Industry
Financial Services
Algorithm Vulnerability: 30%
Data Lifespan: 25%
System Criticality: 20%
Key Size: 10%
Legacy Status: 5%
Third Party: 5%
NCII Sector: 5%
Healthcare
Data Lifespan: 35%
Algorithm Vulnerability: 25%
System Criticality: 15%
Key Size: 10%
Legacy Status: 5%
Third Party: 5%
NCII Sector: 5%
Recalculating Scores
After changing weights, rescore existing devices:
from pqcs.scoring.engine import ScoringEngine
from pqcs.db import init_db, Device
from pqcs.config import AppConfig
config = AppConfig()
db = init_db(config.database.url)
scoring = ScoringEngine(config.scoring, config.ncii_sector)
devices = db.query(Device).all()
for device in devices:
score = scoring.calculate(device, device.assets)
# Update score in database
print(f"Rescored {device.ip_address}: {score.overall_score}")
db.commit()
Monitoring & Alerts
Health Check
# Basic health check
curl http://localhost:8080/health
# Expected response:
{
"status": "ok",
"timestamp": "2026-07-22T12:00:00",
"version": "0.1.0",
"database": "connected"
}
Log Monitoring
Important Log Entries
| Pattern | Meaning | Action |
scan completed | Normal operation | None |
collector error | Scanning issue | Check collector config |
database error | DB issue | Check connectivity |
authentication failed | Login attempt | Review if suspicious |
rate limit exceeded | Too many scans | Adjust thresholds |
Log Rotation
# Add to /etc/logrotate.d/pqcs
/opt/pqcs/logs/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 pqcs pqcs
}
Setting Up Alerts
Email Notifications
# In settings
alert_email = "admin@example.com"
alert_events = ["scan_failed", "high_priority_device", "certificate_expiring"]
Slack Notifications
# Custom webhook
slack_webhook = "https://hooks.slack.com/..."
Maintenance Tasks
Daily
- [ ] Check scan completion status
- [ ] Review failed scans
- [ ] Monitor disk space
Weekly
- [ ] Review new high-priority devices
- [ ] Check certificate expiry (30-day warning)
- [ ] Verify backups
- [ ] Review user access
Monthly
- [ ] Database optimization (VACUUM)
- [ ] Archive old scan data (>90 days)
- [ ] Update algorithm databases
- [ ] Review and adjust scoring weights
- [ ] Security audit of user accounts
Quarterly
- [ ] Full system backup test
- [ ] Disaster recovery drill
- [ ] Update dependencies
- [ ] Review vendor roadmaps
Backup & Recovery
Demo Dataset Backup and Loading
ceria demo-data --count 500 --snapshots 4 --seed 20260722
The command creates a timestamped SQLite backup in backups/ before changing scan-domain records. Configuration and users are preserved. Use --backup-dir PATH to change the destination, --append to retain existing scan data, and --seed to reproduce a dataset.
Generated Report Retention
Report metadata is stored in the database and completed files under outputs/reports. Back up both locations if generated reports must survive recovery. Administrators can download or delete completed files from /report-exports; active jobs cannot be deleted.
Backup Strategy
Automated Daily Backup
#!/bin/bash
# /opt/pqcs/backup.sh
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_DIR="/backups/pqcs"
SOURCE_DB="/var/lib/pqcs/pqcs.db"
# Create backup dir
mkdir -p $BACKUP_DIR
# Backup database
cp $SOURCE_DB "$BACKUP_DIR/pqcs_$DATE.db"
# Compress
gzip "$BACKUP_DIR/pqcs_$DATE.db"
# Backup configuration
tar czf "$BACKUP_DIR/config_$DATE.tar.gz" \
/opt/pqcs/.env \
/opt/pqcs/settings.json
# Upload to S3 (optional)
aws s3 cp "$BACKUP_DIR/pqcs_$DATE.db.gz" s3://pqcs-backups/
# Keep only last 30 days
find $BACKUP_DIR -name "*.gz" -mtime +30 -delete
echo "Backup completed: pqcs_$DATE.db.gz"
Crontab:
0 2 * * * /opt/pqcs/backup.sh >> /var/log/pqcs/backup.log 2>&1
Recovery Procedure
Scenario 1: Database Corruption
# Stop application
sudo systemctl stop pqcs
# Restore from backup
sudo cp /backups/pqcs/pqcs_20260701_020000.db /var/lib/pqcs/pqcs.db
sudo chown pqcs:pqcs /var/lib/pqcs/pqcs.db
# Restart
sudo systemctl start pqcs
sudo systemctl status pqcs
Scenario 2: Complete Server Failure
# On new server
# 1. Install PQC Scanner
pip install -e .
# 2. Restore database
cp /backups/pqcs/pqcs_latest.db /var/lib/pqcs/pqcs.db
# 3. Restore config
cp /backups/pqcs/.env /opt/pqcs/.env
# 4. Set permissions
chown -R pqcs:pqcs /var/lib/pqcs /opt/pqcs
# 5. Start service
systemctl start pqcs
Troubleshooting
Database Locked
# Find and kill blocking process
fuser /var/lib/pqcs/pqcs.db
# Or wait for timeout (SQLite release locks on timeout)
Scan Stuck
# Check if nmap is running
ps aux | grep nmap
# Kill hanging nmap
sudo pkill -9 nmap
# Restart scan
Memory Issues
If scanning large networks:
# Reduce concurrent hosts
export MAX_CONCURRENT_HOSTS=25
# Or use smaller subnets
ceria scan 192.168.1.0/25 # /25 instead of /24
SSL Certificate Errors
# Update certificates
sudo update-ca-certificates
# Or disable verification (testing only)
export REQUESTS_CA_BUNDLE=""
High CPU Usage
# Limit scan threads
export OMP_NUM_THREADS=4
# Or schedule scans during off-hours
Last Updated: 2026-07-22
Deployment Guide
Complete guide for deploying PQC Scanner in production environments.
Table of Contents
- Local Development
- Production Server
- cPanel Shared Hosting
- Docker Deployment
- Cloud Deployment
- SSL/TLS Setup
- Security Hardening
Local Development
Installation
# Clone repository
git clone <repo-url>
cd pqc
# Create virtual environment
python -m venv venv
source venv/bin/activate # Linux/macOS
# or
venv\Scripts\activate # Windows
# Install dependencies
pip install -e ".[dev]"
# Run database migrations (if using Alembic)
# alembic upgrade head
# Start development server
ceria dashboard --port 8080 --verbose
Environment Variables
Create .env file:
# Required
SECRET_KEY=$(openssl rand -hex 32)
DATABASE_URL=sqlite:///pqcs.db
# Optional
DEBUG=true
LOG_LEVEL=DEBUG
DASHBOARD_HOST=127.0.0.1
DASHBOARD_PORT=8080
Production Server
System Requirements
- Python 3.10+
- 2GB RAM minimum
- 10GB disk space
- nmap installed
- WeasyPrint runtime libraries for PDF generation
- SSL certificate (recommended)
Installation on Ubuntu/Debian
# Update system
sudo apt-get update
sudo apt-get upgrade -y
# Install dependencies
sudo apt-get install -y python3 python3-pip python3-venv nmap openssl libpango-1.0-0 libpangoft2-1.0-0
# Create user
sudo useradd -r -s /bin/false pqcs
# Create directories
sudo mkdir -p /opt/pqcs
sudo mkdir -p /var/lib/pqcs
sudo mkdir -p /var/log/pqcs
sudo mkdir -p /var/lib/pqcs/reports
sudo chown -R pqcs:pqcs /opt/pqcs /var/lib/pqcs /var/log/pqcs
# Clone application
cd /opt/pqcs
sudo -u pqcs git clone <repo-url> .
# Setup virtual environment
sudo -u pqcs python3 -m venv venv
sudo -u pqcs venv/bin/pip install -e .
# Create .env file
sudo -u pqcs tee /opt/pqcs/.env << 'EOF'
SECRET_KEY=$(openssl rand -hex 32)
DATABASE_URL=sqlite:////var/lib/pqcs/pqcs.db
DASHBOARD_HOST=0.0.0.0
DASHBOARD_PORT=8080
EOF
# Initialize database
sudo -u pqcs venv/bin/python -c "
from pqcs.db import init_db
from pqcs.config import AppConfig
config = AppConfig.from_env()
init_db(config.database.url)
"
Systemd Service
Create /etc/systemd/system/pqcs.service:
[Unit]
Description=PQC Scanner Dashboard
After=network.target
[Service]
Type=simple
User=pqcs
Group=pqcs
WorkingDirectory=/opt/pqcs
Environment="PATH=/opt/pqcs/venv/bin"
EnvironmentFile=/opt/pqcs/.env
ExecStart=/opt/pqcs/venv/bin/uvicorn pqcs.web.app:create_app --host 0.0.0.0 --port 8080
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Start the service:
sudo systemctl daemon-reload
sudo systemctl enable pqcs
sudo systemctl start pqcs
sudo systemctl status pqcs
Nginx Reverse Proxy
Install Nginx:
sudo apt-get install nginx
Create /etc/nginx/sites-available/pqcs:
server {
listen 80;
server_name pqcs.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name pqcs.example.com;
ssl_certificate /etc/letsencrypt/live/pqcs.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pqcs.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
location /static {
alias /opt/pqcs/pqcs/web/static;
}
}
Enable site:
sudo ln -s /etc/nginx/sites-available/pqcs /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
cPanel Shared Hosting
Prerequisites
- cPanel with Python support
- SSH access
- Python 3.10+ available
Deployment Steps
1. Upload Files
Upload via FTP or SSH to:
/home/username/public_html/pqcs.example.com/
Files needed:
passenger_wsgi.py(cPanel WSGI entry point)requirements.txtpqcs/directory.htaccess
2. Configure .htaccess
Create .htaccess in application root:
PassengerPython /home/username/virtualenv/pqcs/3.11/bin/python
PassengerAppRoot /home/username/public_html/pqcs.example.com
PassengerAppType wsgi
PassengerStartupFile passenger_wsgi.py
3. Create WSGI File
passenger_wsgi.py:
#!/usr/bin/env python3
import os
import sys
APP_ROOT = "/home/username/public_html/pqcs.example.com"
sys.path.insert(0, APP_ROOT)
os.chdir(APP_ROOT)
# Use existing database or create outside web root
DB_PATH = "/home/username/db/pqcs.db"
os.environ['DATABASE_URL'] = f'sqlite:///{DB_PATH}'
from pqcs.web.app import create_app
from pqcs.config import AppConfig
config = AppConfig()
config.database.url = f'sqlite:///{DB_PATH}'
asgi_app = create_app(config)
# WSGI wrapper for FastAPI
import asyncio
class WSGIWrapper:
def __init__(self, asgi_app):
self.asgi_app = asgi_app
def __call__(self, environ, start_response):
scope = {
'type': 'http',
'asgi': {'version': '3.0'},
'method': environ.get('REQUEST_METHOD', 'GET'),
'scheme': environ.get('wsgi.url_scheme', 'https'),
'path': environ.get('PATH_INFO', '/'),
'query_string': environ.get('QUERY_STRING', '').encode(),
'headers': [],
'server': (environ.get('SERVER_NAME', 'localhost'), int(environ.get('SERVER_PORT', 443))),
'client': (environ.get('REMOTE_ADDR', '127.0.0.1'), int(environ.get('REMOTE_PORT', 0) or 0)),
}
# Handle headers and body
body = b''
if 'wsgi.input' in environ:
cl = environ.get('CONTENT_LENGTH')
if cl:
try:
body = environ['wsgi.input'].read(int(cl))
except:
pass
messages = []
async def receive():
return {'type': 'http.request', 'body': body, 'more_body': False}
async def send(message):
messages.append(message)
loop = asyncio.new_event_loop()
try:
asyncio.set_event_loop(loop)
loop.run_until_complete(self.asgi_app(scope, receive, send))
start_msg = next(m for m in messages if m['type'] == 'http.response.start')
status = f"{start_msg['status']}"
headers = [(k.decode() if isinstance(k, bytes) else k,
v.decode() if isinstance(v, bytes) else v)
for k, v in start_msg.get('headers', [])]
start_response(status, headers)
body_parts = [m.get('body', b'') for m in messages if m['type'] == 'http.response.body']
return body_parts if body_parts else [b'']
finally:
loop.close()
application = WSGIWrapper(asgi_app)
4. Setup Python App in cPanel
- Login to cPanel
- Go to Setup Python App
- Click Create Application
- Configure:
- Python version: 3.11
- Application root:
public_html/pqcs.example.com - Application URL:
pqcs.example.com - Application startup file:
passenger_wsgi.py - Application Entry point:
application
- Click Create
5. Install Dependencies
SSH into server:
cd /home/username/public_html/pqcs.example.com
source /home/username/virtualenv/pqcs/3.11/bin/activate
pip install -r requirements.txt
# Create database directory outside web root
mkdir -p /home/username/db
chmod 755 /home/username/db
# Initialize database
python << 'EOF'
import sys
sys.path.insert(0, '/home/username/public_html/pqcs.example.com')
from pqcs.db import init_db
init_db('sqlite:////home/username/db/pqcs.db')
print("Database initialized")
EOF
# Create restart signal
mkdir -p tmp
touch tmp/restart.txt
6. Environment Variables
In cPanel Python App settings, add:
| Variable | Value |
SECRET_KEY | (openssl rand -hex 32) |
DATABASE_URL | sqlite:////home/username/db/pqcs.db |
7. Troubleshooting cPanel
Common issues:
| Issue | Solution |
| 403 Forbidden | Check file permissions (chmod 644 .htaccess passenger_wsgi.py) |
| 500 Error | Check Passenger log in cPanel |
| Database not found | Use absolute path in DATABASE_URL |
| Import errors | Run pip install in virtualenv |
Docker Deployment
Dockerfile
FROM python:3.11-slim
# Install system dependencies
RUN apt-get update && apt-get install -y \
nmap \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Create app directory
WORKDIR /app
# Copy requirements first for caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY . .
RUN pip install -e .
# Create directories
RUN mkdir -p /data /logs
# Environment
ENV DATABASE_URL=sqlite:////data/pqcs.db
ENV DASHBOARD_HOST=0.0.0.0
ENV DASHBOARD_PORT=8080
ENV PYTHONUNBUFFERED=1
# Initialize database
RUN python -c "from pqcs.db import init_db; init_db('$DATABASE_URL')"
EXPOSE 8080
CMD ["pqcs", "dashboard", "--host", "0.0.0.0", "--port", "8080"]
docker-compose.yml
version: '3.8'
services:
pqcs:
build: .
container_name: pqcs
ports:
- "8080:8080"
volumes:
- ./data:/data
- ./logs:/logs
environment:
- SECRET_KEY=${SECRET_KEY}
- DATABASE_URL=sqlite:////data/pqcs.db
restart: unless-stopped
networks:
- pqcs-network
# Optional: Nginx reverse proxy
nginx:
image: nginx:alpine
container_name: pqcs-nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- pqcs
networks:
- pqcs-network
networks:
pqcs-network:
driver: bridge
Build and Run
# Generate secret key
export SECRET_KEY=$(openssl rand -hex 32)
# Create directories
mkdir -p data logs
# Build and run
docker-compose up -d --build
# View logs
docker-compose logs -f pqcs
# Stop
docker-compose down
Cloud Deployment
AWS Elastic Beanstalk
# Install EB CLI
pip install awsebcli
# Initialize
eb init -p python-3.11 pqcs-app
# Create environment
eb create pqcs-env
# Deploy
eb deploy
Heroku
# Create Procfile
echo "web: ceria dashboard --port \$PORT" > Procfile
# Create app
heroku create pqcs-app
# Set environment variables
heroku config:set SECRET_KEY=$(openssl rand -hex 32)
heroku config:set DATABASE_URL=$(heroku config:get DATABASE_URL)
# Deploy
git push heroku main
Railway
# Install Railway CLI
npm install -g @railway/cli
# Login
railway login
# Initialize
railway init
# Deploy
railway up
# Add environment variables in Railway dashboard
SSL/TLS Setup
Let's Encrypt (certbot)
# Install certbot
sudo apt-get install certbot python3-certbot-nginx
# Obtain certificate
sudo certbot --nginx -d pqcs.example.com
# Auto-renewal
sudo certbot renew --dry-run
Self-Signed Certificate (testing)
# Generate certificate
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/pqcs.key \
-out /etc/ssl/certs/pqcs.crt
# Update Nginx config to use these
Security Hardening
File Permissions
# Database
chmod 600 /var/lib/pqcs/pqcs.db
chown pqcs:pqcs /var/lib/pqcs/pqcs.db
# Application files
chmod 755 /opt/pqcs
chmod 644 /opt/pqcs/.env
chown -R pqcs:pqcs /opt/pqcs
# Logs
chmod 755 /var/log/pqcs
chown pqcs:pqcs /var/log/pqcs
Firewall Rules
# Allow only HTTPS
sudo ufw default deny incoming
sudo ufw allow ssh
sudo ufw allow 443/tcp
sudo ufw enable
# Or use iptables
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -P INPUT DROP
Fail2Ban
Install and configure for brute force protection:
sudo apt-get install fail2ban
Create /etc/fail2ban/jail.local:
[pqcs]
enabled = true
port = http,https
filter = pqcs
logpath = /var/log/pqcs/access.log
maxretry = 5
bantime = 3600
Security Headers
Add to Nginx config:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' cdn.jsdelivr.net unpkg.com; style-src 'self' 'unsafe-inline' cdn.jsdelivr.net; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;
Backup Strategy
Persist and back up both the database and generated-report directory. If outputs/reports remains inside the application checkout, include it in deployment backups or configure the service working directory on persistent storage.
# Daily database backup
#!/bin/bash
BACKUP_DIR="/backups/pqcs"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
cp /var/lib/pqcs/pqcs.db "$BACKUP_DIR/pqcs_$DATE.db"
gzip "$BACKUP_DIR/pqcs_$DATE.db"
# Keep only last 30 days
find $BACKUP_DIR -name "*.gz" -mtime +30 -delete
Add to crontab:
0 2 * * * /opt/pqcs/backup.sh
Monitoring
Health Check Endpoint
GET /health
Returns:
{
"status": "ok",
"timestamp": "2026-07-22T12:00:00",
"version": "0.1.0",
"database": "connected"
}
Prometheus Metrics (optional)
Add to requirements:
prometheus-client>=0.17.0
Last Updated: 2026-07-22
Cryptographic Collectors
1. TLS/SSL Collector
Scans for:- TLS versions (1.0, 1.1, 1.2, 1.3)
- Cipher suites (quantum-vulnerable vs PQC-ready)
- Certificate chains
- Weak signatures (MD5, SHA-1)
- Hybrid certificates
TLS collector finds certificates and cipher suites on HTTPS services
Tools: sslyze, nmap scripts
Confidence: 0.95
Default Ports: 443, 8443, 9443
Example findings in device detail:
Detail view of TLS assets including certificates and cipher suites
2. SSH Collector
Scans for:- Key algorithms (RSA, ECDSA, Ed25519)
- KEX algorithms
- MAC algorithms
- Weak curves (secp192, secp224)
3. VPN Collector
Scans for:- IKE version (v1, v2)
- Transform proposals
- DH groups
4. Database Collector
Scans for:- Transparent Data Encryption (TDE)
- Connection encryption
- SSL/TLS configuration
5. OS Crypto Collector
Scans for:- System certificate stores
- Trusted root CAs
- Installed certificates
6. App Config Collector
Scans for:- OpenSSL configs
- Java keystores
- Algorithm configurations
7. Certificate Store Collector
Scans for:- Certificate files (.pem, .crt, .p12)
- Trust stores
- Private key files
Demo Collector Coverage
Enterprise demo data includes findings associated with TLS, SSH, VPN, database encryption, operating-system crypto, application configuration, and certificate-store collectors.
Default Ports
SSH
- 22, 2222
TLS/HTTPS
- 443, 8443, 4443, 993, 995, 990, 636, 3269, 8080, 9090
VPN
- 500, 4500, 1194, 1723
Database
- 5432 (PostgreSQL)
- 1433 (MSSQL)
- 3306 (MySQL)
- 1521 (Oracle)
- 27017 (MongoDB)
- 6379 (Redis)
- 9042 (Cassandra)
- 143, 993 (IMAP)
- 110, 995 (POP3)
- 25, 465, 587 (SMTP)
LDAP/Kerberos
- 389, 636, 88, 3268, 3269
RDP/VNC
- 3389, 5900, 5901
SMB
- 135, 139, 445
Custom Ports
Add custom ports in Settings:
Format: comma-separated or ranges
Example: 9000,9001,9002-9010,10000
Screenshots Gallery
Visual walkthrough of PQC Scanner interface.
Login & Authentication
Login Page
Initial login screen - JWT authentication
Login Form
Login form with credentials entered
Main Interface
Dashboard
Main dashboard showing device summary, risk distribution, and recent activity
Scan Control
Configure and start network scans - set target range and collectors
Device Inventory
All discovered devices with risk scores and filtering options
Settings
Configure SSH credentials, custom ports, and scoring weights
Analysis Pages
HNDL Risk Analysis
Harvest Now Decrypt Later - Mosca's Inequality calculator
Reports & Visualization
Paginated risk assessment, certificate timeline, PQC readiness, and report controls
Export To Menu
Unified report export menu for PDF, PQC Excel, CBOM, CSV, and JSON
Generated Reports
Persistent backend queue with export-type tabs, progress, downloads, and deletion
Screenshots captured from the current local CERIA build on 2026-07-22.
Troubleshooting
Common Issues
403 Forbidden (cPanel)
Symptom: Browser shows "403 Forbidden" error Visual indicator:
Expected: This login page should appear. If you see 403 instead, check permissions.
Solution:
# Fix file permissions via SSH
cd /home/username/public_html/pqcs.example.com
chmod 644 .htaccess passenger_wsgi.py
chmod 755 pqcs/
500 Internal Server Error
Symptom: "500 Internal Server Error" page Solution:- Check cPanel > Logs > Error Log
- Verify Python dependencies:
source /home/username/virtualenv/pqcs/3.11/bin/activate
pip install -r requirements.txt
- Check
passenger_wsgi.pysyntax:
python -m py_compile passenger_wsgi.py
Database Connection Issues
Symptom: "OperationalError: unable to open database file" Solution:# Create database directory outside web root
mkdir -p /home/username/db
chmod 755 /home/username/db
chmod 666 /home/username/db/pqcs.db # or 644 after creation
# Update DATABASE_URL environment variable:
# sqlite:////home/username/db/pqcs.db
Login Failures (422 Error)
Symptom: "Failed to load resource: the server responded with a status of 422"
If login fails after entering correct credentials:
Solution:
- Ensure
SECRET_KEYenvironment variable is set in cPanel - Check
bcryptandpyjwtare installed:
pip list | grep -E 'bcrypt|PyJWT'
- Reset password via CLI if needed:
python << 'EOF'
import bcrypt
from pqcs.db import init_db, User
from pqcs.config import AppConfig
config = AppConfig()
db = init_db(config.database.url)
user = db.query(User).filter_by(username="admin").first()
if user:
new_pw = bcrypt.hashpw(b"admin", bcrypt.gensalt())
user.password_hash = new_pw.decode()
db.commit()
print("Password reset to: admin")
EOF
SSH Connection Failures
- Verify SSH credentials in Settings page:
Configure SSH credentials in Settings page
- Check known_hosts file
- Verify firewall allows SSH (port 22)
Application Won't Start
cPanel specific:- Check app shows as "Running" in cPanel Python App
- Verify
passenger_wsgi.pyexists and exposesapplication - Restart the app:
cd /home/username/public_html/pqcs.example.com
mkdir -p tmp && touch tmp/restart.txt
Debug Mode
# Enable debug logging
ceria --verbose dashboard
# Or set environment variable
export LOG_LEVEL=DEBUG
ceria dashboard
Log Locations
| Platform | Location |
| Local | Console (--verbose) |
| cPanel | /home2/yusricom/logs/passenger.log |
| systemd | journalctl -u pqcs |
Getting Help
- Check this troubleshooting guide
- Review relevant section in User Manual
- Check application logs
- Open issue in repository
Report Job Troubleshooting
- If a job remains queued, confirm the application can write to
outputs/reports; restarting recovers queued work. - If PDF generation fails, verify WeasyPrint and its platform libraries are installed in CERIA's Python environment.
- If PQC Excel generation fails, confirm
docs/PQC Template.xlsxexists and is readable. - Active jobs cannot be deleted; wait for completion or failure.
About
Project Information
| Attribute | Details |
| Name | CERIA |
| Full Title | Crypto Evaluation & Readiness for Infrastructure Adaptation (Post-Quantum) |
| Version | 1.0 |
| Status | Production Ready |
| Author | Yusri |
| Contact | yusri@dysfunktion.tech |
| Live URL | https://pqcs.dysfunktion.tech |
| Last Updated | 2026-07-22 |
About the Author
CERIA was developed by Yusri to address the growing need for post-quantum cryptography assessment tools in Malaysia.
Mission
To help organizations prepare for the quantum computing threat by providing accessible, comprehensive cryptographic assessment tools aligned with Malaysia's NCII framework.What is CERIA?
CERIA is a Post-Quantum Cryptography Scanner that implements Malaysia's NCII SCAD (Sectoral Cybersecurity Assessment Dashboard) Framework. It helps organizations:
- Discover cryptographic assets across their infrastructure
- Assess quantum vulnerability using standardized risk scoring
- Calculate Harvest Now, Decrypt Later (HNDL) risks
- Plan migration to post-quantum cryptography
- Comply with MySEAL and NCII requirements
Deployment
CERIA is currently deployed and running on cPanel Shared Hosting at https://pqcs.dysfunktion.tech.
Technical Stack
- Backend: Python 3.11, FastAPI
- Database: SQLite
- Frontend: HTML/Tailwind CSS
- Scanning: nmap, custom cryptographic collectors
License
CERIA - Post-Quantum Cryptography Scanner
Author: Yusri (yusri@dysfunktion.tech)
Related Documentation
- CERIA Project Index - Project overview and quick links
- Quick Start - Get started in 5 minutes
- Installation - Installation guide
- User Manual - Complete feature documentation
Built with care for the Malaysian cybersecurity community.
Documentation Release
This documentation reflects the 2026-07-22 release with enterprise demo data, paginated analysis, persistent report queues, WeasyPrint PDF generation, and populated PQC Excel exports.