cargo_mate/captain/
binary_encryptor.rs1use anyhow::{Context, Result};
2use std::fs;
3use std::path::Path;
4use base64::{Engine as _, engine::general_purpose};
5pub struct BinaryEncryptor {
6 encryption_key: Vec<u8>,
7}
8impl BinaryEncryptor {
9 pub fn new(key: &str) -> Self {
10 use sha2::{Sha256, Digest};
11 let mut hasher = Sha256::new();
12 hasher.update(key.as_bytes());
13 let encryption_key = hasher.finalize().to_vec();
14 Self { encryption_key }
15 }
16 pub fn encrypt_binary(&self, input_path: &Path, output_path: &Path) -> Result<()> {
17 let binary_data = fs::read(input_path)
18 .with_context(|| {
19 format!("Failed to read binary: {}", input_path.display())
20 })?;
21 let encrypted_data = self.xor_encrypt(&binary_data);
22 fs::write(output_path, encrypted_data)
23 .with_context(|| {
24 format!("Failed to write encrypted binary: {}", output_path.display())
25 })?;
26 Ok(())
27 }
28 pub fn create_self_decrypting_binary(
29 &self,
30 input_path: &Path,
31 output_path: &Path,
32 platform: &str,
33 ) -> Result<()> {
34 let binary_data = fs::read(input_path)
35 .with_context(|| {
36 format!("Failed to read binary: {}", input_path.display())
37 })?;
38 let encrypted_data = self.xor_encrypt(&binary_data);
39 let _loader_code = self.generate_loader_code(&encrypted_data, platform);
40 let mut output_data = b"CARGO_MATE_ENCRYPTED_BINARY_V1\n".to_vec();
41 output_data.extend_from_slice(&self.encryption_key);
42 output_data.extend_from_slice(b"\n");
43 output_data.extend_from_slice(&encrypted_data);
44 fs::write(output_path, output_data)
45 .with_context(|| {
46 format!(
47 "Failed to write self-decrypting binary: {}", output_path.display()
48 )
49 })?;
50 println!("🔐 Created self-decrypting binary: {}", output_path.display());
51 Ok(())
52 }
53 fn xor_encrypt(&self, data: &[u8]) -> Vec<u8> {
54 data.iter()
55 .enumerate()
56 .map(|(i, &byte)| byte ^ self.encryption_key[i % self.encryption_key.len()])
57 .collect()
58 }
59 fn xor_decrypt(&self, data: &[u8]) -> Vec<u8> {
60 self.xor_encrypt(data)
61 }
62 fn generate_loader_code(&self, encrypted_data: &[u8], platform: &str) -> String {
63 let encrypted_b64 = general_purpose::STANDARD.encode(encrypted_data);
64 let key_b64 = general_purpose::STANDARD.encode(&self.encryption_key);
65 format!(
66 r#"
67// Auto-generated loader for encrypted cargo-mate binary
68// Platform: {}
69
70use std::process;
71use std::io::Write;
72use base64::{{Engine as _, engine::general_purpose}};
73
74fn main() -> Result<(), Box<dyn std::error::Error>> {{
75 // Embedded encrypted binary and key
76 let encrypted_b64 = "{}";
77 let key_b64 = "{}";
78
79 // Decode the data
80 let encrypted_data = general_purpose::STANDARD.decode(encrypted_b64)?;
81 let key = general_purpose::STANDARD.decode(key_b64)?;
82
83 // Decrypt the binary
84 let decrypted_data = decrypt_binary(&encrypted_data, &key);
85
86 // Execute the decrypted binary in memory
87 execute_in_memory(&decrypted_data)?;
88
89 Ok(())
90}}
91
92fn decrypt_binary(data: &[u8], key: &[u8]) -> Vec<u8> {{
93 data.iter()
94 .enumerate()
95 .map(|(i, &byte)| byte ^ key[i % key.len()])
96 .collect()
97}}
98
99fn execute_in_memory(binary_data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {{
100 // Create a temporary file for the decrypted binary
101 let temp_path = std::env::temp_dir().join("cargo_mate_decrypted");
102
103 // Write decrypted binary to temp file
104 std::fs::write(&temp_path, binary_data)?;
105
106 // Make it executable
107 #[cfg(unix)]
108 {{
109 use std::os::unix::fs::PermissionsExt;
110 let mut perms = std::fs::metadata(&temp_path)?.permissions();
111 perms.set_mode(0o755);
112 std::fs::set_permissions(&temp_path, perms)?;
113 }}
114
115 // Execute the binary
116 let status = process::Command::new(&temp_path)
117 .args(std::env::args().skip(1))
118 .status()?;
119
120 // Clean up
121 let _ = std::fs::remove_file(&temp_path);
122
123 if !status.success() {{
124 process::exit(status.code().unwrap_or(1));
125 }}
126
127 Ok(())
128}}
129 "#,
130 platform, encrypted_b64, key_b64
131 )
132 }
133}
134pub fn encrypt_releases_directory(
135 releases_dir: &Path,
136 encryption_key: &str,
137) -> Result<()> {
138 let encryptor = BinaryEncryptor::new(encryption_key);
139 for entry in fs::read_dir(releases_dir)? {
140 let entry = entry?;
141 let path = entry.path();
142 if path.extension().map_or(false, |ext| ext == "exe")
143 || path
144 .file_name()
145 .map_or(false, |name| !name.to_string_lossy().contains("."))
146 {
147 let encrypted_path = path
148 .with_extension(
149 format!(
150 "{}.encrypted", path.extension().unwrap_or_default()
151 .to_string_lossy()
152 ),
153 );
154 encryptor.encrypt_binary(&path, &encrypted_path)?;
155 }
156 }
157 Ok(())
158}
159pub fn create_self_decrypting_releases(
160 releases_dir: &Path,
161 encryption_key: &str,
162) -> Result<()> {
163 let encryptor = BinaryEncryptor::new(encryption_key);
164 for entry in fs::read_dir(releases_dir)? {
165 let entry = entry?;
166 let path = entry.path();
167 if let Some(file_name) = path.file_name() {
168 let file_name_str = file_name.to_string_lossy();
169 if file_name_str.contains("linux") || file_name_str.contains("macos")
170 || file_name_str.contains("windows")
171 {
172 let platform = if file_name_str.contains("linux") {
173 "linux"
174 } else if file_name_str.contains("macos") {
175 "macos"
176 } else if file_name_str.contains("windows") {
177 "windows"
178 } else {
179 "unknown"
180 };
181 let self_decrypting_path = path
182 .with_extension(
183 format!(
184 "{}.self", path.extension().unwrap_or_default()
185 .to_string_lossy()
186 ),
187 );
188 encryptor
189 .create_self_decrypting_binary(
190 &path,
191 &self_decrypting_path,
192 platform,
193 )?;
194 }
195 }
196 }
197 Ok(())
198}
199pub fn encrypt_binary(data: &[u8]) -> Result<Vec<u8>> {
200 let encryption_key = "default_encryption_key_32_chars_long";
201 let encryptor = BinaryEncryptor::new(encryption_key);
202 Ok(encryptor.xor_encrypt(data))
203}
204pub fn decrypt_binary(encrypted_data: &[u8]) -> Result<Vec<u8>> {
205 let encryption_key = "default_encryption_key_32_chars_long";
206 let encryptor = BinaryEncryptor::new(encryption_key);
207 Ok(encryptor.xor_decrypt(encrypted_data))
208}