.env files. First, it derives a strong 256-bit key from your passphrase using PBKDF2-HMAC-SHA256, so the raw passphrase never touches the cipher directly. Then it encrypts the file content with AES-256-GCM, an authenticated encryption algorithm that simultaneously protects confidentiality and detects any tampering. The entire implementation runs in a Rust native addon compiled for each supported platform.
Encryption Flow
When you runencryptd encrypt, the following steps execute inside the Rust native addon:
1
Generate a random salt
The Rust runtime calls
OsRng.fill_bytes to generate 16 bytes of cryptographically random salt. This salt is unique to every encryption operation, meaning the same .env file encrypted twice will produce completely different output.2
Derive a 256-bit key with PBKDF2
Your passphrase and the fresh salt are fed into PBKDF2-HMAC-SHA256 with 100,000 iterations, producing a 32-byte (256-bit) key. The high iteration count makes brute-force attacks against the passphrase computationally expensive.
3
Generate a random nonce
Aes256Gcm::generate_nonce produces a 12-byte (96-bit) nonce using OsRng. The nonce ensures that even if you encrypt the same plaintext with the same key, the ciphertext will differ each time.4
Encrypt with AES-256-GCM
The plaintext is encrypted using the derived key and nonce. AES-256-GCM outputs the ciphertext alongside a 16-byte authentication tag appended to the end of the raw output. The Rust code separates the last 16 bytes as the tag.
5
Hex-encode and write as JSON
All binary fields salt, nonce (stored as
iv), ciphertext, and auth tag are hex-encoded and written to a JSON payload on disk.Output: the .env.enc file
After encryption, your encrypted environment file looks like this:
Decryption Flow
When you runencryptd decrypt, the process is the exact reverse:
1
Parse the JSON payload
encryptd reads the
.env.enc file and parses the JSON structure, extracting salt, iv, content, and tag.2
Hex-decode all fields
Each hex string is decoded back to raw bytes. Any malformed hex causes an immediate error with a descriptive message.
3
Re-derive the same key
PBKDF2-HMAC-SHA256 runs again with your passphrase and the stored salt. Because the salt is identical to the one used during encryption, the derived key is identical no key material is ever stored on disk.
4
Decrypt and verify the auth tag
AES-256-GCM decrypts the ciphertext and automatically verifies the 16-byte authentication tag in a single operation. If the file has been tampered with, or if you provide the wrong passphrase, decryption fails immediately with an error no partial output is ever returned.
5
Output UTF-8 plaintext
The decrypted bytes are validated as UTF-8 and returned as the plaintext content of your original
.env file.Why the Same Input Produces Different Output
Each call toencrypt_env independently generates a fresh 16-byte salt and a fresh 12-byte nonce from the operating system’s cryptographically secure random number generator (OsRng). Because the PBKDF2 key derivation includes the salt, and because AES-256-GCM uses the nonce as an input to the cipher, encrypting the same .env twice even with the same passphrase will always produce a distinct salt, iv, content, and tag. This is intentional: it prevents an attacker from detecting whether two encrypted files have the same plaintext.
The Rust Native Addon
encryptd’s cryptographic core is written in Rust and compiled to a platform-specific.node binary. The compiled addon is loaded by the Node.js package at runtime you never execute JavaScript crypto. Every sensitive operation runs in native Rust code with no JavaScript layer in the cryptographic path..png?fit=max&auto=format&n=Fjc5BJwQaMa3_uyF&q=85&s=4368c06aabf42347a7a04b5f52aafc0d)