npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2026 – Pkg Stats / Ryan Hefner

black-forest

v1.0.0

Published

🍫 Universal Steganography Engine β€” Hide any file inside any carrier file format safely.

Readme

🌲 Black Forest

Universal Steganography Engine β€” Hide any file inside any carrier file format safely.

Node.js License: MIT AES-256-GCM


🎯 What is this?

Black Forest is a zero-dependency Node.js steganography engine that lets you hide any file inside any carrier file. The carrier remains fully functional β€” images still open, videos still play, documents still read.

Key Features

  • πŸ” AES-256-GCM encryption with PBKDF2 key derivation (600K iterations)
  • πŸ“ Universal overlay mode β€” works with ANY file format
  • πŸ–ΌοΈ PNG LSB embedding β€” hides data in pixel least-significant bits
  • πŸ“Έ JPEG post-EOI injection β€” stores data after End-of-Image marker
  • 🌊 Streaming support β€” handles files > 50 MB without memory issues
  • πŸ” Auto-detection β€” scans files for hidden data
  • πŸ›‘οΈ Integrity verification β€” CRC32 header checks + GCM auth tags
  • πŸ“Š Capacity estimation β€” know before you embed
  • 🎯 Zero dependencies for core functionality (pngjs optional for PNG mode)

πŸ“¦ Installation

# Global install (recommended for CLI)
npm install -g black-forest

# Local install
npm install black-forest

# From source
git clone https://github.com/your-username/black-forest.git
cd black-forest
npm install
npm link   # Makes CLI available globally

Optional Dependencies

# For PNG LSB steganography mode
npm install pngjs

πŸš€ CLI Usage

Hide a File

# Basic overlay mode (works with any file type)
black-forest hide -f secret.pdf -c photo.jpg -o output.jpg -p "mypassword"

# Short alias
bf hide -f secret.pdf -c photo.jpg -o output.jpg -p "mypassword"

# Specify mode explicitly
black-forest hide -f data.txt -c image.png -o stego.png -p "pass" --mode png

# JPEG mode
black-forest hide -f payload.zip -c vacation.jpg -o vacation_out.jpg -p "secure123" --mode jpeg

Extract a Hidden File

# Auto-detect mode
black-forest extract -i output.jpg -p "mypassword"

# Specify output location
black-forest extract -i stego.png -p "pass" -o ./extracted/

# Specify mode
black-forest extract -i stego.png -p "pass" --mode png

Inspect a File

# Check if a file contains hidden data
black-forest inspect suspicious_file.jpg

Check Capacity

# Estimate how much data a carrier can hold
black-forest capacity photo.png --mode png
black-forest capacity video.mp4 --mode overlay

πŸ“š Programmatic API

const stego = require('black-forest');

// Hide a file
const hideResult = await stego.hide({
  inputFile: 'secret.pdf',
  carrierFile: 'photo.jpg',
  outputFile: 'output.jpg',
  password: 'mypassword',
  mode: 'auto',           // auto, overlay, png, jpeg
  onProgress: (percent, message) => {
    console.log(`${percent}% - ${message}`);
  },
});

console.log(hideResult);
// {
//   success: true,
//   mode: 'overlay',
//   outputFile: 'output.jpg',
//   payloadSize: 12345,
//   encryptedSize: 12361,
//   overhead: 12449,
//   ...
// }

// Extract a file
const extractResult = await stego.extract({
  inputFile: 'output.jpg',
  password: 'mypassword',
  mode: 'auto',
  outputDir: './extracted/',
});

console.log(extractResult);
// {
//   success: true,
//   extractedFile: './extracted/secret.pdf',
//   originalFilename: 'secret.pdf',
//   fileSize: 12345,
// }

// Inspect a file
const info = await stego.inspect('output.jpg');
console.log(info.hasEmbeddedData); // true
console.log(info.embeddedFilename); // 'secret.pdf'

// Check capacity
const cap = await stego.capacity('image.png', 'png');
console.log(cap.maxPayloadHuman); // '1.23 MB'

πŸ—οΈ Architecture

black-forest/
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ encrypt.js     # AES-256-GCM encryption + PBKDF2 key derivation
β”‚   β”œβ”€β”€ decrypt.js     # Decryption with authentication verification
β”‚   β”œβ”€β”€ header.js      # Binary header serialization (magic bytes, CRC32)
β”‚   └── scanner.js     # Reverse file scanner for header detection
β”œβ”€β”€ modes/
β”‚   β”œβ”€β”€ overlay.js     # Universal overlay mode (any file format)
β”‚   β”œβ”€β”€ png-lsb.js     # PNG least-significant-bit embedding
β”‚   └── jpeg-dct.js    # JPEG post-EOI injection
β”œβ”€β”€ utils/
β”‚   β”œβ”€β”€ capacity.js    # Carrier capacity estimation
β”‚   └── filecheck.js   # File type detection via magic bytes
β”œβ”€β”€ index.js           # CLI entry point
β”œβ”€β”€ lib.js             # Library API
└── test/
    └── test.js        # Test suite

