Hardware-backed file encryption using your Ledger device.
Lcrypt ties file encryption directly to your Ledger hardware wallet. No passwords, no key files — the only way to decrypt a file is to physically confirm the operation on your Ledger device.
When you encrypt a file, Lcrypt derives a 256-bit AES key from your Ledger's public key and encrypts the file using AES-256-GCM. The result is a .lenc file that can only be decrypted by the same Ledger device that created it.
Every encrypt and decrypt operation requires a physical button press on the Ledger — nothing happens silently.
- Node.js v18 or later
- A Ledger Nano S / Nano X / Nano S Plus
- The Ethereum app installed and open on your device
Clone the repository and install globally:
git clone https://github.com/yourname/lcrypt
cd lcrypt
npm install -g .That's it. No build step required.
lcrypt statusVerifies your Ledger is connected, unlocked, and the Ethereum app is open. Displays the connected wallet address.
lcrypt encrypt <file># Specify a custom output path
lcrypt encrypt secret.pdf -o /path/to/output.lencYou will be prompted to confirm the operation on your Ledger screen before encryption begins.
lcrypt decrypt <file.lenc># Specify a custom output directory
lcrypt decrypt secret.pdf.lenc -o /path/to/folder/Again, you must physically confirm on your Ledger. The original file is restored with its original filename.
Encrypted .lenc files use a custom binary format:
┌─────────────────────────────────────────────────┐
│ Offset │ Size │ Field │
├─────────────────────────────────────────────────┤
│ 0 │ 4 bytes │ Magic bytes: "LCRY" │
│ 4 │ 1 byte │ Format version (0x01) │
│ 5 │ 65 bytes │ Ledger public key │
│ 70 │ 12 bytes │ AES-GCM nonce (IV) │
│ 82 │ 2 bytes │ Original filename length │
│ 84 │ N bytes │ Original filename │
│ 84+N │ — │ Encrypted file data │
│ last 16 │ 16 bytes │ GCM authentication tag │
└─────────────────────────────────────────────────┘
The encrypted file is always ~109 bytes larger than the original.
AES-256-GCM is used for symmetric encryption. GCM mode provides both confidentiality and integrity — if even a single byte of the encrypted file is modified, decryption will fail with an authentication error.
The AES key is derived from your Ledger's public key using SHA-256. Because the corresponding private key never leaves the Ledger's secure element, decryption is only possible with physical access to the device itself.
Every operation requires a physical confirmation on the Ledger. There is no way to decrypt a file programmatically without the user pressing the button.
If you encrypt a file and then connect a different Ledger, decryption will be rejected — the public key stored in the file header will not match.
$ lcrypt encrypt report.pdf
Lcrypt — File Encryption
─────────────────────────
Input : /home/user/report.pdf
Output : /home/user/report.pdf.lenc
✔ Ledger connected
✔ Public key received
📟 Please confirm on your Ledger...
✔ Confirmed
Encrypting |████████████████████| 100% | 0s remaining
✅ Encryption complete
Encrypted file: /home/user/report.pdf.lenc$ lcrypt decrypt report.pdf.lenc
Lcrypt — File Decryption
─────────────────────────
Input : /home/user/report.pdf.lenc
Output : /home/user/
✔ Ledger connected
✔ Public key received
📟 Please confirm on your Ledger...
✔ Confirmed
Decrypting |████████████████████| 100% | 0s remaining
✅ Decryption complete
Restored file: /home/user/report.pdflcrypt/
├── bin/
│ └── lcrypt.js # CLI entry point (ts-node loader)
├── src/
│ ├── cli.ts # Command definitions (encrypt, decrypt, status)
│ ├── crypto.ts # AES-256-GCM encryption and decryption
│ ├── ledger.ts # Ledger USB connection and signing
│ └── index.ts # Public exports
├── package.json
├── tsconfig.json
└── README.md
MIT