ghostrate 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.1
2
+ Name: ghostrate
3
+ Version: 1.0.0
4
+ Summary: Audio Steganography & Forensic Tool — Hide and reveal spoken messages in music
5
+ Home-page: https://github.com/jawad/ghostrate
6
+ Author: Jawad
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/jawad/ghostrate
9
+ Keywords: audio,steganography,forensics,sound,dsp,encryption,watermark
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
14
+ Classifier: Topic :: Security :: Cryptography
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: License :: OSI Approved :: MIT License
22
+ Classifier: Operating System :: OS Independent
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+
26
+ # GhostRate 🎙️🕵️‍♂️
27
+
28
+ > **Audio Steganography & Forensic Suite — Web Studio + Python CLI.**
29
+
30
+ GhostRate embeds hidden spoken voice messages inside any music track using **Phase Mid-Side Inversion** and **Phantom Center Balancing**.
31
+
32
+ * **Normal Ear:** Plays as a completely standard stereo song on headphones, speakers, or car audio.
33
+ * **Filter-Immune:** Survives external audio converters, resamplers, and anti-aliasing downsampling (unlike fragile high-frequency tricks).
34
+ * **Forensic Extraction:** Mid-side phase cancellation $(L - R)$ cancels the host music into dead silence, revealing the secret spoken voice with $+18\text{ dB}$ make-up gain.
35
+
36
+ ---
37
+
38
+ ## 💻 Web Studio (In-Browser)
39
+
40
+ The Web Studio is a client-side TypeScript application featuring real-time visualizers, microphone recording, stealth gain adjustment, and a 1-click **Universal Decoder**.
41
+
42
+ ```bash
43
+ # Start local dev server
44
+ npm run dev
45
+
46
+ # Run automated test suite
47
+ npm test
48
+
49
+ # Build production bundle
50
+ npm run build
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 🐍 Python CLI (Offline Forensic Tool)
56
+
57
+ GhostRate includes a standalone Python CLI in `python/ghostrate.py` with **zero external dependencies** (uses only Python's standard library: `wave`, `struct`, `argparse`). It can be run on any air-gapped machine, Linux server, or offline terminal.
58
+
59
+ ### 1. Hide Voice Inside Music (With Optional Passcode Encryption)
60
+ ```bash
61
+ # Public (any L-R decoder reveals it):
62
+ python3 python/ghostrate.py hide music.wav voice.wav -o stego_song.wav --stealth 0.06
63
+
64
+ # Encrypted (requires passcode to descramble):
65
+ python3 python/ghostrate.py hide music.wav voice.wav -o stego_song.wav --stealth 0.06 --key "MySecret123"
66
+ ```
67
+ * `--stealth 0.06`: Adjusts voice stealth level (`0.03` for invisible, `0.06` for balanced, `0.15` for louder).
68
+ * `--key "password"`: Scrambles the voice using a deterministic pseudo-random key sequence. Without this key, decoding yields only white noise!
69
+
70
+ ### 2. Reveal Secret Message from Any Stego File
71
+ ```bash
72
+ # Public stego file:
73
+ python3 python/ghostrate.py reveal stego_song.wav -o revealed_secret.wav
74
+
75
+ # Encrypted stego file:
76
+ python3 python/ghostrate.py reveal stego_song.wav -o revealed_secret.wav --key "MySecret123"
77
+ ```
78
+ Cancels out the host music and descrambles the isolated speech.
79
+
80
+ ### 3. Inspect Audio File Phase Correlation
81
+ ```bash
82
+ python3 python/ghostrate.py info stego_song.wav
83
+ ```
84
+ Analyzes stereo difference energy to detect whether an audio track contains a hidden payload.
85
+
86
+ ---
87
+
88
+ ## 🔬 How the Math Works
89
+
90
+ 1. **Phantom Center Normalization:**
91
+ Most commercial songs have wide stereo guitars or synths ($L \ne R$). GhostRate first sums both channels into a phantom center mono base:
92
+ $$M[n] = \frac{\text{Music}_L[n] + \text{Music}_R[n]}{2}$$
93
+
94
+ 2. **Phase Inversion Embedding:**
95
+ $$\text{Left Ear} = M[n] + g \cdot \text{Voice}[n]$$
96
+ $$\text{Right Ear} = M[n] - g \cdot \text{Voice}[n]$$
97
+
98
+ 3. **Phase Cancellation Decoding:**
99
+ $$\text{Decoded} = \text{Left} - \text{Right} = (M - M) + 2g \cdot \text{Voice} = \mathbf{2g \cdot \text{Voice}}$$
100
+ The music vanishes to $0$, and the voice doubles in volume!
@@ -0,0 +1,75 @@
1
+ # GhostRate 🎙️🕵️‍♂️
2
+
3
+ > **Audio Steganography & Forensic Suite — Web Studio + Python CLI.**
4
+
5
+ GhostRate embeds hidden spoken voice messages inside any music track using **Phase Mid-Side Inversion** and **Phantom Center Balancing**.
6
+
7
+ * **Normal Ear:** Plays as a completely standard stereo song on headphones, speakers, or car audio.
8
+ * **Filter-Immune:** Survives external audio converters, resamplers, and anti-aliasing downsampling (unlike fragile high-frequency tricks).
9
+ * **Forensic Extraction:** Mid-side phase cancellation $(L - R)$ cancels the host music into dead silence, revealing the secret spoken voice with $+18\text{ dB}$ make-up gain.
10
+
11
+ ---
12
+
13
+ ## 💻 Web Studio (In-Browser)
14
+
15
+ The Web Studio is a client-side TypeScript application featuring real-time visualizers, microphone recording, stealth gain adjustment, and a 1-click **Universal Decoder**.
16
+
17
+ ```bash
18
+ # Start local dev server
19
+ npm run dev
20
+
21
+ # Run automated test suite
22
+ npm test
23
+
24
+ # Build production bundle
25
+ npm run build
26
+ ```
27
+
28
+ ---
29
+
30
+ ## 🐍 Python CLI (Offline Forensic Tool)
31
+
32
+ GhostRate includes a standalone Python CLI in `python/ghostrate.py` with **zero external dependencies** (uses only Python's standard library: `wave`, `struct`, `argparse`). It can be run on any air-gapped machine, Linux server, or offline terminal.
33
+
34
+ ### 1. Hide Voice Inside Music (With Optional Passcode Encryption)
35
+ ```bash
36
+ # Public (any L-R decoder reveals it):
37
+ python3 python/ghostrate.py hide music.wav voice.wav -o stego_song.wav --stealth 0.06
38
+
39
+ # Encrypted (requires passcode to descramble):
40
+ python3 python/ghostrate.py hide music.wav voice.wav -o stego_song.wav --stealth 0.06 --key "MySecret123"
41
+ ```
42
+ * `--stealth 0.06`: Adjusts voice stealth level (`0.03` for invisible, `0.06` for balanced, `0.15` for louder).
43
+ * `--key "password"`: Scrambles the voice using a deterministic pseudo-random key sequence. Without this key, decoding yields only white noise!
44
+
45
+ ### 2. Reveal Secret Message from Any Stego File
46
+ ```bash
47
+ # Public stego file:
48
+ python3 python/ghostrate.py reveal stego_song.wav -o revealed_secret.wav
49
+
50
+ # Encrypted stego file:
51
+ python3 python/ghostrate.py reveal stego_song.wav -o revealed_secret.wav --key "MySecret123"
52
+ ```
53
+ Cancels out the host music and descrambles the isolated speech.
54
+
55
+ ### 3. Inspect Audio File Phase Correlation
56
+ ```bash
57
+ python3 python/ghostrate.py info stego_song.wav
58
+ ```
59
+ Analyzes stereo difference energy to detect whether an audio track contains a hidden payload.
60
+
61
+ ---
62
+
63
+ ## 🔬 How the Math Works
64
+
65
+ 1. **Phantom Center Normalization:**
66
+ Most commercial songs have wide stereo guitars or synths ($L \ne R$). GhostRate first sums both channels into a phantom center mono base:
67
+ $$M[n] = \frac{\text{Music}_L[n] + \text{Music}_R[n]}{2}$$
68
+
69
+ 2. **Phase Inversion Embedding:**
70
+ $$\text{Left Ear} = M[n] + g \cdot \text{Voice}[n]$$
71
+ $$\text{Right Ear} = M[n] - g \cdot \text{Voice}[n]$$
72
+
73
+ 3. **Phase Cancellation Decoding:**
74
+ $$\text{Decoded} = \text{Left} - \text{Right} = (M - M) + 2g \cdot \text{Voice} = \mathbf{2g \cdot \text{Voice}}$$
75
+ The music vanishes to $0$, and the voice doubles in volume!
@@ -0,0 +1,41 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ghostrate"
7
+ version = "1.0.0"
8
+ description = "Audio Steganography & Forensic Tool — Hide and reveal spoken messages in music"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Jawad" }
14
+ ]
15
+ keywords = ["audio", "steganography", "forensics", "sound", "dsp", "encryption", "watermark"]
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Science/Research",
20
+ "Topic :: Multimedia :: Sound/Audio :: Analysis",
21
+ "Topic :: Security :: Cryptography",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.8",
24
+ "Programming Language :: Python :: 3.9",
25
+ "Programming Language :: Python :: 3.10",
26
+ "Programming Language :: Python :: 3.11",
27
+ "Programming Language :: Python :: 3.12",
28
+ "License :: OSI Approved :: MIT License",
29
+ "Operating System :: OS Independent",
30
+ ]
31
+ dependencies = []
32
+
33
+ [project.urls]
34
+ Homepage = "https://github.com/jawad/ghostrate"
35
+
36
+ [project.scripts]
37
+ ghostrate = "ghostrate.cli:main"
38
+
39
+ [tool.setuptools.packages.find]
40
+ where = ["src"]
41
+ include = ["ghostrate*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,29 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="ghostrate",
5
+ version="1.0.0",
6
+ description="Audio Steganography & Forensic Tool — Hide and reveal spoken messages in music",
7
+ long_description=open("README.md").read(),
8
+ long_description_content_type="text/markdown",
9
+ author="Jawad",
10
+ url="https://github.com/jawad/ghostrate",
11
+ license="MIT",
12
+ package_dir={"": "src"},
13
+ packages=find_packages(where="src"),
14
+ entry_points={
15
+ "console_scripts": [
16
+ "ghostrate=ghostrate.cli:main",
17
+ ],
18
+ },
19
+ classifiers=[
20
+ "Development Status :: 5 - Production/Stable",
21
+ "Intended Audience :: Developers",
22
+ "Topic :: Multimedia :: Sound/Audio :: Analysis",
23
+ "Topic :: Security :: Cryptography",
24
+ "Programming Language :: Python :: 3",
25
+ "License :: OSI Approved :: MIT License",
26
+ "Operating System :: OS Independent",
27
+ ],
28
+ python_requires=">=3.8",
29
+ )
@@ -0,0 +1,34 @@
1
+ """GhostRate — Audio Steganography & Forensic Tool.
2
+
3
+ Embed and reveal hidden spoken messages inside music using phase cancellation
4
+ and cryptographic key scrambling.
5
+ """
6
+
7
+ from .cli import (
8
+ read_wav,
9
+ write_stereo_wav,
10
+ write_mono_wav,
11
+ generate_key_sequence,
12
+ apply_key_scrambler,
13
+ linear_resample,
14
+ normalize,
15
+ hide,
16
+ reveal,
17
+ info,
18
+ main,
19
+ )
20
+
21
+ __version__ = "1.0.0"
22
+ __all__ = [
23
+ "read_wav",
24
+ "write_stereo_wav",
25
+ "write_mono_wav",
26
+ "generate_key_sequence",
27
+ "apply_key_scrambler",
28
+ "linear_resample",
29
+ "normalize",
30
+ "hide",
31
+ "reveal",
32
+ "info",
33
+ "main",
34
+ ]
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/env python3
2
+ """GhostRate CLI & Library Core Implementation.
3
+
4
+ Zero third-party dependencies (uses only standard library wave, struct, argparse).
5
+ """
6
+
7
+ import argparse
8
+ import struct
9
+ import sys
10
+ import wave
11
+
12
+
13
+ def generate_key_sequence(password: str, length: int):
14
+ """Generates a deterministic bipolar pseudo-random sequence {-1.0, 1.0}
15
+ using a 32-bit FNV-1a hash seed and a 32-bit Xorshift PRNG.
16
+ """
17
+ if not password or not password.strip():
18
+ return [1.0] * length
19
+
20
+ seed = 2166136261
21
+ for char in password:
22
+ seed = ((seed ^ ord(char)) * 16777619) & 0xFFFFFFFF
23
+ if seed == 0:
24
+ seed = 1
25
+
26
+ state = seed
27
+ seq = [1.0] * length
28
+ chip_size = 4
29
+ current_sign = 1.0
30
+
31
+ for i in range(length):
32
+ if i % chip_size == 0:
33
+ state = (state ^ ((state << 13) & 0xFFFFFFFF)) & 0xFFFFFFFF
34
+ state = (state ^ (state >> 17)) & 0xFFFFFFFF
35
+ state = (state ^ ((state << 5) & 0xFFFFFFFF)) & 0xFFFFFFFF
36
+ current_sign = 1.0 if (state >> 31) == 0 else -1.0
37
+ seq[i] = current_sign
38
+
39
+ return seq
40
+
41
+
42
+ def apply_key_scrambler(samples, key_seq):
43
+ """Scrambles or descrambles samples with a bipolar key sequence."""
44
+ n = min(len(samples), len(key_seq))
45
+ return [samples[i] * key_seq[i] for i in range(n)]
46
+
47
+
48
+ def read_wav(file_path):
49
+ """Reads a WAV file and returns (samples_left, samples_right, sample_rate, num_channels)."""
50
+ with wave.open(file_path, "rb") as wf:
51
+ num_channels = wf.getnchannels()
52
+ sampwidth = wf.getsampwidth()
53
+ framerate = wf.getframerate()
54
+ nframes = wf.getnframes()
55
+ raw_bytes = wf.readframes(nframes)
56
+
57
+ if sampwidth != 2:
58
+ raise ValueError(
59
+ f"Unsupported sample bit-depth: {sampwidth * 8}-bit. Please provide 16-bit PCM WAV."
60
+ )
61
+
62
+ num_samples = nframes * num_channels
63
+ fmt = f"<{num_samples}h"
64
+ ints = struct.unpack(fmt, raw_bytes)
65
+
66
+ if num_channels == 1:
67
+ mono = [s / 32768.0 for s in ints]
68
+ return mono, mono, framerate, 1
69
+ elif num_channels == 2:
70
+ left = [ints[i * 2] / 32768.0 for i in range(nframes)]
71
+ right = [ints[i * 2 + 1] / 32768.0 for i in range(nframes)]
72
+ return left, right, framerate, 2
73
+ else:
74
+ raise ValueError(f"Unsupported channel count: {num_channels}")
75
+
76
+
77
+ def write_stereo_wav(file_path, left, right, sample_rate):
78
+ """Writes interleaved 16-bit stereo PCM WAV file."""
79
+ nframes = len(left)
80
+ out_ints = []
81
+ for i in range(nframes):
82
+ s_l = max(-1.0, min(1.0, left[i]))
83
+ s_r = max(-1.0, min(1.0, right[i]))
84
+ out_ints.append(int(round(s_l * 32767)))
85
+ out_ints.append(int(round(s_r * 32767)))
86
+
87
+ fmt = f"<{len(out_ints)}h"
88
+ raw_bytes = struct.pack(fmt, *out_ints)
89
+
90
+ with wave.open(file_path, "wb") as wf:
91
+ wf.setnchannels(2)
92
+ wf.setsampwidth(2)
93
+ wf.setframerate(sample_rate)
94
+ wf.writeframes(raw_bytes)
95
+
96
+
97
+ def write_mono_wav(file_path, samples, sample_rate):
98
+ """Writes 16-bit mono PCM WAV file."""
99
+ out_ints = [
100
+ int(round(max(-1.0, min(1.0, s)) * 32767)) for s in samples
101
+ ]
102
+ fmt = f"<{len(out_ints)}h"
103
+ raw_bytes = struct.pack(fmt, *out_ints)
104
+
105
+ with wave.open(file_path, "wb") as wf:
106
+ wf.setnchannels(1)
107
+ wf.setsampwidth(2)
108
+ wf.setframerate(sample_rate)
109
+ wf.writeframes(raw_bytes)
110
+
111
+
112
+ def linear_resample(samples, src_rate, dst_rate):
113
+ """Fast linear interpolation resampler."""
114
+ if src_rate == dst_rate:
115
+ return list(samples)
116
+ ratio = dst_rate / src_rate
117
+ dst_len = int(round(len(samples) * ratio))
118
+ out = [0.0] * dst_len
119
+ for i in range(dst_len):
120
+ src_pos = i / ratio
121
+ idx = int(src_pos)
122
+ frac = src_pos - idx
123
+ if idx + 1 < len(samples):
124
+ out[i] = samples[idx] * (1.0 - frac) + samples[idx + 1] * frac
125
+ elif idx < len(samples):
126
+ out[i] = samples[idx]
127
+ return out
128
+
129
+
130
+ def normalize(samples, target_peak=0.95):
131
+ """Normalizes peak amplitude."""
132
+ peak = max(abs(s) for s in samples) if samples else 0
133
+ if peak == 0:
134
+ return samples
135
+ scale = target_peak / peak
136
+ return [s * scale for s in samples]
137
+
138
+
139
+ def hide(music_path, voice_path, output_path="stego_output.wav", stealth=0.06, password=""):
140
+ """Programmatic API to embed voice into music."""
141
+ music_l, music_r, music_rate, _ = read_wav(music_path)
142
+ voice_l, _, voice_rate, _ = read_wav(voice_path)
143
+
144
+ if voice_rate != music_rate:
145
+ voice_aligned = linear_resample(voice_l, voice_rate, music_rate)
146
+ else:
147
+ voice_aligned = voice_l
148
+
149
+ voice_aligned = normalize(voice_aligned, 0.95)
150
+ music_len = len(music_l)
151
+
152
+ if password:
153
+ key_seq = generate_key_sequence(password, music_len)
154
+ voice_payload = apply_key_scrambler(voice_aligned, key_seq)
155
+ else:
156
+ voice_payload = voice_aligned
157
+
158
+ stego_left = [0.0] * music_len
159
+ stego_right = [0.0] * music_len
160
+
161
+ for i in range(music_len):
162
+ m = (music_l[i] + music_r[i]) * 0.5
163
+ v = (voice_payload[i] if i < len(voice_payload) else 0.0) * stealth
164
+ stego_left[i] = max(-1.0, min(1.0, m + v))
165
+ stego_right[i] = max(-1.0, min(1.0, m - v))
166
+
167
+ write_stereo_wav(output_path, stego_left, stego_right, music_rate)
168
+ return output_path
169
+
170
+
171
+ def reveal(stego_path, output_path="revealed_voice.wav", password=""):
172
+ """Programmatic API to extract hidden voice from stego WAV."""
173
+ stego_l, stego_r, sample_rate, num_channels = read_wav(stego_path)
174
+
175
+ if num_channels < 2:
176
+ raise ValueError("Input file is Mono. Phase steganography requires a stereo file.")
177
+
178
+ nframes = len(stego_l)
179
+ diff = [stego_l[i] - stego_r[i] for i in range(nframes)]
180
+
181
+ if password:
182
+ key_seq = generate_key_sequence(password, nframes)
183
+ revealed_raw = apply_key_scrambler(diff, key_seq)
184
+ else:
185
+ revealed_raw = diff
186
+
187
+ revealed_voice = normalize(revealed_raw, 0.95)
188
+ write_mono_wav(output_path, revealed_voice, sample_rate)
189
+ return output_path
190
+
191
+
192
+ def info(file_path):
193
+ """Analyzes audio file phase difference."""
194
+ l, r, rate, channels = read_wav(file_path)
195
+ dur = len(l) / rate
196
+ diff_energy = sum((l[i] - r[i]) ** 2 for i in range(len(l))) if channels == 2 else 0
197
+ total_energy = sum((l[i] ** 2 + r[i] ** 2) for i in range(len(l))) + 1e-9 if channels == 2 else 1
198
+ ratio = (diff_energy / total_energy) * 100 if channels == 2 else 0
199
+ return {
200
+ "file": file_path,
201
+ "channels": channels,
202
+ "sample_rate": rate,
203
+ "duration": dur,
204
+ "phase_difference_energy_pct": ratio,
205
+ "has_payload": ratio > 0.05,
206
+ }
207
+
208
+
209
+ def main():
210
+ parser = argparse.ArgumentParser(
211
+ prog="ghostrate",
212
+ description="GhostRate CLI — Audio Steganography & Forensic Tool"
213
+ )
214
+ subparsers = parser.add_subparsers(dest="command", required=True)
215
+
216
+ # hide
217
+ p_hide = subparsers.add_parser("hide", help="Embed secret voice into music")
218
+ p_hide.add_argument("music", help="Path to host music WAV file")
219
+ p_hide.add_argument("voice", help="Path to secret voice WAV file")
220
+ p_hide.add_argument("-o", "--output", default="stego_output.wav", help="Output stego WAV path")
221
+ p_hide.add_argument("-s", "--stealth", type=float, default=0.06, help="Stealth gain (default: 0.06)")
222
+ p_hide.add_argument("-k", "--key", "--password", dest="key", default="", help="Cryptographic password")
223
+
224
+ # reveal
225
+ p_reveal = subparsers.add_parser("reveal", help="Extract hidden voice from stego WAV")
226
+ p_reveal.add_argument("input", help="Path to stego WAV file")
227
+ p_reveal.add_argument("-o", "--output", default="revealed_voice.wav", help="Output revealed WAV path")
228
+ p_reveal.add_argument("-k", "--key", "--password", dest="key", default="", help="Decryption password")
229
+
230
+ # info
231
+ p_info = subparsers.add_parser("info", help="Inspect audio file metadata")
232
+ p_info.add_argument("input", help="Path to WAV file")
233
+
234
+ args = parser.parse_args()
235
+
236
+ if args.command == "hide":
237
+ print(f"[*] Embedding secret voice from '{args.voice}' into '{args.music}'...")
238
+ out = hide(args.music, args.voice, args.output, args.stealth, args.key)
239
+ print(f"[SUCCESS] Stego audio saved to: {out}")
240
+ elif args.command == "reveal":
241
+ print(f"[*] Extracting secret voice from '{args.input}'...")
242
+ out = reveal(args.input, args.output, args.key)
243
+ print(f"[SUCCESS] Revealed voice saved to: {out}")
244
+ elif args.command == "info":
245
+ res = info(args.input)
246
+ print("--- Audio File Analysis ---")
247
+ print(f"File: {res['file']}")
248
+ print(f"Channels: {res['channels']}")
249
+ print(f"Sample Rate: {res['sample_rate']} Hz")
250
+ print(f"Duration: {res['duration']:.2f} seconds")
251
+ print(f"Phase Difference Energy: {res['phase_difference_energy_pct']:.3f}%")
252
+ if res['has_payload']:
253
+ print("[NOTE] Significant stereo phase difference detected (likely contains a payload)!")
254
+ else:
255
+ print("[NOTE] Audio channels are mono/centered.")
256
+
257
+
258
+ if __name__ == "__main__":
259
+ main()
@@ -0,0 +1,100 @@
1
+ Metadata-Version: 2.1
2
+ Name: ghostrate
3
+ Version: 1.0.0
4
+ Summary: Audio Steganography & Forensic Tool — Hide and reveal spoken messages in music
5
+ Home-page: https://github.com/jawad/ghostrate
6
+ Author: Jawad
7
+ License: MIT
8
+ Project-URL: Homepage, https://github.com/jawad/ghostrate
9
+ Keywords: audio,steganography,forensics,sound,dsp,encryption,watermark
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
14
+ Classifier: Topic :: Security :: Cryptography
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: License :: OSI Approved :: MIT License
22
+ Classifier: Operating System :: OS Independent
23
+ Requires-Python: >=3.8
24
+ Description-Content-Type: text/markdown
25
+
26
+ # GhostRate 🎙️🕵️‍♂️
27
+
28
+ > **Audio Steganography & Forensic Suite — Web Studio + Python CLI.**
29
+
30
+ GhostRate embeds hidden spoken voice messages inside any music track using **Phase Mid-Side Inversion** and **Phantom Center Balancing**.
31
+
32
+ * **Normal Ear:** Plays as a completely standard stereo song on headphones, speakers, or car audio.
33
+ * **Filter-Immune:** Survives external audio converters, resamplers, and anti-aliasing downsampling (unlike fragile high-frequency tricks).
34
+ * **Forensic Extraction:** Mid-side phase cancellation $(L - R)$ cancels the host music into dead silence, revealing the secret spoken voice with $+18\text{ dB}$ make-up gain.
35
+
36
+ ---
37
+
38
+ ## 💻 Web Studio (In-Browser)
39
+
40
+ The Web Studio is a client-side TypeScript application featuring real-time visualizers, microphone recording, stealth gain adjustment, and a 1-click **Universal Decoder**.
41
+
42
+ ```bash
43
+ # Start local dev server
44
+ npm run dev
45
+
46
+ # Run automated test suite
47
+ npm test
48
+
49
+ # Build production bundle
50
+ npm run build
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 🐍 Python CLI (Offline Forensic Tool)
56
+
57
+ GhostRate includes a standalone Python CLI in `python/ghostrate.py` with **zero external dependencies** (uses only Python's standard library: `wave`, `struct`, `argparse`). It can be run on any air-gapped machine, Linux server, or offline terminal.
58
+
59
+ ### 1. Hide Voice Inside Music (With Optional Passcode Encryption)
60
+ ```bash
61
+ # Public (any L-R decoder reveals it):
62
+ python3 python/ghostrate.py hide music.wav voice.wav -o stego_song.wav --stealth 0.06
63
+
64
+ # Encrypted (requires passcode to descramble):
65
+ python3 python/ghostrate.py hide music.wav voice.wav -o stego_song.wav --stealth 0.06 --key "MySecret123"
66
+ ```
67
+ * `--stealth 0.06`: Adjusts voice stealth level (`0.03` for invisible, `0.06` for balanced, `0.15` for louder).
68
+ * `--key "password"`: Scrambles the voice using a deterministic pseudo-random key sequence. Without this key, decoding yields only white noise!
69
+
70
+ ### 2. Reveal Secret Message from Any Stego File
71
+ ```bash
72
+ # Public stego file:
73
+ python3 python/ghostrate.py reveal stego_song.wav -o revealed_secret.wav
74
+
75
+ # Encrypted stego file:
76
+ python3 python/ghostrate.py reveal stego_song.wav -o revealed_secret.wav --key "MySecret123"
77
+ ```
78
+ Cancels out the host music and descrambles the isolated speech.
79
+
80
+ ### 3. Inspect Audio File Phase Correlation
81
+ ```bash
82
+ python3 python/ghostrate.py info stego_song.wav
83
+ ```
84
+ Analyzes stereo difference energy to detect whether an audio track contains a hidden payload.
85
+
86
+ ---
87
+
88
+ ## 🔬 How the Math Works
89
+
90
+ 1. **Phantom Center Normalization:**
91
+ Most commercial songs have wide stereo guitars or synths ($L \ne R$). GhostRate first sums both channels into a phantom center mono base:
92
+ $$M[n] = \frac{\text{Music}_L[n] + \text{Music}_R[n]}{2}$$
93
+
94
+ 2. **Phase Inversion Embedding:**
95
+ $$\text{Left Ear} = M[n] + g \cdot \text{Voice}[n]$$
96
+ $$\text{Right Ear} = M[n] - g \cdot \text{Voice}[n]$$
97
+
98
+ 3. **Phase Cancellation Decoding:**
99
+ $$\text{Decoded} = \text{Left} - \text{Right} = (M - M) + 2g \cdot \text{Voice} = \mathbf{2g \cdot \text{Voice}}$$
100
+ The music vanishes to $0$, and the voice doubles in volume!
@@ -0,0 +1,10 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ src/ghostrate/__init__.py
5
+ src/ghostrate/cli.py
6
+ src/ghostrate.egg-info/PKG-INFO
7
+ src/ghostrate.egg-info/SOURCES.txt
8
+ src/ghostrate.egg-info/dependency_links.txt
9
+ src/ghostrate.egg-info/entry_points.txt
10
+ src/ghostrate.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ ghostrate = ghostrate.cli:main
@@ -0,0 +1 @@
1
+ ghostrate