Skip to content

LSBGIF

stegobox.codec.LSBGIF

Bases: BaseCodec

Source code in stegobox/codec/lsb_gif.py
class LSBGIF(BaseCodec):
    def __init__(self) -> None:
        """Hide str in GIF image using LSB steganography.

        * To encode: This method is to modify the LSB of each RGB channel for every
        pixel in the cover image.
        * To decode: The least significant bits of the encoded image are read to recover
        the secret image.

        Originally implemented in
        [akfreas/Stegosaurus](https://github.com/akfreas/Stegosaurus)
        """
        super().__init__()

    def encode_bin(self, string):

        # Accepts an ASCII string and outputs its binary representation.

        binstr = ""
        for c in string:
            binstr += bin(ord(c))[2:].rjust(BYTE_LENGTH, "0")
        return binstr

    def encode_mesg(self, mesg):

        # Attaches a header to the message string and encodes the complete message in
        # binary.

        header = "<" + str(len(mesg)) + ">"
        return self.encode_bin(header + mesg)

    def bin2ascii(self, bin_list):

        # Converts a list of byte-delimited binary strings and returns the
        # corresponding ASCII code.
        # Takes binary list separated into bytes and converts it to an ascii list
        return map(lambda x: chr(int(x, 2)), bin_list)

    def encode(self, carrier: Image.Image, payload: str) -> Image.Image:
        """Encoder requires the carrier image to be GIF and the payload to be a string.

        Args:
            carrier: Carrier image in format GIF. Read with 'stegobox.io.image.read()'.
            payload: Payload (secret message) to be encoded.

        Returns:
            Image.Image: Encoded image in format GIF with the payload embeded.
        """
        pix = carrier.load()  # type: ignore
        coord_list = [
            (x, y) for x in range(0, carrier.size[0]) for y in range(0, carrier.size[1])
        ]
        bin_string = self.encode_mesg(payload)
        self.bin_string = bin_string

        coords = coord_list[: len(bin_string)]
        for coord in coords:
            (x, y) = coord
            # set all lsb's in the coordinate list to zero
            pix[x, y] = pix[x, y] >> 1 << 1  # type: ignore

        coords = list(coord_list)

        while len(bin_string) > 0:
            (x, y) = coords.pop(0)
            pix[x, y] = pix[x, y] | int(bin_string[0])  # type: ignore
            bin_string = bin_string[1:]
        return carrier

    def decode(self, carrier: Image.Image) -> str:
        """Decode the secret image from the encoded image.

        Args:
            carrier: The encoded GIF image object with the secret image embedded.

        Returns:
            str: The message extracted from the encoded GIF image.
        """
        pix = carrier.load()  # type: ignore
        coord_list = [
            (x, y) for x in range(0, carrier.size[0]) for y in range(0, carrier.size[1])
        ]
        coords = list(coord_list)
        char = chr(
            int(
                "".join(
                    [
                        bin(pix[x[0], x[1]])[-1:]  # type: ignore
                        for x in coords[:BYTE_LENGTH]
                    ]
                ),
                2,
            )
        )
        length = ""
        if char == "<":
            while char != ">":
                coords = coords[BYTE_LENGTH:]
                char = chr(
                    int(
                        "".join(
                            [
                                bin(pix[x[0], x[1]])[-1:]  # type: ignore
                                for x in coords[:BYTE_LENGTH]
                            ]
                        ),
                        2,
                    )
                )
                if char != ">":
                    length += char
            coord_list = coords[BYTE_LENGTH:]
            le = int(length)
        else:
            le = 0
        coords = list(coord_list)
        # get a list of the binary LSBs for our message
        bin_mesg = [
            bin(pix[x[0], x[1]])[-1:]  # type: ignore
            for x in coords[: le * BYTE_LENGTH]
        ]
        # group list into bytes
        bin_list = [
            "".join(bin_mesg[i : i + BYTE_LENGTH])
            for i in range(0, len(bin_mesg), BYTE_LENGTH)
        ]
        mesg = "".join(self.bin2ascii(bin_list))
        return mesg

__init__()

