From f53bd3e63e4d67930a8fae1d65557eebf20ac1d3 Mon Sep 17 00:00:00 2001
From: Breezy <114720008+breezy-codes@users.noreply.github.com>
Date: Fri, 6 Dec 2024 08:56:11 +1100
Subject: [PATCH] .
---
.idea/.gitignore | 6 -
.idea/cryptography-guide.iml | 8 -
.idea/inspectionProfiles/Project_Default.xml | 13 -
.../inspectionProfiles/profiles_settings.xml | 6 -
.idea/modules.xml | 8 -
.idea/vcs.xml | 6 -
.vscode/my-running-guide.md | 17 +
_toc.yml | 10 +-
ciphers/base64.ipynb | 89 ++
ciphers/morse-code.ipynb | 200 ++++
maths/number-theory/converting-values.ipynb | 933 ++++++++++++++++++
steganography/bitmap-caesar.ipynb | 254 +++++
steganography/bitmap-steganography.ipynb | 332 +++++++
13 files changed, 1834 insertions(+), 48 deletions(-)
delete mode 100644 .idea/.gitignore
delete mode 100644 .idea/cryptography-guide.iml
delete mode 100644 .idea/inspectionProfiles/Project_Default.xml
delete mode 100644 .idea/inspectionProfiles/profiles_settings.xml
delete mode 100644 .idea/modules.xml
delete mode 100644 .idea/vcs.xml
create mode 100644 .vscode/my-running-guide.md
create mode 100644 ciphers/base64.ipynb
create mode 100644 ciphers/morse-code.ipynb
create mode 100644 maths/number-theory/converting-values.ipynb
create mode 100644 steganography/bitmap-caesar.ipynb
create mode 100644 steganography/bitmap-steganography.ipynb
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 8bf4d45..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/cryptography-guide.iml b/.idea/cryptography-guide.iml
deleted file mode 100644
index d0876a7..0000000
--- a/.idea/cryptography-guide.iml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
deleted file mode 100644
index 0700956..0000000
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 105ce2d..0000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 7aa0762..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 35eb1dd..0000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.vscode/my-running-guide.md b/.vscode/my-running-guide.md
new file mode 100644
index 0000000..f1e71ed
--- /dev/null
+++ b/.vscode/my-running-guide.md
@@ -0,0 +1,17 @@
+# to update the book -
+
+cd /home/breezy/Documents/GitHub/Jupyter-Books
+
+jupyter-book build cryptography-guide
+
+or rebuild with
+
+jupyter-book build --all cryptography-guide
+
+# to push the book to GitHub Pages -
+
+cd /home/breezy/Documents/GitHub/Jupyter-Books/cryptography-guide
+
+make sure in main -
+
+ghp-import -n -p -f _build/html
diff --git a/_toc.yml b/_toc.yml
index 133a5bd..6f261c3 100644
--- a/_toc.yml
+++ b/_toc.yml
@@ -16,6 +16,7 @@ parts:
- file: maths/number-theory/prime-factorisation
- file: maths/number-theory/gcd-lcm
- file: maths/number-theory/prime-introduction
+ - file: maths/number-theory/converting-values
- file: maths/modular-arithmetic/mod-arith-intro
sections:
- file: maths/modular-arithmetic/modular-arithmetic
@@ -30,8 +31,15 @@ parts:
chapters:
- file: ciphers/ceaser-cipher
- file: ciphers/hill-cipher
+ - file: ciphers/morse-code
+ - file: ciphers/base64
- caption: RSA Algorithm
numbered: false
chapters:
- file: RSA-Algorithm/RSA-example
- - file: RSA-Algorithm/RSA-with-large-num
\ No newline at end of file
+ - file: RSA-Algorithm/RSA-with-large-num
+ - caption: Steganography
+ numbered: false
+ chapters:
+ - file: steganography/bitmap-steganography
+ - file: steganography/bitmap-caesar
\ No newline at end of file
diff --git a/ciphers/base64.ipynb b/ciphers/base64.ipynb
new file mode 100644
index 0000000..01fa079
--- /dev/null
+++ b/ciphers/base64.ipynb
@@ -0,0 +1,89 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Base64"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "BASE64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def base64_encode(input_string):\n",
+ " encoded_string = \"\"\n",
+ " value = 0\n",
+ " bits = -6\n",
+ " base64_mask = 0x3F\n",
+ "\n",
+ " for character in input_string.encode():\n",
+ " value = (value << 8) + character\n",
+ " bits += 8\n",
+ "\n",
+ " while bits >= 0:\n",
+ " encoded_string += BASE64_CHARS[(value >> bits) & base64_mask]\n",
+ " bits -= 6\n",
+ " \n",
+ " if bits > -6:\n",
+ " encoded_string += BASE64_CHARS[((value << 8) >> (bits + 8)) & base64_mask]\n",
+ " \n",
+ " while len(encoded_string) % 4:\n",
+ " encoded_string += \"=\"\n",
+ " \n",
+ " return encoded_string"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def base64_decode(input_string):\n",
+ " decoded_string = bytearray()\n",
+ " value = 0\n",
+ " bits = -8\n",
+ "\n",
+ " for character in input_string:\n",
+ " if character not in BASE64_CHARS:\n",
+ " if character == \"=\":\n",
+ " break\n",
+ " continue\n",
+ " \n",
+ " value = (value << 6) + BASE64_CHARS.index(character)\n",
+ " bits += 6\n",
+ "\n",
+ " if bits >= 0:\n",
+ " decoded_string.append((value >> bits) & 0xFF)\n",
+ " bits -= 8\n",
+ " \n",
+ " return decoded_string.decode()"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "jupyter-books",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.12.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/ciphers/morse-code.ipynb b/ciphers/morse-code.ipynb
new file mode 100644
index 0000000..f2a4029
--- /dev/null
+++ b/ciphers/morse-code.ipynb
@@ -0,0 +1,200 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# **Morse Code**\n",
+ "\n",
+ "Morse code is a method used in telecommunication to encode text characters as sequences of two different signal durations, called dots and dashes. Named after Samuel Morse, one of the inventors of the telegraph, Morse code is widely used in amateur radio, aviation, and military communications due to its efficiency and reliability.\n",
+ "\n",
+ "In this guide, we will explore Morse code and demonstrate how to create programs for encoding text into Morse code and decoding Morse code back into text."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Encoding Text to Morse Code\n",
+ "\n",
+ "Encoding text to Morse code involves converting each character into its corresponding Morse code sequence. Each letter, number, or symbol has a unique representation in Morse code, and words are separated by spaces or `/`. How Encoding Works:\n",
+ "\n",
+ "- Each character in the input text is matched with its Morse code representation using a dictionary.\n",
+ "- Characters not present in the dictionary are replaced with a placeholder like `?`.\n",
+ "- Words are separated by a `/`, and individual characters are separated by spaces.\n",
+ "\n",
+ "### Steps for Encoding\n",
+ "\n",
+ "\n",
+ "1. Convert the text to uppercase to ensure proper dictionary matching.\n",
+ "2. Loop through each character in the text and find its Morse code equivalent.\n",
+ "3. Combine the Morse code sequences into a single string, separating characters with spaces and words with `/`.\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Morse Code Dictionary\n",
+ "MORSE_CODE_DICT = {\n",
+ " 'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', \n",
+ " 'F': '..-.', 'G': '--.', 'H': '....', 'I': '..', 'J': '.---',\n",
+ " 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---',\n",
+ " 'P': '.--.', 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-',\n",
+ " 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', 'Y': '-.--',\n",
+ " 'Z': '--..', '1': '.----', '2': '..---', '3': '...--', '4': '....-', \n",
+ " '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', \n",
+ " '0': '-----', ',': '--..--', '.': '.-.-.-', '?': '..--..', \n",
+ " \"'\": '.----.', '!': '-.-.--', '/': '-..-.', '(': '-.--.', \n",
+ " ')': '-.--.-', '&': '.-...', ':': '---...', ';': '-.-.-.', \n",
+ " '=': '-...-', '+': '.-.-.', '-': '-....-', '_': '..--.-', \n",
+ " '\"': '.-..-.', '$': '...-..-', '@': '.--.-.', ' ': '/'\n",
+ "}\n",
+ "\n",
+ "# Function to encode text to Morse code\n",
+ "def encode_to_morse(text):\n",
+ " encoded_message = []\n",
+ " for char in text.upper():\n",
+ " if char in MORSE_CODE_DICT:\n",
+ " encoded_message.append(MORSE_CODE_DICT[char])\n",
+ " else:\n",
+ " encoded_message.append('?') # Unknown character\n",
+ " return ' '.join(encoded_message)\n",
+ "\n",
+ "print(\"Enter the text to encode using morse code:\")\n",
+ "text = input()\n",
+ "encoded_text = encode_to_morse(text)\n",
+ "print(\"Each Morse code character is separated by a space, and each word is separated by a /\")\n",
+ "print(f\"The Morse code for '{text}' is:\")\n",
+ "print(encoded_text)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Expected Output\n",
+ "\n",
+ "When you run this program, this is how the text \"Hello and welcome to SplashKit, its great to have you.\" would be encoded in Morse code:\n",
+ "\n",
+ "```shell\n",
+ "Enter the text to encode using morse code:\n",
+ "Hello and welcome to SplashKit, its great to have you.\n",
+ "Each Morse code character is separated by a space, and each word is separated by a /\n",
+ "The Morse code for 'Hello and welcome to SplashKit, its great to have you.' is:\n",
+ ".... . .-.. .-.. --- / .- -. -.. / .-- . .-.. -.-. --- -- . / - --- / ... .--. .-.. .- ... .... -.- .. - --..-- / .. - ... / --. .-. . .- - / - --- / .... .- ...- . / -.-- --- ..- .-.-.-\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Decoding Morse Code to Text\n",
+ "\n",
+ "Decoding Morse code back to text requires reversing the process. The Morse code input is split into sequences representing individual characters, which are then mapped back to their corresponding text representation. Spaces in Morse code are converted back to spaces in the text. How Decoding Works:\n",
+ "\n",
+ "- Each Morse code sequence is matched with its corresponding character using a reversed dictionary.\n",
+ "- Morse code for spaces (`/`) is converted back to spaces in the text.\n",
+ "- Invalid sequences are replaced with a placeholder like `?`.\n",
+ "\n",
+ "### Steps for Decoding\n",
+ "\n",
+ "\n",
+ "1. Split the Morse code input into individual sequences using spaces.\n",
+ "2. Map each sequence to its corresponding character from the reversed dictionary.\n",
+ "3. Combine the characters to form the decoded text, handling `/` as spaces.\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Morse Code Dictionary\n",
+ "MORSE_CODE_DICT = {\n",
+ " 'A': '.-', 'B': '-...', 'C': '-.-.', 'D': '-..', 'E': '.', \n",
+ " 'F': '..-.', 'G': '--.', 'H': '....', 'I': '..', 'J': '.---',\n",
+ " 'K': '-.-', 'L': '.-..', 'M': '--', 'N': '-.', 'O': '---',\n",
+ " 'P': '.--.', 'Q': '--.-', 'R': '.-.', 'S': '...', 'T': '-',\n",
+ " 'U': '..-', 'V': '...-', 'W': '.--', 'X': '-..-', 'Y': '-.--',\n",
+ " 'Z': '--..', '1': '.----', '2': '..---', '3': '...--', '4': '....-', \n",
+ " '5': '.....', '6': '-....', '7': '--...', '8': '---..', '9': '----.', \n",
+ " '0': '-----', ',': '--..--', '.': '.-.-.-', '?': '..--..', \n",
+ " \"'\": '.----.', '!': '-.-.--', '/': '-..-.', '(': '-.--.', \n",
+ " ')': '-.--.-', '&': '.-...', ':': '---...', ';': '-.-.-.', \n",
+ " '=': '-...-', '+': '.-.-.', '-': '-....-', '_': '..--.-', \n",
+ " '\"': '.-..-.', '$': '...-..-', '@': '.--.-.', ' ': '/'\n",
+ "}\n",
+ "\n",
+ "# Function to decode Morse code to text\n",
+ "def decode_from_morse(morse_code):\n",
+ " reversed_dict = {v: k for k, v in MORSE_CODE_DICT.items()}\n",
+ " decoded_message = []\n",
+ " for code in morse_code.split(' '):\n",
+ " if code in reversed_dict:\n",
+ " decoded_message.append(reversed_dict[code])\n",
+ " elif code == '/': # Morse code for space\n",
+ " decoded_message.append(' ')\n",
+ " else:\n",
+ " decoded_message.append('?') # Unknown Morse code\n",
+ " return ''.join(decoded_message)\n",
+ "\n",
+ "print(\"Enter the Morse code to decode:\")\n",
+ "text = input()\n",
+ "decoded_text = decode_from_morse(text)\n",
+ "print(\"Each Morse code character is separated by a space, and each word is separated by a /\")\n",
+ "print(f\"The decoded text for '{text}' is:\")\n",
+ "print(decoded_text)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Expected Output\n",
+ "\n",
+ "When you run this program, this is how the Morse code `.... . .-.. .-.. --- / .- -. -.. / .-- . .-.. -.-. --- -- . / - --- / ... .--. .-.. .- ... .... -.- .. - --..-- / .. - ... / --. .-. . .- - / - --- / .... .- ...- . / -.-- --- ..- .-.-.-` would be decoded back to text:\n",
+ "\n",
+ "```shell\n",
+ "Enter the Morse code to decode:\n",
+ ".... . .-.. .-.. --- / .- -. -.. / .-- . .-.. -.-. --- -- . / - --- / ... .--. .-.. .- ... .... -.- .. - --..-- / .. - ... / --. .-. . .- - / - --- / .... .- ...- . / -.-- --- ..- .-.-.-\n",
+ "Each Morse code character is separated by a space, and each word is separated by a /\n",
+ "The decoded text for '.... . .-.. .-.. --- / .- -. -.. / .-- . .-.. -.-. --- -- . / - --- / ... .--. .-.. .- ... .... -.- .. - --..-- / .. - ... / --. .-. . .- - / - --- / .... .- ...- . / -.-- --- ..- .-.-.-' is:\n",
+ "HELLO AND WELCOME TO SPLASHKIT, ITS GREAT TO HAVE YOU.\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Applications of Morse Code\n",
+ "\n",
+ "Morse code remains relevant in various fields due to its simplicity and reliability. Some of its applications include:\n",
+ "\n",
+ "- **Emergency Communications**: Using short and long signals to communicate distress (e.g., SOS: `... --- ...`).\n",
+ "- **Amateur Radio**: Sending messages over long distances where voice communication may be impractical.\n",
+ "- **Aviation**: Identifying navigational aids with Morse code signals.\n"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "jupyter-books",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.12.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/maths/number-theory/converting-values.ipynb b/maths/number-theory/converting-values.ipynb
new file mode 100644
index 0000000..b01d3e1
--- /dev/null
+++ b/maths/number-theory/converting-values.ipynb
@@ -0,0 +1,933 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Converting Values"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Converting between different numerical and data representations is an essential skill in programming, allowing for efficient data processing, interoperability, and the ability to build versatile applications. This guide will explore how to validate, convert, encode, and decode various formats, making your programs both robust and flexible. These concepts also serve as a foundation for implementing more complex systems in SplashKit, such as cryptographic utilities or network tools.\n",
+ "\n",
+ "## Validation Functions\n",
+ "\n",
+ "Validation is the first step in any reliable conversion process. Ensuring input values conform to their respective formats reduces errors and creates a solid foundation for processing data. For example, binary numbers must consist only of `0`s and `1`s, while hexadecimal values use a combination of numeric and alphabetic characters. In this section, we’ll explore how to check the correctness of binary, decimal, hexadecimal, and octal values, ensuring all inputs are clean and error-free before proceeding with conversions.\n",
+ "\n",
+ ":::note\n",
+ "The following validation functions are used in the conversion operations described later in this guide. They check whether a given string is a valid representation of a binary, decimal, hexadecimal, or octal number, respectively.\n",
+ ":::"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Is Binary\n",
+ "\n",
+ "This function checks if a given string is a valid binary number, ensuring it contains only the characters `0` and `1`. It also verifies that the input is not empty, returning false for any invalid or empty input."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 71,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def is_binary(binary_string):\n",
+ " return all(character in '01' for character in binary_string) and bool(binary_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can use this function within many other functions, or even to just check if a string is a binary number:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 72,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Value 1003300101 is a False binary value\n",
+ "Value 10010101 is a True binary value\n"
+ ]
+ }
+ ],
+ "source": [
+ "binary_string1 = \"1003300101\"\n",
+ "print(F\"Value {binary_string1} is a {is_binary(binary_string1)} binary value\")\n",
+ "\n",
+ "binary_string2 = \"10010101\"\n",
+ "print(F\"Value {binary_string2} is a {is_binary(binary_string2)} binary value\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Is Hexadecimal\n",
+ "\n",
+ "This function validates whether a string represents a valid hexadecimal number. It checks that each character falls within the ranges `0-9`, `A-F`, or `a-f`, while also ensuring the input is not empty."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 73,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def is_hex(hex_string):\n",
+ " return all(character in '0123456789ABCDEFabcdef' for character in hex_string) and bool(hex_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can use this function to verify hexadecimal strings before converting them to other formats:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 74,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Value 1A2B3C4D5F is a True hex value\n",
+ "Value 1A2B3C4D5G is a False hex value\n"
+ ]
+ }
+ ],
+ "source": [
+ "hex_string1 = \"1A2B3C4D5F\"\n",
+ "print(f\"Value {hex_string1} is a {is_hex(hex_string1)} hex value\") # True\n",
+ "\n",
+ "hex_string2 = \"1A2B3C4D5G\"\n",
+ "print(f\"Value {hex_string2} is a {is_hex(hex_string2)} hex value\") # False"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Is Octal\n",
+ "\n",
+ "This function determines if a string is a valid octal number by ensuring all characters are within the range `0-7`. It also returns false if the input string is empty."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 75,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def is_octal(octal_string):\n",
+ " return all(character in '01234567' for character in octal_string) and bool(octal_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "We can use this function to validate octal strings before converting them to other formats:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 76,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Value 1234567 is a True octal value\n",
+ "Value 12345678 is a False octal value\n"
+ ]
+ }
+ ],
+ "source": [
+ "octal_string1 = \"1234567\"\n",
+ "print(f\"Value {octal_string1} is a {is_octal(octal_string1)} octal value\") # True\n",
+ "\n",
+ "octal_string2 = \"12345678\"\n",
+ "print(f\"Value {octal_string2} is a {is_octal(octal_string2)} octal value\") # False"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Basic Conversion Operations\n",
+ "\n",
+ "Conversions between number systems are fundamental to understanding how data is represented in programming. Whether you’re transforming binary to decimal, decimal to hexadecimal, or even converting between less common systems like octal and base-64, these operations provide insight into the underlying mechanics of data storage and manipulation. This section will introduce methods for performing these conversions step by step, helping you understand the relationships between different numerical systems and how to implement them efficiently in code."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Decimal to Binary\n",
+ "\n",
+ "Converting a decimal number to binary involves dividing the number by 2 repeatedly and recording the remainder for each division. These remainders, read in reverse order, form the binary representation of the decimal number. For example, to convert the decimal number 10 to binary, you would perform the following steps: $10 ÷ 2 = 5$ remainder $0$, $5 ÷ 2 = 2$ remainder $1$, $2 ÷ 2 = 1$ remainder $0$, and $1 ÷ 2 = 0$ remainder $1$. Reading the remainders from bottom to top, you get the binary number $1010$. This process can be implemented programmatically to convert any decimal number to its binary equivalent.\n",
+ "\n",
+ ":::tip\n",
+ "This could be useful for encoding data into binary formats like Base64, performing low-level programming tasks, or representing numbers in digital circuits.\n",
+ ":::"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 77,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def dec_to_bin(decimal_value):\n",
+ " if decimal_value == 0:\n",
+ " return \"0\"\n",
+ " \n",
+ " binary_string = \"\"\n",
+ " while decimal_value > 0:\n",
+ " binary_string = (\"1\" if decimal_value & 1 else \"0\") + binary_string\n",
+ " decimal_value >>= 1\n",
+ " return binary_string"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 78,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Binary value: 1010\n"
+ ]
+ }
+ ],
+ "source": [
+ "decimal_value = 10\n",
+ "binary_string = dec_to_bin(decimal_value)\n",
+ "print(\"Binary value:\", binary_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $22$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 79,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Binary value: 10110\n"
+ ]
+ }
+ ],
+ "source": [
+ "decimal_value = 22\n",
+ "binary_string = dec_to_bin(decimal_value)\n",
+ "print(\"Binary value:\", binary_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Binary to Decimal\n",
+ "\n",
+ "Converting a binary number to decimal involves multiplying each digit by $2^n$, where $n$ is the position of the digit from the rightmost bit, starting at $0$. For example, to convert the binary number $1010$ to decimal, you would calculate $1 \\times 2^3 + 0 \\times 2^2 + 1 \\times 2^1 + 0 \\times 2^0 = 10$. This process can be implemented programmatically to convert any binary number to its decimal equivalent."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 80,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def bin_to_dec(binary_string):\n",
+ " if not is_binary(binary_string):\n",
+ " return 0\n",
+ "\n",
+ " decimal_value = 0\n",
+ " for i, character in enumerate(reversed(binary_string)):\n",
+ " if character == '1':\n",
+ " decimal_value += (1 << i)\n",
+ " return decimal_value"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 81,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Decimal value: 10\n"
+ ]
+ }
+ ],
+ "source": [
+ "binary_string = \"1010\"\n",
+ "decimal_value = bin_to_dec(binary_string)\n",
+ "print(\"Decimal value:\", decimal_value)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $10110$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 82,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Decimal value: 22\n"
+ ]
+ }
+ ],
+ "source": [
+ "binary_string = \"10110\"\n",
+ "decimal_value = bin_to_dec(binary_string)\n",
+ "print(\"Decimal value:\", decimal_value)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Hexadecimal to Binary\n",
+ "\n",
+ "Converting a hexadecimal number to binary involves converting each hexadecimal digit to its binary equivalent. For example, the hexadecimal number $A3$ can be converted to binary by converting $A$ to $1010$ and $3$ to $0011$, resulting in the binary number $10100011$. This process can be implemented programmatically to convert any hexadecimal number to its binary equivalent."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 83,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def hex_to_bin(hex_string):\n",
+ " if not is_hex(hex_string):\n",
+ " return \"\"\n",
+ " \n",
+ " binary_string = \"\"\n",
+ " for hex_character in hex_string:\n",
+ " hex_value = int(hex_character, 16)\n",
+ " for i in range(3, -1, -1):\n",
+ " binary_string += \"1\" if (hex_value >> i) & 1 else \"0\"\n",
+ " \n",
+ " if len(hex_string) == 1:\n",
+ " first_one = binary_string.find('1')\n",
+ " return \"0\" if first_one == -1 else binary_string[first_one:]\n",
+ " \n",
+ " return binary_string"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 84,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Binary value: 10100011\n"
+ ]
+ }
+ ],
+ "source": [
+ "hex_string = \"A3\"\n",
+ "binary_string = hex_to_bin(hex_string)\n",
+ "print(\"Binary value:\", binary_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $FA$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 85,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Binary value: 11111010\n"
+ ]
+ }
+ ],
+ "source": [
+ "hex_string = \"FA\"\n",
+ "binary_string = hex_to_bin(hex_string)\n",
+ "print(\"Binary value:\", binary_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Binary to Hexadecimal\n",
+ "\n",
+ "Converting a binary number to hexadecimal involves grouping the binary digits into sets of four, starting from the rightmost bit. Each group of four bits corresponds to a single hexadecimal digit, allowing you to convert the binary number to its hexadecimal equivalent. For example, the binary number $10100011$ can be grouped as $1010$ and $0011$, which correspond to the hexadecimal digits $A$ and $3$, respectively. This process can be implemented programmatically to convert any binary number to its hexadecimal equivalent."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 86,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def bin_to_hex(binary_string):\n",
+ " if not is_binary(binary_string):\n",
+ " return \"\"\n",
+ " \n",
+ " length = len(binary_string)\n",
+ " padding = (4 - (length % 4)) % 4\n",
+ " padded_binary_string = \"0\" * padding + binary_string\n",
+ " \n",
+ " hex_string = \"\"\n",
+ " for i in range(0, len(padded_binary_string), 4):\n",
+ " hex_value = int(padded_binary_string[i:i+4], 2)\n",
+ " hex_string += hex(hex_value)[2:].upper()\n",
+ " return hex_string"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 87,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hexadecimal value: A3\n"
+ ]
+ }
+ ],
+ "source": [
+ "binary_string = \"10100011\"\n",
+ "hex_string = bin_to_hex(binary_string)\n",
+ "print(\"Hexadecimal value:\", hex_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $1100101011$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 88,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hexadecimal value: 32B\n"
+ ]
+ }
+ ],
+ "source": [
+ "binary_string = \"1100101011\"\n",
+ "hex_string = bin_to_hex(binary_string)\n",
+ "print(\"Hexadecimal value:\", hex_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Decimal to Octal\n",
+ "\n",
+ "Converting a decimal number to octal involves dividing the number by 8 repeatedly and recording the remainder for each division. These remainders, read in reverse order, form the octal representation of the decimal number. For example, to convert the decimal number 10 to octal, you would perform the following steps: $10 ÷ 8 = 1$ remainder $2$, and $1 ÷ 8 = 0$ remainder $1$. Reading the remainders from bottom to top, you get the octal number $12$. This process can be implemented programmatically to convert any decimal number to its octal equivalent."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 89,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def dec_to_oct(decimal_value):\n",
+ " if decimal_value == 0:\n",
+ " return \"0\"\n",
+ " \n",
+ " octal_string = \"\"\n",
+ " while decimal_value > 0:\n",
+ " octal_string = str(decimal_value % 8) + octal_string\n",
+ " decimal_value //= 8\n",
+ " return octal_string"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 90,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Octal value: 12\n"
+ ]
+ }
+ ],
+ "source": [
+ "decimal_value = 10\n",
+ "octal_string = dec_to_oct(decimal_value)\n",
+ "print(\"Octal value:\", octal_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $87$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 91,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Octal value: 127\n"
+ ]
+ }
+ ],
+ "source": [
+ "decimal_value = 87\n",
+ "octal_string = dec_to_oct(decimal_value)\n",
+ "print(\"Octal value:\", octal_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Octal to Decimal\n",
+ "\n",
+ "Converting an octal number to decimal involves multiplying each digit by $8^n$, where $n$ is the position of the digit from the rightmost bit, starting at $0$. For example, to convert the octal number 12 to decimal, you would calculate $1 \\times 8^1 + 2 \\times 8^0 = 10$. This process can be implemented programmatically to convert any octal number to its decimal equivalent."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 92,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def oct_to_dec(octal_string):\n",
+ " if not is_octal(octal_string):\n",
+ " return 0\n",
+ "\n",
+ " decimal_value = 0\n",
+ " for i, character in enumerate(reversed(octal_string)):\n",
+ " decimal_value += int(character) * (8 ** i)\n",
+ " return decimal_value"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 93,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Decimal value: 10\n"
+ ]
+ }
+ ],
+ "source": [
+ "octal_string = \"12\"\n",
+ "decimal_value = oct_to_dec(octal_string)\n",
+ "print(\"Decimal value:\", decimal_value)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $26$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 94,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Decimal value: 22\n"
+ ]
+ }
+ ],
+ "source": [
+ "octal_string = \"26\"\n",
+ "decimal_value = oct_to_dec(octal_string)\n",
+ "print(\"Decimal value:\", decimal_value)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Octal to Binary\n",
+ "\n",
+ "Converting an octal number to binary involves converting each octal digit to its binary equivalent. For example, the octal number $12$ can be converted to binary by converting $1$ to $001$ and $2$ to $010$, resulting in the binary number $001010$. This process can be implemented programmatically to convert any octal number to its binary equivalent."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 95,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def oct_to_bin(octal_string):\n",
+ " if not is_octal(octal_string):\n",
+ " return \"\"\n",
+ " \n",
+ " binary_string = \"\"\n",
+ " for octal_character in octal_string:\n",
+ " octal_value = int(octal_character)\n",
+ " for i in range(2, -1, -1):\n",
+ " binary_string += \"1\" if (octal_value >> i) & 1 else \"0\"\n",
+ " \n",
+ " first_one = binary_string.find('1')\n",
+ " return \"0\" if first_one == -1 else binary_string[first_one:]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 96,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Binary value: 1010\n"
+ ]
+ }
+ ],
+ "source": [
+ "octal_string = \"12\"\n",
+ "binary_string = oct_to_bin(octal_string)\n",
+ "print(\"Binary value:\", binary_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $26$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 97,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Binary value: 10110\n"
+ ]
+ }
+ ],
+ "source": [
+ "octal_string = \"26\"\n",
+ "binary_string = oct_to_bin(octal_string)\n",
+ "print(\"Binary value:\", binary_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Binary to Octal\n",
+ "\n",
+ "Converting a binary number to octal involves grouping the binary digits into sets of three, starting from the rightmost bit. Each group of three bits corresponds to a single octal digit, allowing you to convert the binary number to its octal equivalent. For example, the binary number $101010$ can be grouped as $101$ and $010$, which correspond to the octal digits $5$ and $2$, respectively. This process can be implemented programmatically to convert any binary number to its octal equivalent."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 98,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def bin_to_oct(binary_string):\n",
+ " if not is_binary(binary_string):\n",
+ " return \"\"\n",
+ " \n",
+ " padding = (3 - (len(binary_string) % 3)) % 3\n",
+ " padded_binary_string = \"0\" * padding + binary_string\n",
+ " \n",
+ " octal_string = \"\"\n",
+ " for i in range(0, len(padded_binary_string), 3):\n",
+ " octal_value = int(padded_binary_string[i:i+3], 2)\n",
+ " octal_string += str(octal_value)\n",
+ " \n",
+ " first_non_zero = octal_string.find('1')\n",
+ " return \"0\" if first_non_zero == -1 else octal_string[first_non_zero:]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 99,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Octal value: 0\n"
+ ]
+ }
+ ],
+ "source": [
+ "binary_string = \"101010\"\n",
+ "octal_string = bin_to_oct(binary_string)\n",
+ "print(\"Octal value:\", octal_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $101110010$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 100,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Octal value: 0\n"
+ ]
+ }
+ ],
+ "source": [
+ "binary_string = \"101110010\"\n",
+ "octal_string = bin_to_oct(binary_string)\n",
+ "print(\"Octal value:\", octal_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Hexadecimal to Octal\n",
+ "\n",
+ "Converting a hexadecimal number to octal involves converting the hexadecimal number to binary and then converting the binary number to octal. This process can be implemented programmatically to convert any hexadecimal number to its octal equivalent.\n",
+ "\n",
+ ":::note\n",
+ "This function relies on the `hex_to_bin` and the `bin_to_oct` functions defined above.\n",
+ ":::"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 101,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def hex_to_oct(hex_string):\n",
+ " if not is_hex(hex_string):\n",
+ " return \"\"\n",
+ " \n",
+ " binary_string = hex_to_bin(hex_string)\n",
+ " return bin_to_oct(binary_string)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 102,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Octal value: 0\n"
+ ]
+ }
+ ],
+ "source": [
+ "hex_string = \"A3\"\n",
+ "octal_string = hex_to_oct(hex_string)\n",
+ "print(\"Octal value:\", octal_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $FAA$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 103,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Octal value: 0\n"
+ ]
+ }
+ ],
+ "source": [
+ "hex_string = \"FAA\"\n",
+ "octal_string = hex_to_oct(hex_string)\n",
+ "print(\"Octal value:\", octal_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Octal to Hexadecimal\n",
+ "\n",
+ "Converting an octal number to hexadecimal involves converting the octal number to binary and then converting the binary number to hexadecimal. This process can be implemented programmatically to convert any octal number to its hexadecimal equivalent.\n",
+ "\n",
+ ":::note\n",
+ "This function relies on the `oct_to_bin` and `bin_to_hex` functions defined above.\n",
+ ":::"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 104,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def oct_to_hex(octal_string):\n",
+ " if not is_octal(octal_string):\n",
+ " return \"\"\n",
+ " \n",
+ " binary_string = oct_to_bin(octal_string)\n",
+ " return bin_to_hex(binary_string)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 105,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hexadecimal value: A\n"
+ ]
+ }
+ ],
+ "source": [
+ "octal_string = \"12\"\n",
+ "hex_string = oct_to_hex(octal_string)\n",
+ "print(\"Hexadecimal value:\", hex_string)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "If we change the input value to $26$, the output will be:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 109,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Hexadecimal value: 16\n"
+ ]
+ }
+ ],
+ "source": [
+ "octal_string = \"26\"\n",
+ "hex_string = oct_to_hex(octal_string)\n",
+ "print(\"Hexadecimal value:\", hex_string)"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "jupyter-books",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/steganography/bitmap-caesar.ipynb b/steganography/bitmap-caesar.ipynb
new file mode 100644
index 0000000..128f6e8
--- /dev/null
+++ b/steganography/bitmap-caesar.ipynb
@@ -0,0 +1,254 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# **Bitmap Caesar**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Enhancing Security with the Caesar Cipher\n",
+ "\n",
+ "Before embedding the message in the image using Base64 encoding, an additional layer of obfuscation can be applied to make the message more secure. One simple technique for this is the **Caesar Cipher**. Named after Julius Caesar, who reportedly used it in his private correspondence, the Caesar Cipher is a substitution cipher that shifts each character in the plaintext by a fixed number of positions in the alphabet.\n",
+ "\n",
+ "By applying a Caesar Cipher to the message prior to Base64 encoding, you introduce an extra hurdle for anyone trying to extract and interpret the hidden message without the necessary key. This is particularly useful when the steganographic embedding is coupled with plaintext messages. However, in real-world scenarios, more advanced encryption techniques should be used for sensitive information as the Caesar Cipher is relatively easy to break.\n",
+ "\n",
+ "### How the Caesar Cipher Works\n",
+ "\n",
+ "The Caesar Cipher replaces each letter in the message with another letter a fixed number of positions down (or up) the alphabet. For example, with a shift of 3:\n",
+ "\n",
+ "- `A` becomes `D`\n",
+ "- `B` becomes `E`\n",
+ "- `C` becomes `F`\n",
+ "\n",
+ "The process wraps around at the end of the alphabet, so `X` becomes `A`, `Y` becomes `B`, and `Z` becomes `C`. Numbers and punctuation are typically left unchanged, but this can vary based on implementation.\n",
+ "\n",
+ "To decrypt a Caesar Cipher message, the recipient simply shifts the letters in the opposite direction by the same number of positions."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Encode\n",
+ "\n",
+ "Here’s how the process works:\n",
+ "\n",
+ "\n",
+ "1. **Plaintext Message:** Start with the original message (e.g., `\"im a cat\"`).\n",
+ "2. **Apply Caesar Cipher:** Obfuscate the message using a chosen shift value (e.g., `3`). The message `\"im a cat\"` might become `\"lp d fdw\"`.\n",
+ "3. **Encode in Base64:** Convert the obfuscated message into Base64, producing a string of printable characters.\n",
+ "4. **Embed in Image:** Use LSB steganography to embed the Base64-encoded string into the image.\n",
+ "\n",
+ "\n",
+ "To extract and interpret the message, the reverse process is followed:\n",
+ "\n",
+ "\n",
+ "1. **Extract the Base64 Message:** Decode the embedded Base64 string from the image.\n",
+ "2. **Decrypt Caesar Cipher:** Apply the inverse Caesar Cipher shift to recover the original plaintext message.\n",
+ "\n",
+ "\n",
+ "By combining Caesar Cipher obfuscation with LSB steganography, you can enhance the security of your hidden messages while exploring the principles of encryption and steganography. Here is how you can implement this in your code:\n",
+ "\n",
+ ":::note\n",
+ "You will need to update the path to be the path to your bitmap file.\n",
+ ":::"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "vscode": {
+ "languageId": "plaintext"
+ }
+ },
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "\n",
+ "path = \"PATH TO YOUR FOLDER HERE\"\n",
+ "\n",
+ "def ceaser_cipher_encode(input_string, shift):\n",
+ " encoded_string = \"\"\n",
+ " for character in input_string:\n",
+ " if character.isalpha():\n",
+ " base = ord('a') if character.islower() else ord('A')\n",
+ " encoded_string += chr((ord(character) - base + shift) % 26 + base)\n",
+ " else:\n",
+ " encoded_string += character # Non-alphabet characters remain unchanged\n",
+ " return encoded_string\n",
+ "\n",
+ "def base64_encode(input_string):\n",
+ " BASE64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n",
+ " encoded_string = \"\"\n",
+ " value = 0\n",
+ " bits = -6\n",
+ " base64_mask = 0x3F\n",
+ "\n",
+ " for character in input_string.encode():\n",
+ " value = (value << 8) + character\n",
+ " bits += 8\n",
+ "\n",
+ " while bits >= 0:\n",
+ " encoded_string += BASE64_CHARS[(value >> bits) & base64_mask]\n",
+ " bits -= 6\n",
+ " \n",
+ " if bits > -6:\n",
+ " encoded_string += BASE64_CHARS[((value << 8) >> (bits + 8)) & base64_mask]\n",
+ " \n",
+ " while len(encoded_string) % 4:\n",
+ " encoded_string += \"=\"\n",
+ " \n",
+ " return encoded_string\n",
+ "\n",
+ "# This will allow us to highlight the differences in the binary data\n",
+ "def highlight_changes(original, modified):\n",
+ " highlighted_original = []\n",
+ " highlighted_modified = []\n",
+ "\n",
+ " for o, m in zip(original, modified):\n",
+ " if o != m:\n",
+ " highlighted_original.append(f\"[{o}]\")\n",
+ " highlighted_modified.append(f\"[{m}]\")\n",
+ " else:\n",
+ " highlighted_original.append(o)\n",
+ " highlighted_modified.append(m)\n",
+ "\n",
+ " return ''.join(highlighted_original), ''.join(highlighted_modified)\n",
+ "\n",
+ "def embed_message(data, message, offset, shift):\n",
+ " # Apply Caesar cipher shift to the message\n",
+ " shifted_message = ceaser_cipher_encode(message, shift)\n",
+ " print(f\"Caesar cipher shifted message: {shifted_message}\")\n",
+ "\n",
+ " # Encode the shifted message using Base64\n",
+ " base64_message = base64_encode(shifted_message)\n",
+ " print(f\"Base64-encoded message: {base64_message}\")\n",
+ " print(f\"Base64 length (in characters): {len(base64_message)}\")\n",
+ "\n",
+ " # Convert the Base64 message to binary\n",
+ " binary_message = ''.join(format(ord(char), '08b') for char in base64_message)\n",
+ " print(f\"Binary message: {binary_message}\")\n",
+ "\n",
+ " # Embed the length of the Base64 message (in bytes) in the first 32 bits\n",
+ " length_bits = format(len(base64_message), '032b')\n",
+ " print(f\"Length bits: {length_bits}\")\n",
+ "\n",
+ " data = bytearray(data)\n",
+ "\n",
+ " # Extract original binary at embedding positions\n",
+ " original_binary = \"\".join(format(data[offset + i], '08b') for i in range(len(length_bits + binary_message)))\n",
+ " modified_data = bytearray(data)\n",
+ "\n",
+ " # Embed the message into the least significant bits\n",
+ " for i, bit in enumerate(length_bits + binary_message):\n",
+ " modified_data[offset + i] = (modified_data[offset + i] & 0xFE) | int(bit)\n",
+ "\n",
+ " # Extract modified binary at embedding positions\n",
+ " modified_binary = \"\".join(format(modified_data[offset + i], '08b') for i in range(len(length_bits + binary_message)))\n",
+ "\n",
+ " highlighted_original, highlighted_modified = highlight_changes(original_binary, modified_binary)\n",
+ " \n",
+ " # Truncate for readability\n",
+ " def truncate_binary(binary_str, show_bits=64):\n",
+ " if len(binary_str) > show_bits * 2:\n",
+ " return binary_str[:show_bits] + \"...\" + binary_str[-show_bits:]\n",
+ " return binary_str\n",
+ "\n",
+ " print(\"\\nOriginal binary data at embedding positions (truncated):\")\n",
+ " print(truncate_binary(highlighted_original))\n",
+ "\n",
+ " print(\"\\nModified binary data at embedding positions (truncated):\")\n",
+ " print(truncate_binary(highlighted_modified))\n",
+ "\n",
+ " return modified_data\n",
+ "\n",
+ "input_file_path = os.path.join(path, \"cat.bmp\")\n",
+ "output_file_path = os.path.join(path, \"hiddencat.bmp\")\n",
+ "with open(input_file_path, \"rb\") as f:\n",
+ " data = f.read()\n",
+ "\n",
+ "print(\"Enter the message to embed: \")\n",
+ "message_to_embed = input()\n",
+ "\n",
+ "print(\"Enter the Caesar cipher shift value: \")\n",
+ "shift_value = int(input())\n",
+ "\n",
+ "# Specify the offset where the pixel data starts (e.g., 54 for standard BMP)\n",
+ "pixel_data_offset = int.from_bytes(data[10:14], byteorder='little')\n",
+ "\n",
+ "encoded_data = embed_message(data, message_to_embed, pixel_data_offset, shift_value)\n",
+ "with open(output_file_path, \"wb\") as f:\n",
+ " f.write(encoded_data)\n",
+ "print(f\"Message embedded successfully in Base64! Encoded image saved as {output_file_path}.\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Expected Output\n",
+ "\n",
+ "After extracting the message and decrypting it using the Caesar Cipher, you'll see an output like:\n",
+ "\n",
+ "```shell\n",
+ "Enter the message to embed: \n",
+ "im a cat \n",
+ "Enter the Caesar cipher shift value: \n",
+ "8\n",
+ "Caesar cipher shifted message: qu i kib\n",
+ "Base64-encoded message: cXUgaSBraWI=\n",
+ "Base64 length (in characters): 12\n",
+ "Binary message: 011000110101100001010101011001110110000101010011010000100111001001100001010101110100100100111101\n",
+ "Length bits: 00000000000000000000000000001100\n",
+ "\n",
+ "Original binary data at embedding positions (truncated):\n",
+ "0011100[1]00100100000101100001011[1]011111101100000[1]0000101[1]...100110001111001[0]0010000[0]0101111[0]1000110[0]0000110010100101\n",
+ "\n",
+ "Modified binary data at embedding positions (truncated):\n",
+ "0011100[0]00100100000101100001011[0]011111101100000[0]0000101[0]...100110001111001[1]0010000[1]0101111[1]1000110[1]0000110010100101\n",
+ "Message embedded successfully in Base64! Encoded image saved as /yourfolders/hiddencat.bmp.\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Decode\n",
+ "\n",
+ "make one that brute forces"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {
+ "vscode": {
+ "languageId": "plaintext"
+ }
+ },
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Expected Output"
+ ]
+ }
+ ],
+ "metadata": {
+ "language_info": {
+ "name": "python"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/steganography/bitmap-steganography.ipynb b/steganography/bitmap-steganography.ipynb
new file mode 100644
index 0000000..8a6896e
--- /dev/null
+++ b/steganography/bitmap-steganography.ipynb
@@ -0,0 +1,332 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# **Bitmap Encoding**"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Steganography is the practice of concealing a message within another message or medium. In this guide, we will explore how to use steganography to hide messages in bitmaps, covering how to implement a program to embed and extract messages from images using Least Significant Bit (LSB) steganography. We will also discuss how to enhance the security of hidden messages by applying the Caesar Cipher to the plaintext before embedding it in the image.\n",
+ "\n",
+ "## What is Steganography?\n",
+ "\n",
+ "Steganography is an ancient technique of hiding information in plain sight. The term is derived from the Greek words steganos (covered) and graphein (writing), meaning \"covered writing.\" Unlike encryption, which scrambles the content of a message to make it unreadable to unauthorised parties, steganography disguises the very existence of the message by embedding it within another seemingly innocuous medium, such as an image, audio file, or text document.\n",
+ "\n",
+ "Modern digital steganography often takes advantage of the characteristics of multimedia files to hide information. Images are particularly useful for this purpose because their pixel data provides a high degree of redundancy, which means small changes in pixel values are imperceptible to the human eye. For added security, steganography is frequently combined with encryption, ensuring that even if a hidden message is discovered, it remains unreadable without the proper decryption key.\n",
+ "\n",
+ "### Applications of Steganography\n",
+ "\n",
+ "Steganography has a range of applications, both benign and malicious. Legitimate uses include watermarking to protect intellectual property, secure communication in censorship-prone environments, and embedding metadata for digital forensics. However, it has also been misused for covert communication in cybercrime and espionage. This dual-use nature makes it a fascinating but critical subject in cybersecurity.\n",
+ "\n",
+ "## How Does Steganography Work?\n",
+ "\n",
+ "At its core, digital steganography involves embedding a secret message within a host medium. For images, this is typically done by modifying the binary representation of pixel values. Each pixel in a digital image is represented by a combination of red, green, and blue (RGB) color values. These values are stored as binary numbers, allowing for subtle alterations to be made without visibly affecting the image.\n",
+ "\n",
+ "The most common method is Least Significant Bit (LSB) Steganography, where the least significant bit (the last bit in a binary number) of each pixel is replaced with a bit from the secret message. This approach leverages the fact that small changes to the least significant bit have negligible visual impact on the image.\n",
+ "\n",
+ "For example, consider the binary representation of a pixel's red channel:\n",
+ "\n",
+ "```shell\n",
+ "Original: 11110010\n",
+ "Modified: 11110011\n",
+ "```\n",
+ "\n",
+ "The difference between these two values is imperceptible to the human eye, but the change encodes a bit of the hidden message.\n",
+ "\n",
+ "To ensure the hidden message can be retrieved, both the sender and receiver must agree on an encoding scheme. This includes specifying which bits will carry the hidden data and how the message length will be encoded.\n",
+ "\n",
+ "### Why Use Base64 Encoding?\n",
+ "\n",
+ "Before embedding the message, encoding it in a format like Base64 is common. Base64 ensures that the message is represented using only printable characters, making it easier to handle and less prone to corruption during transmission. This step is particularly useful when the message contains non-textual or binary data.\n",
+ "\n",
+ "## Using Steganography to Hide Messages in Images\n",
+ "\n",
+ "In this guide, we will demonstrate how to use steganography to hide messages within bitmap images using LSB steganography. This technique is straightforward, making it ideal for beginners, while still being robust enough to illustrate the core principles of steganography.\n",
+ "\n",
+ "### Embedding a Message in an Image\n",
+ "\n",
+ "To hide a message:\n",
+ "\n",
+ "\n",
+ "1. **Choose an Image:** Any bitmap image can be used, but high-resolution images provide more space for hiding data. For this guide, we'll use a bitmap image of a cat.\n",
+ "2. **Prepare the Message:** The message will be encoded in Base64 before embedding to ensure compatibility and readability.\n",
+ "3. **Embed the Message:** Using LSB steganography, replace the least significant bits of the image's pixel data with bits from the encoded message.\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Encode\n",
+ "\n",
+ "### Embedding a Message in an Image\n",
+ "\n",
+ "To hide a message:\n",
+ "\n",
+ "\n",
+ "1. **Choose an Image:** Any bitmap image can be used, but high-resolution images provide more space for hiding data. For this guide, we'll use a bitmap image of a cat.\n",
+ "2. **Prepare the Message:** The message will be encoded in Base64 before embedding to ensure compatibility and readability.\n",
+ "3. **Embed the Message:** Using LSB steganography, replace the least significant bits of the image's pixel data with bits from the encoded message.\n",
+ "\n",
+ "\n",
+ ":::note\n",
+ "You will need to update the path to be the path to your bitmap file.\n",
+ ":::"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "\n",
+ "path = \"/home/breezy/Documents/GitHub/Small-Projects/Thoth-Tech-Code-Files/steganography/programs/\"\n",
+ "\n",
+ "def base64_encode(input_string):\n",
+ " BASE64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n",
+ " encoded_string = \"\"\n",
+ " value = 0\n",
+ " bits = -6\n",
+ " base64_mask = 0x3F\n",
+ "\n",
+ " for character in input_string.encode():\n",
+ " value = (value << 8) + character\n",
+ " bits += 8\n",
+ "\n",
+ " while bits >= 0:\n",
+ " encoded_string += BASE64_CHARS[(value >> bits) & base64_mask]\n",
+ " bits -= 6\n",
+ " \n",
+ " if bits > -6:\n",
+ " encoded_string += BASE64_CHARS[((value << 8) >> (bits + 8)) & base64_mask]\n",
+ " \n",
+ " while len(encoded_string) % 4:\n",
+ " encoded_string += \"=\"\n",
+ " \n",
+ " return encoded_string\n",
+ "\n",
+ "# This will allow us to highlight the differences in the binary data\n",
+ "def highlight_changes(original, modified):\n",
+ " highlighted_original = []\n",
+ " highlighted_modified = []\n",
+ "\n",
+ " for o, m in zip(original, modified):\n",
+ " if o != m:\n",
+ " highlighted_original.append(f\"[{o}]\")\n",
+ " highlighted_modified.append(f\"[{m}]\")\n",
+ " else:\n",
+ " highlighted_original.append(o)\n",
+ " highlighted_modified.append(m)\n",
+ "\n",
+ " return ''.join(highlighted_original), ''.join(highlighted_modified)\n",
+ "\n",
+ "def embed_message(data, message, offset):\n",
+ " # Encode the message using Base64\n",
+ " base64_message = base64_encode(message)\n",
+ " print(f\"Base64-encoded message: {base64_message}\")\n",
+ " print(f\"Base64 length (in characters): {len(base64_message)}\")\n",
+ "\n",
+ " binary_message = ''.join(format(ord(char), '08b') for char in base64_message)\n",
+ " print(f\"Binary message: {binary_message}\")\n",
+ "\n",
+ " # Embed the length of the Base64 message (in bytes) in the first 32 bits\n",
+ " length_bits = format(len(base64_message), '032b')\n",
+ " print(f\"Length bits: {length_bits}\")\n",
+ "\n",
+ " data = bytearray(data)\n",
+ " # Extract original binary at embedding positions\n",
+ " original_binary = \"\".join(format(data[offset + i], '08b') for i in range(len(length_bits + binary_message)))\n",
+ " modified_data = bytearray(data)\n",
+ "\n",
+ " # Embed the message into the least significant bits\n",
+ " for i, bit in enumerate(length_bits + binary_message):\n",
+ " modified_data[offset + i] = (modified_data[offset + i] & 0xFE) | int(bit)\n",
+ "\n",
+ " # Extract modified binary at embedding positions\n",
+ " modified_binary = \"\".join(format(modified_data[offset + i], '08b') for i in range(len(length_bits + binary_message)))\n",
+ "\n",
+ " # Highlight changes\n",
+ " highlighted_original, highlighted_modified = highlight_changes(original_binary, modified_binary)\n",
+ "\n",
+ " # Truncate for readability\n",
+ " def truncate_binary(binary_str, show_bits=64):\n",
+ " if len(binary_str) > show_bits * 2:\n",
+ " return binary_str[:show_bits] + \"...\" + binary_str[-show_bits:]\n",
+ " return binary_str\n",
+ "\n",
+ " print(\"\\nOriginal binary data at embedding positions (truncated):\")\n",
+ " print(truncate_binary(highlighted_original))\n",
+ "\n",
+ " print(\"\\nModified binary data at embedding positions (truncated):\")\n",
+ " print(truncate_binary(highlighted_modified))\n",
+ "\n",
+ " return modified_data\n",
+ "\n",
+ "\n",
+ "input_file_path = os.path.join(path, \"cat.bmp\")\n",
+ "output_file_path = os.path.join(path, \"hiddencat.bmp\")\n",
+ "\n",
+ "with open(input_file_path, \"rb\") as f:\n",
+ " data = f.read()\n",
+ "\n",
+ "print(\"Enter the message to embed: \")\n",
+ "message_to_embed = input()\n",
+ "\n",
+ "# Specify the offset where the pixel data starts (e.g., 54 for standard BMP)\n",
+ "pixel_data_offset = int.from_bytes(data[10:14], byteorder='little')\n",
+ "\n",
+ "encoded_data = embed_message(data, message_to_embed, pixel_data_offset)\n",
+ "\n",
+ "with open(output_file_path, \"wb\") as f:\n",
+ " f.write(encoded_data)\n",
+ "\n",
+ "print(f\"Message embedded successfully in Base64! Encoded image saved as {output_file_path}.\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Expected Output\n",
+ "\n",
+ "After embedding the message, you'll see an output like:\n",
+ "\n",
+ "```shell\n",
+ "Enter the message to embed: \n",
+ "im a cat\n",
+ "Base64-encoded message: aW0gYSBjYXQ=\n",
+ "Base64 length (in characters): 12\n",
+ "Binary message: 011000010101011100110000011001110101100101010011010000100110101001011001010110000101000100111101\n",
+ "Length bits: 00000000000000000000000000001100\n",
+ "\n",
+ "Original binary data at embedding positions (truncated):\n",
+ "0011100[1]00100100000101100001011[1]011111101100000[1]0000101[1]...100110001111001[0]0010000[0]0101111[0]1000110[0]0000110010100101\n",
+ "\n",
+ "Modified binary data at embedding positions (truncated):\n",
+ "0011100[0]00100100000101100001011[0]011111101100000[0]0000101[0]...100110001111001[1]0010000[1]0101111[1]1000110[1]0000110010100101\n",
+ "Message embedded successfully in Base64! Encoded image saved as /yourfolders/hiddencat.bmp.\n",
+ "```\n",
+ "\n",
+ "The comparison between the original and modified binary data highlights the subtle but precise changes made during the embedding process. Notice how the least significant bits (LSBs) of the original binary data are modified to encode the length and content of the hidden message. These alterations are so minor that they do not visibly affect the image, yet they securely store the message within its pixel data. This clever manipulation of binary values demonstrates the power of steganography, where seemingly insignificant details carry meaningful information—hidden in plain sight. By preserving the image's integrity while embedding a secret, this technique showcases how technology can be used creatively to protect and communicate information."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Decode\n",
+ "\n",
+ "## Extracting a Message from an Image\n",
+ "\n",
+ "To retrieve the hidden message, the recipient must reverse the embedding process. This involves:\n",
+ "\n",
+ "\n",
+ "1. **Load the Image:** Open the image containing the hidden message.\n",
+ "2. **Extract the Message Length:** Retrieve the length of the hidden message from the least significant bits of the image's pixel data.\n",
+ "3. **Extract the Message:** Using the message length, extract the hidden message from the least significant bits of the image's pixel data.\n",
+ "4. **Decode the Message:** Decode the extracted message from Base64 to reveal the original content.\n",
+ "\n",
+ "\n",
+ ":::note\n",
+ "You will need to update the path to be the path to your bitmap file.\n",
+ ":::\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "path = \"/home/breezy/Documents/GitHub/Small-Projects/Thoth-Tech-Code-Files/steganography/programs/\"\n",
+ "\n",
+ "def base64_decode(input_string):\n",
+ " BASE64_CHARS = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n",
+ " decoded_string = bytearray()\n",
+ " value = 0\n",
+ " bits = -8\n",
+ "\n",
+ " for character in input_string:\n",
+ " if character not in BASE64_CHARS:\n",
+ " if character == \"=\":\n",
+ " break\n",
+ " continue\n",
+ " \n",
+ " value = (value << 6) + BASE64_CHARS.index(character)\n",
+ " bits += 6\n",
+ "\n",
+ " if bits >= 0:\n",
+ " decoded_string.append((value >> bits) & 0xFF)\n",
+ " bits -= 8\n",
+ " \n",
+ " return decoded_string.decode()\n",
+ "\n",
+ "def extract_message(data, offset):\n",
+ " # Extract the length of the Base64 message (first 32 bits)\n",
+ " length_bits = ''.join(str(data[offset + i] & 1) for i in range(32))\n",
+ " print(f\"Length bits: {length_bits}\")\n",
+ " base64_length = int(length_bits, 2)\n",
+ " print(f\"Extracted Base64 length (in characters): {base64_length}\")\n",
+ "\n",
+ " # Extract the Base64 message\n",
+ " binary_message = ''.join(str(data[offset + 32 + i] & 1) for i in range(base64_length * 8))\n",
+ " base64_message = ''.join(chr(int(binary_message[i:i+8], 2)) for i in range(0, len(binary_message), 8))\n",
+ " print(f\"Extracted Base64 message: {base64_message}\")\n",
+ " print(f\"Extracted Binary message: {binary_message}\")\n",
+ "\n",
+ " # Decode the Base64 message\n",
+ " return base64_decode(base64_message)\n",
+ "\n",
+ "encoded_file_path = os.path.join(path, \"hiddencat.bmp\")\n",
+ "with open(encoded_file_path, \"rb\") as f: data = f.read()\n",
+ "\n",
+ "# Specify the offset where the pixel data starts (e.g., 54 for standard BMP)\n",
+ "pixel_data_offset = int.from_bytes(data[10:14], byteorder='little')\n",
+ "\n",
+ "hidden_message = extract_message(data, pixel_data_offset)\n",
+ "print(f\"Extracted message: {hidden_message}\")\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Expected Output\n",
+ "\n",
+ "After extracting the message, you'll see an output like:\n",
+ "\n",
+ "```shell\n",
+ "Length bits: 00000000000000000000000000001100\n",
+ "Extracted Base64 length (in characters): 12\n",
+ "Extracted Base64 message: aW0gYSBjYXQ=\n",
+ "Extracted Binary message: 011000010101011100110000011001110101100101010011010000100110101001011001010110000101000100111101\n",
+ "Extracted message: im a cat\n",
+ "```\n",
+ "\n",
+ "The extracted message is identical to the original message, demonstrating the successful retrieval of the hidden information. By following the reverse process of the embedding algorithm, the recipient can recover the message without any visible changes to the image. This seamless integration of data within the image's pixel data showcases the elegance and effectiveness of LSB steganography as a method of secure communication."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "jupyter-books",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.12.7"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}