miniDSP
A small C library for audio DSP
Loading...
Searching...
No Matches
minidsp_steg.c File Reference

Audio steganography: hide secret messages inside audio signals. More...

#include "minidsp.h"
#include "minidsp_internal.h"

Go to the source code of this file.

Macros

#define HEADER_BITS   32
 Bits needed for the message-length header (32-bit unsigned).
#define PAYLOAD_TYPE_BIT   (1u << 31)
 Bit 31 of the header: payload type flag (0 = text, 1 = binary).
#define LENGTH_MASK   0x7FFFFFFFu
 Mask to extract the message length from the raw header (bits 0–30).
#define FREQ_LO   18500.0
 Carrier for bit 0 (Hz).
#define FREQ_HI   19500.0
 Carrier for bit 1 (Hz).
#define CHIP_MS   3.0
 Duration of one bit chip (ms).
#define TONE_AMP   0.02
 Additive tone amplitude.
#define SPECTEXT_FREQ_LO   18000.0
 Bottom of visual band (Hz).
#define SPECTEXT_FREQ_HI   23500.0
 Top of visual band (Hz, below Nyquist).
#define SPECTEXT_COL_MS   30.0
 Column duration (ms).
#define SPECTEXT_COLS_PER_CHAR   8
 Bitmap columns per character.
#define SPECTEXT_TARGET_SR   48000.0
 Output sample rate (Hz).
#define SPECTEXT_AMP   0.02
 Spectrogram art amplitude.
#define SPECTEXT_NORM_PEAK   0.9
 MD_spectrogram_text peak.
#define SPECTEXT_PAD_SEC   0.25
 Silence before spectrogram text (s).
#define SPECTEXT_SEC_PER_CHAR   (SPECTEXT_COL_MS / 1000.0 * SPECTEXT_COLS_PER_CHAR)
 Seconds per character in the spectrogram visual.

Functions

static double clamp (double x)
 Clamp a double to [-1, 1].
static int double_to_pcm16 (double sample)
 Convert a double sample in [-1, 1] to a signed 16-bit PCM value.
static double pcm16_to_double (int pcm)
 Convert a signed 16-bit PCM value back to double in [-1, 1].
static unsigned lsb_capacity (unsigned signal_len)
static unsigned lsb_encode (const double *host, double *output, unsigned signal_len, const unsigned char *data, unsigned data_len, unsigned flags)
static unsigned lsb_read_header (const double *signal)
 Read the raw 32-bit LSB header from the first HEADER_BITS samples.
static unsigned lsb_decode (const double *stego, unsigned signal_len, unsigned char *data_out, unsigned max_len)
static unsigned chip_samples (double sample_rate)
static unsigned freq_capacity_cs (unsigned signal_len, unsigned cs)
static unsigned freq_capacity (unsigned signal_len, double sample_rate)
static void _bfsk_setup (double sample_rate)
void md_steg_teardown (void)
 Tear down the BFSK sine carrier cache.
static void encode_one_bit (double *output, unsigned signal_len, unsigned chip_idx, unsigned cs, const double *carrier)
 Encode one bit by adding a precomputed BFSK tone burst at the given chip.
static unsigned freq_encode (const double *host, double *output, unsigned signal_len, double sample_rate, const unsigned char *data, unsigned data_len, unsigned flags)
static unsigned decode_one_bit (const double *stego, unsigned signal_len, unsigned chip_idx, unsigned cs, const double *sin_lo, const double *sin_hi, double *corr_out)
 Decode one bit by correlating a chip against precomputed BFSK carriers.
static unsigned freq_decode (const double *stego, unsigned signal_len, double sample_rate, unsigned char *data_out, unsigned max_len)
static unsigned spectext_vis_capacity (double duration_sec)
 Maximum number of visually displayable characters for a given duration.
static unsigned spectext_output_len (unsigned signal_len, double sample_rate)
 Compute the output signal length at 48 kHz for a given input.
static unsigned spectext_capacity (unsigned signal_len, double sample_rate)
static unsigned spectext_encode (const double *host, double *output, unsigned signal_len, double sample_rate, const unsigned char *data, unsigned data_len, unsigned flags)
static double spectext_ultrasonic_rms (const double *signal, unsigned signal_len, double sample_rate)
 Probe for ultrasonic energy in the 18-24 kHz band.
unsigned MD_steg_capacity (unsigned signal_len, double sample_rate, int method)
 Compute the maximum message length (in bytes) that can be hidden.
static unsigned encode_common (const double *host, double *output, unsigned signal_len, double sample_rate, const unsigned char *data, unsigned data_len, int method, unsigned flags)
 Shared encode logic for both text and binary public API functions.
