git_crypt/lib.rs
1//! # git-crypt
2//!
3//! A Rust implementation of git-crypt for transparent encryption of files in a git repository.
4//!
5//! ## Features
6//!
7//! - **Transparent Encryption**: Files are automatically encrypted when committed and decrypted when checked out
8//! - **AES-256-GCM Encryption**: Strong, authenticated encryption with built-in tamper detection
9//! - **Git Filter Integration**: Uses git's clean/smudge filters for seamless operation
10//! - **Key Management**: Export and import symmetric keys for secure sharing
11//! - **GPG Support**: Optional GPG integration for team key distribution
12//! - **SSH/age Sharing**: Optional age/rage integration for sharing keys with SSH recipients
13//! - **Simple CLI**: Easy-to-use command-line interface
14//!
15//! ## Quick Start
16//!
17//! ### Installation
18//!
19//! Install from GitHub:
20//! ```bash
21//! cargo install --git https://github.com/AprilNEA/git-crypt-rs
22//! ```
23//!
24//! Or build from source:
25//! ```bash
26//! cargo build --release
27//! # Binary will be at target/release/git-crypt
28//! ```
29//!
30//! ### Basic Usage
31//!
32//! ```bash
33//! # Initialize in your git repository
34//! git-crypt init
35//!
36//! # Configure which files to encrypt in .gitattributes
37//! echo "*.secret filter=git-crypt diff=git-crypt" >> .gitattributes
38//! git add .gitattributes
39//! git commit -m "Configure git-crypt"
40//!
41//! # Add encrypted files (automatically encrypted)
42//! echo "my secret data" > test.secret
43//! git add test.secret
44//! git commit -m "Add encrypted file"
45//!
46//! # Export key for sharing
47//! git-crypt export-key git-crypt-key.bin
48//! ```
49//!
50//! ## How It Works
51//!
52//! git-crypt uses git's filter system to transparently encrypt and decrypt files:
53//!
54//! 1. **Clean filter** (encryption): When you `git add` a file, the clean filter encrypts it before storing in the repository
55//! 2. **Smudge filter** (decryption): When you `git checkout`, the smudge filter decrypts it in your working directory
56//! 3. **Diff filter**: When you `git diff`, it shows that the file is encrypted rather than binary gibberish
57//!
58//! The encryption key is stored in `.git/git-crypt/keys/default` and is never committed to the repository.
59//!
60//! ### Data Flow
61//!
62//! **Encryption (git add):**
63//! ```text
64//! File content → git add → clean filter → encrypt → store in .git
65//! ```
66//!
67//! **Decryption (git checkout):**
68//! ```text
69//! Encrypted data in .git → smudge filter → decrypt → working directory
70//! ```
71//!
72//! ## Module Overview
73//!
74//! - [`crypto`] - Core AES-256-GCM encryption/decryption operations
75//! - [`key`] - Key management, storage, export/import
76//! - [`git`] - Git filter integration and repository operations
77//! - [`gpg`] - Optional GPG support for key sharing (requires `gpg` feature)
78//! - [`rage`] - Optional age/rage-based SSH key sharing (requires `ssh` feature)
79//! - [`error`] - Error types and unified error handling
80//!
81//! ## Commands
82//!
83//! - `init` - Initialize git-crypt in the current repository
84//! - `lock` - Lock the repository (remove filters, show encrypted content)
85//! - `unlock [--key-file PATH]` - Unlock the repository
86//! - `export-key OUTPUT` - Export the symmetric key to a file
87//! - `import-key INPUT` - Import a symmetric key from a file
88//! - `add-gpg-user GPG_ID` - Grant access to a GPG user (requires `gpg` feature)
89//! - `add-ssh-user --ssh-key PATH` - Encrypt the key for an SSH recipient via age/rage (requires `ssh` feature)
90//! - `import-age-key --input FILE --identity SSH_KEY` - Decrypt an age/rage key blob with your SSH key (requires `ssh` feature)
91//! - `status` - Show status of encrypted files (not yet implemented)
92//!
93//! ## Examples
94//!
95//! ### Complete Workflow
96//!
97//! ```bash
98//! # 1. Initialize a git repository
99//! git init my-secure-repo
100//! cd my-secure-repo
101//!
102//! # 2. Initialize git-crypt
103//! git-crypt init
104//!
105//! # 3. Configure encryption patterns in .gitattributes
106//! cat > .gitattributes << 'EOF'
107//! # Encrypt all files in the secrets/ directory
108//! secrets/** filter=git-crypt diff=git-crypt
109//!
110//! # Encrypt specific file types
111//! *.key filter=git-crypt diff=git-crypt
112//! *.secret filter=git-crypt diff=git-crypt
113//!
114//! # Encrypt specific config files
115//! config/database.yml filter=git-crypt diff=git-crypt
116//! .env.production filter=git-crypt diff=git-crypt
117//! EOF
118//!
119//! git add .gitattributes
120//! git commit -m "Configure git-crypt"
121//!
122//! # 4. Add encrypted files
123//! mkdir -p secrets
124//! echo "AWS_SECRET_KEY=secret123" > secrets/api_keys.txt
125//! git add secrets/
126//! git commit -m "Add encrypted secrets"
127//!
128//! # 5. Share access with team members
129//! git-crypt export-key team-key.bin
130//! # Share team-key.bin securely (password manager, secure channel, etc.)
131//! ```
132//!
133//! ### Unlocking on Another Machine
134//!
135//! ```bash
136//! # Clone the repository
137//! git clone <repository-url>
138//! cd <repository>
139//!
140//! # At this point, encrypted files show as encrypted data
141//!
142//! # Unlock with the shared key
143//! git-crypt unlock --key-file team-key.bin
144//!
145//! # Refresh working directory
146//! git checkout HEAD -- .
147//!
148//! # Now files are decrypted
149//! cat secrets/api_keys.txt
150//! ```
151//!
152//! ### Lock/Unlock
153//!
154//! ```bash
155//! # Lock repository (useful before sharing working directory)
156//! git-crypt lock
157//! # Now all encrypted files show their encrypted content
158//!
159//! # Unlock again
160//! git-crypt unlock
161//! git checkout HEAD -- .
162//! ```
163//!
164//! ## Security Considerations
165//!
166//! ### Threat Model
167//!
168//! **Protected against:**
169//! - Unauthorized access to repository content
170//! - Accidental exposure of secrets in public repositories
171//! - Historical secret leakage in git history
172//!
173//! **Not protected against:**
174//! - Attacks on the working directory (files are plaintext there)
175//! - Compromised git client or filters
176//! - Key extraction from `.git` directory
177//! - Side-channel attacks
178//!
179//! ### Best Practices
180//!
181//! 1. Keep `.git/git-crypt/` directory secure
182//! 2. Use restrictive file permissions (automatic on Unix)
183//! 3. Never commit key files to the repository
184//! 4. Use GPG for team key distribution when possible
185//! 5. Rotate keys if compromised
186//! 6. Consider full-disk encryption for additional security
187//! 7. Share exported keys through secure channels only
188//!
189//! ## Cryptography Details
190//!
191//! - **Algorithm**: AES-256-GCM (Galois/Counter Mode)
192//! - **Key size**: 256 bits (32 bytes)
193//! - **Nonce size**: 96 bits (12 bytes), randomly generated per encryption
194//! - **Authentication**: Built into GCM mode (16-byte tag)
195//!
196//! ### Encrypted File Format
197//!
198//! ```text
199//! [GITCRYPT][12-byte nonce][variable-length ciphertext + 16-byte GCM tag]
200//! ```
201//!
202//! The magic header ensures reliable detection of encrypted data and provides
203//! versioning capability for future format changes.
204//!
205//! ## GPG Support (Optional)
206//!
207//! To enable GPG support, install system dependencies and build with the `gpg` feature:
208//!
209//! **macOS:**
210//! ```bash
211//! brew install nettle gmp
212//! cargo install --git https://github.com/AprilNEA/git-crypt-rs --features gpg
213//! ```
214//!
215//! **Ubuntu/Debian:**
216//! ```bash
217//! sudo apt-get install libnettle-dev libgmp-dev
218//! cargo install --git https://github.com/AprilNEA/git-crypt-rs --features gpg
219//! ```
220//!
221//! Then use GPG for key sharing:
222//! ```bash
223//! git-crypt add-gpg-user user@example.com
224//! ```
225//!
226//! ## SSH/age Support (Optional)
227//!
228//! Build with the `ssh` feature (which pulls in the `age` dependency) to share repository keys using SSH recipients via age/rage:
229//!
230//! ```bash
231//! cargo install --git https://github.com/AprilNEA/git-crypt-rs --features ssh
232//!
233//! # Encrypt the repo key for a teammate's SSH public key
234//! git-crypt add-ssh-user --ssh-key ~/.ssh/id_ed25519.pub --alias teammate
235//!
236//! # Teammate imports it with their private key
237//! git-crypt import-age-key --input .git/git-crypt/keys/age/teammate.age --identity ~/.ssh/id_ed25519
238//! ```
239//!
240//! ## Compatibility
241//!
242//! **Not compatible with original git-crypt:**
243//! - Different file format (magic header + nonce prepended)
244//! - Different key storage location
245//! - Different filter commands
246//!
247//! This is a complete reimplementation focusing on:
248//! - Memory safety (Rust)
249//! - Modern cryptography practices
250//! - Simplicity and maintainability
251//! - Optional features (GPG)
252//!
253//! ## Testing
254//!
255//! The project has a comprehensive test suite with **63 tests** covering:
256//!
257//! ### Unit Tests (29 tests)
258//!
259//! Run all unit tests:
260//! ```bash
261//! cargo test --lib
262//! ```
263//!
264//! - **Crypto module** ([`crypto`]): Encryption correctness, authentication, edge cases
265//! - **Key management** ([`key`]): File operations, permissions, key lifecycle
266//!
267//! ### Integration Tests (16 tests)
268//!
269//! Run all integration tests:
270//! ```bash
271//! cargo test --test integration_test
272//! ```
273//!
274//! Tests complete workflows: initialization, lock/unlock, key export/import, multi-repo isolation.
275//!
276//! ### Filter Tests (6 tests)
277//!
278//! Run filter tests:
279//! ```bash
280//! cargo test --test filter_test
281//! ```
282//!
283//! Tests git filter operations: clean (encrypt), smudge (decrypt), diff.
284//!
285//! ### Edge Case Tests (12 tests)
286//!
287//! Run edge case tests:
288//! ```bash
289//! cargo test --test edge_cases_test
290//! ```
291//!
292//! Tests corner cases: large files (10MB), empty files, binary data, Unicode,
293//! corruption detection, concurrency, permissions.
294//!
295//! ## Running All Tests
296//!
297//! ```bash
298//! # Run all tests
299//! cargo test
300//!
301//! # Run with output
302//! cargo test -- --nocapture
303//!
304//! # Run with backtrace
305//! RUST_BACKTRACE=1 cargo test
306//!
307//! # Run specific test
308//! cargo test test_encrypt_decrypt
309//! ```
310//!
311//! ## Test Coverage
312//!
313//! Generate coverage report (requires cargo-tarpaulin):
314//! ```bash
315//! cargo install cargo-tarpaulin
316//! cargo tarpaulin --out Html
317//! ```
318//!
319//! ## Security Testing
320//!
321//! Tests verify security properties:
322//! - ✅ Authentication (wrong key fails decryption)
323//! - ✅ Tamper detection (corrupted data rejected)
324//! - ✅ File permissions (0600 on Unix)
325//! - ✅ Key isolation (different repos use different keys)
326//! - ✅ Nonce uniqueness (no nonce reuse)
327
328// Library exports for testing
329pub mod crypto;
330pub mod error;
331pub mod git;
332pub mod gpg;
333pub mod key;
334#[cfg(feature = "ssh")]
335pub mod rage;
336pub mod sync;
337
338// Re-export commonly used types
339pub use crypto::CryptoKey;
340pub use error::{GitCryptError, Result};
341pub use git::GitRepo;
342pub use key::KeyManager;