πŸ” How It Works

Overlay Mode (Primary)

The overlay mode works by appending encrypted data after the carrier file's original content:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Original Carrier   β”‚   Encrypted Payload      β”‚  USTG Header   β”‚
β”‚   (unchanged)        β”‚   (AES-256-GCM)          β”‚  (metadata)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  1. The carrier file is copied to the output
  2. The payload is encrypted with AES-256-GCM
  3. A binary header with metadata, salt, IV, and auth tag is created
  4. Encrypted payload + header are appended to the carrier
  5. The carrier remains fully functional (images open, videos play, etc.)

Header Format

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Field            β”‚ Size (bytes)  β”‚ Description                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Magic Bytes      β”‚ 4             β”‚ "USTG" identifier             β”‚
β”‚ Version          β”‚ 1             β”‚ Protocol version              β”‚
β”‚ Mode             β”‚ 1             β”‚ Embedding mode                β”‚
β”‚ Filename Length  β”‚ 2             β”‚ Original filename length      β”‚
β”‚ Filename         β”‚ variable      β”‚ UTF-8 encoded filename        β”‚
β”‚ Payload Size     β”‚ 8             β”‚ Encrypted payload size        β”‚
β”‚ Salt             β”‚ 32            β”‚ PBKDF2 salt                   β”‚
β”‚ IV               β”‚ 16            β”‚ AES-GCM initialization vector β”‚
β”‚ Auth Tag         β”‚ 16            β”‚ GCM authentication tag        β”‚
β”‚ Header CRC       β”‚ 4             β”‚ CRC32 integrity check         β”‚
β”‚ Header Sentinel  β”‚ 4             β”‚ "HEND" end marker             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

PNG LSB Mode

Hides data in the least significant bits of RGB pixel values. Changes are imperceptible to the human eye.

Original pixel:  R=10110110  G=11001010  B=01111001
Hidden bit:                ↓           ↓           ↓
Modified pixel:  R=10110111  G=11001011  B=01111000

JPEG Mode

Stores data after the JPEG End-of-Image (EOI) marker. Most image viewers ignore post-EOI data.


πŸ”’ Security Considerations

Strengths

| Feature | Detail | |---------|--------| | Encryption | AES-256-GCM (authenticated encryption) | | Key Derivation | PBKDF2 with 600,000 iterations (OWASP 2023) | | Salt | 256-bit random salt per file | | IV | 128-bit random IV per file | | Integrity | GCM auth tag + CRC32 header verification | | Memory | Keys are zeroed after use |

Limitations

  • Overlay mode is detectable by checking if file size exceeds expected format size
  • PNG LSB changes pixel values slightly (detectable by statistical analysis tools like StegExpose)
  • JPEG post-EOI detection is trivial if someone looks for data after EOI marker
  • This tool provides encryption-level security, not deniability
  • Metadata (filename, size) is encrypted within the AES payload but header structure is visible

Best Practices

  1. Use strong passwords (12+ characters, mixed case, numbers, symbols)
  2. Use carriers that naturally vary in size (photos, videos)
  3. Keep the payload small relative to the carrier to reduce suspicion
  4. For PNG LSB mode, prefer photographic images over flat graphics (noise hides changes)
  5. Never reuse the same carrier for multiple embeddings

⚑ Performance

| Operation | 1 MB file | 10 MB file | 100 MB file | |-----------|-----------|------------|-------------| | Hide (overlay) | ~1.2s | ~2.5s | ~8s (streaming) | | Extract (overlay) | ~1.1s | ~2.3s | ~7s | | Hide (PNG LSB) | ~2s | N/A* | N/A* |

*PNG LSB capacity is limited by image dimensions.

Key derivation (PBKDF2 with 600K iterations) takes ~0.8-1.2s β€” this is intentional for security.

Tips for Large Files

  • Files > 50 MB automatically use streaming mode (overlay)
  • Streaming mode processes data in chunks to avoid memory exhaustion
  • PNG and JPEG modes load the full carrier into memory

πŸ§ͺ Testing

# Run test suite
npm test

# Run with debug output
DEBUG=1 npm test

πŸ›£οΈ Roadmap

  • [ ] PDF object stream injection
  • [ ] MP4 metadata atom injection
  • [ ] EXE PE overlay section injection
  • [ ] Argon2 key derivation (via native addon)
  • [ ] Chunk splitting across multiple carriers
  • [ ] Steganography detection/analysis tools
  • [ ] Web UI for browser-based usage
  • [ ] WASM build for cross-platform support

πŸ“„ License

MIT Β© Black Forest Contributors


⚠️ Disclaimer

This tool is for educational and legitimate privacy purposes only. The authors are not responsible for any misuse. Always comply with applicable laws and regulations regarding data encryption and steganography in your jurisdiction.