unsigned MD_steg_encode_bytes (const double *host, double *output, unsigned signal_len, double sample_rate, const unsigned char *data, unsigned data_len, int method)
 Encode arbitrary binary data into a host audio signal.
unsigned MD_steg_decode_bytes (const double *stego, unsigned signal_len, double sample_rate, unsigned char *data_out, unsigned max_len, int method)
 Decode binary data from a stego audio signal.
unsigned MD_steg_encode (const double *host, double *output, unsigned signal_len, double sample_rate, const char *message, int method)
 Encode a secret message into a host audio signal.
unsigned MD_steg_decode (const double *stego, unsigned signal_len, double sample_rate, char *message_out, unsigned max_msg_len, int method)
 Decode a secret message from a stego audio signal.
int MD_steg_detect (const double *signal, unsigned signal_len, double sample_rate, int *payload_type_out)
 Detect which steganography method (if any) was used to encode a signal.

Variables

static double * _bfsk_sin_lo = NULL
static double * _bfsk_sin_hi = NULL
static unsigned _bfsk_cs = 0

Detailed Description

Audio steganography: hide secret messages inside audio signals.

Three methods are provided:

  • LSB (Least Significant Bit) — encodes message bits in the lowest bit of a 16-bit PCM representation of each sample. High capacity, negligible audible distortion, but fragile to any signal processing.
  • Frequency-band modulation — encodes bits as the presence or absence of a near-ultrasonic tone (default 18.5 kHz / 19.5 kHz BFSK) in short time chips. Lower capacity but survives mild resampling and compression. Requires sample_rate >= 40000 Hz so the carrier frequencies remain below Nyquist.
  • Spectrogram text (spectext) — hybrid: LSB for machine-readable data + spectrogram text art in the 18-24 kHz ultrasonic band for visual verification. Auto-upsamples to 48 kHz. The visual channel uses a fixed 30 ms column width (240 ms per character).

Both methods prepend a 32-bit little-endian header before the payload. Bits 0–30 hold the message byte count; bit 31 is a payload type flag (0 = text, 1 = binary). This enables blind decoding without knowing the original message length, and allows MD_steg_detect() to identify the payload type.

Definition in file minidsp_steg.c.

Macro Definition Documentation

◆ CHIP_MS

#define CHIP_MS   3.0

Duration of one bit chip (ms).

Definition at line 192 of file minidsp_steg.c.

◆ FREQ_HI

#define FREQ_HI   19500.0

Carrier for bit 1 (Hz).

Definition at line 191 of file minidsp_steg.c.

◆ FREQ_LO

#define FREQ_LO   18500.0

Carrier for bit 0 (Hz).

Definition at line 190 of file minidsp_steg.c.

◆ HEADER_BITS

#define HEADER_BITS   32

Bits needed for the message-length header (32-bit unsigned).

Definition at line 37 of file minidsp_steg.c.

◆ LENGTH_MASK

#define LENGTH_MASK   0x7FFFFFFFu

Mask to extract the message length from the raw header (bits 0–30).

Definition at line 43 of file minidsp_steg.c.

◆ PAYLOAD_TYPE_BIT

#define PAYLOAD_TYPE_BIT   (1u << 31)

Bit 31 of the header: payload type flag (0 = text, 1 = binary).

Definition at line 40 of file minidsp_steg.c.

◆ SPECTEXT_AMP

#define SPECTEXT_AMP   0.02

Spectrogram art amplitude.

Definition at line 394 of file minidsp_steg.c.

◆ SPECTEXT_COL_MS

#define SPECTEXT_COL_MS   30.0

Column duration (ms).

Definition at line 391 of file minidsp_steg.c.

◆ SPECTEXT_COLS_PER_CHAR

#define SPECTEXT_COLS_PER_CHAR   8

Bitmap columns per character.

Definition at line 392 of file minidsp_steg.c.

◆ SPECTEXT_FREQ_HI

#define SPECTEXT_FREQ_HI   23500.0

Top of visual band (Hz, below Nyquist).

Definition at line 390 of file minidsp_steg.c.

◆ SPECTEXT_FREQ_LO

#define SPECTEXT_FREQ_LO   18000.0

Bottom of visual band (Hz).

Definition at line 389 of file minidsp_steg.c.

◆ SPECTEXT_NORM_PEAK

#define SPECTEXT_NORM_PEAK   0.9

MD_spectrogram_text peak.

Definition at line 395 of file minidsp_steg.c.

◆ SPECTEXT_PAD_SEC

#define SPECTEXT_PAD_SEC   0.25

Silence before spectrogram text (s).

