Skip to content

Commit

Permalink
encoding files wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nyashaChiza committed Aug 18, 2024
1 parent c0548e5 commit 143a21b
Show file tree
Hide file tree
Showing 14 changed files with 396 additions and 94 deletions.
11 changes: 9 additions & 2 deletions stegnography/forms.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# myapp/forms.py
from django import forms

class EncodeForm(forms.Form):
class TextEncodeForm(forms.Form):
message = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control', 'placeholder': 'Message to hide'}))
cover_image = forms.ImageField(widget=forms.FileInput(attrs={'class': 'form-control'}))

class FileEncodeForm(forms.Form):
file = forms.FileField(widget=forms.ClearableFileInput(attrs={'class': 'form-control'}))
cover_image = forms.ImageField(widget=forms.FileInput(attrs={'class': 'form-control'}))

class TextDecodeForm(forms.Form):
stego_image = forms.ImageField(widget=forms.FileInput(attrs={'class': 'form-control'}))


class DecodeForm(forms.Form):
class FileDecodeForm(forms.Form):
stego_image = forms.ImageField(widget=forms.FileInput(attrs={'class': 'form-control'}))
81 changes: 81 additions & 0 deletions stegnography/helpers/convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from PIL import Image

def file_to_binary(file_bytes):
return ''.join(format(byte, '08b') for byte in file_bytes)


def binary_to_bytes(binary_data):
byte_data = bytearray(int(binary_data[i:i+8], 2) for i in range(0, len(binary_data), 8))
return bytes(byte_data)


def file_to_bytes(file_path):
with open(file_path, 'rb') as file:
file_bytes = file.read()
return file_bytes


def bytes_to_file(file_path, file_bytes):
with open(file_path, 'wb') as file:
file.write(file_bytes)


def hide_data_in_image(image_path, file_bytes, output_image_path):
image = Image.open(image_path)
pixels = list(image.getdata())

binary_data = file_to_binary(file_bytes)
binary_data += '1111111111111110' # Add a delimiter to signify the end of data

new_pixels = []
data_index = 0
for pixel in pixels:
r, g, b = pixel[:3]
if data_index < len(binary_data):
new_r = (r & ~1) | int(binary_data[data_index])
data_index += 1
else:
new_r = r

if data_index < len(binary_data):
new_g = (g & ~1) | int(binary_data[data_index])
data_index += 1
else:
new_g = g

if data_index < len(binary_data):
new_b = (b & ~1) | int(binary_data[data_index])
data_index += 1
else:
new_b = b

# Maintain the alpha channel if present
if len(pixel) == 4:
new_pixels.append((new_r, new_g, new_b, pixel[3]))
else:
new_pixels.append((new_r, new_g, new_b))

new_image = Image.new(image.mode, image.size)
new_image.putdata(new_pixels)
new_image.save(output_image_path)


def extract_data_from_image(image_path):
image = Image.open(image_path)
pixels = list(image.getdata())

binary_data = ""
for pixel in pixels:
r, g, b = pixel[:3]
binary_data += str(r & 1)
binary_data += str(g & 1)
binary_data += str(b & 1)

# Find the delimiter and cut the data there
delimiter = '1111111111111110'
end_index = binary_data.find(delimiter)
if end_index != -1:
binary_data = binary_data[:end_index]

return binary_to_bytes(binary_data)

6 changes: 4 additions & 2 deletions stegnography/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from stegnography import views

urlpatterns = [
path('encode/', views.encode_view, name='encode'),
path('decode/', views.decode_view, name='decode'),
path('text/encode/', views.text_encode_view, name='text_encode'),
path('text/decode/', views.text_decode_view, name='text_decode'),
path('file/encode/', views.file_encode_view, name='file_encode'),
path('file/decode/', views.file_decode_view, name='file_decode'),
path('download/<str:file_name>/', views.download_file, name='download'),
]
83 changes: 0 additions & 83 deletions stegnography/views.py
Original file line number Diff line number Diff line change
@@ -1,83 +0,0 @@
import os
import uuid
import io
from django.conf import settings
from django.http import Http404, HttpResponse
from django.shortcuts import render
from django.core.files.base import ContentFile
from stegnography.forms import EncodeForm, DecodeForm
from stegano import lsb
from PIL import Image
from django.utils.http import unquote

def encode_view(request):
if request.method == 'POST':
form = EncodeForm(request.POST, request.FILES)
if form.is_valid():
# Get the form data
message = form.cleaned_data['message']
cover_image = form.cleaned_data['cover_image']

# Process the image and message
image_file = cover_image.read()
image = Image.open(io.BytesIO(image_file))
stego_image = lsb.hide(image, message)

# Save the stego image to an in-memory file
output = io.BytesIO()
stego_image.save(output, format="PNG")
output.seek(0)

# Generate a unique file name
file_name = f'stego_image_{uuid.uuid4().hex[:6]}.png'
stego_image_file = ContentFile(output.read(), file_name)

# Save file to media folder
file_path = os.path.join(settings.MEDIA_ROOT, file_name)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'wb') as f:
f.write(stego_image_file.read())

# Extract just the file name from the path
file_name_only = os.path.basename(file_path)

# Pass file_name_only to the context
return render(request, 'encryption/encrypt_result.html', {'stego_image_file_name': file_name_only})

else:
form = EncodeForm()

