added a shift parameter for the lsbset module.

This commit is contained in:
Cédric Bonhomme 2018-12-18 21:38:25 +01:00
parent a86361dd27
commit ea2de8142c
No known key found for this signature in database
GPG key ID: A1CB94DE57B7A70D
6 changed files with 47 additions and 15 deletions

View file

@ -1,6 +1,11 @@
Release History Release History
=============== ===============
0.9.0 (2018-12-18)
------------------
* added the possibility to shift the encoded bits when using the lsbset module.
0.8.6 (2018-11-05) 0.8.6 (2018-11-05)
------------------ ------------------

View file

@ -55,6 +55,8 @@ parser_hide.add_argument("-g", "--generator", dest="generator_function",
choices=[generator[0] for generator in \ choices=[generator[0] for generator in \
inspect.getmembers(generators, inspect.isfunction)], inspect.getmembers(generators, inspect.isfunction)],
required=True, help="Generator") required=True, help="Generator")
parser_hide.add_argument("-s", "--shift", dest="shift",
default=0, help="Shift for the generator")
group_secret = parser_hide.add_mutually_exclusive_group(required=True) group_secret = parser_hide.add_mutually_exclusive_group(required=True)
# Non binary secret message to hide # Non binary secret message to hide
@ -81,6 +83,8 @@ parser_reveal.add_argument("-g", "--generator", dest="generator_function",
choices=[generator[0] for generator in \ choices=[generator[0] for generator in \
inspect.getmembers(generators, inspect.isfunction)], inspect.getmembers(generators, inspect.isfunction)],
required=True, help="Generator") required=True, help="Generator")
parser_reveal.add_argument("-s", "--shift", dest="shift",
default=0, help="Shift for the generator")
parser_reveal.add_argument("-o", dest="secret_binary", parser_reveal.add_argument("-o", dest="secret_binary",
help="Output for the binary secret (Text or any binary file).") help="Output for the binary secret (Text or any binary file).")
@ -111,7 +115,8 @@ if arguments.command == 'hide':
elif arguments.secret_file != "": elif arguments.secret_file != "":
secret = tools.binary2base64(arguments.secret_file) secret = tools.binary2base64(arguments.secret_file)
img_encoded = lsbset.hide(arguments.input_image_file, secret, generator) img_encoded = lsbset.hide(arguments.input_image_file, secret, generator,
int(arguments.shift))
try: try:
img_encoded.save(arguments.output_image_file) img_encoded.save(arguments.output_image_file)
except Exception as e: except Exception as e:
@ -120,7 +125,8 @@ if arguments.command == 'hide':
elif arguments.command == 'reveal': elif arguments.command == 'reveal':
try: try:
secret = lsbset.reveal(arguments.input_image_file, generator) secret = lsbset.reveal(arguments.input_image_file, generator,
int(arguments.shift))
except IndexError: except IndexError:
print("Impossible to detect message.") print("Impossible to detect message.")
exit(0) exit(0)

View file

