Skip to main content

hexz_cli/cmd/sys/
sign.rs

1//! Cryptographically sign Hexz archives with Ed25519 signatures.
2//!
3//! This module implements the `sign` command, which creates a cryptographic
4//! signature for a Hexz archive to ensure authenticity and integrity.
5//!
6//! # Signing Process
7//!
8//! The signing operation follows these steps:
9//!
10//! 1. **Load Header**: Read and parse the archive header
11//! 2. **Read Master Index**: Read the entire index structure (block mappings)
12//! 3. **Compute Digest**: Calculate SHA-256 hash of the index
13//! 4. **Sign Digest**: Create Ed25519 signature using private key
14//! 5. **Append Signature**: Write 64-byte signature to end of file
15//! 6. **Update Header**: Record signature offset and length in header
16//!
17//! # What Gets Signed
18//!
19//! The signature covers the **Master Index** only, not the entire file. This is
20//! because:
21//! - The header is mutable (to store signature metadata)
22//! - Data blocks are content-addressed via their hashes in the index
23//! - Signing the index ensures block mappings haven't been tampered with
24//!
25//! # Signature Format
26//!
27//! - **Algorithm**: Ed25519 (EdDSA on Curve25519)
28//! - **Digest**: SHA-256 of Master Index
29//! - **Signature Size**: 64 bytes
30//! - **Storage**: Appended to end of archive file
31//!
32//! # Security Properties
33//!
34//! - **Authenticity**: Proves the archive was created by holder of private key
35//! - **Integrity**: Detects any modification to the index structure
36//! - **Non-repudiation**: Signer cannot deny creating the signature
37//!
38//! # Usage
39//!
40//! ```bash
41//! # Generate keys first
42//! hexz sys keygen --output-dir ~/.hexz/keys
43//!
44//! # Sign an archive
45//! hexz sys sign --key ~/.hexz/keys/private.key snapshot.st
46//!
47//! # Verify the signature
48//! hexz sys verify --key ~/.hexz/keys/public.key snapshot.st
49//! ```
50//!
51//! # File Format Changes
52//!
53//! After signing, the archive structure becomes:
54//!
55//! ```text
56//! ┌─────────────────┐
57//! │  Header         │ signature_offset, signature_length fields updated
58//! ├─────────────────┤
59//! │  Index          │ ← This is what gets signed (SHA-256 digest)
60//! ├─────────────────┤
61//! │  Data Blocks    │
62//! ├─────────────────┤
63//! │  Signature      │ ← 64-byte Ed25519 signature (appended)
64//! └─────────────────┘
65//! ```
66
67use anyhow::Result;
68use hexz_core::ops::sign::sign_snapshot;
69use std::path::PathBuf;
70
71/// Sign a Hexz archive with an Ed25519 private key.
72///
73/// This function creates a cryptographic signature for the archive's Master Index
74///and embeds it in the archive file, updating the header to record the signature's
75/// location.
76///
77/// # Arguments
78///
79/// * `key_path` - Path to the Ed25519 private key file (32 bytes)
80/// * `image_path` - Path to the Hexz archive file to sign
81///
82/// # Process
83///
84/// 1. Opens the archive and reads the header
85/// 2. Reads the entire Master Index structure
86/// 3. Computes SHA-256 digest of the index
87/// 4. Signs the digest with Ed25519 private key
88/// 5. Appends 64-byte signature to end of file
89/// 6. Updates header with signature offset/length
90///
91/// # Returns
92///
93/// Returns `Ok(())` on success, or an error if:
94/// - Private key file cannot be read
95/// - Archive file cannot be opened or is malformed
96/// - Header cannot be parsed
97/// - Signature generation fails
98/// - File I/O errors occur
99///
100/// # Side Effects
101///
102/// - Modifies the archive file (appends signature, updates header)
103/// - Existing signature (if any) is replaced
104///
105/// # Example
106///
107/// ```no_run
108/// # use std::path::PathBuf;
109/// # use hexz_cli::cmd::sys::sign;
110/// let key = PathBuf::from("~/.hexz/keys/private.key");
111/// let archive = PathBuf::from("snapshot.hxz");
112/// sign::run(key, archive)?;
113/// # Ok::<(), anyhow::Error>(())
114/// ```
115pub fn run(key_path: PathBuf, image_path: PathBuf) -> Result<()> {
116    println!("Signing {:?} with key {:?}...", image_path, key_path);
117    sign_snapshot(&image_path, &key_path)?;
118    println!("Signature written to image.");
119    Ok(())
120}