Definition at line 396 of file minidsp_steg.c.

◆ SPECTEXT_SEC_PER_CHAR

#define SPECTEXT_SEC_PER_CHAR   (SPECTEXT_COL_MS / 1000.0 * SPECTEXT_COLS_PER_CHAR)

Seconds per character in the spectrogram visual.

Definition at line 399 of file minidsp_steg.c.

◆ SPECTEXT_TARGET_SR

#define SPECTEXT_TARGET_SR   48000.0

Output sample rate (Hz).

Definition at line 393 of file minidsp_steg.c.

◆ TONE_AMP

#define TONE_AMP   0.02

Additive tone amplitude.

Definition at line 193 of file minidsp_steg.c.

Function Documentation

◆ _bfsk_setup()

void _bfsk_setup ( double sample_rate)
static

Definition at line 227 of file minidsp_steg.c.

◆ chip_samples()

unsigned chip_samples ( double sample_rate)
static

Definition at line 195 of file minidsp_steg.c.

◆ clamp()

double clamp ( double x)
static

Clamp a double to [-1, 1].

Definition at line 57 of file minidsp_steg.c.

◆ decode_one_bit()

unsigned decode_one_bit ( const double * stego,
unsigned signal_len,
unsigned chip_idx,
unsigned cs,
const double * sin_lo,
const double * sin_hi,
double * corr_out )
static

Decode one bit by correlating a chip against precomputed BFSK carriers.

Optionally returns the winning correlation magnitude via corr_out.

Definition at line 307 of file minidsp_steg.c.

◆ double_to_pcm16()

int double_to_pcm16 ( double sample)
static

Convert a double sample in [-1, 1] to a signed 16-bit PCM value.

Uses rounding (not truncation) so the conversion survives a double → float → double WAV roundtrip.

Definition at line 67 of file minidsp_steg.c.

◆ encode_common()

unsigned encode_common ( const double * host,
double * output,
unsigned signal_len,
double sample_rate,
const unsigned char * data,
unsigned data_len,
int method,
unsigned flags )
static

Shared encode logic for both text and binary public API functions.

Definition at line 588 of file minidsp_steg.c.

◆ encode_one_bit()

void encode_one_bit ( double * output,
unsigned signal_len,
unsigned chip_idx,
unsigned cs,
const double * carrier )
static

Encode one bit by adding a precomputed BFSK tone burst at the given chip.

Definition at line 257 of file minidsp_steg.c.

◆ freq_capacity()

unsigned freq_capacity ( unsigned signal_len,
double sample_rate )
static

Definition at line 209 of file minidsp_steg.c.

◆ freq_capacity_cs()

unsigned freq_capacity_cs ( unsigned signal_len,
unsigned cs )
static

Definition at line 200 of file minidsp_steg.c.

◆ freq_decode()

unsigned freq_decode ( const double * stego,
unsigned signal_len,
double sample_rate,
unsigned char * data_out,
unsigned max_len )
static

Definition at line 326 of file minidsp_steg.c.

◆ freq_encode()

unsigned freq_encode ( const double * host,
double * output,
unsigned signal_len,
double sample_rate,
const unsigned char * data,
unsigned data_len,
unsigned flags )
static

Definition at line 266 of file minidsp_steg.c.

◆ lsb_capacity()

unsigned lsb_capacity ( unsigned signal_len)
static

Definition at line 85 of file minidsp_steg.c.

◆ lsb_decode()

unsigned lsb_decode ( const double * stego,
unsigned signal_len,
unsigned char * data_out,
unsigned max_len )
static

Definition at line 144 of file minidsp_steg.c.

◆ lsb_encode()

unsigned lsb_encode ( const double * host,
double * output,
unsigned signal_len,
const unsigned char * data,
unsigned data_len,
unsigned flags )
static

Definition at line 92 of file minidsp_steg.c.

◆ lsb_read_header()

unsigned lsb_read_header ( const double * signal)
static

Read the raw 32-bit LSB header from the first HEADER_BITS samples.

Definition at line 133 of file minidsp_steg.c.

◆ MD_steg_capacity()

unsigned MD_steg_capacity ( unsigned signal_len,
double sample_rate,
int method )

Compute the maximum message length (in bytes) that can be hidden.

Parameters
signal_lenLength of the host signal in samples.
sample_rateSample rate in Hz.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Maximum message bytes that fit (excluding null terminator).

Definition at line 571 of file minidsp_steg.c.

◆ MD_steg_decode()

unsigned MD_steg_decode ( const double * stego,
unsigned signal_len,
double sample_rate,
char * message_out,
unsigned max_msg_len,
int method )

