Bases: BaseCodec
This module implements simple LSB steganography in WAV audios.
with code shamelessly taken from
https://daniellerch.me/stego/lab/intro/lsb-en/#lsb-steganography-in-wav-audio-files
Source code in stegobox/codec/lsb_wav.py
| class LSBWav(BaseCodec):
"""
This module implements simple LSB steganography in WAV audios.
with code shamelessly taken from
https://daniellerch.me/stego/lab/intro/lsb-en/#lsb-steganography-in-wav-audio-files
"""
def __init__(self) -> None:
super().__init__()
def encode(
self, carrier: wave.Wave_read, payload: str
) -> tuple[bytes, wave._wave_params]:
"""Encoder requires the carrier audio to be WAV and the payload to be a string.
Args:
carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
payload: Payload (secret message) to be encoded.
Returns:
bytes: Frame information in bytes of the audio with the payload embedded.
wave._wave_params: Parameters for audio with the payload embedded.
"""
self._check_empty_payload(payload)
# Read audio frame information
frames = bytearray(carrier.readframes(carrier.getnframes()))
# Convert payload into bits
message_bits = []
for pl in payload:
message_bits += [(ord(pl) >> i) & 1 for i in range(8)]
# LSB matching
for i in range(len(message_bits)):
if frames[i] % 2 != message_bits[i]:
if frames[i] == 255:
s = -1
elif frames[i] == 0:
s = +1
else:
s = random.choice([-1, +1])
frames[i] = frames[i] + s
return bytes(frames), carrier.getparams()
def decode(self, carrier: wave.Wave_read, payload_length: int = 20) -> str:
"""Decode the secret payload from the carrier audio
Args:
carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
payload_length: the length of secret message
Returns:
The decoded payload (secret message).
"""
# Read audio frame information
frames = bytearray(carrier.readframes(carrier.getnframes()))
# Get the least significant bits of each frame of audio
message_bits = [int(f) % 2 for f in frames]
# Convert bits into bytes
message_ex = []
value = 0
for i in range(len(message_bits)):
if i % 8 == 0 and i != 0:
message_ex.append(value)
value = 0
value |= message_bits[i] << i % 8
# Generates information based on bytes
payload = "".join([chr(L) for L in message_ex])[:payload_length]
return payload
def _check_empty_payload(self, payload: str) -> None:
if not payload:
raise Exception("Payload must not be empty.")
|
encode(carrier, payload)
Encoder requires the carrier audio to be WAV and the payload to be a string.
Parameters:
Name |
Type |
Description |
Default |
carrier |
Wave_read
|
Carrier audio in format WAV. Read with stegobox.io.audio.read() .
|
required
|
payload |
str
|
Payload (secret message) to be encoded.
|
required
|
Returns:
Name | Type |
Description |
bytes |
bytes
|
Frame information in bytes of the audio with the payload embedded.
|
|
_wave_params
|
wave._wave_params: Parameters for audio with the payload embedded.
|
Source code in stegobox/codec/lsb_wav.py
| def encode(
self, carrier: wave.Wave_read, payload: str
) -> tuple[bytes, wave._wave_params]:
"""Encoder requires the carrier audio to be WAV and the payload to be a string.
Args:
carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
payload: Payload (secret message) to be encoded.
Returns:
bytes: Frame information in bytes of the audio with the payload embedded.
wave._wave_params: Parameters for audio with the payload embedded.
"""
self._check_empty_payload(payload)
# Read audio frame information
frames = bytearray(carrier.readframes(carrier.getnframes()))
# Convert payload into bits
message_bits = []
for pl in payload:
message_bits += [(ord(pl) >> i) & 1 for i in range(8)]
# LSB matching
for i in range(len(message_bits)):
if frames[i] % 2 != message_bits[i]:
if frames[i] == 255:
s = -1
elif frames[i] == 0:
s = +1
else:
s = random.choice([-1, +1])
frames[i] = frames[i] + s
return bytes(frames), carrier.getparams()
|
decode(carrier, payload_length=20)
Decode the secret payload from the carrier audio
Parameters:
Name |
Type |
Description |
Default |
carrier |
Wave_read
|
Carrier audio in format WAV. Read with stegobox.io.audio.read() .
|
required
|
payload_length |
int
|
the length of secret message
|
20
|
Returns:
Type |
Description |
str
|
The decoded payload (secret message).
|
Source code in stegobox/codec/lsb_wav.py
| def decode(self, carrier: wave.Wave_read, payload_length: int = 20) -> str:
"""Decode the secret payload from the carrier audio
Args:
carrier: Carrier audio in format WAV. Read with `stegobox.io.audio.read()`.
payload_length: the length of secret message
Returns:
The decoded payload (secret message).
"""
# Read audio frame information
frames = bytearray(carrier.readframes(carrier.getnframes()))
# Get the least significant bits of each frame of audio
message_bits = [int(f) % 2 for f in frames]
# Convert bits into bytes
message_ex = []
value = 0
for i in range(len(message_bits)):
if i % 8 == 0 and i != 0:
message_ex.append(value)
value = 0
value |= message_bits[i] << i % 8
# Generates information based on bytes
payload = "".join([chr(L) for L in message_ex])[:payload_length]
return payload
|