lupin 0.1.0

A lightweight steganography tool for hiding binary data inside PDF files.
Documentation
lupin-0.1.0 has been yanked.

πŸ•΅οΈ Lupin

CI License Rust

A blazing-fast, lightweight steganography tool for concealing data inside PDF files. Lupin exploits the fact that PDF viewers ignore content after the %%EOF marker, allowing arbitrary payloads to be appended to a document without affecting how it is displayed by standard PDF readers.

Written in Rust for performance and safety, Lupin provides a simple command-line interface for embedding and extracting hidden files. It is cross-platform and works on Linux, macOS and Windows.

In an era when privacy is important, Lupin offers a discreet way to conceal sensitive information within ordinary documents. It is named after Arsène Lupin, the fictional gentleman thief — a nod to the project's goal of invisibly hiding data inside ordinary files.

πŸš€ Quick Start

Installation

You can build Lupin from source:

git clone https://github.com/niclashedam/lupin.git
cd lupin
cargo build --release

Alternatively, download the latest binary for your platform from the releases page.

Basic usage

# Hide a secret file inside a PDF
lupin embed document.pdf secret.txt output.pdf

# Extract the hidden file
lupin extract output.pdf recovered_secret.txt

# Extract to stdout (useful for piping)
lupin extract output.pdf -

πŸ”§ How it works

Lupin exploits a feature of the PDF format: content after the %%EOF marker is ignored by PDF readers but remains part of the file. The tool implements two main operations:

  1. Embedding: finds the last %%EOF marker in the PDF and appends base64-encoded payload data directly after it.
  2. Extraction: locates the %%EOF marker and decodes everything after it back to the original binary data.

In short, Lupin uses the PDF as a container for hidden data while preserving the original document so it opens normally in any PDF viewer.

πŸ’‘ Usage examples

Hide a text message

echo "Meet me at the park at 5 pm" > secret.txt
lupin embed document.pdf secret.txt innocent_looking.pdf

Hide an image

lupin embed report.pdf vacation_photo.jpg boring_report.pdf

Hide an archive

# Create a zip archive of a folder
zip -r secrets.zip confidential_folder/

# Embed the archive into a PDF
lupin embed presentation.pdf secrets.zip presentation_with_secrets.pdf

Extract and view

# Extract to a file
lupin extract presentation_with_secrets.pdf extracted_secrets.zip

# Extract and pipe to another command
lupin extract presentation_with_secrets.pdf - | unzip -

πŸ—οΈ Building from source

Prerequisites

  • Rust 1.70 or later
  • Cargo (included with Rust)

Build commands

# Development build
cargo build

# Optimised release build
cargo build --release

# Run tests
cargo test

# Check code formatting
cargo fmt --check

# Run the linter
cargo clippy

πŸ§ͺ Testing

The project includes comprehensive tests to ensure reliability:

# Run all tests
cargo test

# Run tests with verbose output
cargo test --verbose

# Run a single test
cargo test test_encode_and_extract_payload

The CI pipeline also performs integration tests by embedding and extracting data from the included examples/cat.pdf file.

πŸ“ Project structure

lupin/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ main.rs              # CLI interface and argument parsing
β”‚   └── lib.rs               # Core library with modular components
β”œβ”€β”€ examples/
β”‚   β”œβ”€β”€ cat.pdf              # Sample PDF for testing
β”‚   β”œβ”€β”€ out.pdf              # Sample output PDF after embedding message.txt
β”‚   └── message.txt          # Sample payload file
└── .github/workflows/       # CI/CD pipelines

πŸ“š Library usage

You can also use Lupin as a Rust library:

use lupin::operations::{embed, extract};
use std::path::Path;

fn main() -> std::io::Result<()> {
    // Embed a payload
    embed(
        Path::new("source.pdf"),
        Path::new("payload.bin"),
        Path::new("output.pdf"),
    )?;

    // Extract the payload
    extract(
        Path::new("output.pdf"),
        Path::new("recovered.bin"),
    )?;

    Ok(())
}

🀝 Contributing

Contributions are welcome. To contribute:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/your-feature)
  3. Commit your changes (git commit -m "Add your feature")
  4. Push to the branch (git push origin feature/your-feature)
  5. Open a pull request

Development guidelines

  • Follow Rust formatting conventions (cargo fmt)
  • Ensure all tests pass (cargo test)
  • Add tests for new functionality
  • Update documentation as appropriate

πŸ“œ License

This project is licensed under the Apache License 2.0 β€” see the LICENSE file for details.


Disclaimer: This tool is intended for educational and legitimate use only. Users are responsible for complying with applicable laws and regulations relating to data hiding and steganography.