From 21544969fb4927435280bf454b59e9117e0afba5 Mon Sep 17 00:00:00 2001 From: devoalda Date: Fri, 19 May 2023 16:49:39 +0800 Subject: [PATCH] Initial Commit --- encoded_image.png | Bin 0 -> 285071 bytes image.png | Bin 0 -> 4827 bytes lsb.py | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 encoded_image.png create mode 100644 image.png create mode 100644 lsb.py diff --git a/encoded_image.png b/encoded_image.png new file mode 100644 index 0000000000000000000000000000000000000000..2aa93d9921a177d0c25b8454f3799397baabc819 GIT binary patch literal 285071 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 str | list[str]: + """ + Convert data to binary format as string + Args: + data: String + + Returns: + Binary Data: String | List[String] + """ + if isinstance(data, str): + return ''.join([format(ord(i), "08b") for i in data]) + elif isinstance(data, bytes) or isinstance(data, np.ndarray): + return [format(i, "08b") for i in data] + elif isinstance(data, int) or isinstance(data, np.unit8): + return format(data, "08b") + else: + raise TypeError("Type not supported") + + def from_bin(self, data: str) -> str: + """ + Convert binary `data` back to the original format + Args: + data: String + + Returns: + Original Data: String + """ + return ''.join([chr(int(data[i:i + 8], 2)) for i in range(0, len(data), 8)]) + + def decode(self): + """ + Decode the data hidden in the image + Returns: + Decoded Data: str + """ + print("[+] Decoding...") + image = cv2.imread(self.image_name) # read image + binary_data = "" + for row in image: + for pixel in row: + r, g, b = self.to_bin(pixel) + binary_data += r[self.bit_to_hide] + binary_data += g[self.bit_to_hide] + binary_data += b[self.bit_to_hide] + # Split by 8 bits + all_bytes = [binary_data[i: i + 8] for i in range(0, len(binary_data), 8)] + # Convert from bits to characters + decoded_data = self.from_bin(''.join(all_bytes)) + if decoded_data.endswith("===="): + decoded_data = decoded_data[:-4] + return decoded_data + + def encode(self, secret_data: str = "Hello World") -> np.ndarray: + """ + Encode the secret data in the image + Args: + secret_data: str + + Returns: + Encoded Image: np.ndarray + """ + image = cv2.imread(self.image_name) # read image + n_bytes = image.shape[0] * image.shape[1] * 3 // 8 # Max bytes to encode + print("[*] Maximum bytes to encode:", n_bytes) + secret_data += "====" # Stopping Criteria + if len(secret_data) > n_bytes: + raise ValueError("[!] Insufficient bytes, need a bigger image or less data") + print("[*] Encoding Data...") + + # Convert bit to hide position + bit_to_hide = 2 - self.bit_to_hide + data_index = 0 + binary_secret_data = self.to_bin(secret_data) # Convert data to binary + data_len = len(binary_secret_data) # size of data to hide + for row in image: + for pixel in row: + r, g, b = self.to_bin(pixel) # Convert RGB Values to binary format + if data_index < data_len: + r = list(r) + r[bit_to_hide] = binary_secret_data[data_index] # hide data into least significant bit of red pixel + pixel[0] = int(''.join(r), 2) + data_index += 1 + if data_index < data_len: + g = list(g) + g[bit_to_hide] = binary_secret_data[data_index] + pixel[1] = int(''.join(g), 2) + data_index += 1 + if data_index < data_len: + b = list(b) + b[bit_to_hide] = binary_secret_data[data_index] + pixel[2] = int(''.join(b), 2) + data_index += 1 + if data_index >= data_len: + break + return image + + +def main(): + print("Welcome to Image Steganography") + print("1. Encode\n2. Decode\n3. Exit") + choice = int(input("Enter your choice: ")) + if choice == 1: + image_name = input("Enter name of image to encode: ") + secret_data = input("Enter data to encode: ") + bit_to_hide = int(input("Enter bit to hide (1-8): ")) + encoded_image = img_steg(image_name, bit_to_hide).encode(secret_data) + cv2.imwrite("encoded_image.png", encoded_image) + print("Image Encoded Successfully") + elif choice == 2: + image_name = input("Enter name of image to decode: ") + bit_to_hide = int(input("Enter bit to hide (1-8): ")) + decoded_data = img_steg(image_name, bit_to_hide).decode() + print("Decoded Data:", decoded_data) + + +if __name__ == "__main__": + main() + +# FOR REFERENCE +# Welcome to Image Steganography +# 1. Encode +# 2. Decode +# 3. Exit +# Enter your choice: 2 +# Enter name of image to decode: encoded_image.png +# Enter bit to hide (1-8): 5 +# [+] Decoding... +# Decoded Data: abc123abcasdf==== \ No newline at end of file