return render(request, 'encryption/encode.html', {'form': form})

def decode_view(request):
decoded_message = None
if request.method == 'POST':
form = DecodeForm(request.POST, request.FILES)
if form.is_valid():
# Get the uploaded stego image
stego_image = form.cleaned_data['stego_image']

# Read the image file into memory
image_file = stego_image.read()
image = Image.open(io.BytesIO(image_file))

# Decode the message from the image
decoded_message = lsb.reveal(image)
else:
form = DecodeForm()

return render(request, 'encryption/decode.html', {'form': form, 'decoded_message': decoded_message})

def download_file(request, file_name):
# Construct the file path
file_path = os.path.join(settings.MEDIA_ROOT, file_name)

# Check if the file exists
if not os.path.exists(file_path):
raise Http404("File does not exist")

# Open the file
with open(file_path, 'rb') as f:
response = HttpResponse(f.read(), content_type='application/octet-stream')
response['Content-Disposition'] = f'attachment; filename="{unquote(file_name)}"'
return response
2 changes: 2 additions & 0 deletions stegnography/views/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from stegnography.views.text_encoding import *
from stegnography.views.file_encoding import *
142 changes: 142 additions & 0 deletions stegnography/views/file_encoding.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import os
import uuid
import io
from django.conf import settings
from django.shortcuts import render
from django.core.files.base import ContentFile
from PIL import Image
from stegnography.forms import FileEncodeForm, FileDecodeForm # Ensure you have this form

# Utility functions for binary conversion
def file_to_binary(file_bytes):
return ''.join(format(byte, '08b') for byte in file_bytes)

def binary_to_bytes(binary_data):
byte_data = bytearray(int(binary_data[i:i+8], 2) for i in range(0, len(binary_data), 8))
return bytes(byte_data)

def file_encode_view(request):
if request.method == 'POST':
form = FileEncodeForm(request.POST, request.FILES)
if form.is_valid():
# Get the form data
file = form.cleaned_data['file'] # This should be a file
cover_image = form.cleaned_data['cover_image']

# Read file into memory
file_content = file.read()
binary_data = file_to_binary(file_content)

# Process the image and file content
image_file = cover_image.read()
image = Image.open(io.BytesIO(image_file))

# Encode the file content into the image
pixels = list(image.getdata())
binary_data += '1111111111111110' # Add a delimiter to signify the end of data

new_pixels = []
data_index = 0
settings.LOGGER.critical('processing pixels')
for pixel in pixels:
r, g, b = pixel[:3]
if data_index < len(binary_data):
new_r = (r & ~1) | int(binary_data[data_index])
data_index += 1
else:
new_r = r

if data_index < len(binary_data):
new_g = (g & ~1) | int(binary_data[data_index])
data_index += 1
else:
new_g = g

if data_index < len(binary_data):
new_b = (b & ~1) | int(binary_data[data_index])
data_index += 1
else:
new_b = b

if len(pixel) == 4:
new_pixels.append((new_r, new_g, new_b, pixel[3]))
else:
new_pixels.append((new_r, new_g, new_b))

new_image = Image.new(image.mode, image.size)
new_image.putdata(new_pixels)

# Save the stego image to an in-memory file
output = io.BytesIO()
new_image.save(output, format="PNG")
output.seek(0)

# Generate a unique file name
file_name = f'stego_image_{uuid.uuid4().hex[:6]}.png'
stego_image_file = ContentFile(output.read(), file_name)

# Save file to media folder
file_path = os.path.join(settings.MEDIA_ROOT, file_name)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'wb') as f:
f.write(stego_image_file.read())

# Pass file_name_only to the context
return render(request, 'encryption/file/encrypt_result.html', {'stego_image_file_name': file_name})

else:
form = FileEncodeForm()

return render(request, 'encryption/file/encode.html', {'form': form})


def file_decode_view(request):
if request.method == 'POST':
form = FileDecodeForm(request.POST, request.FILES)

if form.is_valid():
# Get the uploaded stego image
stego_image = form.cleaned_data['stego_image']

# Read the image file into memory
image_file = stego_image.read()
image = Image.open(io.BytesIO(image_file))

# Decode the message from the image
pixels = list(image.getdata())

binary_data = ""
for count ,pixel in enumerate(pixels):
settings.LOGGER.debug(f'processing pixels: {count/len(pixels) * 100:.2f}%')
r, g, b = pixel[:3]
binary_data += str(r & 1)
binary_data += str(g & 1)
binary_data += str(b & 1)

# Find the delimiter and cut the data there
delimiter = '1111111111111110'
end_index = binary_data.find(delimiter)
if end_index != -1:
binary_data = binary_data[:end_index]

decoded_file_content = binary_to_bytes(binary_data)

file_name = 'decoded_file' # Adjust the file extension as needed

# Save the decoded file to an in-memory file
output = io.BytesIO(decoded_file_content)
content_file = ContentFile(output.read(), file_name)

# Save file to media folder
file_path = os.path.join(settings.MEDIA_ROOT, file_name)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, 'wb') as f:
f.write(content_file.read())

# Pass file_name to the context
return render(request, 'encryption/file/decode_result.html', {'decoded_file_name': file_name})

else:
form = FileDecodeForm()

return render(request, 'encryption/file/decode.html', {'form': form})
Loading

0 comments on commit 143a21b

Please sign in to comment.