From 48ff22476f658c6ab8c79162b534c92c756da342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Fri, 31 May 2019 22:15:04 +0200 Subject: [PATCH 1/8] fixes #23: lsbset.hide cause .png transparent area lost. --- stegano/lsbset/lsbset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stegano/lsbset/lsbset.py b/stegano/lsbset/lsbset.py index 04fa9fa..65f08e8 100644 --- a/stegano/lsbset/lsbset.py +++ b/stegano/lsbset/lsbset.py @@ -89,14 +89,14 @@ def hide( # Save the new pixel if img.mode == "RGBA": - img_list[generated_number] = (r, g, b, a[0]) + img_list[generated_number] = (r, g, b, *a) else: img_list[generated_number] = (r, g, b) index += 3 # create empty new image of appropriate format - encoded = Image.new("RGB", (img.size)) + encoded = Image.new(img.mode, (img.size)) # insert saved data into the image encoded.putdata(img_list) @@ -126,7 +126,7 @@ def reveal( while True: generated_number = next(generator) # color = [r, g, b] - for color in img_list[generated_number]: + for color in img_list[generated_number][0:3]: buff += (color & 1) << (tools.ENCODINGS[encoding] - 1 - count) count += 1 if count == tools.ENCODINGS[encoding]: From 0e18b2f95acca68547db001d7ef372036cf3d29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Fri, 31 May 2019 22:21:35 +0200 Subject: [PATCH 2/8] Ignore the alpha component when revealing a message. --- stegano/lsbset/lsbset.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stegano/lsbset/lsbset.py b/stegano/lsbset/lsbset.py index 65f08e8..93a6d77 100644 --- a/stegano/lsbset/lsbset.py +++ b/stegano/lsbset/lsbset.py @@ -126,7 +126,7 @@ def reveal( while True: generated_number = next(generator) # color = [r, g, b] - for color in img_list[generated_number][0:3]: + for color in img_list[generated_number][:3]: # ignore the alpha buff += (color & 1) << (tools.ENCODINGS[encoding] - 1 - count) count += 1 if count == tools.ENCODINGS[encoding]: From 1704aec690c6c0a9237af95823d7fc7eaf153d81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Fri, 31 May 2019 22:30:14 +0200 Subject: [PATCH 3/8] Updated revision date. --- stegano/lsbset/lsbset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stegano/lsbset/lsbset.py b/stegano/lsbset/lsbset.py index 93a6d77..2f04eba 100644 --- a/stegano/lsbset/lsbset.py +++ b/stegano/lsbset/lsbset.py @@ -20,9 +20,9 @@ # along with this program. If not, see __author__ = "Cedric Bonhomme" -__version__ = "$Revision: 0.6 $" +__version__ = "$Revision: 0.7 $" __date__ = "$Date: 2016/03/13 $" -__revision__ = "$Date: 2018/12/18 $" +__revision__ = "$Date: 2019/05/31 $" __license__ = "GPLv3" from typing import IO, Iterator, Union From 5694e5c806f2fba148cd59d1d32740eff756f0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Sat, 1 Jun 2019 00:58:00 +0200 Subject: [PATCH 4/8] Ackermann is now encapsulated in a generator. --- stegano/lsbset/generators.py | 11 +++++++++-- tests/test_lsbset.py | 12 ++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/stegano/lsbset/generators.py b/stegano/lsbset/generators.py index f0bdee9..b82371c 100644 --- a/stegano/lsbset/generators.py +++ b/stegano/lsbset/generators.py @@ -118,14 +118,14 @@ def ackermann_naive(m: int, n: int) -> int: return ackermann(m - 1, ackermann(m, n - 1)) -def ackermann(m: int, n: int) -> int: +def ackermann_fast(m: int, n: int) -> int: """Ackermann number. """ while m >= 4: if n == 0: n = 1 else: - n = ackermann(m, n - 1) + n = ackermann_fast(m, n - 1) m -= 1 if m == 3: return (1 << n + 3) - 3 @@ -136,6 +136,13 @@ def ackermann(m: int, n: int) -> int: else: return n + 1 +def ackermann(m: int) -> Iterator[int]: + """Ackermann written as a generator. + """ + n = 0 + while True: + yield ackermann_fast(m, n) + n += 1 def fibonacci() -> Iterator[int]: """Generate the sequence of Fibonacci. diff --git a/tests/test_lsbset.py b/tests/test_lsbset.py index 82fe754..548cac8 100644 --- a/tests/test_lsbset.py +++ b/tests/test_lsbset.py @@ -54,6 +54,18 @@ class TestLSBSet(unittest.TestCase): generators.eratosthenes()) self.assertEqual(message, clear_message) + + def test_hide_and_reveal_with_ackermann(self): + messages_to_hide = ["foo"] + for message in messages_to_hide: + secret = lsbset.hide("./tests/sample-files/Lenna.png", message, + generators.ackermann(m=3)) + secret.save("./image.png") + + clear_message = lsbset.reveal("./image.png", + generators.ackermann(m=3)) + + self.assertEqual(message, clear_message) def test_hide_and_reveal_with_shift(self): messages_to_hide = ["a", "foo", "Hello World!", ":Python:"] From f3cbe09b219da49257f5eb16e881bce5fb1a2a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Sat, 1 Jun 2019 01:20:26 +0200 Subject: [PATCH 5/8] mypy tests were failing --- stegano/lsbset/generators.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stegano/lsbset/generators.py b/stegano/lsbset/generators.py index b82371c..ab8bacb 100644 --- a/stegano/lsbset/generators.py +++ b/stegano/lsbset/generators.py @@ -113,9 +113,9 @@ def ackermann_naive(m: int, n: int) -> int: if m == 0: return n + 1 elif n == 0: - return ackermann(m - 1, 1) + return ackermann_naive(m - 1, 1) else: - return ackermann(m - 1, ackermann(m, n - 1)) + return ackermann_naive(m - 1, ackermann_naive(m, n - 1)) def ackermann_fast(m: int, n: int) -> int: @@ -137,7 +137,7 @@ def ackermann_fast(m: int, n: int) -> int: return n + 1 def ackermann(m: int) -> Iterator[int]: - """Ackermann written as a generator. + """Ackermann encapsulated in a generator. """ n = 0 while True: From 37aeb391671e9448a66d5e19b297046e0ff20833 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Sat, 1 Jun 2019 01:39:53 +0200 Subject: [PATCH 6/8] fixed ackermann tests --- tests/test_generators.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_generators.py b/tests/test_generators.py index 2d64ec1..58d9df3 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -91,17 +91,17 @@ class TestGenerators(unittest.TestCase): """Test the Ackermann set. """ - self.assertEqual(generators.ackermann(3, 1), 13) - self.assertEqual(generators.ackermann(3, 2), 29) + self.assertEqual(generators.ackermann_naive(3, 1), 13) + self.assertEqual(generators.ackermann_naive(3, 2), 29) def test_ackermann(self): """Test the Ackermann set. """ with open('./tests/expected-results/ackermann', 'r') as f: - self.assertEqual(generators.ackermann(3, 1), int(f.readline())) - self.assertEqual(generators.ackermann(3, 2), int(f.readline())) - self.assertEqual(generators.ackermann(4, 1), int(f.readline())) - self.assertEqual(generators.ackermann(4, 2), int(f.readline())) + self.assertEqual(generators.ackermann_fast(3, 1), int(f.readline())) + self.assertEqual(generators.ackermann_fast(3, 2), int(f.readline())) + self.assertEqual(generators.ackermann_fast(4, 1), int(f.readline())) + self.assertEqual(generators.ackermann_fast(4, 2), int(f.readline())) if __name__ == '__main__': unittest.main() From c3f6f392f371329780b44c3e0fa97a4b01678eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Sat, 1 Jun 2019 11:53:07 +0200 Subject: [PATCH 7/8] added a shift parameter for the lsb module. closes #25 --- bin/stegano-lsb | 16 +++++++++++----- stegano/lsb/lsb.py | 19 ++++++++++++++----- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/bin/stegano-lsb b/bin/stegano-lsb index 5fa4681..d7dcd02 100755 --- a/bin/stegano-lsb +++ b/bin/stegano-lsb @@ -20,9 +20,9 @@ # along with this program. If not, see __author__ = "Cedric Bonhomme" -__version__ = "$Revision: 0.7 $" +__version__ = "$Revision: 0.8 $" __date__ = "$Date: 2016/08/04 $" -__revision__ = "$Date: 2017/05/16 $" +__revision__ = "$Date: 2019/06/01 $" __license__ = "GPLv3" try: @@ -58,6 +58,9 @@ group_secret.add_argument("-f", dest="secret_file", parser_hide.add_argument("-o", "--output", dest="output_image_file", required=True, help="Output image containing the secret.") +# Shift the message to hide +parser_hide.add_argument("-s", "--shift", dest="shift", default=0, + help="Shift for the message to hide") # Subparser: Reveal parser_reveal = subparsers.add_parser('reveal', help='reveal help') @@ -69,7 +72,9 @@ parser_reveal.add_argument("-e", "--encoding", dest="encoding", " UTF-8 (default) or UTF-32LE.") parser_reveal.add_argument("-o", dest="secret_binary", help="Output for the binary secret (Text or any binary file).") - +# Shift the message to reveal +parser_reveal.add_argument("-s", "--shift", dest="shift", default=0, + help="Shift for the reveal") arguments = parser.parse_args() @@ -81,7 +86,7 @@ if arguments.command == 'hide': secret = tools.binary2base64(arguments.secret_file) img_encoded = lsb.hide(arguments.input_image_file, secret, - arguments.encoding) + arguments.encoding, int(arguments.shift)) try: img_encoded.save(arguments.output_image_file) except Exception as e: @@ -89,7 +94,8 @@ if arguments.command == 'hide': print(e) elif arguments.command == 'reveal': - secret = lsb.reveal(arguments.input_image_file, arguments.encoding) + secret = lsb.reveal(arguments.input_image_file, arguments.encoding, + int(arguments.shift)) if arguments.secret_binary != None: data = tools.base642binary(secret) with open(arguments.secret_binary, "wb") as f: diff --git a/stegano/lsb/lsb.py b/stegano/lsb/lsb.py index 8c0ac87..3cc083c 100755 --- a/stegano/lsb/lsb.py +++ b/stegano/lsb/lsb.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stéganô - Stegano is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano @@ -20,9 +20,9 @@ # along with this program. If not, see __author__ = "Cedric Bonhomme" -__version__ = "$Revision: 0.3 $" +__version__ = "$Revision: 0.4 $" __date__ = "$Date: 2016/08/04 $" -__revision__ = "$Date: 2017/05/04 $" +__revision__ = "$Date: 2019/06/01 $" __license__ = "GPLv3" from typing import IO, Union @@ -34,6 +34,7 @@ def hide( input_image: Union[str, IO[bytes]], message: str, encoding: str = "UTF-8", + shift: int = 0, auto_convert_rgb: bool = False, ): """Hide a message (string) in an image with the @@ -72,6 +73,9 @@ def hide( ) for row in range(height): for col in range(width): + if shift != 0: + shift -= 1 + continue if index + 3 <= len_message_bits: # Get the colour component. @@ -97,7 +101,10 @@ def hide( return encoded -def reveal(input_image: Union[str, IO[bytes]], encoding="UTF-8"): +def reveal(input_image: Union[str, IO[bytes]], + encoding: str = "UTF-8", + shift: int = 0 +): """Find a message in an image (with the LSB technique). """ img = tools.open_image(input_image) @@ -107,7 +114,9 @@ def reveal(input_image: Union[str, IO[bytes]], encoding="UTF-8"): limit = None for row in range(height): for col in range(width): - + if shift != 0: + shift -= 1 + continue # pixel = [r, g, b] or [r,g,b,a] pixel = img.getpixel((col, row)) if img.mode == "RGBA": From 5df01ea7375986850bf9c057fe8633b366d29402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Sat, 1 Jun 2019 12:01:15 +0200 Subject: [PATCH 8/8] Cosmethic changes. --- bin/stegano-lsb | 4 ++-- bin/stegano-red | 4 ++-- bin/stegano-steganalysis-parity | 4 ++-- bin/stegano-steganalysis-statistics | 4 ++-- stegano/exifHeader/exifHeader.py | 2 +- stegano/lsb/lsb.py | 2 +- stegano/lsbset/generators.py | 2 +- stegano/lsbset/lsbset.py | 2 +- stegano/red/red.py | 2 +- stegano/steganalysis/parity.py | 2 +- stegano/steganalysis/statistics.py | 2 +- stegano/tools.py | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/bin/stegano-lsb b/bin/stegano-lsb index d7dcd02..b49fd11 100755 --- a/bin/stegano-lsb +++ b/bin/stegano-lsb @@ -1,8 +1,8 @@ #!/usr/bin/env python #-*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. -# Copyright (C) 2010-2017 Cédric Bonhomme - https://www.cedricbonhomme.org +# Stegano - Stegano is a basic Python Steganography module. +# Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano # diff --git a/bin/stegano-red b/bin/stegano-red index ef36caf..5798f55 100644 --- a/bin/stegano-red +++ b/bin/stegano-red @@ -1,8 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. -# Copyright (C) 2010-2017 Cédric Bonhomme - https://www.cedricbonhomme.org +# Stegano - Stegano is a basic Python Steganography module. +# Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano # diff --git a/bin/stegano-steganalysis-parity b/bin/stegano-steganalysis-parity index 4d54586..32e4ef3 100644 --- a/bin/stegano-steganalysis-parity +++ b/bin/stegano-steganalysis-parity @@ -1,8 +1,8 @@ #!/usr/bin/env python #-*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. -# Copyright (C) 2010-2017 Cédric Bonhomme - https://www.cedricbonhomme.org +# Stegano - Stegano is a basic Python Steganography module. +# Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano # diff --git a/bin/stegano-steganalysis-statistics b/bin/stegano-steganalysis-statistics index 1cbe28b..a368c03 100644 --- a/bin/stegano-steganalysis-statistics +++ b/bin/stegano-steganalysis-statistics @@ -1,8 +1,8 @@ #!/usr/bin/env python #-*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. -# Copyright (C) 2010-2017 Cédric Bonhomme - https://www.cedricbonhomme.org +# Stegano - Stegano is a basic Python Steganography module. +# Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano # diff --git a/stegano/exifHeader/exifHeader.py b/stegano/exifHeader/exifHeader.py index 9a15ce2..e16f5ff 100644 --- a/stegano/exifHeader/exifHeader.py +++ b/stegano/exifHeader/exifHeader.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stegano - Stegano is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano diff --git a/stegano/lsb/lsb.py b/stegano/lsb/lsb.py index 3cc083c..9ea1095 100755 --- a/stegano/lsb/lsb.py +++ b/stegano/lsb/lsb.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stegano is a basic Python Steganography module. +# Stegano - Stegano is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano diff --git a/stegano/lsbset/generators.py b/stegano/lsbset/generators.py index ab8bacb..5db3a7f 100644 --- a/stegano/lsbset/generators.py +++ b/stegano/lsbset/generators.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stegano - Stegano is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano diff --git a/stegano/lsbset/lsbset.py b/stegano/lsbset/lsbset.py index 2f04eba..5e0c22a 100644 --- a/stegano/lsbset/lsbset.py +++ b/stegano/lsbset/lsbset.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stegano - Stegano is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano diff --git a/stegano/red/red.py b/stegano/red/red.py index ff841b5..a17bc52 100755 --- a/stegano/red/red.py +++ b/stegano/red/red.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stegano - Stéganô is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano diff --git a/stegano/steganalysis/parity.py b/stegano/steganalysis/parity.py index e0e76c6..0b7d0e4 100644 --- a/stegano/steganalysis/parity.py +++ b/stegano/steganalysis/parity.py @@ -1,7 +1,7 @@ #!/usr/bin/env python #-*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stegano - Stegano is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano diff --git a/stegano/steganalysis/statistics.py b/stegano/steganalysis/statistics.py index 45794a6..d85248b 100644 --- a/stegano/steganalysis/statistics.py +++ b/stegano/steganalysis/statistics.py @@ -1,7 +1,7 @@ #!/usr/bin/env python #-*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stegano - Stegano is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano diff --git a/stegano/tools.py b/stegano/tools.py index 897bba4..9870000 100755 --- a/stegano/tools.py +++ b/stegano/tools.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Stéganô - Stéganô is a basic Python Steganography module. +# Stegano - Stéganô is a basic Python Steganography module. # Copyright (C) 2010-2019 Cédric Bonhomme - https://www.cedricbonhomme.org # # For more information : https://github.com/cedricbonhomme/Stegano