Crate git_crypt

Crate git_crypt 

Source
Expand description

§git-crypt

A Rust implementation of git-crypt for transparent encryption of files in a git repository.

§Features

  • Transparent Encryption: Files are automatically encrypted when committed and decrypted when checked out
  • AES-256-GCM Encryption: Strong, authenticated encryption with built-in tamper detection
  • Git Filter Integration: Uses git’s clean/smudge filters for seamless operation
  • Key Management: Export and import symmetric keys for secure sharing
  • GPG Support: Optional GPG integration for team key distribution
  • SSH/age Sharing: Optional age/rage integration for sharing keys with SSH recipients
  • Simple CLI: Easy-to-use command-line interface

§Quick Start

§Installation

Install from GitHub:

cargo install --git https://github.com/AprilNEA/git-crypt-rs

Or build from source:

cargo build --release
# Binary will be at target/release/git-crypt

§Basic Usage

# Initialize in your git repository
git-crypt init

# Configure which files to encrypt in .gitattributes
echo "*.secret filter=git-crypt diff=git-crypt" >> .gitattributes
git add .gitattributes
git commit -m "Configure git-crypt"

# Add encrypted files (automatically encrypted)
echo "my secret data" > test.secret
git add test.secret
git commit -m "Add encrypted file"

# Export key for sharing
git-crypt export-key git-crypt-key.bin

§How It Works

git-crypt uses git’s filter system to transparently encrypt and decrypt files:

  1. Clean filter (encryption): When you git add a file, the clean filter encrypts it before storing in the repository
  2. Smudge filter (decryption): When you git checkout, the smudge filter decrypts it in your working directory
  3. Diff filter: When you git diff, it shows that the file is encrypted rather than binary gibberish

The encryption key is stored in .git/git-crypt/keys/default and is never committed to the repository.

§Data Flow

Encryption (git add):

File content → git add → clean filter → encrypt → store in .git

Decryption (git checkout):

Encrypted data in .git → smudge filter → decrypt → working directory

§Module Overview

  • crypto - Core AES-256-GCM encryption/decryption operations
  • key - Key management, storage, export/import
  • git - Git filter integration and repository operations
  • gpg - Optional GPG support for key sharing (requires gpg feature)
  • rage_support - Optional age/rage-based SSH key sharing (requires ssh feature)
  • error - Error types and unified error handling

§Commands

  • init - Initialize git-crypt in the current repository
  • lock - Lock the repository (remove filters, show encrypted content)
  • unlock [--key-file PATH] - Unlock the repository
  • export-key OUTPUT - Export the symmetric key to a file
  • import-key INPUT - Import a symmetric key from a file
  • add-gpg-user GPG_ID - Grant access to a GPG user (requires gpg feature)
  • add-ssh-user --ssh-key PATH - Encrypt the key for an SSH recipient via age/rage (requires ssh feature)
  • import-age-key --input FILE --identity SSH_KEY - Decrypt an age/rage key blob with your SSH key (requires ssh feature)
  • status - Show status of encrypted files (not yet implemented)

§Examples

§Complete Workflow

# 1. Initialize a git repository
git init my-secure-repo
cd my-secure-repo

# 2. Initialize git-crypt
git-crypt init

