| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
A lightweight, file-based steganography CLI written in Go. Hide files, folders, or text inside ordinary files with optional AES-256-GCM encryption.
ByteVeil is a command-line tool for file-based steganography.
It allows you to hide:
inside a cover file.
Payloads are compressed with gzip before being stored. If a password is provided, ByteVeil additionally encrypts the compressed payload using AES-256-GCM with a key derived through PBKDF2-HMAC-SHA256.
ByteVeil detects the cover file format and uses a format-specific embedding strategy when supported. For unrecognized formats, it falls back to a generic append strategy.
The result is a single file that can later be decoded by ByteVeil to recover the original payload.
ENCODE
File / Folder / Text
│
▼
┌──────────────┐
│ gzip │
│ compression │
└──────┬───────┘
│
▼
┌──────────────┐
│ Optional │
│ AES-256-GCM │
│ encryption │
└──────┬───────┘
│
▼
┌──────────────┐
│ ByteVeil │
│ payload │
└──────┬───────┘
│
▼
Cover File
│
▼
Stego File
ByteVeil recognizes the following file formats:
| Format | Detection | Embedding Method |
|---|---|---|
| JPEG | Yes | Appended after JPEG data |
| PNG | Yes | Custom stEg chunk before IEND |
| MP4 / ISO-BMFF | Yes | Appended free box |
| MP3 | Yes | PRIV frame in ID3v2 |
| GIF | Yes | Appended after file data |
| BMP | Yes | Appended after bitmap data |
| RIFF | Yes | Generic append |
| WAV | Yes | Generic append |
| AVI | Yes | Generic append |
| WEBP | Yes | Generic append |
| OGG | Yes | Generic append |
| Yes | Appended after %%EOF | |
| ZIP | Yes | ZIP EOCD comment |
| DOCX | Yes | ZIP EOCD comment |
| XLSX | Yes | ZIP EOCD comment |
| PPTX | Yes | ZIP EOCD comment |
| JAR | Yes | ZIP EOCD comment |
| APK | Yes | ZIP EOCD comment |
| Other files | Fallback | Generic append |
Format detection is performed using file signatures rather than filename extensions.
For example, a file named:
photo.dat
can still be recognized as PNG if its binary signature is a valid PNG signature.
Clone the repository:
git clone https://github.com/batmanpriv/ByteVeil.gitEnter the project directory:
cd ByteVeilBuild ByteVeil:
go build -o ByteVeil .On Windows:
go build -o ByteVeil.exe .You can then run the binary directly.
Linux/macOS:
./ByteVeilWindows:
.\ByteVeil.exeYou can also install ByteVeil directly using go install:
go install github.com/batmanpriv/ByteVeil@v1.0.0Make sure your Go binary directory is included in your system PATH.
Then run:
ByteVeilHide secret.pdf inside cover.png:
ByteVeil encode -in cover.png -out secret.png -data secret.pdfExtract it:
ByteVeil decode -in secret.png -out extracted.pdfHide a text message inside a JPEG:
ByteVeil encode -in cover.jpg -out message.jpg -text "Meet me at 9pm."Extract it:
ByteVeil decode -in message.jpgIf no output path is specified, ByteVeil uses the filename stored inside the payload.
Text messages are stored with:
message.txt
as their default filename.
Provide a password to enable encryption:
ByteVeil encode -in cover.png -out secret.png -data secret.pdf -password "your-strong-password"Extract it using the same password:
ByteVeil decode -in secret.png -out secret.pdf -password "your-strong-password"Without the correct password, the encrypted payload cannot be successfully decrypted.
ByteVeil can hide an entire directory:
ByteVeil encode -in cover.png -out backup.png -data ./my-folder -password "your-strong-password"The directory is packed into a TAR stream before compression and optional encryption.
Extract it:
ByteVeil decode -in backup.png -out ./restored-folder -password "your-strong-password"ByteVeil automatically detects that the payload represents a directory and extracts it into the specified output directory.
ByteVeil provides two commands:
encode
decode
Creates a new file containing a hidden ByteVeil payload.
ByteVeil encode -in <cover> -out <output> (-data <file-or-folder> | -text <message>) [-password <password>]
| Flag | Required | Description |
|---|---|---|
| -in | Yes | Path to the cover file |
| -out | Yes | Path to the resulting stego file |
| -data | Conditional | File or directory to hide |
| -text | Conditional | Text message to hide |
| -password | No | Password used to enable AES-256-GCM encryption |
Exactly one of -data or -text must be provided.
ByteVeil encode -in cover.png -out output.png -data secret.pdfByteVeil encode -in cover.jpg -out output.jpg -text "This is a hidden message."ByteVeil encode -in cover.png -out output.png -data secret.pdf -password "strong-password"ByteVeil encode -in cover.png -out output.png -data ./my-folder -password "strong-password"Extracts a hidden ByteVeil payload.
ByteVeil decode -in <stego-file> [-out <output>] [-password <password>]
| Flag | Required | Description |
|---|---|---|
| -in | Yes | Stego file containing the hidden payload |
| -out | No | Output file or directory |
| -password | No | Password for encrypted payloads |
ByteVeil decode -in output.pngByteVeil decode -in output.png -out restored.pdfByteVeil decode -in output.png -out restored.pdf -password "strong-password"ByteVeil decode -in output.png -out ./restored -password "strong-password"ByteVeil uses a custom binary payload container.
The encoding pipeline is:
Original Payload
│
├── File
├── Folder
└── Text
│
▼
Directory → TAR
│
▼
gzip
│
▼
Optional AES-256-GCM
│
▼
ByteVeil Inner Payload
│
▼
ByteVeil Outer Blob
│
▼
Format-Specific Embedding
│
▼
Stego File
The decoding pipeline reverses these operations:
Stego File
│
▼
Locate ByteVeil Blob
│
▼
Validate Payload
│
▼
Decrypt if Required
│
▼
gzip Decompression
│
▼
TAR Extraction if Directory
│
▼
Original Payload
The outer ByteVeil blob begins with the following magic marker:
STEGOv1\x00
The outer structure is:
+-------------------+
| STEGOv1\x00 |
+-------------------+
| Payload Length |
| 8 bytes, BE |
+-------------------+
| Inner Payload |
+-------------------+
The inner payload begins with:
STG1
The current payload version is:
1
The inner payload contains metadata describing the stored data.
Conceptually:
+-----------------------+
| STG1 |
+-----------------------+
| Version |
+-----------------------+
| Flags |
+-----------------------+
| Filename (optional) |
+-----------------------+
| Salt (optional) |
+-----------------------+
| Nonce (optional) |
+-----------------------+
| Data Length |
+-----------------------+
| Compressed/Encrypted |
| Payload |
+-----------------------+
| CRC32 |
+-----------------------+
The payload format is versioned so that future versions can introduce compatible format changes.
ByteVeil compresses payload data using gzip before storing it.
For normal files and text:
Original Data
↓
gzip
↓
Compressed Data
For directories:
Directory
↓
TAR
↓
TAR Stream
↓
gzip
↓
Compressed TAR
Compression happens before encryption.
This is important because encrypted data generally does not compress effectively.
Encryption is optional.
When -password is provided, ByteVeil derives a 256-bit encryption key using:
PBKDF2-HMAC-SHA256
with:
Iterations: 200,000
Key length: 32 bytes
Salt length: 16 bytes
The resulting key is used with:
AES-256-GCM
A fresh random salt and nonce are generated for every encoded payload.
The encryption flow is:
Password
│
▼
PBKDF2-HMAC-SHA256
│
├── 200,000 iterations
├── 16-byte random salt
└── 32-byte derived key
│
▼
AES-256-GCM
│
└── 12-byte random nonce
The salt and nonce are stored alongside the encrypted payload because they are not secrets.
The password itself is never stored in the ByteVeil payload.
ByteVeil stores a CRC32 checksum for the inner payload.
During decoding, the checksum is verified before the payload is processed.
This allows ByteVeil to detect accidental corruption or truncation.
For encrypted payloads, AES-GCM additionally provides authenticated encryption.
Therefore:
CRC32
→ detects payload corruption/truncation
AES-GCM authentication
→ detects invalid/tampered encrypted data
CRC32 is not a cryptographic security mechanism.
When -data points to a directory, ByteVeil creates a TAR archive in memory.
The TAR archive can contain:
The original directory name is stored in the payload metadata.
For example:
my-project/
├── main.go
├── README.md
├── src/
│ └── app.go
└── assets/
└── config.json
is packed into a TAR stream before compression.
When decoded, ByteVeil recognizes the directory flag and extracts the archive.
JPEG payloads are appended after the original JPEG data.
Conceptually:
[JPEG DATA][ByteVeil BLOB]
The JPEG content itself is not modified by the embedding operation.
PNG payloads are stored in a custom ancillary chunk:
stEg
The chunk is inserted before the PNG IEND chunk.
Conceptually:
PNG Signature
│
├── IHDR
├── ...
├── stEg
│ └── ByteVeil Blob
└── IEND
The custom chunk also has its own CRC.
For MP4-family files, ByteVeil adds a free box containing the ByteVeil payload.
Conceptually:
[Existing MP4 Boxes][free][ByteVeil Blob]
For MP3 files with a compatible ID3v2 tag, ByteVeil stores the payload inside a PRIV frame.
The private owner identifier used by the implementation is:
stego-tool
If a suitable ID3v2 tag is not present, ByteVeil creates an ID3v2.3 tag containing the private frame.
GIF payloads are appended after the existing file data.
BMP payloads are appended after the existing bitmap data.
These formats are recognized as RIFF-family files.
The current implementation uses a generic append strategy for these formats.
OGG files are recognized and use the generic append strategy.
PDF payloads are appended after the existing %%EOF marker.
This means strict PDF readers or processors may not always accept a modified PDF containing an appended ByteVeil payload.
ZIP-based files use the ZIP End of Central Directory comment field.
This applies to:
.zip
.docx
.xlsx
.pptx
.jar
.apk
and other ZIP-based formats.
The ZIP comment field has a maximum size of:
65,535 bytes
Therefore ZIP-based cover files have a hard payload-size limitation.
If ByteVeil does not recognize the cover file format, it falls back to generic append embedding.
Conceptually:
[Original File][ByteVeil Blob]
This allows ByteVeil to work with arbitrary binary files, but compatibility with third-party applications is not guaranteed.
ByteVeil operates at the file-byte level.
As a result, it can survive operations that preserve the original bytes, but it generally cannot survive operations that decode and re-encode the media.
Examples of operations that normally preserve the payload:
For example:
ByteVeil File
│
▼
"Send as File"
│
▼
Same Bytes
│
▼
Payload Still Present
Media transcoding or recompression can destroy the payload.
For example:
ByteVeil JPEG
│
▼
Platform decodes JPEG
│
▼
Platform recompresses JPEG
│
▼
New JPEG
│
▼
ByteVeil payload may be gone
The same applies to video and audio transcoding.
This is a fundamental limitation of file-level embedding.
Steganography and encryption provide different protections.
Steganography attempts to hide the presence or location of information.
Encryption protects the contents of the information.
Without a password:
Hidden + Compressed
With a password:
Hidden + Compressed + Encrypted
For sensitive payloads, use a strong password.
Avoid weak passwords such as:
password
123456
qwerty
hunter2
Prefer a long, unique passphrase.
For example:
correct-horse-battery-staple-7f3a91
Do not commit passwords to Git repositories.
Do not place passwords in shell scripts that may be committed to source control.
ByteVeil does not provide password recovery.
If an encrypted payload is created with a lost password, there is no recovery mechanism built into the tool.
ByteVeil does not claim to provide undetectable steganography.
It uses file-level embedding rather than modifying pixel values or audio samples, but the presence of a ByteVeil payload may still be detectable by someone inspecting the file structure or searching for the ByteVeil magic marker.
The goal is practical data hiding, not provable invisibility.
ByteVeil does not guarantee survival through:
ZIP-based covers are limited by the maximum ZIP comment size:
65,535 bytes
This includes:
For larger payloads, use another supported cover format.
The current implementation reads and constructs payload data in memory.
For very large files or directories, memory usage can therefore become significant.
The current implementation is not a streaming steganography pipeline.
Unknown formats use generic append embedding.
Although this makes ByteVeil flexible, applications that strictly validate file length or reject trailing data may refuse to open such files.
ByteVeil guarantees that its own decoder can recover a valid payload from an appropriately preserved ByteVeil file.
It does not guarantee that every third-party application will accept every modified cover file.
ByteVeil validates its payload before extraction.
Typical errors include:
no hidden payload marker found in this file
This means ByteVeil could not find the STEGOv1 marker.
checksum mismatch: payload is corrupted or truncated
The CRC32 check failed.
this payload is encrypted; a password is required
The payload is encrypted but no password was supplied.
decryption failed: wrong password or corrupted data
AES-GCM authentication failed.
declared payload length exceeds file size (truncated file?)
The file is shorter than the length declared by the ByteVeil container.
ByteVeil encode -in photo.png -out hidden.png -data secret.pdfExtract:
ByteVeil decode -in hidden.png -out secret.pdfByteVeil encode -in photo.png -out hidden.png -data secret.pdf -password "strong-password"Extract:
ByteVeil decode -in hidden.png -out secret.pdf -password "strong-password"ByteVeil encode -in photo.jpg -out hidden.jpg -text "This message is hidden."Extract:
ByteVeil decode -in hidden.jpgByteVeil encode -in cover.png -out backup.png -data ./project -password "strong-password"Extract:
ByteVeil decode -in backup.png -out ./restored-project -password "strong-password"ByteVeil encode -in music.mp3 -out hidden.mp3 -data secret.txt -password "strong-password"Extract:
ByteVeil decode -in hidden.mp3 -out secret.txt -password "strong-password"Because ZIP comments have a hard size limit, keep the payload small:
ByteVeil encode -in archive.zip -out hidden.zip -text "Hidden ZIP message"Extract:
ByteVeil decode -in hidden.zipEncode a file:
ByteVeil encode -in <cover> -out <output> -data <file>
Encode a folder:
ByteVeil encode -in <cover> -out <output> -data <folder>
Encode text:
ByteVeil encode -in <cover> -out <output> -text "<message>"
Encrypt:
ByteVeil encode -in <cover> -out <output> -data <file> -password "<password>"
Decode:
ByteVeil decode -in <stego-file>
Decode to a specific file:
ByteVeil decode -in <stego-file> -out <output>
Decode encrypted payload:
ByteVeil decode -in <stego-file> -out <output> -password "<password>"
Clone the repository:
git clone https://github.com/batmanpriv/ByteVeil.gitEnter the directory:
cd ByteVeilBuild:
go build .Run:
go run . encode -in cover.png -out output.png -text "Hello from ByteVeil"Build a named binary:
Linux/macOS:
go build -o ByteVeil .Windows:
go build -o ByteVeil.exe .The current implementation is intentionally compact.
ByteVeil/
└── main.go
The main source file contains the following logical components:
Payload
├── buildInner
├── parseInner
├── wrapBlob
└── findBlob
Cryptography
└── pbkdf2
Format Detection
└── sniffFormat
Embedding
├── embedJPEG
├── embedPNG
├── embedMP4
├── embedMP3
├── embedGeneric
└── embedZIP
Directory Handling
├── tarDir
└── untarToDir
CLI
├── encode
├── decode
├── usage
└── main
ByteVeil currently uses the Go standard library only.
Important packages include:
archive/tar
bytes
compress/gzip
crypto/aes
crypto/cipher
crypto/hmac
crypto/rand
crypto/sha256
encoding/binary
errors
flag
fmt
hash/crc32
io
os
path/filepath
strings
No external runtime dependency is required.
Current release:
v1.0.0
Payload format:
STEGOv1
STG1
version 1
Versioning is included in the payload format to allow future versions of ByteVeil to evolve the container format.
| Back | FazBrowse Home | New Git URL |