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