openadp_ocrypt/lib.rs
1//! # OpenADP Rust SDK
2//!
3//! This crate provides a complete Rust implementation of the OpenADP (Open Advanced Data Protection)
4//! distributed secret sharing system, designed to protect against nation-state attacks.
5//!
6//! ## Core Features
7//!
8//! - **Ed25519 elliptic curve operations** with point compression/decompression
9//! - **Shamir secret sharing** with threshold recovery
10//! - **Noise-NK protocol** for secure server communication
11//! - **JSON-RPC 2.0 API** with multi-server support
12//! - **Cross-language compatibility** with Go and Python implementations
13//!
14//! ## Quick Start
15//!
16//! ```rust,no_run
17//! use openadp_ocrypt::{generate_encryption_key, recover_encryption_key, get_servers, Identity};
18//!
19//! #[tokio::main]
20//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
21//! // Get live servers
22//! let servers = get_servers("").await?;
23//!
24//! // Create Identity for the encryption operation
25//! let identity = Identity::new(
26//! "user@example.com".to_string(), // UID - user identifier
27//! "laptop-2024".to_string(), // DID - device identifier
28//! "document.pdf".to_string() // BID - backup identifier
29//! );
30//!
31//! // Generate encryption key with distributed backup
32//! let result = generate_encryption_key(
33//! &identity,
34//! "secure_password",
35//! 10, // max_guesses
36//! 0, // expiration
37//! servers,
38//! ).await?;
39//!
40//! if let Some(key) = result.encryption_key {
41//! println!("Generated key: {} bytes", key.len());
42//!
43//! // Later: recover the key
44//! let recovered = recover_encryption_key(
45//! &identity,
46//! "secure_password",
47//! result.server_infos.unwrap(),
48//! result.threshold.unwrap(),
49//! result.auth_codes.unwrap(),
50//! ).await?;
51//!
52//! if let Some(recovered_key) = recovered.encryption_key {
53//! assert_eq!(key, recovered_key);
54//! println!("Successfully recovered key!");
55//! }
56//! }
57//!
58//! Ok(())
59//! }
60//! ```
61
62use std::path::Path;
63
64/// Derive identifiers from filename, user_id, and hostname
65/// This matches the Go DeriveIdentifiers function behavior
66pub fn derive_identifiers(filename: &str, user_id: &str, hostname: &str) -> (String, String, String) {
67 let hostname = if hostname.is_empty() {
68 gethostname::gethostname().to_string_lossy().to_string()
69 } else {
70 hostname.to_string()
71 };
72
73 let bid = format!("file://{}", Path::new(filename).file_name().unwrap_or_default().to_string_lossy());
74
75 (user_id.to_string(), hostname, bid)
76}
77
78pub mod crypto;
79pub mod client;
80pub mod keygen;
81pub mod ocrypt;
82pub mod recovery;
83
84// Re-export main functionality
85pub use crypto::*;
86pub use client::*;
87pub use keygen::*;
88pub use ocrypt::*;
89pub use recovery::*;
90
91// Error types
92use thiserror::Error;
93
94#[derive(Error, Debug)]
95pub enum OpenADPError {
96 #[error("Network error: {0}")]
97 Network(#[from] reqwest::Error),
98
99 #[error("JSON error: {0}")]
100 Json(#[from] serde_json::Error),
101
102 #[error("Cryptographic error: {0}")]
103 Crypto(String),
104
105 #[error("Invalid input: {0}")]
106 InvalidInput(String),
107
108 #[error("Server error: {0}")]
109 Server(String),
110
111 #[error("Authentication failed: {0}")]
112 Authentication(String),
113
114 #[error("No servers available")]
115 NoServers,
116
117 #[error("Insufficient servers for threshold")]
118 InsufficientServers,
119
120 #[error("Invalid response from server")]
121 InvalidResponse,
122
123 #[error("Encryption/decryption failed")]
124 EncryptionFailed,
125
126 #[error("Point operation failed: {0}")]
127 PointOperation(String),
128
129 #[error("Secret sharing failed: {0}")]
130 SecretSharing(String),
131
132 #[error("I/O error: {0}")]
133 Io(String),
134
135 #[error("Invalid format: {0}")]
136 InvalidFormat(String),
137}
138
139pub type Result<T> = std::result::Result<T, OpenADPError>;
140
141// Constants
142pub const DEFAULT_REGISTRY_URL: &str = "https://servers.openadp.org/api/servers.json";
143pub const FIELD_PRIME: &str = "57896044618658097711785492504343953926634992332820282019728792003956564819949"; // 2^255 - 19
144pub const CURVE_ORDER: &str = "7237005577332262213973186563042994240857116359379907606001950938285454250989"; // 2^252 + 27742317777372353535851937790883648493
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn test_constants() {
152 // Basic sanity checks
153 assert!(FIELD_PRIME.len() > 50);
154 assert!(CURVE_ORDER.len() > 50);
155 }
156
157 #[test]
158 fn test_error_types() {
159 let err = OpenADPError::InvalidInput("test".to_string());
160 assert!(err.to_string().contains("Invalid input"));
161 }
162}