Bases: BaseCodec
LSBJpeg: Hide text into JPEG using LSB.
- Created by: Jiayao Yang
- Created time: 2022/10/10
Source code derived from:
VasilisG/LSB-steganography
Source code in stegobox/codec/jpeg_lsb.py
| class LSBJpeg(BaseCodec):
"""
LSBJpeg: Hide text into JPEG using LSB.
* Created by: Jiayao Yang
* Created time: 2022/10/10
Source code derived from:
[VasilisG/LSB-steganography](https://github.com/VasilisG/LSB-steganography)
"""
def __init__(self) -> None:
super().__init__()
def encode(self, carrier: Image.Image, payload: str) -> Image.Image:
"""Simple LSB steganography using JPEG images.
Args:
carrier: Input JPEG image.
payload: Secret payload message.
Raises:
ValueError: If the payload is too large for the carrier.
Returns:
The encrypted steganography image. Note that the image must be saved as PNG
format for decoding to work properly.
"""
width, height = carrier.size
image_capacity = width * height * BITS_PER_PIXEL
message_capacity = (len(payload) * BITS_PER_CHAR) - (BITS_PER_CHAR + 2)
if not image_capacity >= message_capacity:
raise ValueError("Sorry, payload should be smaller than host image.")
size = carrier.size
# Create binary triple pairs
binaries = list(
"".join([bin(ord(i))[2:].rjust(BITS_PER_CHAR, "0") for i in payload])
+ "".join(["0"] * BITS_PER_CHAR)
)
binaries = binaries + ["0"] * (len(binaries) % BITS_PER_PIXEL)
binaries = [
binaries[i * BITS_PER_PIXEL : i * BITS_PER_PIXEL + BITS_PER_PIXEL]
for i in range(0, int(len(binaries) / BITS_PER_PIXEL))
]
binary_triple_pairs = binaries
# Embed bits to pixels
pixels = list(carrier.getdata())
binary_pixels = [
list(bin(p)[2:].rjust(BITS_PER_CHAR, "0") for p in pixel)
for pixel in pixels
]
for i in range(len(binary_triple_pairs)):
for j in range(len(binary_triple_pairs[i])):
binary_pixels[i][j] = list(binary_pixels[i][j]) # type: ignore
binary_pixels[i][j][-1] = binary_triple_pairs[i][j] # type: ignore
binary_pixels[i][j] = "".join(binary_pixels[i][j])
new_pixels = [tuple(int(p, 2) for p in pixel) for pixel in binary_pixels]
new_img = Image.new("RGB", size)
new_img.putdata(new_pixels) # type: ignore
return new_img
def decode(self, carrier: Image.Image) -> str:
"""Decode the secret payload from the carrier image
Args:
carrier: Carrier image in format png.
Returns:
str: The decoded payload (secret message).
"""
self._check_png(carrier) # Must be a PNG image for decoding to work.
pixels = list(carrier.getdata())
binary_pixels = [
list(bin(p)[2:].rjust(BITS_PER_CHAR, "0") for p in pixel)
for pixel in pixels
]
# Get LSBs from pixels
bin_list = self._get_lsbs_from_pixels(binary_pixels)
payload = "".join(
[
chr(int("".join(bin_list[i : i + BITS_PER_CHAR]), 2))
for i in range(0, len(bin_list) - BITS_PER_CHAR, BITS_PER_CHAR)
]
)
return payload
def _get_lsbs_from_pixels(self, binary_pixels: list) -> list:
total_zeros = 0
bin_list = []
for binary_pixel in binary_pixels:
for p in binary_pixel:
if p[-1] == "0":
total_zeros = total_zeros + 1
else:
total_zeros = 0
bin_list.append(p[-1])
if total_zeros == BITS_PER_CHAR:
return bin_list
raise ValueError("LSB not found.")
def _check_png(self, image: Image.Image) -> None:
if image.format != "PNG":
raise Exception("PNG images are required for decoding to work normally.")
|
encode(carrier, payload)
Simple LSB steganography using JPEG images.
Parameters:
Name |
Type |
Description |
Default |
carrier |
Image
|
|
required
|
payload |
str
|
|
required
|
Raises:
Type |
Description |
ValueError
|
If the payload is too large for the carrier.
|
Returns:
Type |
Description |
Image
|
The encrypted steganography image. Note that the image must be saved as PNG
|
Image
|
format for decoding to work properly.
|
Source code in stegobox/codec/jpeg_lsb.py
| def encode(self, carrier: Image.Image, payload: str) -> Image.Image:
"""Simple LSB steganography using JPEG images.
Args:
carrier: Input JPEG image.
payload: Secret payload message.
Raises:
ValueError: If the payload is too large for the carrier.
Returns:
The encrypted steganography image. Note that the image must be saved as PNG
format for decoding to work properly.
"""
width, height = carrier.size
image_capacity = width * height * BITS_PER_PIXEL
message_capacity = (len(payload) * BITS_PER_CHAR) - (BITS_PER_CHAR + 2)
if not image_capacity >= message_capacity:
raise ValueError("Sorry, payload should be smaller than host image.")
size = carrier.size
# Create binary triple pairs
binaries = list(
"".join([bin(ord(i))[2:].rjust(BITS_PER_CHAR, "0") for i in payload])
+ "".join(["0"] * BITS_PER_CHAR)
)
binaries = binaries + ["0"] * (len(binaries) % BITS_PER_PIXEL)
binaries = [
binaries[i * BITS_PER_PIXEL : i * BITS_PER_PIXEL + BITS_PER_PIXEL]
for i in range(0, int(len(binaries) / BITS_PER_PIXEL))
]
binary_triple_pairs = binaries
# Embed bits to pixels
pixels = list(carrier.getdata())
binary_pixels = [
list(bin(p)[2:].rjust(BITS_PER_CHAR, "0") for p in pixel)
for pixel in pixels
]
for i in range(len(binary_triple_pairs)):
for j in range(len(binary_triple_pairs[i])):
binary_pixels[i][j] = list(binary_pixels[i][j]) # type: ignore
binary_pixels[i][j][-1] = binary_triple_pairs[i][j] # type: ignore
binary_pixels[i][j] = "".join(binary_pixels[i][j])
new_pixels = [tuple(int(p, 2) for p in pixel) for pixel in binary_pixels]
new_img = Image.new("RGB", size)
new_img.putdata(new_pixels) # type: ignore
return new_img
|
decode(carrier)
Decode the secret payload from the carrier image
Parameters:
Name |
Type |
Description |
Default |
carrier |
Image
|
Carrier image in format png.
|
required
|
Returns:
Name | Type |
Description |
str |
str
|
The decoded payload (secret message).
|
Source code in stegobox/codec/jpeg_lsb.py
| def decode(self, carrier: Image.Image) -> str:
"""Decode the secret payload from the carrier image
Args:
carrier: Carrier image in format png.
Returns:
str: The decoded payload (secret message).
"""
self._check_png(carrier) # Must be a PNG image for decoding to work.
pixels = list(carrier.getdata())
binary_pixels = [
list(bin(p)[2:].rjust(BITS_PER_CHAR, "0") for p in pixel)
for pixel in pixels
]
# Get LSBs from pixels
bin_list = self._get_lsbs_from_pixels(binary_pixels)
payload = "".join(
[
chr(int("".join(bin_list[i : i + BITS_PER_CHAR]), 2))
for i in range(0, len(bin_list) - BITS_PER_CHAR, BITS_PER_CHAR)
]
)
return payload
|