Dimitri Merejkowsky преди 5 години
родител
ревизия
b1d49d5235
променени са 5 файла, в които са добавени 138 реда и са изтрити 0 реда
  1. +21
    -0
      sources/stegano/requirements.lock
  2. +24
    -0
      sources/stegano/setup.cfg
  3. +2
    -0
      sources/stegano/setup.py
  4. +82
    -0
      sources/stegano/stegano.py
  5. +9
    -0
      sources/stegano/test_stegano.py

+ 21
- 0
sources/stegano/requirements.lock Целия файл

@@ -0,0 +1,21 @@
# Generated with dmenv 0.15.0, python 3.7.1, on Linux
appdirs==1.4.3
atomicwrites==1.3.0
attrs==19.1.0
black==19.3b0
Click==7.0
importlib-metadata==0.18
more-itertools==7.1.0
packaging==19.0
Pillow==6.0.0
pip==19.1.1
pluggy==0.12.0
py==1.8.0
pyparsing==2.4.0
pytest==4.6.3
setuptools==41.0.1
six==1.12.0
toml==0.10.0
wcwidth==0.1.7
wheel==0.33.4
zipp==0.5.1

+ 24
- 0
sources/stegano/setup.cfg Целия файл

@@ -0,0 +1,24 @@
[metadata]
name = stegano
version = 0.1.0
description = simple steagography script
author = e2l

[options]
py_modules = ["stegano"],

install_requires =
Pillow

classifiers =
"Programming Language :: Python :: 3"


[options.extras_require]
dev =
black
pytest

[options.entry_points]
console_scripts =
stegano = stegano:main

+ 2
- 0
sources/stegano/setup.py Целия файл

@@ -0,0 +1,2 @@
from setuptools import setup
setup()

+ 82
- 0
sources/stegano/stegano.py Целия файл

@@ -0,0 +1,82 @@
import PIL.Image
import itertools

import sys


def get_bitstream(message):
for c in message:
bin_string = "{:08b}".format(c)
for bit in bin_string:
yield int(bit)


def parse_bitstream(stream):
for bits in by_chunk(stream, 8, fillvalue=0):
binstr = "".join([str(b) for b in bits])
c = int(binstr, 2)
if chr(c) == "\n":
break
yield c


def by_chunk(iterable, size, fillvalue=0):
"Collect data into fixed-length chunks or blocks"
args = [iter(iterable)] * size
return itertools.zip_longest(*args, fillvalue=fillvalue)


def set_bit(old_byte, new_bit):
b = list(bin(old_byte))
b[-1] = str(new_bit)
return int("".join(b), 2)


def main_encrypt():
base_name = sys.argv[2]
message = (sys.argv[3] + "\n").encode()
carrier_name = base_name.replace(".png", ".carrier.png")
base_image = PIL.Image.open(base_name)
width, height = base_image.size
new_image = PIL.Image.new("RGB", (width, height), "white")
bitstream = get_bitstream(message)
for row in range(height):
for col in range(width):
r, g, b = base_image.getpixel((col, row))
value = None
try:
value = next(bitstream)
except StopIteration:
pass
if value is not None:
r = set_bit(r, value)
new_image.putpixel((col, row), (r, g, b))

new_image.save(carrier_name, "png")
print("carrier written to", carrier_name)


def yield_bits(carrier_image):
width, height = carrier_image.size
for row in range(height):
for col in range(width):
r, g, b = carrier_image.getpixel((col, row))
last_bit = int(bin(r)[-1])
yield last_bit


def main_decrypt():
carrier_name = sys.argv[2]
carrier_image = PIL.Image.open(carrier_name)
encoded = yield_bits(carrier_image)
decoded = bytes(parse_bitstream(encoded))
print(decoded.decode())


def main():
if sys.argv[1] == "encrypt":
main_encrypt()
elif sys.argv[1] == "decrypt":
main_decrypt()
else:
sys.exit("choose from encrypt, decrypt")

+ 9
- 0
sources/stegano/test_stegano.py Целия файл

@@ -0,0 +1,9 @@
import stegano


def test_message_conversion():
message = b"I love you\ngarbage"
encoded = list(stegano.get_bitstream(message))

decoded = bytes(stegano.parse_bitstream(encoded))
assert decoded == b"I love you"