f5

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 30, 2026 License: MIT Imports: 0 Imported by: 0

README

f5

A pure-Go toolkit for the F5 JPEG steganography algorithm (Westfeld, 2001): embed a message into the quantized DCT coefficients of a JPEG, extract it back, produce f5.jar-compatible carriers, and statistically detect F5 with the Fridrich–Goljan–Hogea (2002) attack.

The module is split into independent, narrowly scoped packages. A Go module is the unit of review and release; a Go package is the unit of compilation. So a build only ever compiles the capability it imports — importing embed never compiles detect or encode, and the lightest path pulls in no JPEG codec.

import path: github.com/0verkilll/f5

Packages

Package Purpose Pulls in a JPEG codec?
embed F5 message embedding into []int16 DCT coefficients no — lightest path
extract F5 message extraction from []int16 DCT coefficients no
encode Byte-identical re-implementation of the James R. Weeks / f5.jar JPEG encoder yes
detect Statistical F5 detection (Fridrich 2002); pure statistics, no machine learning yes
i18nx Opt-in localization loader for embed/extract error messages no

embed and extract operate on coefficient slices, not pixels: obtain the coefficients from a JPEG decoder, embed or extract, then re-encode (for example with encode). Keeping the codec out of these two packages is what lets them compile to TinyGo/WebAssembly.

Install

go get github.com/0verkilll/f5

Usage

Embed
import "github.com/0verkilll/f5/embed"

result, err := embed.Embed(coefficients, "passphrase", []byte("hidden message"))
if err != nil {
	return err
}
// result.KParameter, result.BytesEmbedded, result.ShrinkageCount
Extract

The extractor is constructed with an injected SHA-1 Hasher, a Fisher-Yates Permutator, and the PRNG factory, so the extraction PRNG path mirrors embedding exactly. See examples/roundtrip for the two small adapters that bridge the upstream sha1 and fisheryates primitives.

import "github.com/0verkilll/f5/extract"

extractor := extract.NewExtractor(hasher, permutator,
	extract.WithPRNGFactory(f5prng.NewDefaultFactory()))

message, err := extractor.ExtractBytes(coefficients, "passphrase")
Encode
import "github.com/0verkilll/f5/encode"

jpegBytes, err := encode.WeeksEncodeToBytes(img, 80) // quality 1..100
Detect
import "github.com/0verkilll/f5/detect"

detected, confidence, err := detect.DetectF5(jpegBytes)

result, err := detect.Analyze(jpegBytes)
// result.Verdict (clean / stego_detected / inconclusive), result.Beta, result.Quality
// result.Signatures — structural carrier fingerprint (see below)

