Sep-26-2024, 12:43 PM
Hi! :)
I have programmed a Steganography app which runs on Python Streamlit.
1. It currently works for if the payload is txt or text file. But I need to make it possible for me to encode any payload file type to any image, audio, video or text file.
2. I also need the encoding process randomized. For example, if I encode an image, it should not be obvious that first row of image pixels has been encoded with the contents of the payload. Random pixels should be selected to be encoded without repeated encoding. I am also trying to apply this concept for audio, video and txt encoding too.
Any help is much appreciated! If you have any past projects that fit the description, I would also greatly appreciate it if you could share it with me :)
Here is the file:
I have programmed a Steganography app which runs on Python Streamlit.
1. It currently works for if the payload is txt or text file. But I need to make it possible for me to encode any payload file type to any image, audio, video or text file.
2. I also need the encoding process randomized. For example, if I encode an image, it should not be obvious that first row of image pixels has been encoded with the contents of the payload. Random pixels should be selected to be encoded without repeated encoding. I am also trying to apply this concept for audio, video and txt encoding too.
Any help is much appreciated! If you have any past projects that fit the description, I would also greatly appreciate it if you could share it with me :)
Here is the file:
import streamlit as st
import numpy as np
from PIL import Image
from pydub import AudioSegment
import wave
import moviepy.editor as mp
import os
import io
# Function to encode text into an image with delimiter
def encode_image(image_path, payload_text, num_lsb):
image = Image.open(image_path)
img_data = np.array(image)
# Convert payload to binary and add delimiter
payload_bin = ''.join(format(ord(char), '08b') for char in payload_text) + '1111111111111110'
# Calculate maximum bytes to encode
max_bytes = img_data.size * num_lsb // 8
if len(payload_bin) > max_bytes:
raise ValueError("Payload size exceeds cover image capacity.")
data_index = 0
for row in img_data:
for pixel in row:
for channel in range(3): # R, G, B channels
if data_index < len(payload_bin):
pixel[channel] = (pixel[channel] & ~((1 << num_lsb) - 1)) | int(payload_bin[data_index:data_index + num_lsb], 2)
data_index += num_lsb
else:
break
stego_image = Image.fromarray(img_data)
return stego_image
# Function to decode text from an image with delimiter
def decode_image(stego_image_path, num_lsb):
image = Image.open(stego_image_path)
img_data = np.array(image)
payload_bin = ""
for row in img_data:
for pixel in row:
for channel in range(3): # R, G, B channels
payload_bin += format(pixel[channel] & ((1 << num_lsb) - 1), '0' + str(num_lsb) + 'b')
# Convert binary to ASCII and check for delimiter
payload = ""
for i in range(0, len(payload_bin), 8):
byte = payload_bin[i:i + 8]
if byte == '11111111': # End of data (delimiter)
break
payload += chr(int(byte, 2))
return payload
# Function to encode text into text with LSB
def encode_text_to_text(payload_text, num_lsb):
# Convert text to binary and add delimiter
payload_bin = ''.join(format(ord(char), f'0{num_lsb}b') for char in payload_text) + '1111111111111110'
return payload_bin
# Function to decode text from text binary
def decode_text_from_text(payload_bin, num_lsb):
# Convert binary to ASCII and check for delimiter
payload = ""
for i in range(0, len(payload_bin), num_lsb):
byte = payload_bin[i:i + 8]
if byte == '11111111': # End of data (delimiter)
break
payload += chr(int(byte, 2))
return payload
# Function to encode text into an audio file (MP3 and WAV supported)
def encode_audio(audio_path, text, num_lsb):
if audio_path.lower().endswith('.mp3'):
audio = AudioSegment.from_mp3(audio_path)
frames = bytearray(audio.raw_data)
else:
audio = wave.open(audio_path, 'rb')
frames = bytearray(list(audio.readframes(audio.getnframes())))
binary_text = ''.join(format(ord(char), '08b') for char in text) + '1111111111111110' # Add delimiter
binary_index = 0
for i in range(len(frames)):
if binary_index < len(binary_text):
frames[i] = (frames[i] & ~1) | int(binary_text[binary_index])
binary_index += 1
new_audio_path = os.path.splitext(audio_path)[0] + "_stego.wav"
if audio_path.lower().endswith('.mp3'):
new_audio = AudioSegment(
data=bytes(frames),
sample_width=audio.sample_width,
frame_rate=audio.frame_rate,
channels=audio.channels
)
new_audio.export(new_audio_path, format="wav")
else:
new_audio = wave.open(new_audio_path, 'wb')
new_audio.setparams(audio.getparams())
new_audio.writeframes(frames)
new_audio.close()
return new_audio_path
# Function to decode text from an audio file
def decode_audio(audio_path, num_lsb):
if audio_path.lower().endswith('.mp3'):
audio = AudioSegment.from_mp3(audio_path)
frames = bytearray(audio.raw_data)
else:
audio = wave.open(audio_path, 'rb')
frames = bytearray(list(audio.readframes(audio.getnframes())))
binary_text = ''
for frame in frames:
binary_text += str(frame & 1)
text = ''
for i in range(0, len(binary_text), 8):
byte = binary_text[i:i + 8]
if byte == '11111111': # End of data (delimiter)
break
text += chr(int(byte, 2))
return text
# Function to encode text into an MP4 video file
def encode_video(video_path, text, num_lsb):
video = mp.VideoFileClip(video_path)
frames = [frame.copy() for frame in video.iter_frames()] # Make frames writable
# Convert text to binary
binary_text = ''.join(format(ord(char), '08b') for char in text) + '1111111111111110'
binary_index = 0
for frame in frames:
for row in frame:
for pixel in row:
for channel in range(3): # R, G, B channels
if binary_index < len(binary_text):
pixel[channel] = (pixel[channel] & ~((1 << num_lsb) - 1)) | int(binary_text[binary_index:binary_index + num_lsb], 2)
binary_index += num_lsb
else:
break
# Save the modified frames back to a video
new_video_path = os.path.splitext(video_path)[0] + "_stego.mp4"
new_video = mp.ImageSequenceClip(frames, fps=video.fps)
new_video = new_video.set_audio(video.audio) # Add audio to the stego video
new_video.write_videofile(new_video_path, codec='libx264')
return new_video_path
# Function to decode text from an MP4 video file
def decode_video(video_path, num_lsb):
video = mp.VideoFileClip(video_path)
frames = [frame for frame in video.iter_frames()]
binary_text = ""
for frame in frames:
for row in frame:
for pixel in row:
for channel in range(3): # R, G, B channels
binary_text += format(pixel[channel] & ((1 << num_lsb) - 1), '0' + str(num_lsb) + 'b')
# Convert binary to ASCII and check for delimiter
text = ""
for i in range(0, len(binary_text), 8):
byte = binary_text[i:i + 8]
if byte == '11111111': # End of data (delimiter)
break
text += chr(int(byte, 2))
return text
# Main Streamlit interface
def main():
st.title("Steganography with Streamlit")
st.write("Encode and decode text, images, audio, and videos using LSB steganography.")
# Sidebar for encoding/decoding
st.sidebar.title("Options")
operation = st.sidebar.radio("Choose operation", ("Encode", "Decode"))
# Payload type selection for encoding
if operation == "Encode":
payload_type = st.sidebar.radio("Select payload type", ("Text", "Image", "Audio", "Video"))
cover_type = st.sidebar.radio("Select cover object type", ("Text", "Image", "Audio", "Video"))
# File type filters for each category
image_types = ["jpeg", "jpg", "png", "bmp", "gif"]
audio_types = ["mp3", "wav"]
video_types = ["mp4"]
text_types = ["txt"]
# Upload Payload File
if payload_type == "Text":
payload_file = st.file_uploader("Upload a text file payload", type=text_types)
payload_text = st.text_area("Or enter the text payload:")
elif payload_type == "Image":
payload_file = st.file_uploader("Upload an image file payload", type=image_types)
elif payload_type == "Audio":
payload_file = st.file_uploader("Upload an audio file payload", type=audio_types)
elif payload_type == "Video":
payload_file = st.file_uploader("Upload a video file payload", type=video_types)
# Upload Cover Object File
if cover_type == "Text":
cover_file = st.file_uploader("Upload a text file cover object", type=text_types)
elif cover_type == "Image":
cover_file = st.file_uploader("Upload an image file cover object", type=image_types)
elif cover_type == "Audio":
cover_file = st.file_uploader("Upload an audio file cover object", type=audio_types)
elif cover_type == "Video":
cover_file = st.file_uploader("Upload a video file cover object", type=video_types)
# Select number of LSBs
num_lsb = st.slider("Select number of LSBs to use", 1, 8, 1)
# Encode Button
if payload_file and cover_file:
if st.button("Encode Payload into Cover Object"):
try:
# Depending on the payload and cover types, call appropriate encoding functions
if payload_type == "Text" and cover_type == "Image":
stego_image = encode_image(cover_file, payload_text, num_lsb)
st.image(stego_image, caption="Stego Image with Hidden Text")
buf = io.BytesIO()
stego_image.save(buf, format='PNG')
byte_im = buf.getvalue()
st.download_button("Download Stego Image", data=byte_im, file_name="stego_image.png", mime="image/png")
elif payload_type == "Video" and cover_type == "Image":
stego_image = encode_video(cover_file, payload_file, num_lsb)
st.image(stego_image, caption="Stego Image with Hidden Video")
buf = io.BytesIO()
stego_image.save(buf, format='PNG')
byte_im = buf.getvalue()
st.download_button("Download Stego Image", data=byte_im, file_name="stego_image.png", mime="image/png")
# Add other encoding combinations as needed
except Exception as e:
st.error(f"Error: {e}")
# Stego object type selection for decoding
elif operation == "Decode":
# Select the type of stego object that contains the hidden payload
stego_type = st.sidebar.radio("Select stego object type", ("Text", "Image", "Audio", "Video"))
# File type filters for each category
image_types = ["jpeg", "jpg", "png", "bmp", "gif"]
audio_types = ["mp3", "wav"]
video_types = ["mp4"]
text_types = ["txt"]
# Upload Stego File (the file containing hidden data)
if stego_type == "Text":
stego_file = st.file_uploader("Upload a stego text file", type=text_types)
elif stego_type == "Image":
stego_file = st.file_uploader("Upload a stego image file", type=image_types)
elif stego_type == "Audio":
stego_file = st.file_uploader("Upload a stego audio file", type=audio_types)
elif stego_type == "Video":
stego_file = st.file_uploader("Upload a stego video file", type=video_types)
# Select number of LSBs used during encoding
num_lsb = st.slider("Select number of LSBs used during encoding", 1, 8, 1)
# Decode Button
if stego_file:
if st.button("Decode Payload from Stego Object"):
try:
# Depending on the stego type, call appropriate decoding functions
if stego_type == "Text":
decoded_text = decode_text_from_text(stego_file.read().decode("utf-8"), num_lsb)
st.text_area("Decoded Text", value=decoded_text)
elif stego_type == "Image":
decoded_text = decode_image(stego_file, num_lsb)
st.image(stego_file, caption="Stego Image with Hidden Data")
elif stego_type == "Audio":
decoded_text = decode_audio(stego_file, num_lsb)
st.audio(stego_file, format="audio/wav")
elif stego_type == "Video":
decoded_video = decode_video(stego_file, num_lsb)
st.video(decoded_video)
# Add other decoding combinations as needed
except Exception as e:
st.error(f"Error: {e}")
if __name__ == "__main__":
main()
Attached Files
