This commit is contained in:
unknown 2015-10-03 20:57:26 -07:00
parent 81019bbaa7
commit dd4bacf3ab
3 changed files with 60 additions and 18 deletions

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e890b050800c2ba0f0dc1aab56519c0c43b5d20fca4908976ddd41505a0393af
size 136

View file

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:19681c97997aaa6a0382b91bd62d71fd3ee85f5443597888acbcdf4f537187b7
size 125

View file

@ -3,14 +3,45 @@ For each color channel of each pixel in an Image, modify the least significant b
This changes the RGB value of the pixel by a usually-imperceptible amount. This changes the RGB value of the pixel by a usually-imperceptible amount.
The first 32 bits (10.66 pixels) will be used to store the length of the Secret content in big endian. The first 32 bits (10.66 pixels) will be used to store the length of the Secret content in big endian.
Then, the Secret's extension is stored. A null byte indicates the end of the extension. This section is of variable length. Then, the Secret's extension is stored. A null byte indicates the end of the extension. This section is of variable length.
A file with no extension will still require that null byte. A file with an extension will require 1 byte per character. A file with no extension requires only that null byte. A file with an extension requires 1 additional byte per character.
Each Image pixel holds 3 Secret bits, so the Image must have at least ((secretbytes * (8 / 3)) + 19) pixels Smallest image possible = 16 pixels with 48 bit secret: 32 for header; 8 for null extension; 8 for data
An Image can hold ((3 * (pixels - 19)) / 8) Secret bytes. Each Image pixel holds 3 Secret bits, so the Image must have at least ((secretbytes * (8 / 3)) + 14) pixels
An Image can hold ((3 * (pixels - 14)) / 8) Secret bytes.
Usage: Usage:
> 3bitspixel.py encode imagefilename.png secretfilename.ext > 3bitspixel.py encode imagefilename.png secretfilename.ext
> 3bitspixel.py decode lacedimagename.png > 3bitspixel.py decode lacedimagename.png
Reference table for files with NO EXTENSION.
For each extension character, subtract 1 byte from secret size
pixels | example dimensions | Secret file size
100 | 10 x 10 | 32 bytes
400 | 20 x 20 | 144 bytes
2,500 | 50 x 50 | 932 bytes
10,000 | 100 x 100 | 3,744 bytes
40,000 | 200 x 200 | 14,994 bytes
25,000 | 500 x 500 | 93,744 bytes (91 kb)
1,000,000 | 1,000 x 1,000 | 374,994 bytes (366 kb)
4,000,000 | 2,000 x 2,000 | 1,499,994 bytes (1.43 mb)
25,000,000 | 5,000 x 5,000 | 9,374,994 bytes (8.94 mb)
100,000,000 | 10,000 x 10,000 | 37,499,994 bytes (35.7 mb)
pixels | example dimensions | Secret file size
100 | 10 x 10 | 32 bytes
697 | 25 x 28 (700) | 256 bytes
2,745 | 50 x 55 (2,750) | 1,024 bytes (1 kb)
21,860 | 142 x 154 (21,868) | 8,192 bytes (8 kb)
87,396 | 230 x 380 (87,400) | 32,768 bytes (32 kb)
349,540 | 463 x 755 (349,565) | 131,072 bytes (128 kb)
1,398,116 | 1146 x 1120 (1,398,120) | 524,288 bytes (512 kb)
2,796,217 | 1621 x 1725 (2,796,225) | 1,048,576 bytes (1 mb)
11,184,825 | 3500 x 3200 (11,200,000) | 4,194,304 bytes (4 mb)
44,739,257 | 6700 x 6700 (44,890,000) | 16,777,216 bytes (16 mb)
89,478,500 | 9500 x 9500 (90,250,000) | 33,554,432 bytes (32 mb)
''' '''
from PIL import Image from PIL import Image
import binascii import binascii
@ -18,8 +49,8 @@ import math
import os import os
import sys import sys
# 11 for the content length, and AT LEAST 8 for the extension (which always ends in 1 null byte) # 11 for the content length
HEADER_SIZE = 19 HEADER_SIZE = 11
class StegError(Exception): class StegError(Exception):
pass pass
@ -44,6 +75,11 @@ def increment_pixel(save=True):
pixel = list(image.getpixel( (pixel_index % image.size[0], pixel_index // image.size[0]) )) pixel = list(image.getpixel( (pixel_index % image.size[0], pixel_index // image.size[0]) ))
#print('opend', pixel) #print('opend', pixel)
def bytes_to_pixels(bytes):
return ((bytes * (8 / 3)) + 14)
def pixels_to_bytes(pixels):
return ((3 * (pixels - 14)) / 8)
############## #### #### ######## ###### ########## ############## ############## #### #### ######## ###### ########## ##############
#### ## #### #### #### #### #### #### #### #### #### ## #### ## #### #### #### #### #### #### #### #### #### ##
@ -62,6 +98,18 @@ def encode(imagefilename, secretfilename):
pixel_index = 0 pixel_index = 0
channel_index = 0 channel_index = 0
def modify_pixel(bit):
global pixel
global channel_index
#print(channel_index, bit)
#print(pixel_index, channel_index, bit)
channel = pixel[channel_index]
channel = binary(channel)[:7] + bit
channel = int(channel, 2)
pixel[channel_index] = channel
#print(pixel)
print('Hiding "%s" within "%s"' % (secretfilename, imagefilename)) print('Hiding "%s" within "%s"' % (secretfilename, imagefilename))
image = Image.open(imagefilename) image = Image.open(imagefilename)
@ -78,25 +126,13 @@ def encode(imagefilename, secretfilename):
secret_extension = os.path.splitext(secretfilename)[1][1:] secret_extension = os.path.splitext(secretfilename)[1][1:]
secret_content_length = (len(secret) * 8) + (len(secret_extension) * 8) + 8 secret_content_length = (len(secret) * 8) + (len(secret_extension) * 8) + 8
requiredpixels = math.ceil((secret_content_length / 3) + HEADER_SIZE) requiredpixels = math.ceil((secret_content_length + 32) / 3)
if totalpixels < requiredpixels: if totalpixels < requiredpixels:
raise StegError('Image does not have enough pixels to store the Secret' raise StegError('Image does not have enough pixels to store the Secret'
'Must have at least %d pixels' % requiredpixels) 'Must have at least %d pixels' % requiredpixels)
print('%d available pixels, %d required' % (totalpixels, requiredpixels)) print('%d available pixels, %d required' % (totalpixels, requiredpixels))
def modify_pixel(bit):
global pixel
global channel_index
#print(channel_index, bit)
#print(pixel_index, channel_index, bit)
channel = pixel[channel_index]
channel = binary(channel)[:7] + bit
channel = int(channel, 2)
pixel[channel_index] = channel
#print(pixel)
# --> YOU ARE HERE <-- # --> YOU ARE HERE <--
pixel = list(image.getpixel((0, 0))) pixel = list(image.getpixel((0, 0)))