Hide str in GIF image using LSB steganography.

  • To encode: This method is to modify the LSB of each RGB channel for every pixel in the cover image.
  • To decode: The least significant bits of the encoded image are read to recover the secret image.

Originally implemented in akfreas/Stegosaurus

Source code in stegobox/codec/lsb_gif.py
def __init__(self) -> None:
    """Hide str in GIF image using LSB steganography.

    * To encode: This method is to modify the LSB of each RGB channel for every
    pixel in the cover image.
    * To decode: The least significant bits of the encoded image are read to recover
    the secret image.

    Originally implemented in
    [akfreas/Stegosaurus](https://github.com/akfreas/Stegosaurus)
    """
    super().__init__()

encode(carrier, payload)

Encoder requires the carrier image to be GIF and the payload to be a string.

Parameters:

Name Type Description Default
carrier Image

Carrier image in format GIF. Read with 'stegobox.io.image.read()'.

required
payload str

Payload (secret message) to be encoded.

required

Returns:

Type Description
Image

Image.Image: Encoded image in format GIF with the payload embeded.

Source code in stegobox/codec/lsb_gif.py
def encode(self, carrier: Image.Image, payload: str) -> Image.Image:
    """Encoder requires the carrier image to be GIF and the payload to be a string.

    Args:
        carrier: Carrier image in format GIF. Read with 'stegobox.io.image.read()'.
        payload: Payload (secret message) to be encoded.

    Returns:
        Image.Image: Encoded image in format GIF with the payload embeded.
    """
    pix = carrier.load()  # type: ignore
    coord_list = [
        (x, y) for x in range(0, carrier.size[0]) for y in range(0, carrier.size[1])
    ]
    bin_string = self.encode_mesg(payload)
    self.bin_string = bin_string

    coords = coord_list[: len(bin_string)]
    for coord in coords:
        (x, y) = coord
        # set all lsb's in the coordinate list to zero
        pix[x, y] = pix[x, y] >> 1 << 1  # type: ignore

    coords = list(coord_list)

    while len(bin_string) > 0:
        (x, y) = coords.pop(0)
        pix[x, y] = pix[x, y] | int(bin_string[0])  # type: ignore
        bin_string = bin_string[1:]
    return carrier

decode(carrier)

Decode the secret image from the encoded image.

Parameters:

Name Type Description Default
carrier Image

The encoded GIF image object with the secret image embedded.

required

Returns:

Name Type Description
str str

The message extracted from the encoded GIF image.

Source code in stegobox/codec/lsb_gif.py
def decode(self, carrier: Image.Image) -> str:
    """Decode the secret image from the encoded image.

    Args:
        carrier: The encoded GIF image object with the secret image embedded.

    Returns:
        str: The message extracted from the encoded GIF image.
    """
    pix = carrier.load()  # type: ignore
    coord_list = [
        (x, y) for x in range(0, carrier.size[0]) for y in range(0, carrier.size[1])
    ]
    coords = list(coord_list)
    char = chr(
        int(
            "".join(
                [
                    bin(pix[x[0], x[1]])[-1:]  # type: ignore
                    for x in coords[:BYTE_LENGTH]
                ]
            ),
            2,
        )
    )
    length = ""
    if char == "<":
        while char != ">":
            coords = coords[BYTE_LENGTH:]
            char = chr(
                int(
                    "".join(
                        [
                            bin(pix[x[0], x[1]])[-1:]  # type: ignore
                            for x in coords[:BYTE_LENGTH]
                        ]
                    ),
                    2,
                )
            )
            if char != ">":
                length += char
        coord_list = coords[BYTE_LENGTH:]
        le = int(length)
    else:
        le = 0
    coords = list(coord_list)
    # get a list of the binary LSBs for our message
    bin_mesg = [
        bin(pix[x[0], x[1]])[-1:]  # type: ignore
        for x in coords[: le * BYTE_LENGTH]
    ]
    # group list into bytes
    bin_list = [
        "".join(bin_mesg[i : i + BYTE_LENGTH])
        for i in range(0, len(bin_mesg), BYTE_LENGTH)
    ]
    mesg = "".join(self.bin2ascii(bin_list))
    return mesg