mirror of
https://github.com/cedricbonhomme/Stegano.git
synced 2025-05-12 17:18:30 +02:00
added a shift parameter for the lsbset module.
This commit is contained in:
parent
a86361dd27
commit
ea2de8142c
6 changed files with 47 additions and 15 deletions
|
@ -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)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -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,
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -53,17 +53,29 @@ class TestLSBSet(unittest.TestCase):
|
||||||
generators.eratosthenes())
|
generators.eratosthenes())
|
||||||
|
|
||||||
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):
|
||||||
|
|
Loading…
Add table
Reference in a new issue