# 3. Configure encryption patterns in .gitattributes
cat > .gitattributes << 'EOF'
# Encrypt all files in the secrets/ directory
secrets/** filter=git-crypt diff=git-crypt

# Encrypt specific file types
*.key filter=git-crypt diff=git-crypt
*.secret filter=git-crypt diff=git-crypt

# Encrypt specific config files
config/database.yml filter=git-crypt diff=git-crypt
.env.production filter=git-crypt diff=git-crypt
EOF

git add .gitattributes
git commit -m "Configure git-crypt"

# 4. Add encrypted files
mkdir -p secrets
echo "AWS_SECRET_KEY=secret123" > secrets/api_keys.txt
git add secrets/
git commit -m "Add encrypted secrets"

# 5. Share access with team members
git-crypt export-key team-key.bin
# Share team-key.bin securely (password manager, secure channel, etc.)

§Unlocking on Another Machine

# Clone the repository
git clone <repository-url>
cd <repository>

# At this point, encrypted files show as encrypted data

# Unlock with the shared key
git-crypt unlock --key-file team-key.bin

# Refresh working directory
git checkout HEAD -- .

# Now files are decrypted
cat secrets/api_keys.txt

§Lock/Unlock

# Lock repository (useful before sharing working directory)
git-crypt lock
# Now all encrypted files show their encrypted content

# Unlock again
git-crypt unlock
git checkout HEAD -- .

§Security Considerations

§Threat Model

Protected against:

  • Unauthorized access to repository content
  • Accidental exposure of secrets in public repositories
  • Historical secret leakage in git history

Not protected against:

  • Attacks on the working directory (files are plaintext there)
  • Compromised git client or filters
  • Key extraction from .git directory
  • Side-channel attacks

§Best Practices

  1. Keep .git/git-crypt/ directory secure
  2. Use restrictive file permissions (automatic on Unix)
  3. Never commit key files to the repository
  4. Use GPG for team key distribution when possible
  5. Rotate keys if compromised
  6. Consider full-disk encryption for additional security
  7. Share exported keys through secure channels only

§Cryptography Details

  • Algorithm: AES-256-GCM (Galois/Counter Mode)
  • Key size: 256 bits (32 bytes)
  • Nonce size: 96 bits (12 bytes), randomly generated per encryption
  • Authentication: Built into GCM mode (16-byte tag)

§Encrypted File Format

[GITCRYPT][12-byte nonce][variable-length ciphertext + 16-byte GCM tag]

The magic header ensures reliable detection of encrypted data and provides versioning capability for future format changes.

§GPG Support (Optional)

To enable GPG support, install system dependencies and build with the gpg feature:

macOS:

brew install nettle gmp
cargo install --git https://github.com/AprilNEA/git-crypt-rs --features gpg

Ubuntu/Debian:

sudo apt-get install libnettle-dev libgmp-dev
cargo install --git https://github.com/AprilNEA/git-crypt-rs --features gpg

Then use GPG for key sharing:

git-crypt add-gpg-user user@example.com

§SSH/age Support (Optional)

Build with the ssh feature (which pulls in the age dependency) to share repository keys using SSH recipients via age/rage:

cargo install --git https://github.com/AprilNEA/git-crypt-rs --features ssh

# Encrypt the repo key for a teammate's SSH public key
git-crypt add-ssh-user --ssh-key ~/.ssh/id_ed25519.pub --alias teammate

# Teammate imports it with their private key
git-crypt import-age-key --input .git/git-crypt/keys/age/teammate.age --identity ~/.ssh/id_ed25519

§Compatibility

Not compatible with original git-crypt:

  • Different file format (magic header + nonce prepended)
  • Different key storage location
  • Different filter commands

This is a complete reimplementation focusing on:

  • Memory safety (Rust)
  • Modern cryptography practices
  • Simplicity and maintainability
  • Optional features (GPG)

§Testing

The project has a comprehensive test suite with 63 tests covering:

§Unit Tests (29 tests)

Run all unit tests:

cargo test --lib
  • Crypto module (crypto): Encryption correctness, authentication, edge cases
  • Key management (key): File operations, permissions, key lifecycle

§Integration Tests (16 tests)

Run all integration tests:

cargo test --test integration_test

Tests complete workflows: initialization, lock/unlock, key export/import, multi-repo isolation.

§Filter Tests (6 tests)

Run filter tests:

cargo test --test filter_test

Tests git filter operations: clean (encrypt), smudge (decrypt), diff.

§Edge Case Tests (12 tests)

Run edge case tests:

cargo test --test edge_cases_test

Tests corner cases: large files (10MB), empty files, binary data, Unicode, corruption detection, concurrency, permissions.

§Running All Tests

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Run with backtrace
RUST_BACKTRACE=1 cargo test

# Run specific test
cargo test test_encrypt_decrypt

§Test Coverage

Generate coverage report (requires cargo-tarpaulin):

cargo install cargo-tarpaulin
cargo tarpaulin --out Html

§Security Testing

Tests verify security properties:

  • ✅ Authentication (wrong key fails decryption)
  • ✅ Tamper detection (corrupted data rejected)
  • ✅ File permissions (0600 on Unix)
  • ✅ Key isolation (different repos use different keys)
  • ✅ Nonce uniqueness (no nonce reuse)

Re-exports§

pub use crypto::CryptoKey;
pub use error::GitCryptError;
pub use error::Result;
pub use git::GitRepo;
pub use key::KeyManager;

Modules§

crypto
Cryptographic Operations
error
git
gpg
key
Key Management
rage_support