/ friend_tool / src / main.rs
main.rs
  1  use pqcrypto_kyber::kyber1024;
  2  use pqcrypto_traits::kem::{SecretKey, Ciphertext, SharedSecret};
  3  use std::fs;
  4  use std::path::PathBuf;
  5  use std::io::{self, Write};
  6  use hex;
  7  use aes_gcm::{Aes256Gcm, Nonce, aead::{Aead, KeyInit, Payload}};
  8  use sha3::{Shake256, Sha3_256, digest::{ExtendableOutput, Update, XofReader, Digest}};
  9  use zeroize::Zeroize;
 10  
 11  fn main() -> Result<(), Box<dyn std::error::Error>> {
 12      println!("=== GHOSTLINE OTP RECEIVER (QUANTUM-SAFE) ===");
 13      println!("For friends to decrypt OTPs from GhostLine admin\n");
 14      
 15      // 1. GET SECRET KEY
 16      println!("1. 🔑 YOUR SECRET KEY");
 17      print!("Path to your Kyber secret.key: ");
 18      io::stdout().flush()?;
 19      let mut secret_path = String::new();
 20      io::stdin().read_line(&mut secret_path)?;
 21      let secret_path = secret_path.trim();
 22      
 23      let secret_bytes = fs::read(secret_path)
 24          .map_err(|e| format!("Failed to read secret key: {}", e))?;
 25      let my_secret = kyber1024::SecretKey::from_bytes(&secret_bytes)
 26          .map_err(|e| format!("Invalid secret key format: {}", e))?;
 27      println!("✅ Loaded secret key");
 28      
 29      // 2. GET YOUR PACKAGE FILES
 30      println!("\n2. 📁 YOUR PACKAGE FROM GHOSTLINE ADMIN");
 31      
 32      print!("Directory containing your package: ");
 33      io::stdout().flush()?;
 34      let mut package_dir = String::new();
 35      io::stdin().read_line(&mut package_dir)?;
 36      let package_dir = package_dir.trim();
 37      
 38      print!("Directory containing common files: ");
 39      io::stdout().flush()?;
 40      let mut common_dir = String::new();
 41      io::stdin().read_line(&mut common_dir)?;
 42      let common_dir = common_dir.trim();
 43      
 44      // 3. LOAD YOUR FILES
 45      println!("\n3. 🔍 LOADING FILES...");
 46      
 47      let kyber_ct_path = PathBuf::from(package_dir).join("kyber_ciphertext.bin");
 48      let wrapped_key_path = PathBuf::from(package_dir).join("wrapped_aes_key.bin");
 49      let wrap_nonce_path = PathBuf::from(package_dir).join("wrap_nonce.bin");
 50      
 51      let ct_bytes = fs::read(&kyber_ct_path)
 52          .map_err(|e| format!("Failed to read kyber_ciphertext.bin: {}", e))?;
 53      println!("✅ Kyber ciphertext: {} bytes", ct_bytes.len());
 54      
 55      let wrapped_aes_key = fs::read(&wrapped_key_path)
 56          .map_err(|e| format!("Failed to read wrapped_aes_key.bin: {}", e))?;
 57      println!("✅ Wrapped AES key: {} bytes", wrapped_aes_key.len());
 58      
 59      let wrap_nonce_data = fs::read(&wrap_nonce_path)
 60          .map_err(|e| format!("Failed to read wrap_nonce.bin: {}", e))?;
 61      println!("✅ Wrap nonce: {} bytes", wrap_nonce_data.len());
 62      
 63      // 4. LOAD COMMON FILES
 64      let encrypted_otp_path = PathBuf::from(common_dir).join("encrypted_otp.bin");
 65      let aes_nonce_path = PathBuf::from(common_dir).join("aes_nonce.bin");
 66      
 67      let encrypted_otp = fs::read(&encrypted_otp_path)
 68          .map_err(|e| format!("Failed to read encrypted_otp.bin: {}", e))?;
 69      println!("✅ Encrypted OTP: {} bytes", encrypted_otp.len());
 70      
 71      let aes_nonce_data = fs::read(&aes_nonce_path)
 72          .map_err(|e| format!("Failed to read aes_nonce.bin: {}", e))?;
 73      println!("✅ AES nonce: {} bytes", aes_nonce_data.len());
 74      
 75      // 5. DECRYPT KYBER TO GET SHARED SECRET
 76      println!("\n4. 🔐 DECRYPTING KYBER CIPHERTEXT");
 77      let ciphertext = kyber1024::Ciphertext::from_bytes(&ct_bytes)
 78          .map_err(|e| format!("Invalid Kyber ciphertext: {}", e))?;
 79      let shared_secret = kyber1024::decapsulate(&ciphertext, &my_secret);
 80      let secret_bytes = shared_secret.as_bytes();
 81      
 82      println!("✅ Recovered shared secret: {}...", hex::encode(&secret_bytes[..8]));
 83      
 84      // 6. DERIVE WRAP KEY WITH SHAKE256 - MUST MATCH ADMIN EXACTLY
 85      println!("\n5. 🔑 DERIVING WRAP KEY (SHAKE256)");
 86      
 87      let mut shake = Shake256::default();
 88      Update::update(&mut shake, secret_bytes);
 89      Update::update(&mut shake, b"GHOSTLINE-AES-KEY-WRAP-v1");
 90      Update::update(&mut shake, &ct_bytes[..32]);
 91      // NO OTP SIZE - MUST MATCH ADMIN EXACTLY!
 92      
 93      let mut wrap_key = [0u8; 32];
 94      let mut reader = shake.finalize_xof();
 95      reader.read(&mut wrap_key);
 96      
 97      println!("✅ Wrap key derived: {}...", hex::encode(&wrap_key[..8]));
 98      
 99      // 7. DECRYPT THE WRAPPED AES KEY
100      println!("\n6. 🔓 UNWRAPPING AES KEY");
101      
102      let wrap_cipher = Aes256Gcm::new_from_slice(&wrap_key)?;
103      let wrap_nonce = Nonce::from_slice(&wrap_nonce_data);
104      
105      let payload = Payload {
106          msg: &wrapped_aes_key,
107          aad: b"",
108      };
109      
110      let aes_key_vec = wrap_cipher.decrypt(wrap_nonce, payload)
111          .map_err(|e| format!("Failed to unwrap AES key: {}", e))?;
112      
113      if aes_key_vec.len() != 32 {
114          return Err(format!("Invalid AES key length: {} bytes", aes_key_vec.len()).into());
115      }
116      
117      let mut aes_key = [0u8; 32];
118      aes_key.copy_from_slice(&aes_key_vec[..32]);
119      
120      println!("✅ AES-256 key recovered: {}...", hex::encode(&aes_key[..8]));
121      
122      // 8. DECRYPT OTP WITH AES KEY
123      println!("\n7. 🔓 DECRYPTING OTP");
124      
125      let cipher = Aes256Gcm::new_from_slice(&aes_key)?;
126      let aes_nonce = Nonce::from_slice(&aes_nonce_data);
127      
128      let payload = Payload {
129          msg: &encrypted_otp,
130          aad: b"",
131      };
132      
133      let decrypted_otp = cipher.decrypt(aes_nonce, payload)
134          .map_err(|e| format!("Failed to decrypt OTP: {}", e))?;
135      
136      println!("✅ OTP decrypted: {} bytes", decrypted_otp.len());
137      
138      // 9. SAVE OTP
139      println!("\n8. 💾 SAVING DECRYPTED OTP");
140      
141      let output_path = "./ghostline_otp.bin";
142      fs::write(output_path, &decrypted_otp)?;
143      
144      println!("✅ OTP saved to: {}", output_path);
145      
146      // 10. VERIFICATION WITH SHA3-256
147      println!("\n9. ✅ VERIFICATION");
148      
149      let mut hasher = Sha3_256::new();
150      Update::update(&mut hasher, &decrypted_otp);
151      let otp_hash = hasher.finalize();
152      
153      println!("OTP SHA3-256 hash: {}", hex::encode(otp_hash));
154      println!("Share this hash with GhostLine admin to verify ALL friends got same OTP.");
155      
156      // 11. CLEAR SENSITIVE DATA
157      wrap_key.zeroize();
158      aes_key.zeroize();
159      
160      println!("\n=== READY FOR GHOSTLINE ===");
161      println!("Run GhostLine with this OTP:");
162      println!("  ghostline --otp {}", output_path);
163      
164      Ok(())
165  }