Alongside the statistical β attack, Analyze attaches a set of structural signatures (result.Signatures, also detect.Signatures(jpegBytes) standalone) that fingerprint the JPEG itself rather than its statistics. None of them mean "F5" on their own; added up they describe whether an image is a plausible F5 carrier and what encoder produced it:

  • decodable_format — baseline or progressive frame (F5 coefficients survive); lossless/re-encoded means they are gone
  • embedding_capacity — has usable non-zero AC coefficients (a solid black/white image cannot carry F5)
  • chroma_420 — 4:2:0 subsampling, the James/f5.jar encoder's fixed mode
  • weeks_app0 — the JFIF APP0 f5.jar writes (units=0, density 1×1)
  • weeks_com — the James R. Weeks copyright COM comment (with f5.jar's length-field truncation)
  • ijg_quant_tables — luminance quantization table on the standard IJG quality curve

Score is the summed weight of matched signatures (0–1); CarrierViable is a hard gate (decodable format with real capacity). This is useful precisely when β is inconclusive — e.g. a double-compressed f5.jar stego can saturate β yet still score 1.0 on the structural signatures. f5 detect prints them; -json includes the full report.

Runnable versions of all four live under examples/:

go run ./examples/embed
go run ./examples/roundtrip   # embed then extract
go run ./examples/encode
go run ./examples/detect

Command-line tool and TUI

cmd/f5 is a single binary that drives the whole toolkit. Run it with no arguments on a terminal for an interactive Bubble Tea UI; pass a subcommand to script it. The UI dependency (Bubble Tea) lives only in this command — importing any library package never pulls it in.

go build -o f5 ./cmd/f5

f5                      # interactive TUI (menu: detect / embed / extract / encode)
f5 detect    in.jpg [-threshold T] [-json]
f5 embed     cover.jpg -p PASS (-m "msg" | -in msg.txt) -o stego.jpg
f5 embed-jar image.png -p PASS (-m "msg" | -in msg.txt) [-q 80] -o stego.jpg
f5 extract   stego.jpg -p PASS [-o out.bin]
f5 encode    image.png [-q 80] -o out.jpg
f5 help

The file argument may come before or after the flags. embed/extract decode the JPEG to DCT coefficients, run F5, and (for embed) re-encode with the original image metadata, so f5 embed … && f5 extract … round-trips a message through a real JPEG.

embed-jar is the bit-exact path: it takes pixels (PNG/JPEG/GIF) and reproduces the reference f5.jar's encode + embed exactly, so the output JPEG is byte-for-byte identical to what f5.jar would produce for the same pixels, message, password, and quality. The library entry point is encode.EmbedJPEGIdentical(img, quality, password, message); encode.WriteBMP24 emits the 24-bit BMP f5.jar reads, for cross-checking.

Design

  • Single responsibility per package. Each capability is self-contained; the root package is documentation only, with no facade that would couple them.
  • Dependency inversion. Optional logging and localization are injected through small interfaces (SetLogger, SetTranslator) and default to no-ops, so a minimal build links neither a logger nor the locale tables.
  • Pay for what you import. Shared algorithm code lives once under internal/ (permutation, coefficient, valid, logx). The locale tables live in the opt-in i18nx package, which no library package imports.
  • No cgo, no unsafe, no panics in library code. All errors are returned. Enforced by forbidigo, gosec, and errcheck (with check-blank).
TinyGo / WebAssembly

Every package builds for both standard GOOS=js GOARCH=wasm and TinyGo -target=wasm. embed and extract are the lightest (no JPEG codec); encode and detect are larger because they pull in the JPEG codec, but still compile under TinyGo.

Package GOOS=js GOARCH=wasm TinyGo -target=wasm
embed yes yes
extract yes yes
i18nx yes yes
encode yes yes
detect yes yes

Localization

Error messages default to English. To localize, inject a translator built from the bundled locale tables:

import "github.com/0verkilll/f5/i18nx"

t, _ := i18nx.NewTranslator("es-ES")
embed.SetTranslator(t)
extract.SetTranslator(t)

Because library code depends only on a small translator interface (never on i18nx), builds that skip localization do not compile the locale tables.

Security notes

  • F5 seeds its permutation PRNG with the password via Java's SHA1PRNG for byte-parity with the reference f5.jar. SHA1PRNG is not a modern KDF; the password protects ordering, not the payload. Encrypt sensitive payloads before embedding.
  • F5 is statistically detectable. The detect package implements the published 2002 attack against it. Treat F5 as a study/forensics subject, not as a secure channel.

Development

The module depends on a set of github.com/0verkilll/* primitive modules (f5core, f5coefficient, f5matrix, f5prng, fisheryates, securerandom, sha1, jpeg, logger, i18n), each published with its own v1.0.x tag, so a plain go get github.com/0verkilll/f5 resolves them from the public proxy. No replace block is needed.

Only cmd/f5 depends on Bubble Tea (github.com/charmbracelet/*); those modules resolve normally from the public proxy.

Verification matrix (build, vet, race tests, lint, wasm, TinyGo, and the dependency-segregation assertions):

./scripts/verify.sh

Run tests and fuzzers directly:

go test ./...
go test ./extract -run=x -fuzz=FuzzExtract -fuzztime=30s

References

  • A. Westfeld. F5 — A Steganographic Algorithm: High Capacity Despite Better Steganalysis. Information Hiding 2001, LNCS 2137. (docs/)
  • J. Fridrich, M. Goljan, D. Hogea. Steganalysis of JPEG Images: Breaking the F5 Algorithm. Information Hiding 2002, LNCS 2578. (docs/)

License

MIT. See LICENSE.

Documentation

Overview

Package f5 is the umbrella module for the F5 JPEG steganography toolkit.

The module is intentionally split into independent, narrowly-scoped packages so that a build only ever compiles the capability it imports. There is no umbrella facade here on purpose: importing this root package pulls in nothing but documentation, and importing one capability (for example embed) never compiles another (for example [detect] or [encode]).

Packages

embed    F5 message embedding into JPEG DCT coefficients (Westfeld 2001).
         The lightest package: it operates on []int16 coefficients and never
         pulls in a JPEG codec.
extract  F5 message extraction from JPEG DCT coefficients.
encode   Byte-identical re-implementation of the James R. Weeks JPEG encoder
         used by the original f5.jar, suitable for producing carriers.
detect   Statistical detection of F5 steganography using the Fridrich,
         Goljan and Hogea (2002) attack. Pure statistics, no machine learning.

Design constraints

Every package compiles to TinyGo/WebAssembly: no cgo, no unsafe, no panics in library code, and all errors are returned rather than swallowed. Optional integrations (structured logging and localized error messages) are injected through small interfaces and default to no-ops, so a minimal build links neither a logger nor the localization tables.

See the package-level documentation of each capability for details and the reference papers in the module's docs directory.

Directories

Path Synopsis
cmd
f5 command
Command f5 is a unified front-end for the F5 JPEG steganography toolkit.
Command f5 is a unified front-end for the F5 JPEG steganography toolkit.
wasm command
Command wasm exposes the f5 light-detection path (structural f5.jar/PixelKnot fingerprint + the Fridrich β attack) to the browser as a syscall/js function, for the f5-scan extension.
Command wasm exposes the f5 light-detection path (structural f5.jar/PixelKnot fingerprint + the Fridrich β attack) to the browser as a syscall/js function, for the f5-scan extension.
wasmneural command
Command wasmneural exposes the FULL f5 neural detection pipeline to the browser — the same pipeline the `f5` binary runs: the chroma-subsampling rule-out, the structural f5.jar/PixelKnot fingerprint, the embedded Tier-2 neural ensemble + recompression gate (ARTIFACT routing), all fused through the shared fuse package so the verdict matches the binary byte-for-byte on the same image.
Command wasmneural exposes the FULL f5 neural detection pipeline to the browser — the same pipeline the `f5` binary runs: the chroma-subsampling rule-out, the structural f5.jar/PixelKnot fingerprint, the embedded Tier-2 neural ensemble + recompression gate (ARTIFACT routing), all fused through the shared fuse package so the verdict matches the binary byte-for-byte on the same image.
Package steganalysis provides statistical detection of F5 steganography in JPEG images.
Package steganalysis provides statistical detection of F5 steganography in JPEG images.
internal/calibration
Package calibration implements double compression detection and multi-quality-factor calibration for JPEG steganalysis.
Package calibration implements double compression detection and multi-quality-factor calibration for JPEG steganalysis.
internal/codec
Package codec provides the JPEG adapter layer for the steganalysis package.
Package codec provides the JPEG adapter layer for the steganalysis package.
internal/estimator
Package estimator implements the core estimation algorithms for F5 steganalysis.
Package estimator implements the core estimation algorithms for F5 steganalysis.
internal/jpegscan
Package jpegscan is a lightweight, allocation-frugal JPEG marker scanner used by the detection-signature layer.
Package jpegscan is a lightweight, allocation-frugal JPEG marker scanner used by the detection-signature layer.
Package embed implements the F5 steganographic algorithm for embedding hidden messages into JPEG DCT coefficients.
Package embed implements the F5 steganographic algorithm for embedding hidden messages into JPEG DCT coefficients.
examples
detect command
Command detect-example runs the Fridrich (2002) statistical F5 detector over a freshly encoded, clean JPEG and prints the verdict.
Command detect-example runs the Fridrich (2002) statistical F5 detector over a freshly encoded, clean JPEG and prints the verdict.
embed command
Command embed-example shows the minimal F5 embedding flow.
Command embed-example shows the minimal F5 embedding flow.
encode command
Command encode-example encodes a synthetic image to a JPEG whose bytes match the original James R. Weeks / f5.jar encoder, then prints the output size.
Command encode-example encodes a synthetic image to a JPEG whose bytes match the original James R. Weeks / f5.jar encoder, then prints the output size.
roundtrip command
Command roundtrip-example embeds a message and extracts it back, exercising the embed and extract packages together.
Command roundtrip-example embeds a message and extracts it back, exercising the embed and extract packages together.
Package extract implements the F5 steganographic algorithm for extracting hidden messages from JPEG DCT coefficients.
Package extract implements the F5 steganographic algorithm for extracting hidden messages from JPEG DCT coefficients.
Package fuse is the F5 detection decision layer: it fuses the three detectors (the neural ensemble + recompression gate, the Fridrich β attack, and the structural f5.jar/PixelKnot fingerprint) into one verdict and likelihood score.
Package fuse is the F5 detection decision layer: it fuses the three detectors (the neural ensemble + recompression gate, the Fridrich β attack, and the structural f5.jar/PixelKnot fingerprint) into one verdict and likelihood score.
Package gate runs the trained F5 steganalysis CNN models in pure Go (no cgo), over the standalone ONNX engine github.com/0verkilll/onnx.
Package gate runs the trained F5 steganalysis CNN models in pure Go (no cgo), over the standalone ONNX engine github.com/0verkilll/onnx.
embedded
Package embedded ships the redesign_v5 detection models inside the binary (compiled in with the standard library's embed package), so the full pipeline runs turnkey with no external files.
Package embedded ships the redesign_v5 detection models inside the binary (compiled in with the standard library's embed package), so the full pipeline runs turnkey with no external files.
Package i18nx is the opt-in localization loader for the F5 toolkit's embed and extract packages.
Package i18nx is the opt-in localization loader for the F5 toolkit's embed and extract packages.
internal
coefficient
Package coefficient adapts the f5coefficient primitive to the internal API used by the embed and extract capabilities.
Package coefficient adapts the f5coefficient primitive to the internal API used by the embed and extract capabilities.
logx
Package logx provides a tiny, thread-safe holder for an injected logger.Logger.
Package logx provides a tiny, thread-safe holder for an injected logger.Logger.
permutation
Package permutation provides the shared F5 permutative-straddling primitives: PRNG seeding, Fisher-Yates permutation generation, and the JPEG de-zigzag index transform.
Package permutation provides the shared F5 permutative-straddling primitives: PRNG seeding, Fisher-Yates permutation generation, and the JPEG de-zigzag index transform.
valid
Package valid holds the shared input-validation rules for F5 coefficients and passwords.
Package valid holds the shared input-validation rules for F5 coefficients and passwords.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL