else
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 211 KiB After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 129 B |
3
.GitImages/steganographic_logo.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:fd2967fd1cf2c3e9cd0e5c419bae1af75c0f279c27b589e0fd44a66bb0381036
|
||||
size 35430
|
70
.GitImages/steganographic_logo.svg
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 419 KiB After Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 130 B |
7
.gitattributes
vendored
|
@ -20,3 +20,10 @@
|
|||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
*.psd filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.db filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.ico filter=lfs diff=lfs merge=lfs -text
|
||||
'*.png' filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
4
ICO/README.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
ICO conversion
|
||||
==============
|
||||
|
||||
Converts image files to the Windows .ico format
|
3
ICO/examples/012609897180.ico
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:540b93378da4a4a4bae2b0e864a65c20617649fe748fa353ec363563b57e5c42
|
||||
size 270398
|
3
ICO/examples/327482101461.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e6edb44cafd358e081fca018fb8c016fabd1b5714163ee0884001bed30d351c8
|
||||
size 18472
|
3
ICO/filestructure.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:12e16e357cd8297545653cfebea1c89595b5dd45aec6d7ead5d5313c1694fda3
|
||||
size 182465
|
164
ICO/icoconvert.py
Normal file
|
@ -0,0 +1,164 @@
|
|||
# https://en.wikipedia.org/wiki/ICO_(file_format)
|
||||
|
||||
# All values in ICO/CUR files are represented in little-endian byte order.
|
||||
|
||||
# Header
|
||||
#
|
||||
# ICONDIR structure
|
||||
# _________________________________________________________________________________
|
||||
# | Offset | Size (in bytes) | Purpose |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 0 | 2 | Reserved. Must always be 0. |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 2 | 2 | Specifies image type: 1 for icon (.ICO) image, |
|
||||
# | | | 2 for cursor (.CUR) image. Other values are invalid. |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 4 | 2 | Specifies number of images in the file. |
|
||||
# |________|_________________|______________________________________________________|
|
||||
|
||||
# Structure of image directory
|
||||
# _______________________________________
|
||||
# | Image #1 | Entry for the first image |
|
||||
# |----------|----------------------------|
|
||||
# | Image #2 | Entry for the second image |
|
||||
# |----------|----------------------------|
|
||||
# | ... | |
|
||||
# |----------|----------------------------|
|
||||
# | Image #n | Entry for the last image |
|
||||
# |__________|____________________________|
|
||||
|
||||
# Image entry
|
||||
#
|
||||
# ICONDIRENTRY structure
|
||||
# _________________________________________________________________________________
|
||||
# | Offset | Size (in bytes) | Purpose |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 0 (06) | 1 | Specifies image width in pixels. Can be any number |
|
||||
# | | | between 0 and 255. Value 0 means image width is 256 |
|
||||
# | | | pixels. |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 1 (07) | 1 | Specifies image height in pixels. Can be any number |
|
||||
# | | | between 0 and 255. Value 0 means image height is 256 |
|
||||
# | | | pixels. |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 2 (08) | 1 | Specifies number of colors in the color palette. |
|
||||
# | | | Should be 0 if the image does not use a color palette|
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 3 (09) | 1 | Reserved. Should be 0. |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 4 (10) | 2 | In ICO format: Specifies color planes. |
|
||||
# | | | Should be 0 or 1. |
|
||||
# | | | In CUR format: Specifies the horizontal coordinates |
|
||||
# | | | of the hotspot in number of pixels from the left. |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 6 (12) | 2 | In ICO format: Specifies bits per pixel. |
|
||||
# | | | In CUR format: Specifies the vertical coordinates of |
|
||||
# | | | the hotspot in number of pixels from the top. |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# | 8 (14) | 4 | Specifies the size of the image's data in bytes |
|
||||
# |--------|-----------------|------------------------------------------------------|
|
||||
# |12 (18) | 4 | Specifies the offset of BMP or PNG data from the |
|
||||
# | | | beginning of the ICO/CUR file |
|
||||
# |________|_________________|______________________________________________________|
|
||||
|
||||
import binascii
|
||||
import sys
|
||||
from PIL import Image
|
||||
|
||||
try:
|
||||
INPUTFILE = sys.argv[1]
|
||||
except:
|
||||
print('Please provide an image file')
|
||||
quit()
|
||||
|
||||
def little_endian(hexstring):
|
||||
#print(hexstring)
|
||||
assert len(hexstring) % 2 == 0
|
||||
doublets = [hexstring[x*2:(x*2)+2] for x in range(len(hexstring)//2)]
|
||||
#print(doublets)
|
||||
doublets.reverse()
|
||||
hexstring = ''.join(doublets)
|
||||
return hexstring
|
||||
|
||||
def fit_into_bounds(self, iw, ih, fw, fh):
|
||||
'''
|
||||
Given the w+h of the image and the w+h of the frame,
|
||||
return new w+h that fits the image into the frame
|
||||
while maintaining the aspect ratio and leaving blank space
|
||||
everywhere else
|
||||
'''
|
||||
ratio = min(fw/iw, fh/ih)
|
||||
|
||||
w = int(iw * ratio)
|
||||
h = int(ih * ratio)
|
||||
return (w, h)
|
||||
|
||||
def image_to_ico(filename):
|
||||
print('Icofying %s' % filename)
|
||||
image = Image.open(filename)
|
||||
if min(image.size) > 256:
|
||||
w = image.size[0]
|
||||
h = image.size[1]
|
||||
image = image.resize((256, 256))
|
||||
image = image.convert('RGBA')
|
||||
|
||||
print('Building ico header')
|
||||
output_bytes = ''
|
||||
output_bytes += '00' '00' # reserved 0
|
||||
output_bytes += '01' '00' # 1 = ico
|
||||
output_bytes += '01' '00' # number of images
|
||||
#### ICO HEADER ####
|
||||
|
||||
print('Building image entry')
|
||||
# width and height. 00 acts as 256
|
||||
output_bytes += '%02x' % image.size[0] if image.size[0] < 256 else '00'
|
||||
output_bytes += '%02x' % image.size[1] if image.size[1] < 256 else '00'
|
||||
output_bytes += '00' # colors in palette
|
||||
output_bytes += '00' # reserved 0
|
||||
output_bytes += '01' '00' # color planes
|
||||
output_bytes += '20' '00' # bits per pixel (32)
|
||||
output_bytes += little_endian('%08x' % ((image.size[0] * image.size[1] * 4)+8192)) # image bytes size
|
||||
output_bytes += '16' '00' '00' '00' # image offset from start of file (begins right after this)
|
||||
#### IMAGE ENTRY ####
|
||||
|
||||
print('Building image header')
|
||||
output_bytes += '28' '00' '00' '00' # BMP DIB header size (always 40)
|
||||
output_bytes += little_endian('%08x' % image.size[0])
|
||||
output_bytes += little_endian('%08x' % (image.size[1] * 2)) # I'm not sure why * 2
|
||||
output_bytes += '01' '00' # color planes
|
||||
output_bytes += '20' '00' # bits per pixel (32)
|
||||
output_bytes += '00' '00' '00' '00' # Compression (None)
|
||||
image_bytesize = image.size[0] * image.size[1] * 4
|
||||
# BMP pixel array must always end on a 4th byte.
|
||||
image_nullpadding = 4 - (image_bytesize % 4)
|
||||
image_nullpadding = 0 if image_nullpadding == 4 else image_nullpadding
|
||||
output_bytes += little_endian('%08x' % (image_bytesize + image_nullpadding)) # BMP file size
|
||||
output_bytes += '00' '00' '00' '00' # Print width (unnecessary)
|
||||
output_bytes += '00' '00' '00' '00' # Print height (unecessary)
|
||||
output_bytes += '00' '00' '00' '00' # colors in palette
|
||||
output_bytes += '00' '00' '00' '00' # "important colors"
|
||||
#### IMAGE HEADER ####
|
||||
|
||||
print('Writing pixels')
|
||||
image_data = ''
|
||||
for y in range(image.size[1]-1, -1, -1):
|
||||
for x in range(image.size[0]):
|
||||
pixel = image.getpixel( (x, y) )
|
||||
#print(pixel)
|
||||
r = '%02x' % pixel[0]
|
||||
g = '%02x' % pixel[1]
|
||||
b = '%02x' % pixel[2]
|
||||
o = '%02x' % pixel[3]
|
||||
image_data += b + g + r + o
|
||||
|
||||
image_data += '00' * 8192
|
||||
output_bytes += image_data
|
||||
output_bytes = binascii.a2b_hex(output_bytes)
|
||||
name = filename.split('.')[0] + '.ico'
|
||||
output_file = open(name, 'wb')
|
||||
output_file.write(output_bytes)
|
||||
output_file.close()
|
||||
print('Finished %s.' % name)
|
||||
|
||||
|
||||
image_to_ico(INPUTFILE)
|
1
ServerReference/admin/stop.txt
Normal file
|
@ -0,0 +1 @@
|
|||
you're not allowed to see this.
|
1
ServerReference/files/heyo.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Hello!
|
|
@ -1,21 +1,46 @@
|
|||
import http.server
|
||||
import os
|
||||
|
||||
f = open('favicon.png', 'rb')
|
||||
FAVI = f.read()
|
||||
f.close()
|
||||
|
||||
# The paths of the root folder which the user may access
|
||||
# Attempting to access any other files in the root folder
|
||||
# will 403
|
||||
OKAY_BASE_PATHS = set(x.lower() for x in ['/', '/favicon.ico'])
|
||||
FORBIDDEN_PATHS = set(x.lower() for x in ['/admin'])
|
||||
|
||||
class RequestHandler(http.server.BaseHTTPRequestHandler):
|
||||
def write(self, string):
|
||||
if isinstance(string, str):
|
||||
string = string.encode('utf-8')
|
||||
self.wfile.write(string)
|
||||
|
||||
def read_filebytes(self, path):
|
||||
#print(path)
|
||||
if os.path.isfile(path):
|
||||
f = open(path, 'rb')
|
||||
fr = f.read()
|
||||
f.close()
|
||||
return fr
|
||||
if os.path.isdir(path):
|
||||
return self.read_filebytes(os.path.join(path, 'index.html'))
|
||||
self.send_error(404)
|
||||
return b''
|
||||
|
||||
def do_GET(self):
|
||||
#print(dir(self))
|
||||
print(self.path)
|
||||
if self.path == '/favicon.ico':
|
||||
self.write(FAVI)
|
||||
self.write('heyo')
|
||||
path = self.path.lower()
|
||||
if os.path.dirname(path) in FORBIDDEN_PATHS:
|
||||
self.send_error(403, 'Forbidden path!')
|
||||
return
|
||||
if path not in OKAY_BASE_PATHS and (os.path.dirname(path) == '/'):
|
||||
self.send_error(403, 'Stop that!')
|
||||
return
|
||||
path = os.path.join(os.getcwd(), path[1:])
|
||||
d = self.read_filebytes(path)
|
||||
self.write(d)
|
||||
|
||||
server = http.server.HTTPServer(('', 80), RequestHandler)
|
||||
print('server starting')
|
||||
|
|
|
@ -70,7 +70,7 @@ class SpinalClient:
|
|||
self.t.mainloop()
|
||||
|
||||
def add_pathline(self):
|
||||
|
||||
pass
|
||||
|
||||
if __name__ == '__main__':
|
||||
s = SpinalClient()
|
||||
|
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 131 B |
BIN
SpinalTap/testdata/largerfile.png
vendored
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 131 B |
8
Steganographic/README.md
Normal file
|
@ -0,0 +1,8 @@
|
|||
Steganographic
|
||||
==============
|
||||
|
||||
Let's be honest, this was really just an excuse to make big Terminal headers out of hashmarks.
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/voussoir/else/blob/master/.GitImages/steganographic_logo.png?raw=true" alt="steganographic"/>
|
||||
</p>
|
1209
Steganographic/asciibet.txt
Normal file
3
Steganographic/examples/18pixels.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:02a13340f3e9725002eb3e1c9836c6d741bd23b1e1c9f46fe668bf8d4e8d23eb
|
||||
size 72
|
3
Steganographic/examples/19pixels.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2de9722143b871485253c18018a9fc844678925e04565cab181682ee0c937507
|
||||
size 72
|
3
Steganographic/examples/20pixels.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:96b62948f6dbaa9a8cc68e6dfc2ddd95582e6678a0e4cdf89aa43727cb31af01
|
||||
size 93
|
3
Steganographic/examples/33pixels.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:669f3a4d521192d33f930883ef5ed1f633a05bd7c299217c437ce1ed900a1bfb
|
||||
size 98
|
0
Steganographic/examples/empty.txt
Normal file
3
Steganographic/examples/notbigenough.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4dd394c21bfb1fa529e16db74b53b9a2809222d351b66a10e83ff4a251b2fccf
|
||||
size 216
|
3
Steganographic/examples/solid.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:930df36d4338f591646cd096dc4def34b258d57bffa542844e37bf76f7baf433
|
||||
size 1798
|
3
Steganographic/examples/supersmall.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4451c74d0e9d63b4cf28b2809149b4b71b8ff84364bf3cd3570fca6913d432cf
|
||||
size 85
|
1
Steganographic/examples/text.txt
Normal file
|
@ -0,0 +1 @@
|
|||
a
|
1
Steganographic/examples/text_noex
Normal file
|
@ -0,0 +1 @@
|
|||
s
|
BIN
Steganographic/examples/thats_advertising.mp4
Normal file
BIN
Steganographic/examples/thats_advertising_noex
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d4ce1789cfb3ed83ff177fde898526318666dbfb77b95f70b8038d4367c45dca
|
||||
size 6002883
|
3
Steganographic/examples/trespassing.png
Normal file
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:197816675c6345bbd922b2f99569a25a0b97b206b622000afb265f00db3f931a
|
||||
size 5618458
|
31
Steganographic/steg_test.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
import steganographic
|
||||
import time
|
||||
import traceback
|
||||
def encode(i, s):
|
||||
try:
|
||||
steganographic.encode(i, s)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
time.sleep(0.1)
|
||||
print()
|
||||
def decode(i):
|
||||
try:
|
||||
steganographic.decode(i)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
time.sleep(0.1)
|
||||
print()
|
||||
#encode('examples\\steg_notbigenough.png', 'examples\\steg_thats_advertising.mp4')
|
||||
#encode('examples\\steg_supersmall.png', 'examples\\steg_thats_advertising.mp4')
|
||||
#encode('examples\\steg_18pixels.png', 'examples\\steg_thats_advertising.mp4')
|
||||
#encode('examples\\steg_19pixels.png', 'examples\\steg_thats_advertising.mp4')
|
||||
#encode('examples\\steg_20pixels.png', 'examples\\steg_empty.txt')
|
||||
#encode('examples\\steg_20pixels.png', 'examples\\steg_text.txt')
|
||||
#encode('examples\\steg_33pixels.png', 'examples\\steg_text.txt')
|
||||
#encode('examples\\steg_33pixels.png', 'examples\\steg_text_noex')
|
||||
|
||||
#decode('examples\\steg_33pixels (steg_text_txt).png')
|
||||
#decode('examples\\steg_trespassing (3bp_thats_advertising_mp4).png')
|
||||
|
||||
encode('examples\\trespassing.png', 'examples\\thats_advertising.mp4')
|
||||
decode('examples\\trespassing (thats_advertising_mp4).png')
|
244
Steganographic/steganographic.py
Normal file
|
@ -0,0 +1,244 @@
|
|||
'''
|
||||
For each color channel of each pixel in an Image, modify the least significant bit to represent a bit of the Secret file.
|
||||
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.
|
||||
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.
|
||||
|
||||
Each Image pixel holds 3 Secret bits, so the Image must have at least ((secretbytes * (8 / 3)) + 19) pixels
|
||||
An Image can hold ((3 * (pixels - 19)) / 8) Secret bytes.
|
||||
|
||||
Usage:
|
||||
> 3bitspixel.py encode imagefilename.png secretfilename.ext
|
||||
> 3bitspixel.py decode lacedimagename.png
|
||||
'''
|
||||
from PIL import Image
|
||||
import binascii
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
|
||||
# 11 for the content length, and AT LEAST 8 for the extension (which always ends in 1 null byte)
|
||||
HEADER_SIZE = 19
|
||||
|
||||
class StegError(Exception):
|
||||
pass
|
||||
|
||||
def binary(i):
|
||||
return bin(i)[2:].rjust(8, '0')
|
||||
|
||||
def increment_pixel(save=True):
|
||||
'''
|
||||
Increment the active channel, and roll to the next pixel when appropriate.
|
||||
'''
|
||||
global pixel
|
||||
global pixel_index
|
||||
global channel_index
|
||||
channel_index += 1
|
||||
if channel_index == 3:
|
||||
channel_index = 0
|
||||
if save:
|
||||
image.putpixel((pixel_index % image.size[0], pixel_index // image.size[0]), tuple(pixel))
|
||||
#print('wrote', pixel)
|
||||
pixel_index += 1
|
||||
pixel = list(image.getpixel( (pixel_index % image.size[0], pixel_index // image.size[0]) ))
|
||||
#print('opend', pixel)
|
||||
|
||||
|
||||
############## #### #### ######## ###### ########## ##############
|
||||
#### ## #### #### #### #### #### #### #### #### #### ##
|
||||
#### ###### #### #### #### #### #### #### #### ####
|
||||
#### ## ######## #### #### #### #### #### #### #### ##
|
||||
########## ############## #### #### #### #### #### ##########
|
||||
#### ## #### ######## #### #### #### #### #### #### ##
|
||||
#### #### ###### #### #### #### #### #### #### ####
|
||||
#### ## #### #### #### #### #### #### #### #### #### ##
|
||||
############## #### #### ######## ###### ########## ##############
|
||||
def encode(imagefilename, secretfilename):
|
||||
global image
|
||||
global pixel
|
||||
global pixel_index
|
||||
global channel_index
|
||||
pixel_index = 0
|
||||
channel_index = 0
|
||||
|
||||
print('Hiding "%s" within "%s"' % (secretfilename, imagefilename))
|
||||
image = Image.open(imagefilename)
|
||||
|
||||
totalpixels = image.size[0] * image.size[1]
|
||||
if totalpixels < HEADER_SIZE:
|
||||
raise StegError('Image cannot have fewer than %d pixels. They are used to store Secret\'s length' % HEADER_SIZE)
|
||||
|
||||
secretfile = open(secretfilename, 'rb')
|
||||
secret = secretfile.read()
|
||||
secret = list(secret)
|
||||
|
||||
if secret == []:
|
||||
raise StegError('The Secret can\'t be 0 bytes.')
|
||||
|
||||
secret_extension = os.path.splitext(secretfilename)[1][1:]
|
||||
secret_content_length = (len(secret) * 8) + (len(secret_extension) * 8) + 8
|
||||
requiredpixels = math.ceil((secret_content_length / 3) + HEADER_SIZE)
|
||||
if totalpixels < requiredpixels:
|
||||
raise StegError('Image does not have enough pixels to store the Secret'
|
||||
'Must have at least %d pixels' % 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 <--
|
||||
pixel = list(image.getpixel((0, 0)))
|
||||
|
||||
# Write secret length
|
||||
secret_content_length_b = bin(secret_content_length)[2:].rjust(32, '0')
|
||||
for x in range(32):
|
||||
modify_pixel(secret_content_length_b[x])
|
||||
increment_pixel()
|
||||
|
||||
# Write the secret extension
|
||||
for character in (secret_extension + chr(0)):
|
||||
character = ord(character)
|
||||
character = binary(character)
|
||||
for bit in character:
|
||||
modify_pixel(bit)
|
||||
increment_pixel()
|
||||
|
||||
# Write the secret data
|
||||
for (index, byte) in enumerate(secret):
|
||||
if index % 1024 == 0:
|
||||
percentage = (index + 1) / len(secret)
|
||||
percentage = '%07.3f%%\r' % (100 * percentage)
|
||||
print(percentage, end='')
|
||||
# Convert byte integer to a binary string, and loop through characters
|
||||
byte = binary(byte)
|
||||
for (bindex, bit) in enumerate(byte):
|
||||
modify_pixel(bit)
|
||||
if not (index == secret_content_length -1 and bindex == 7):
|
||||
# If your Image dimensions are at the extreme limit of the Secret size,
|
||||
# this would otherwise raise IndexError as it tries to grab the next pixel
|
||||
# off the canvas.
|
||||
increment_pixel()
|
||||
print('100.000%') # you know it
|
||||
|
||||
if channel_index != 0:
|
||||
# The Secret data has finished, but we still have an unsaved pixel
|
||||
# (because channel_index is set to 0 when we save the active pixel above)
|
||||
image.putpixel((pixel_index % image.size[0], pixel_index // image.size[0]), tuple(pixel))
|
||||
|
||||
newname = os.path.splitext(imagefilename)[0]
|
||||
newname = '%s (%s).png' % (newname, os.path.basename(secretfilename).replace('.', '_'))
|
||||
print(newname)
|
||||
image.save(newname)
|
||||
|
||||
|
||||
|
||||
########## ############## ######## ###### ########## ##############
|
||||
#### #### #### ## #### #### #### #### #### #### #### ##
|
||||
#### #### #### #### #### #### #### #### #### ####
|
||||
#### #### #### ## #### #### #### #### #### #### ##
|
||||
#### #### ########## #### #### #### #### #### ##########
|
||||
#### #### #### ## #### #### #### #### #### #### ##
|
||||
#### #### #### #### #### #### #### #### #### ####
|
||||
#### #### #### ## #### #### #### #### #### #### #### ##
|
||||
########## ############## ######## ###### ########## ##############
|
||||
def decode(imagefilename):
|
||||
global image
|
||||
global pixel
|
||||
global pixel_index
|
||||
global channel_index
|
||||
pixel_index = 0
|
||||
channel_index = 0
|
||||
|
||||
print('Extracting content from "%s"' % imagefilename)
|
||||
image = Image.open(imagefilename)
|
||||
|
||||
# determine the content length
|
||||
content_length = ''
|
||||
for x in range(11):
|
||||
pixel = list(image.getpixel( (pixel_index % image.size[0], pixel_index // image.size[0]) ))
|
||||
pixel = pixel[:3]
|
||||
#print(pixel)
|
||||
content_length += ''.join([bin(i)[-1] for i in pixel])
|
||||
pixel_index += 1
|
||||
content_length = content_length[:-1]
|
||||
content_length = int(content_length, 2)
|
||||
print('Content bits:', content_length)
|
||||
|
||||
# Continue from the end of the header
|
||||
# This would have been automatic if I used `increment_pixel`
|
||||
pixel_index = 10
|
||||
channel_index = 2
|
||||
|
||||
# determine secret extension
|
||||
extension = ''
|
||||
while extension[-8:] != '00000000' or len(extension) % 8 != 0:
|
||||
channel = pixel[channel_index]
|
||||
channel = binary(channel)
|
||||
channel = channel[-1]
|
||||
extension += channel
|
||||
increment_pixel(save=False)
|
||||
extension = extension[:-8]
|
||||
extension = [extension[8*x: (8*x)+8] for x in range(len(extension)//8)]
|
||||
extension = [chr(int(x, 2)) for x in extension]
|
||||
extension = ''.join(extension)
|
||||
print('Extension:', extension)
|
||||
|
||||
# Remove the extension length
|
||||
content_length -= 8
|
||||
content_length -= 8 * len(extension)
|
||||
|
||||
# Prepare writes
|
||||
newname = os.path.splitext(imagefilename)[0]
|
||||
if extension != '':
|
||||
extension = '.' + extension
|
||||
newname = '%s (extracted)%s' % (newname, extension)
|
||||
outfile = open(newname, 'wb')
|
||||
|
||||
# extract data
|
||||
content_bytes = content_length // 8
|
||||
for byte in range(content_bytes):
|
||||
if byte % 1024 == 0:
|
||||
percentage = (byte + 1) / content_bytes
|
||||
percentage = '%07.3f%%\r' % (100 * percentage)
|
||||
print(percentage, end='')
|
||||
|
||||
activebyte = ''
|
||||
for bit in range(8):
|
||||
channel = pixel[channel_index]
|
||||
channel = binary(channel)[-1]
|
||||
activebyte += channel
|
||||
if not (byte == content_bytes - 1 and bit == 7):
|
||||
# If your Image dimensions are at the extreme limit of the Secret size,
|
||||
# this would otherwise raise IndexError as it tries to grab the next pixel
|
||||
# off the canvas.
|
||||
increment_pixel(save=False)
|
||||
activebyte = '%02x' % int(activebyte, 2)
|
||||
outfile.write(binascii.a2b_hex(activebyte))
|
||||
print('100.000%') # I'm on fire
|
||||
print(newname)
|
||||
outfile.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
if (len(sys.argv) == 1) or (sys.argv[1] not in ['encode', 'decode']):
|
||||
print('Usage:')
|
||||
print('> 3bitspixel.py encode imagefilename.png secretfilename.ext')
|
||||
print('> 3bitspixel.py decode lacedimagename.png')
|
||||
|
||||
imagefilename = sys.argv[2]
|
||||
|
||||
if sys.argv[1] == 'encode':
|
||||
secretfilename = sys.argv[3]
|
||||
encode(imagefilename, secretfilename)
|
||||
else:
|
||||
decode(imagefilename)
|
25
Toolbox/filenameorderedrandomness.pyw
Normal file
|
@ -0,0 +1,25 @@
|
|||
'''
|
||||
Drag multiple files on top of this .py file. The first file will have its
|
||||
name randomly scrambled into 12 digits. The others will increment that number b
|
||||
1.
|
||||
'''
|
||||
|
||||
import os
|
||||
import random
|
||||
import string
|
||||
import sys
|
||||
|
||||
argv = sys.argv[1:]
|
||||
print(argv)
|
||||
|
||||
randname = [random.choice(string.digits) for x in range(12)]
|
||||
randname = int(''.join(randname))
|
||||
for originalname in argv:
|
||||
folder = os.path.dirname(originalname)
|
||||
basename = os.path.basename(originalname)
|
||||
extension = basename.split('.')[-1]
|
||||
newname = randname
|
||||
randname += 1
|
||||
newname = '%s/%d.%s' % (folder, newname, extension)
|
||||
print('%s -> %s' % (originalname, newname))
|
||||
os.rename(originalname, newname)
|
|
@ -18,6 +18,8 @@ ctime = '-c' in sys.argv
|
|||
IGNORE_EXTENSIONS = ['.py', '.lnk']
|
||||
|
||||
prefix = sys.argv[1]
|
||||
if prefix != '':
|
||||
prefix += '_'
|
||||
files = [os.path.abspath(x) for x in os.listdir()]
|
||||
files = [item for item in files if os.path.isfile(item)]
|
||||
if __file__ in files:
|
||||
|
@ -28,7 +30,7 @@ zeropadding = len(str(len(files)))
|
|||
zeropadding = max(2, zeropadding)
|
||||
zeropadding = str(zeropadding)
|
||||
|
||||
format = '%s_%0{pad}d%s'.format(pad=zeropadding)
|
||||
format = '%s%0{pad}d%s'.format(pad=zeropadding)
|
||||
print(format)
|
||||
|
||||
def natural_sort(l):
|
||||
|
|
|
@ -10,7 +10,7 @@ DOWNLOAD_DIRECTORY = ''
|
|||
# Save files to this folder
|
||||
# If blank, it uses the local folder
|
||||
|
||||
IMGUR_ALBUM_INDV = 'Viewfullresolution<'
|
||||
IMGUR_ALBUM_INDV = '<metaproperty="og:image"'
|
||||
IMGUR_ALBUM_INDV2 = 'linkrel="image_src"'
|
||||
# The HTML string which tells us that an image link is
|
||||
# on this line.
|
||||
|
@ -100,22 +100,12 @@ def request_get(url, stream=False, headers={}):
|
|||
def handle_imgur_html(url):
|
||||
pagedata = request_get(url)
|
||||
pagedata = pagedata.text.replace(' ', '')
|
||||
pagedata = pagedata.replace('src="', 'href="')
|
||||
pagedata = pagedata.replace(IMGUR_ALBUM_INDV2, IMGUR_ALBUM_INDV)
|
||||
pagedata = pagedata.split('\n')
|
||||
pagedata = [line.strip() for line in pagedata]
|
||||
pagedata = [line for line in pagedata if IMGUR_ALBUM_INDV in line]
|
||||
pagedata = [line.split('href=')[1] for line in pagedata]
|
||||
pagedata = [line.replace('"//', '"http://') for line in pagedata]
|
||||
pagedata = [line.split('"')[1] for line in pagedata]
|
||||
links = []
|
||||
first = pagedata[0].split('.')[0]
|
||||
if [x.split('.')[0] for x in pagedata].count(first) > 1:
|
||||
pagedata = pagedata[1:]
|
||||
for image in pagedata:
|
||||
image = image.split('?')[0]
|
||||
if image not in links:
|
||||
links.append(image)
|
||||
pagedata = [line.split('content="')[1] for line in pagedata]
|
||||
links = [line.split('"')[0] for line in pagedata]
|
||||
links = [line.split('?')[0] for line in links]
|
||||
print(links)
|
||||
return links
|
||||
|
||||
def handle_imgur(url, albumid='', customname=None):
|
||||
|
|
53
Trash/karmadecaycheck.txt
Normal file
|
@ -0,0 +1,53 @@
|
|||
import praw,bot
|
||||
import requests
|
||||
import re
|
||||
r=bot.oG()
|
||||
KARMADECAY_URL = 'http://karmadecay.com/r/%s/comments/%s/'
|
||||
REPATTERN = 'href="/r/.* title='
|
||||
HEADERS = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'
|
||||
}
|
||||
def get_karmadecay(subreddit, iid):
|
||||
url = KARMADECAY_URL % (subreddit, iid)
|
||||
page = requests.get(url, headers=HEADERS, timeout=60)
|
||||
page.raise_for_status()
|
||||
return page.text
|
||||
|
||||
def extract_reddit_ids(karmadecay):
|
||||
if 'Unable to find an image at' in karmadecay:
|
||||
print('unable to find any images')
|
||||
return []
|
||||
if 'No very similar images were found' in karmadecay:
|
||||
print('no very similar images')
|
||||
return []
|
||||
if 'very similar images' not in karmadecay:
|
||||
print('expected "very similar" is missing')
|
||||
return []
|
||||
|
||||
karmadecay = karmadecay.split('Less similar images')[0]
|
||||
karmadecay = karmadecay.split('very similar images')[1]
|
||||
|
||||
matches = re.findall(REPATTERN, karmadecay)
|
||||
matches = [m.split('"')[1] for m in matches]
|
||||
matches = [m.split('/comments/')[1].split('/')[0] for m in matches]
|
||||
matches = ['t3_' + m for m in matches]
|
||||
|
||||
return matches
|
||||
|
||||
SAMPLES = [
|
||||
('pics', '3i4gjy'), # valid submission with matches
|
||||
('goldtesting', '26wkzi'), # valid submission with no matches
|
||||
('goldtesting', '3cychc'), # selfpost, should fail
|
||||
]
|
||||
for sample in SAMPLES:
|
||||
print(sample)
|
||||
a = get_karmadecay(*sample)
|
||||
a = extract_reddit_ids(a)
|
||||
if len(a) == 0:
|
||||
print('Got no items')
|
||||
continue
|
||||
print(a)
|
||||
submissions = r.get_info(thing_id=a)
|
||||
for submission in submissions:
|
||||
print(submission.id, submission.created_utc, submission.title)
|
||||
print()
|
21
Trash/randomwikipage.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
import json
|
||||
import requests
|
||||
import time
|
||||
import string
|
||||
import random
|
||||
def get_random_wikipages(count):
|
||||
print('requesting wiki pages')
|
||||
HEADERS={'User-Agent': 'Random wikipage fetcher v1 - puts random wiki pages into reddit comments'}
|
||||
links = []
|
||||
url = 'https://powerlisting.wikia.com/wiki/Special:Random'
|
||||
for x in range(count):
|
||||
page = requests.get(url, '%x' % random.getrandbits(16), headers=HEADERS)
|
||||
page.raise_for_status()
|
||||
title = page.text.split('<title>')[1].split('</title>')[0]
|
||||
title = title.replace(' - Superpower Wiki', '')
|
||||
print(''.join(c for c in title if c in string.printable))
|
||||
links.append('[%s](%s)' % (title, page.url))
|
||||
time.sleep(5)
|
||||
return '\n'.join(links)
|
||||
|
||||
print(get_random_wikipages(3))
|