@ -33,7 +33,7 @@ with codecs.open(os.path.join(here, 'CHANGELOG.rst'), encoding='utf-8') as f:
setup( setup(
name='Stegano', name='Stegano',
version='0.8.6', version='0.9.0',
author='Cédric Bonhomme', author='Cédric Bonhomme',
author_email='cedric@cedricbonhomme.org', author_email='cedric@cedricbonhomme.org',
packages=packages, packages=packages,

View file

@ -2,7 +2,7 @@
#-*- coding: utf-8 -*- #-*- coding: utf-8 -*-
# Stéganô - Stéganô is a basic Python Steganography module. # Stéganô - Stéganô is a basic Python Steganography module.
# Copyright (C) 2010-2017 Cédric Bonhomme - https://www.cedricbonhomme.org # Copyright (C) 2010-2018 Cédric Bonhomme - https://www.cedricbonhomme.org
# #
# For more information : https://github.com/cedricbonhomme/Stegano # For more information : https://github.com/cedricbonhomme/Stegano
# #
@ -20,9 +20,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/> # along with this program. If not, see <http://www.gnu.org/licenses/>
__author__ = "Cedric Bonhomme" __author__ = "Cedric Bonhomme"
__version__ = "$Revision: 0.5 $" __version__ = "$Revision: 0.6 $"
__date__ = "$Date: 2016/03/13 $" __date__ = "$Date: 2016/03/13 $"
__revision__ = "$Date: 2017/05/04 $" __revision__ = "$Date: 2018/12/18 $"
__license__ = "GPLv3" __license__ = "GPLv3"
import sys import sys
@ -36,6 +36,7 @@ from . import generators
def hide(input_image: Union[str, IO[bytes]], def hide(input_image: Union[str, IO[bytes]],
message: str, message: str,
generator: Iterator[int], generator: Iterator[int],
shift: int = 0,
encoding: str = 'UTF-8', encoding: str = 'UTF-8',
auto_convert_rgb: bool = False): auto_convert_rgb: bool = False):
"""Hide a message (string) in an image with the """Hide a message (string) in an image with the
@ -68,6 +69,9 @@ def hide(input_image: Union[str, IO[bytes]],
if len_message_bits > npixels * 3: if len_message_bits > npixels * 3:
raise Exception("The message you want to hide is too long: {}". \ raise Exception("The message you want to hide is too long: {}". \
format(message_length)) format(message_length))
while shift != 0:
next(generator)
shift -= 1
while index + 3 <= len_message_bits : while index + 3 <= len_message_bits :
generated_number = next(generator) generated_number = next(generator)
@ -97,6 +101,7 @@ def hide(input_image: Union[str, IO[bytes]],
def reveal(input_image: Union[str, IO[bytes]], def reveal(input_image: Union[str, IO[bytes]],
generator: Iterator[int], generator: Iterator[int],
shift: int = 0,
encoding: str = 'UTF-8'): encoding: str = 'UTF-8'):
"""Find a message in an image (with the LSB technique). """Find a message in an image (with the LSB technique).
""" """
@ -107,6 +112,10 @@ def reveal(input_image: Union[str, IO[bytes]],
bitab = [] bitab = []
limit = None limit = None
while shift != 0:
next(generator)
shift -= 1
while True: while True:
generated_number = next(generator) generated_number = next(generator)
# color = [r, g, b] # color = [r, g, b]

View file

@ -54,20 +54,20 @@ class TestLSB(unittest.TestCase):
def test_hide_and_reveal_UTF32LE(self): def test_hide_and_reveal_UTF32LE(self):
messages_to_hide = 'I love 🍕 and 🍫!' messages_to_hide = 'I love 🍕 and 🍫!'
secret = lsb.hide("./tests/sample-files/Lenna.png", secret = lsb.hide("./tests/sample-files/Lenna.png",
messages_to_hide, 'UTF-32LE') messages_to_hide, encoding='UTF-32LE')
secret.save("./image.png") secret.save("./image.png")
clear_message = lsb.reveal("./image.png", 'UTF-32LE') clear_message = lsb.reveal("./image.png", encoding='UTF-32LE')
self.assertEqual(messages_to_hide, clear_message) self.assertEqual(messages_to_hide, clear_message)
def test_with_transparent_png(self): def test_with_transparent_png(self):
messages_to_hide = ['🍕', 'a', 'foo', 'Hello World!', ':Python:'] messages_to_hide = ['🍕', 'a', 'foo', 'Hello World!', ':Python:']
for message in messages_to_hide: for message in messages_to_hide:
secret = lsb.hide("./tests/sample-files/transparent.png", secret = lsb.hide("./tests/sample-files/transparent.png",
message, 'UTF-32LE') message, encoding='UTF-32LE')
secret.save("./image.png") secret.save("./image.png")
clear_message = lsb.reveal("./image.png", 'UTF-32LE') clear_message = lsb.reveal("./image.png", encoding='UTF-32LE')
self.assertEqual(message, clear_message) self.assertEqual(message, clear_message)
@ -75,19 +75,19 @@ class TestLSB(unittest.TestCase):
def test_manual_convert_rgb(self, input): def test_manual_convert_rgb(self, input):
message_to_hide = 'I love 🍕 and 🍫!' message_to_hide = 'I love 🍕 and 🍫!'
secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png", secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png",
message_to_hide, 'UTF-32LE') message_to_hide, encoding='UTF-32LE')
@patch('builtins.input', return_value='n') @patch('builtins.input', return_value='n')
def test_refuse_convert_rgb(self, input): def test_refuse_convert_rgb(self, input):
message_to_hide = 'I love 🍕 and 🍫!' message_to_hide = 'I love 🍕 and 🍫!'
with self.assertRaises(Exception): with self.assertRaises(Exception):
secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png", secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png",
message_to_hide, 'UTF-32LE') message_to_hide, encoding='UTF-32LE')
def test_auto_convert_rgb(self): def test_auto_convert_rgb(self):
message_to_hide = 'I love 🍕 and 🍫!' message_to_hide = 'I love 🍕 and 🍫!'
secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png", secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png",
message_to_hide, 'UTF-32LE', True) message_to_hide, encoding='UTF-32LE', auto_convert_rgb=True)
def test_with_text_file(self): def test_with_text_file(self):
text_file_to_hide = './tests/sample-files/lorem_ipsum.txt' text_file_to_hide = './tests/sample-files/lorem_ipsum.txt'

View file

@ -54,16 +54,28 @@ class TestLSBSet(unittest.TestCase):
self.assertEqual(message, clear_message) self.assertEqual(message, clear_message)
def test_hide_and_reveal_with_shift(self):
messages_to_hide = ["a", "foo", "Hello World!", ":Python:"]
for message in messages_to_hide:
secret = lsbset.hide("./tests/sample-files/Lenna.png", message,
generators.eratosthenes(), 4)
secret.save("./image.png")
clear_message = lsbset.reveal("./image.png",
generators.eratosthenes(), 4)
self.assertEqual(message, clear_message)
def test_hide_and_reveal_UTF32LE(self): def test_hide_and_reveal_UTF32LE(self):
messages_to_hide = 'I love 🍕 and 🍫!' messages_to_hide = 'I love 🍕 and 🍫!'
secret = lsbset.hide("./tests/sample-files/Lenna.png", secret = lsbset.hide("./tests/sample-files/Lenna.png",
messages_to_hide, messages_to_hide,
generators.eratosthenes(), generators.eratosthenes(),
'UTF-32LE') encoding='UTF-32LE')
secret.save("./image.png") secret.save("./image.png")
clear_message = lsbset.reveal("./image.png", generators.eratosthenes(), clear_message = lsbset.reveal("./image.png", generators.eratosthenes(),
'UTF-32LE') encoding='UTF-32LE')
self.assertEqual(messages_to_hide, clear_message) self.assertEqual(messages_to_hide, clear_message)
def test_with_transparent_png(self): def test_with_transparent_png(self):