Skip to content

StecoStegKeyImage

stegobox.codec.StecoStegKeyImage

Bases: BaseCodec

StecoStegKeyImage - This module implements StecoStegKeyImage in JPEG images.

  • To encode:

    1. Specify a JPEG image as a carrier.
    2. Specify a payload to encode.
    3. Retreive the output PNG image.
  • To decode:

    1. Specify a PNG image as carrier and a original JPEG image as key.
    2. Retrieve the original payload.
Source code in stegobox/codec/stecosteg_key_img.py
class StecoStegKeyImage(BaseCodec):
    """StecoStegKeyImage - This module implements StecoStegKeyImage in JPEG images.

    * To encode:
        1. Specify a JPEG image as a carrier.
        2. Specify a payload to encode.
        3. Retreive the output PNG image.

    * To decode:
        1. Specify a PNG image as carrier and a original JPEG image as key.
        2. Retrieve the original payload.
    """

    def __init__(self) -> None:
        self.key: Image.Image
        super().__init__()

    def encode(self, carrier: Image.Image, payload: str) -> Image.Image:
        image = carrier.convert("RGB")
        width, height = image.size
        self.key = carrier.convert("RGB")
        byte_s = payload.encode("utf-8")
        hex_bin = byte_s.hex()
        colors: dict = {}
        for x in range(width):
            for y in range(height):
                if image.getpixel((x, y)) in colors:
                    colors[image.getpixel((x, y))] += 1
                else:
                    colors[image.getpixel((x, y))] = 1
        colorslist = [(item[1], item) for item in colors.items()]
        colorslist.sort()
        colorssorted = [value[1] for value in colorslist]
        substitutioncolors: dict = {}
        if len(hex_bin) % 3 == 1:
            lenth_hex = hex(len(hex_bin))[2:].zfill(6)
            lenth_hex = "aa" + lenth_hex
        if len(hex_bin) % 3 == 2:
            lenth_hex = hex(len(hex_bin))[2:].zfill(6)
            lenth_hex = "b" + lenth_hex
        if len(hex_bin) % 3 == 0:
            lenth_hex = hex(len(hex_bin))[2:].zfill(6)
        secret_bin = lenth_hex + hex_bin  # type: ignore
        for i in range(int(len(secret_bin) / 3)):
            substitutioncolors[colorssorted[i][0]] = [
                (
                    int(secret_bin[i * 3], 16),
                    int(secret_bin[i * 3 + 1], 16),
                    int(secret_bin[i * 3 + 2], 16),
                ),
                i,
            ]
        key = []
        for i in range(len(substitutioncolors)):
            key.append((0, 0))
        for x in range(width):
            for y in range(height):
                if image.getpixel((x, y)) in substitutioncolors.keys():
                    image.putpixel(
                        (x, y), substitutioncolors[image.getpixel((x, y))][0]
                    )
        return image

    def decode(self, carrier: Image.Image) -> str:
        coordinates = []
        colors1: dict = {}
        colors2: dict = {}
        image = carrier.convert("RGB")
        width, height = image.size
        for x in range(width):
            for y in range(height):
                if image.getpixel((x, y)) in colors1:
                    colors1[image.getpixel((x, y))] += 1

                else:
                    colors1[image.getpixel((x, y))] = 1
        for x in range(width):
            for y in range(height):
                if self.key.getpixel((x, y)) in colors2:
                    colors2[self.key.getpixel((x, y))] += 1
                else:
                    colors2[self.key.getpixel((x, y))] = 1
        colors1list = [(item[1], item) for item in colors1.items()]
        colors1list.sort()
        colors1sorted = [value[1] for value in colors1list]
        colors2list = [(item[1], item) for item in colors2.items()]
        colors2list.sort()
        colors2sorted = [value[1] for value in colors2list]
        difference = list(set(colors2sorted) - set(colors1sorted))
        difference2 = list(set(colors1sorted) - set(colors2sorted))
        difference2.sort()
        difference.sort()
        for i in range(len(difference2)):
            for j in range(len(difference)):
                if difference2[i][0] == difference[j][0]:
                    difference.remove(difference[j])
                    break
        total = len(difference)
        for pixel in difference:
            if total == 0:
                break
            total -= 1
            for x in range(width):
                for y in range(height):
                    if self.key.getpixel((x, y)) == pixel[0]:
                        coordinates.append((x, y))
        str = ""
        for coordinate in coordinates:
            str += hex(image.getpixel(coordinate)[0])[2:]
            str += hex(image.getpixel(coordinate)[1])[2:]
            str += hex(image.getpixel(coordinate)[2])[2:]
        if str[0] == "b":
            return bytes.fromhex(str[7:]).decode("utf-8")
        elif str[0] == "a":
            return bytes.fromhex(str[8:]).decode("utf-8")
        else:
            return bytes.fromhex(str[6:]).decode("utf-8")

    def getkey(self) -> Image.Image:
        return self.key