Decode a secret message from a stego audio signal.

Reads the 32-bit length header, then extracts message bytes using the same method that was used for encoding.

Parameters
stegoThe stego signal containing the hidden message.
signal_lenLength of the stego signal in samples.
sample_rateSample rate in Hz.
message_outOutput buffer for the decoded message (caller-allocated).
max_msg_lenSize of message_out buffer (including null terminator).
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of message bytes decoded (0 if none found).
char recovered[256];
unsigned n = MD_steg_decode(stego, 44100, 44100.0,
recovered, 256, MD_STEG_LSB);
printf("Hidden message: %s\n", recovered);
unsigned MD_steg_decode(const double *stego, unsigned signal_len, double sample_rate, char *message_out, unsigned max_msg_len, int method)
Decode a secret message from a stego audio signal.
#define MD_STEG_LSB
Steganography method: least-significant-bit encoding.
Definition minidsp.h:1538

Definition at line 656 of file minidsp_steg.c.

◆ MD_steg_decode_bytes()

unsigned MD_steg_decode_bytes ( const double * stego,
unsigned signal_len,
double sample_rate,
unsigned char * data_out,
unsigned max_len,
int method )

Decode binary data from a stego audio signal.

Works like MD_steg_decode() but writes raw bytes without null termination, suitable for recovering binary payloads.

Parameters
stegoThe stego signal containing the hidden data.
signal_lenLength of the stego signal in samples.
sample_rateSample rate in Hz.
data_outOutput buffer for the decoded bytes (caller-allocated).
max_lenMaximum number of bytes to write to data_out.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of data bytes decoded (0 if none found).
unsigned char recovered[1024];
unsigned n = MD_steg_decode_bytes(stego, 44100, 44100.0,
recovered, 1024, MD_STEG_LSB);
// recovered[0..n-1] contains the original binary data
unsigned MD_steg_decode_bytes(const double *stego, unsigned signal_len, double sample_rate, unsigned char *data_out, unsigned max_len, int method)
Decode binary data from a stego audio signal.

Definition at line 625 of file minidsp_steg.c.

◆ MD_steg_detect()

int MD_steg_detect ( const double * signal,
unsigned signal_len,
double sample_rate,
int * payload_type_out )

Detect which steganography method (if any) was used to encode a signal.

Probes the signal for a valid steganographic header using both LSB and frequency-band (BFSK) methods. If a valid header is found, returns the method identifier and optionally the payload type (text or binary).

BFSK detection is only attempted when sample_rate >= 40000 Hz. If both methods appear valid, BFSK is preferred (lower false-positive rate).

Parameters
signalThe signal to inspect.
signal_lenLength of the signal in samples.
sample_rateSample rate in Hz.
payload_type_outIf non-null, receives MD_STEG_TYPE_TEXT or MD_STEG_TYPE_BINARY when a method is detected.
Returns
MD_STEG_LSB, MD_STEG_FREQ_BAND, MD_STEG_SPECTEXT, or -1 if no steganographic content is detected.
int payload_type;
int method = MD_steg_detect(signal, signal_len, 44100.0, &payload_type);
if (method >= 0) {
printf("Detected %s payload (%s)\n",
payload_type == MD_STEG_TYPE_BINARY ? "binary" : "text",
method == MD_STEG_LSB ? "LSB" : "BFSK");
}
#define MD_STEG_TYPE_BINARY
Payload type flag: binary (raw byte buffer).
Definition minidsp.h:1561
int MD_steg_detect(const double *signal, unsigned signal_len, double sample_rate, int *payload_type_out)
Detect which steganography method (if any) was used to encode a signal.

Definition at line 670 of file minidsp_steg.c.

◆ MD_steg_encode()

unsigned MD_steg_encode ( const double * host,
double * output,
unsigned signal_len,
double sample_rate,
const char * message,
int method )

Encode a secret message into a host audio signal.

The host signal is copied to output, then the message is embedded using the selected method. A 32-bit length header is prepended so that MD_steg_decode() can recover the message without knowing its length in advance.

  • MD_STEG_LSB — flips the least-significant bit of a 16-bit PCM representation of each sample. Distortion is at most ±1/32768 (≈ −90 dB). Works at any sample rate.
  • MD_STEG_FREQ_BAND — adds a low-amplitude BFSK tone in the near-ultrasonic band (18.5 / 19.5 kHz). Requires sample_rate >= 40000 Hz so the carriers remain below Nyquist.
  • MD_STEG_SPECTEXT — hybrid: LSB data + spectrogram text art in the 18–23.5 kHz band. Auto-upsamples to 48 kHz; output buffer must be sized for the 48 kHz signal length when input rate < 48 kHz.
Parameters
hostInput host signal (not modified).
outputOutput stego signal (caller-allocated; for MD_STEG_SPECTEXT with sample_rate < 48 kHz, must hold MD_resample_output_len(signal_len, sample_rate, 48000) samples).
signal_lenLength of host and output in samples.
sample_rateSample rate in Hz.
messageNull-terminated message string to hide.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of message bytes encoded (0 on failure).
double host[44100], stego[44100];
MD_sine_wave(host, 44100, 0.8, 440.0, 44100.0);
unsigned n = MD_steg_encode(host, stego, 44100, 44100.0,
"secret", MD_STEG_LSB);
void MD_sine_wave(double *output, unsigned N, double amplitude, double freq, double sample_rate)
Generate a sine wave.
unsigned MD_steg_encode(const double *host, double *output, unsigned signal_len, double sample_rate, const char *message, int method)
Encode a secret message into a host audio signal.

Definition at line 646 of file minidsp_steg.c.

◆ MD_steg_encode_bytes()

unsigned MD_steg_encode_bytes ( const double * host,
double * output,
unsigned signal_len,
double sample_rate,
const unsigned char * data,
unsigned data_len,
int method )

Encode arbitrary binary data into a host audio signal.

Works like MD_steg_encode() but accepts a raw byte buffer instead of a null-terminated string, so it can embed data containing 0x00 bytes (e.g. images, compressed archives, cryptographic keys).

Parameters
hostInput host signal (not modified).
outputOutput stego signal (caller-allocated, same length).
signal_lenLength of host and output in samples.
sample_rateSample rate in Hz.
dataPointer to the binary data to hide.
data_lenLength of data in bytes.
methodMD_STEG_LSB, MD_STEG_FREQ_BAND, or MD_STEG_SPECTEXT.
Returns
Number of data bytes encoded (0 on failure).
double host[44100], stego[44100];
MD_sine_wave(host, 44100, 0.8, 440.0, 44100.0);
unsigned char png_data[332];
// ... read PNG file into png_data ...
unsigned n = MD_steg_encode_bytes(host, stego, 44100, 44100.0,
png_data, 332, MD_STEG_LSB);
unsigned MD_steg_encode_bytes(const double *host, double *output, unsigned signal_len, double sample_rate, const unsigned char *data, unsigned data_len, int method)
Encode arbitrary binary data into a host audio signal.

Definition at line 616 of file minidsp_steg.c.

◆ md_steg_teardown()

void md_steg_teardown ( void )

Tear down the BFSK sine carrier cache.

Called only from MD_shutdown().

Definition at line 247 of file minidsp_steg.c.

◆ pcm16_to_double()

double pcm16_to_double ( int pcm)
static

Convert a signed 16-bit PCM value back to double in [-1, 1].

The result is snapped to float precision so that a WAV write/read cycle (which stores IEEE float) preserves the exact value.

Definition at line 80 of file minidsp_steg.c.

◆ spectext_capacity()

unsigned spectext_capacity ( unsigned signal_len,
double sample_rate )
static

Definition at line 419 of file minidsp_steg.c.

◆ spectext_encode()

unsigned spectext_encode ( const double * host,
double * output,
unsigned signal_len,
double sample_rate,
const unsigned char * data,
unsigned data_len,
unsigned flags )
static

Definition at line 428 of file minidsp_steg.c.

◆ spectext_output_len()

unsigned spectext_output_len ( unsigned signal_len,
double sample_rate )
static

Compute the output signal length at 48 kHz for a given input.

Definition at line 412 of file minidsp_steg.c.

◆ spectext_ultrasonic_rms()

double spectext_ultrasonic_rms ( const double * signal,
unsigned signal_len,
double sample_rate )
static

Probe for ultrasonic energy in the 18-24 kHz band.

Computes RMS of the signal bandpass-filtered to that range using a simple DFT bin summation approach.

Definition at line 515 of file minidsp_steg.c.

◆ spectext_vis_capacity()

unsigned spectext_vis_capacity ( double duration_sec)
static

Maximum number of visually displayable characters for a given duration.

Subtracts the leading pad from the available time.

Definition at line 404 of file minidsp_steg.c.

Variable Documentation

◆ _bfsk_cs

unsigned _bfsk_cs = 0
static

Definition at line 225 of file minidsp_steg.c.

◆ _bfsk_sin_hi

double* _bfsk_sin_hi = NULL
static

Definition at line 224 of file minidsp_steg.c.

◆ _bfsk_sin_lo

double* _bfsk_sin_lo = NULL
static

Definition at line 223 of file minidsp_steg.c.