From 71f6c08c2823e5ea8aac81ebf7090d216b7a068c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Bonhomme?= Date: Tue, 17 Dec 2019 09:18:37 +0100 Subject: [PATCH] Improved code style. --- stegano/exifHeader/__init__.py | 2 +- stegano/exifHeader/exifHeader.py | 6 +- stegano/lsb/__init__.py | 2 +- stegano/lsb/lsb.py | 13 +--- stegano/lsbset/__init__.py | 2 +- stegano/lsbset/generators.py | 64 ++++++++-------- stegano/lsbset/lsbset.py | 10 +-- stegano/red/__init__.py | 2 +- stegano/steganalysis/__init__.py | 2 +- stegano/steganalysis/statistics.py | 12 +-- stegano/tools.py | 4 +- tests/test_exifHeader.py | 43 ++++++----- tests/test_generators.py | 119 ++++++++++++++++++----------- tests/test_lsb.py | 70 ++++++++++------- tests/test_lsbset.py | 115 +++++++++++++++++----------- tests/test_red.py | 4 +- tests/test_steganalysis.py | 9 +-- tests/test_tools.py | 77 +++++++++++-------- tools/run_mypy.py | 32 +++++--- 19 files changed, 335 insertions(+), 253 deletions(-) diff --git a/stegano/exifHeader/__init__.py b/stegano/exifHeader/__init__.py index a4c17d0..a64a46c 100644 --- a/stegano/exifHeader/__init__.py +++ b/stegano/exifHeader/__init__.py @@ -1,4 +1,4 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from .exifHeader import * diff --git a/stegano/exifHeader/exifHeader.py b/stegano/exifHeader/exifHeader.py index 7a79dc9..af25f30 100644 --- a/stegano/exifHeader/exifHeader.py +++ b/stegano/exifHeader/exifHeader.py @@ -30,11 +30,7 @@ from stegano import tools def hide( - input_image_file, - img_enc, - secret_message=None, - secret_file=None, - img_format=None, + input_image_file, img_enc, secret_message=None, secret_file=None, img_format=None, ): """Hide a message (string) in an image. """ diff --git a/stegano/lsb/__init__.py b/stegano/lsb/__init__.py index a3c093c..1ffc44a 100644 --- a/stegano/lsb/__init__.py +++ b/stegano/lsb/__init__.py @@ -1,4 +1,4 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from .lsb import * diff --git a/stegano/lsb/lsb.py b/stegano/lsb/lsb.py index 88f0fe0..6550e8f 100755 --- a/stegano/lsb/lsb.py +++ b/stegano/lsb/lsb.py @@ -47,9 +47,7 @@ def hide( if img.mode not in ["RGB", "RGBA"]: if not auto_convert_rgb: - print( - "The mode of the image is not RGB. Mode is {}".format(img.mode) - ) + print("The mode of the image is not RGB. Mode is {}".format(img.mode)) answer = input("Convert the image to RGB ? [Y / n]\n") or "Y" if answer.lower() == "n": raise Exception("Not a RGB image.") @@ -67,9 +65,7 @@ def hide( len_message_bits = len(message_bits) if len_message_bits > npixels * 3: raise Exception( - "The message you want to hide is too long: {}".format( - message_length - ) + "The message you want to hide is too long: {}".format(message_length) ) for row in range(height): for col in range(width): @@ -101,10 +97,7 @@ def hide( return encoded -def reveal(input_image: Union[str, IO[bytes]], - encoding: str = "UTF-8", - shift: int = 0 -): +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) diff --git a/stegano/lsbset/__init__.py b/stegano/lsbset/__init__.py index 034bb97..22954f0 100644 --- a/stegano/lsbset/__init__.py +++ b/stegano/lsbset/__init__.py @@ -1,4 +1,4 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from .lsbset import * diff --git a/stegano/lsbset/generators.py b/stegano/lsbset/generators.py index c2b1912..6a22ac0 100644 --- a/stegano/lsbset/generators.py +++ b/stegano/lsbset/generators.py @@ -175,36 +175,38 @@ def log_gen() -> Iterator[int]: y = y + int(adder) -polys = {2: [2, 1], - 3: [3, 1], - 4: [4, 1], - 5: [5, 2], - 6: [6, 1], - 7: [7, 1], - 8: [8, 4, 3, 2], - 9: [9, 4], - 10: [10, 3], - 11: [11, 2], - 12: [12, 6, 4, 1], - 13: [13, 4, 3, 1], - 14: [14, 8, 6, 1], - 15: [15, 1], - 16: [16, 12, 3, 1], - 17: [17, 3], - 18: [18, 7], - 19: [19, 5, 2, 1], - 20: [20, 3], - 21: [21, 2], - 22: [22, 1], - 23: [23, 5], - 24: [24, 7, 2, 1], - 25: [25, 3], - 26: [26, 6, 2, 1], - 27: [27, 5, 2, 1], - 28: [28, 3], - 29: [29, 2], - 30: [30, 23, 2, 1], - 31: [31, 3]} +polys = { + 2: [2, 1], + 3: [3, 1], + 4: [4, 1], + 5: [5, 2], + 6: [6, 1], + 7: [7, 1], + 8: [8, 4, 3, 2], + 9: [9, 4], + 10: [10, 3], + 11: [11, 2], + 12: [12, 6, 4, 1], + 13: [13, 4, 3, 1], + 14: [14, 8, 6, 1], + 15: [15, 1], + 16: [16, 12, 3, 1], + 17: [17, 3], + 18: [18, 7], + 19: [19, 5, 2, 1], + 20: [20, 3], + 21: [21, 2], + 22: [22, 1], + 23: [23, 5], + 24: [24, 7, 2, 1], + 25: [25, 3], + 26: [26, 6, 2, 1], + 27: [27, 5, 2, 1], + 28: [28, 3], + 29: [29, 2], + 30: [30, 23, 2, 1], + 31: [31, 3], +} def LFSR(m: int) -> Iterator[int]: @@ -227,5 +229,5 @@ def LFSR(m: int) -> Iterator[int]: # Add the feedback bit state.insert(0, feedback) # Convert the registers to an int - out = sum([e * (2**i) for i, e in enumerate(state)]) + out = sum([e * (2 ** i) for i, e in enumerate(state)]) yield out diff --git a/stegano/lsbset/lsbset.py b/stegano/lsbset/lsbset.py index fd8dec0..7108f40 100644 --- a/stegano/lsbset/lsbset.py +++ b/stegano/lsbset/lsbset.py @@ -50,9 +50,7 @@ def hide( if img.mode not in ["RGB", "RGBA"]: if not auto_convert_rgb: - print( - "The mode of the image is not RGB. Mode is {}".format(img.mode) - ) + print("The mode of the image is not RGB. Mode is {}".format(img.mode)) answer = input("Convert the image to RGB ? [Y / n]\n") or "Y" if answer.lower() == "n": raise Exception("Not a RGB image.") @@ -70,9 +68,7 @@ def hide( len_message_bits = len(message_bits) if len_message_bits > npixels * 3: raise Exception( - "The message you want to hide is too long: {}".format( - message_length - ) + "The message you want to hide is too long: {}".format(message_length) ) while shift != 0: next(generator) @@ -126,7 +122,7 @@ def reveal( while True: generated_number = next(generator) # color = [r, g, b] - for color in img_list[generated_number][:3]: # ignore the alpha + 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]: diff --git a/stegano/red/__init__.py b/stegano/red/__init__.py index 72a6728..d3c8604 100644 --- a/stegano/red/__init__.py +++ b/stegano/red/__init__.py @@ -1,4 +1,4 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from .red import * diff --git a/stegano/steganalysis/__init__.py b/stegano/steganalysis/__init__.py index a64a030..239d66c 100644 --- a/stegano/steganalysis/__init__.py +++ b/stegano/steganalysis/__init__.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- from .parity import * from .statistics import * diff --git a/stegano/steganalysis/statistics.py b/stegano/steganalysis/statistics.py index 985ecf1..cda10a0 100644 --- a/stegano/steganalysis/statistics.py +++ b/stegano/steganalysis/statistics.py @@ -32,26 +32,28 @@ from PIL import Image from collections import Counter from collections import OrderedDict + def steganalyse(img): """ Steganlysis of the LSB technique. """ encoded = img.copy() width, height = img.size - colours_counter = Counter() # type: typing.Counter[int] + colours_counter = Counter() # type: typing.Counter[int] for row in range(height): for col in range(width): r, g, b = img.getpixel((col, row)) colours_counter[r] += 1 most_common = colours_counter.most_common(10) - dict_colours = OrderedDict(sorted(list(colours_counter.items()), - key=lambda t: t[1])) + dict_colours = OrderedDict( + sorted(list(colours_counter.items()), key=lambda t: t[1]) + ) - colours = 0 # type: float + colours = 0 # type: float for colour in list(dict_colours.keys()): colours += colour colours = colours / len(dict_colours) - #return colours.most_common(10) + # return colours.most_common(10) return list(dict_colours.keys())[:30], most_common diff --git a/stegano/tools.py b/stegano/tools.py index bf40d1b..4ec1eae 100755 --- a/stegano/tools.py +++ b/stegano/tools.py @@ -41,9 +41,7 @@ def a2bits(chars: str) -> str: >>> a2bits("Hello World!") '010010000110010101101100011011000110111100100000010101110110111101110010011011000110010000100001' """ - return bin(reduce(lambda x, y: (x << 8) + y, (ord(c) for c in chars), 1))[ - 3: - ] + return bin(reduce(lambda x, y: (x << 8) + y, (ord(c) for c in chars), 1))[3:] def a2bits_list(chars: str, encoding: str = "UTF-8") -> List[str]: diff --git a/tests/test_exifHeader.py b/tests/test_exifHeader.py index 758ef3c..0ecc6c7 100644 --- a/tests/test_exifHeader.py +++ b/tests/test_exifHeader.py @@ -31,14 +31,15 @@ import io from stegano import exifHeader -class TestEXIFHeader(unittest.TestCase): +class TestEXIFHeader(unittest.TestCase): def test_hide_empty_message(self): """Test hiding the empty string. """ - secret = exifHeader.hide("./tests/sample-files/20160505T130442.jpg", - "./image.jpg", secret_message="") - #secret.save(""./image.png"") + secret = exifHeader.hide( + "./tests/sample-files/20160505T130442.jpg", "./image.jpg", secret_message="" + ) + # secret.save(""./image.png"") clear_message = exifHeader.reveal("./image.jpg") @@ -48,17 +49,21 @@ class TestEXIFHeader(unittest.TestCase): messages_to_hide = ["a", "foo", "Hello World!", ":Python:"] for message in messages_to_hide: - secret = exifHeader.hide("./tests/sample-files/20160505T130442.jpg", - "./image.jpg", secret_message=message) + secret = exifHeader.hide( + "./tests/sample-files/20160505T130442.jpg", + "./image.jpg", + secret_message=message, + ) clear_message = exifHeader.reveal("./image.jpg") self.assertEqual(message, message) def test_with_image_without_exif_data(self): - secret = exifHeader.hide("./tests/sample-files/Lenna.jpg", - "./image.jpg", secret_message="") - #secret.save(""./image.png"") + secret = exifHeader.hide( + "./tests/sample-files/Lenna.jpg", "./image.jpg", secret_message="" + ) + # secret.save(""./image.png"") clear_message = exifHeader.reveal("./image.jpg") @@ -68,17 +73,20 @@ class TestEXIFHeader(unittest.TestCase): text_file_to_hide = "./tests/sample-files/lorem_ipsum.txt" with open(text_file_to_hide, "rb") as f: message = f.read() - secret = exifHeader.hide("./tests/sample-files/20160505T130442.jpg", - img_enc="./image.jpg", - secret_file=text_file_to_hide) + secret = exifHeader.hide( + "./tests/sample-files/20160505T130442.jpg", + img_enc="./image.jpg", + secret_file=text_file_to_hide, + ) clear_message = exifHeader.reveal("./image.jpg") self.assertEqual(message, clear_message) def test_with_png_image(self): - secret = exifHeader.hide("./tests/sample-files/Lenna.png", - "./image.png", secret_message="Secret") - #secret.save(""./image.png"") + secret = exifHeader.hide( + "./tests/sample-files/Lenna.png", "./image.png", secret_message="Secret" + ) + # secret.save(""./image.png"") with self.assertRaises(ValueError): clear_message = exifHeader.reveal("./image.png") @@ -86,7 +94,7 @@ class TestEXIFHeader(unittest.TestCase): def test_with_bytes(self): outputBytes = io.BytesIO() message = b"Secret" - with open("./tests/sample-files/20160505T130442.jpg", 'rb') as f: + with open("./tests/sample-files/20160505T130442.jpg", "rb") as f: exifHeader.hide(f, outputBytes, secret_message=message) clear_message = exifHeader.reveal(outputBytes) @@ -102,5 +110,6 @@ class TestEXIFHeader(unittest.TestCase): except: pass -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/tests/test_generators.py b/tests/test_generators.py index ccb5b01..70c6b94 100644 --- a/tests/test_generators.py +++ b/tests/test_generators.py @@ -32,109 +32,140 @@ from stegano.lsbset import generators class TestGenerators(unittest.TestCase): - def test_identity(self): """Test the identity generator. """ - self.assertEqual(tuple(itertools.islice(generators.identity(), 15)), - (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)) + self.assertEqual( + tuple(itertools.islice(generators.identity(), 15)), + (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), + ) def test_fibonacci(self): """Test the Fibonacci generator. """ - self.assertEqual(tuple(itertools.islice(generators.fibonacci(), 20)), - (1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, - 987, 1597, 2584, 4181, 6765, 10946)) + self.assertEqual( + tuple(itertools.islice(generators.fibonacci(), 20)), + ( + 1, + 2, + 3, + 5, + 8, + 13, + 21, + 34, + 55, + 89, + 144, + 233, + 377, + 610, + 987, + 1597, + 2584, + 4181, + 6765, + 10946, + ), + ) def test_eratosthenes(self): """Test the Eratosthenes sieve. """ - with open('./tests/expected-results/eratosthenes', 'r') as f: - self.assertEqual(tuple(itertools.islice(generators.eratosthenes(), 168)), - tuple(int(line) for line in f)) + with open("./tests/expected-results/eratosthenes", "r") as f: + self.assertEqual( + tuple(itertools.islice(generators.eratosthenes(), 168)), + tuple(int(line) for line in f), + ) def test_composite(self): """Test the composite sieve. """ - with open('./tests/expected-results/composite', 'r') as f: - self.assertEqual(tuple(itertools.islice(generators.composite(), 114)), - tuple(int(line) for line in f)) + with open("./tests/expected-results/composite", "r") as f: + self.assertEqual( + tuple(itertools.islice(generators.composite(), 114)), + tuple(int(line) for line in f), + ) def test_fermat(self): """Test the Fermat generator. """ - with open('./tests/expected-results/fermat', 'r') as f: - self.assertEqual(tuple(itertools.islice(generators.fermat(), 9)), - tuple(int(line) for line in f)) + with open("./tests/expected-results/fermat", "r") as f: + self.assertEqual( + tuple(itertools.islice(generators.fermat(), 9)), + tuple(int(line) for line in f), + ) def test_triangular_numbers(self): """Test the Triangular numbers generator. """ - with open('./tests/expected-results/triangular_numbers', 'r') as f: - self.assertEqual(tuple(itertools.islice(generators.triangular_numbers(), 54)), - tuple(int(line) for line in f)) + with open("./tests/expected-results/triangular_numbers", "r") as f: + self.assertEqual( + tuple(itertools.islice(generators.triangular_numbers(), 54)), + tuple(int(line) for line in f), + ) def test_mersenne(self): """Test the Mersenne generator. """ - with open('./tests/expected-results/mersenne', 'r') as f: - self.assertEqual(tuple(itertools.islice(generators.mersenne(), 20)), - tuple(int(line) for line in f)) + with open("./tests/expected-results/mersenne", "r") as f: + self.assertEqual( + tuple(itertools.islice(generators.mersenne(), 20)), + tuple(int(line) for line in f), + ) def test_carmichael(self): """Test the Carmichael generator. """ - with open('./tests/expected-results/carmichael', 'r') as f: - self.assertEqual(tuple(itertools.islice(generators.carmichael(), 33)), - tuple(int(line) for line in f)) + with open("./tests/expected-results/carmichael", "r") as f: + self.assertEqual( + tuple(itertools.islice(generators.carmichael(), 33)), + tuple(int(line) for line in f), + ) def test_ackermann_slow(self): """Test the Ackermann set. """ - with open('./tests/expected-results/ackermann', 'r') as f: - self.assertEqual(generators.ackermann_slow( - 3, 1), int(f.readline())) - self.assertEqual(generators.ackermann_slow( - 3, 2), int(f.readline())) + with open("./tests/expected-results/ackermann", "r") as f: + self.assertEqual(generators.ackermann_slow(3, 1), int(f.readline())) + self.assertEqual(generators.ackermann_slow(3, 2), int(f.readline())) def test_ackermann_naive(self): """Test the Naive Ackermann generator """ gen = generators.ackermann_naive(3) next(gen) - with open('./tests/expected-results/ackermann', 'r') as f: + with open("./tests/expected-results/ackermann", "r") as f: self.assertEqual(next(gen), int(f.readline())) self.assertEqual(next(gen), int(f.readline())) def test_ackermann_fast(self): """Test the Ackermann set. """ - with open('./tests/expected-results/ackermann', 'r') as f: - 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())) + with open("./tests/expected-results/ackermann", "r") as f: + 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())) def test_ackermann(self): """Test the Ackermann generator """ gen = generators.ackermann(3) next(gen) - with open('./tests/expected-results/ackermann', 'r') as f: + with open("./tests/expected-results/ackermann", "r") as f: self.assertEqual(next(gen), int(f.readline())) self.assertEqual(next(gen), int(f.readline())) def test_LFSR(self): """ Test the LFSR generator """ - with open('./tests/expected-results/LFSR', 'r') as f: - self.assertEqual(tuple(itertools.islice(generators.LFSR(2**8), 256)), - tuple(int(line) for line in f)) + with open("./tests/expected-results/LFSR", "r") as f: + self.assertEqual( + tuple(itertools.islice(generators.LFSR(2 ** 8), 256)), + tuple(int(line) for line in f), + ) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/test_lsb.py b/tests/test_lsb.py index 8fd0e0c..203c3c7 100644 --- a/tests/test_lsb.py +++ b/tests/test_lsb.py @@ -33,8 +33,8 @@ from unittest.mock import patch from stegano import lsb -class TestLSB(unittest.TestCase): +class TestLSB(unittest.TestCase): def test_hide_empty_message(self): """ Test hiding the empty string. @@ -43,7 +43,7 @@ class TestLSB(unittest.TestCase): secret = lsb.hide("./tests/sample-files/Lenna.png", "") def test_hide_and_reveal(self): - messages_to_hide = ['a', 'foo', 'Hello World!', ':Python:'] + messages_to_hide = ["a", "foo", "Hello World!", ":Python:"] for message in messages_to_hide: secret = lsb.hide("./tests/sample-files/Lenna.png", message) secret.save("./image.png") @@ -52,45 +52,57 @@ class TestLSB(unittest.TestCase): self.assertEqual(message, clear_message) def test_hide_and_reveal_UTF32LE(self): - messages_to_hide = 'I love 🍕 and 🍫!' - secret = lsb.hide("./tests/sample-files/Lenna.png", - messages_to_hide, encoding='UTF-32LE') + messages_to_hide = "I love 🍕 and 🍫!" + secret = lsb.hide( + "./tests/sample-files/Lenna.png", messages_to_hide, encoding="UTF-32LE" + ) secret.save("./image.png") - clear_message = lsb.reveal("./image.png", encoding='UTF-32LE') + clear_message = lsb.reveal("./image.png", encoding="UTF-32LE") self.assertEqual(messages_to_hide, clear_message) 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: - secret = lsb.hide("./tests/sample-files/transparent.png", - message, encoding='UTF-32LE') + secret = lsb.hide( + "./tests/sample-files/transparent.png", message, encoding="UTF-32LE" + ) secret.save("./image.png") - clear_message = lsb.reveal("./image.png", encoding='UTF-32LE') + clear_message = lsb.reveal("./image.png", encoding="UTF-32LE") self.assertEqual(message, clear_message) - @patch('builtins.input', return_value='y') + @patch("builtins.input", return_value="y") def test_manual_convert_rgb(self, input): - message_to_hide = 'I love 🍕 and 🍫!' - secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png", - message_to_hide, encoding='UTF-32LE') + message_to_hide = "I love 🍕 and 🍫!" + secret = lsb.hide( + "./tests/sample-files/Lenna-grayscale.png", + 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): - message_to_hide = 'I love 🍕 and 🍫!' + message_to_hide = "I love 🍕 and 🍫!" with self.assertRaises(Exception): - secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png", - message_to_hide, encoding='UTF-32LE') + secret = lsb.hide( + "./tests/sample-files/Lenna-grayscale.png", + message_to_hide, + encoding="UTF-32LE", + ) def test_auto_convert_rgb(self): - message_to_hide = 'I love 🍕 and 🍫!' - secret = lsb.hide("./tests/sample-files/Lenna-grayscale.png", - message_to_hide, encoding='UTF-32LE', auto_convert_rgb=True) + message_to_hide = "I love 🍕 and 🍫!" + secret = lsb.hide( + "./tests/sample-files/Lenna-grayscale.png", + message_to_hide, + encoding="UTF-32LE", + auto_convert_rgb=True, + ) 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" with open(text_file_to_hide) as f: message = f.read() secret = lsb.hide("./tests/sample-files/Lenna.png", message) @@ -108,23 +120,23 @@ class TestLSB(unittest.TestCase): secret.save("./image.png") clear_message = lsb.reveal("./image.png") - clear_message += '===' + clear_message += "===" clear_message = base64.b64decode(clear_message) - with open('file1', 'wb') as f: + with open("file1", "wb") as f: f.write(clear_message) - with open('file1', 'rb') as bin_file: + with open("file1", "rb") as bin_file: encoded_string = base64.b64encode(bin_file.read()) message1 = encoded_string.decode() self.assertEqual(message, message1) try: - os.unlink('./file1') + os.unlink("./file1") except: pass def test_with_too_long_message(self): with open("./tests/sample-files/lorem_ipsum.txt") as f: message = f.read() - message += message*2 + message += message * 2 with self.assertRaises(Exception): lsb.hide("./tests/sample-files/Lenna.png", message) @@ -133,7 +145,7 @@ class TestLSB(unittest.TestCase): for message in messages_to_hide: outputBytes = io.BytesIO() - with open("./tests/sample-files/20160505T130442.jpg", 'rb') as f: + with open("./tests/sample-files/20160505T130442.jpg", "rb") as f: bytes_image = lsb.hide(f, message) bytes_image.save(outputBytes, "PNG") outputBytes.seek(0) @@ -162,5 +174,5 @@ class TestLSB(unittest.TestCase): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/test_lsbset.py b/tests/test_lsbset.py index e256b51..0823478 100644 --- a/tests/test_lsbset.py +++ b/tests/test_lsbset.py @@ -33,96 +33,111 @@ from unittest.mock import patch from stegano import lsbset from stegano.lsbset import generators -class TestLSBSet(unittest.TestCase): +class TestLSBSet(unittest.TestCase): def test_hide_empty_message(self): """ Test hiding the empty string. """ with self.assertRaises(AssertionError): - secret = lsbset.hide("./tests/sample-files/Lenna.png", "", - generators.eratosthenes()) + secret = lsbset.hide( + "./tests/sample-files/Lenna.png", "", generators.eratosthenes() + ) def test_hide_and_reveal(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()) + secret = lsbset.hide( + "./tests/sample-files/Lenna.png", message, generators.eratosthenes() + ) secret.save("./image.png") - clear_message = lsbset.reveal("./image.png", - generators.eratosthenes()) + clear_message = lsbset.reveal("./image.png", 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 = 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)) + 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:"] for message in messages_to_hide: - secret = lsbset.hide("./tests/sample-files/Lenna.png", message, - generators.eratosthenes(), 4) + 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) + clear_message = lsbset.reveal("./image.png", generators.eratosthenes(), 4) self.assertEqual(message, clear_message) def test_hide_and_reveal_UTF32LE(self): - messages_to_hide = 'I love 🍕 and 🍫!' - secret = lsbset.hide("./tests/sample-files/Lenna.png", - messages_to_hide, - generators.eratosthenes(), - encoding='UTF-32LE') + messages_to_hide = "I love 🍕 and 🍫!" + secret = lsbset.hide( + "./tests/sample-files/Lenna.png", + messages_to_hide, + generators.eratosthenes(), + encoding="UTF-32LE", + ) secret.save("./image.png") - clear_message = lsbset.reveal("./image.png", generators.eratosthenes(), - encoding='UTF-32LE') + clear_message = lsbset.reveal( + "./image.png", generators.eratosthenes(), encoding="UTF-32LE" + ) self.assertEqual(messages_to_hide, clear_message) def test_with_transparent_png(self): messages_to_hide = ["a", "foo", "Hello World!", ":Python:"] for message in messages_to_hide: - secret = lsbset.hide("./tests/sample-files/transparent.png", - message, generators.eratosthenes()) + secret = lsbset.hide( + "./tests/sample-files/transparent.png", + message, + generators.eratosthenes(), + ) secret.save("./image.png") - clear_message = lsbset.reveal("./image.png", - generators.eratosthenes()) + clear_message = lsbset.reveal("./image.png", generators.eratosthenes()) self.assertEqual(message, clear_message) - @patch('builtins.input', return_value='y') + @patch("builtins.input", return_value="y") def test_manual_convert_rgb(self, input): message_to_hide = "Hello World!" - secret = lsbset.hide("./tests/sample-files/Lenna-grayscale.png", - message_to_hide, generators.eratosthenes()) + secret = lsbset.hide( + "./tests/sample-files/Lenna-grayscale.png", + message_to_hide, + generators.eratosthenes(), + ) - @patch('builtins.input', return_value='n') + @patch("builtins.input", return_value="n") def test_refuse_convert_rgb(self, input): message_to_hide = "Hello World!" with self.assertRaises(Exception): - secret = lsbset.hide("./tests/sample-files/Lenna-grayscale.png", - message_to_hide, generators.eratosthenes()) + secret = lsbset.hide( + "./tests/sample-files/Lenna-grayscale.png", + message_to_hide, + generators.eratosthenes(), + ) def test_with_location_of_image_as_argument(self): messages_to_hide = ["Hello World!"] for message in messages_to_hide: outputBytes = io.BytesIO() - bytes_image = lsbset.hide("./tests/sample-files/20160505T130442.jpg", message, - generators.identity()) + bytes_image = lsbset.hide( + "./tests/sample-files/20160505T130442.jpg", + message, + generators.identity(), + ) bytes_image.save(outputBytes, "PNG") outputBytes.seek(0) @@ -132,22 +147,27 @@ class TestLSBSet(unittest.TestCase): def test_auto_convert_rgb(self): message_to_hide = "Hello World!" - secret = lsbset.hide("./tests/sample-files/Lenna-grayscale.png", - message_to_hide, generators.eratosthenes(), - auto_convert_rgb=True) + secret = lsbset.hide( + "./tests/sample-files/Lenna-grayscale.png", + message_to_hide, + generators.eratosthenes(), + auto_convert_rgb=True, + ) def test_with_too_long_message(self): with open("./tests/sample-files/lorem_ipsum.txt") as f: message = f.read() - message += message*2 + message += message * 2 with self.assertRaises(Exception): - lsbset.hide("./tests/sample-files/Lenna.png", message, - generators.identity()) + lsbset.hide( + "./tests/sample-files/Lenna.png", message, generators.identity() + ) def test_hide_and_reveal_with_bad_generator(self): message_to_hide = "Hello World!" - secret = lsbset.hide("./tests/sample-files/Lenna.png", message_to_hide, - generators.eratosthenes()) + secret = lsbset.hide( + "./tests/sample-files/Lenna.png", message_to_hide, generators.eratosthenes() + ) secret.save("./image.png") with self.assertRaises(IndexError): @@ -156,8 +176,11 @@ class TestLSBSet(unittest.TestCase): def test_with_unknown_generator(self): message_to_hide = "Hello World!" with self.assertRaises(AttributeError): - secret = lsbset.hide("./tests/sample-files/Lenna.png", - message_to_hide, generators.eratosthene()) + secret = lsbset.hide( + "./tests/sample-files/Lenna.png", + message_to_hide, + generators.eratosthene(), + ) def tearDown(self): try: @@ -166,5 +189,5 @@ class TestLSBSet(unittest.TestCase): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/test_red.py b/tests/test_red.py index 4e9d224..db6ba23 100644 --- a/tests/test_red.py +++ b/tests/test_red.py @@ -29,8 +29,8 @@ import unittest from stegano import red -class TestRed(unittest.TestCase): +class TestRed(unittest.TestCase): def test_hide_empty_message(self): """ Test hiding the empty string. @@ -62,5 +62,5 @@ class TestRed(unittest.TestCase): pass -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/test_steganalysis.py b/tests/test_steganalysis.py index 0eb60d5..65cfdc4 100644 --- a/tests/test_steganalysis.py +++ b/tests/test_steganalysis.py @@ -37,11 +37,10 @@ from PIL import Image, ImageChops class TestSteganalysis(unittest.TestCase): - def test_parity(self): """Test stegano.steganalysis.parity """ - text_file_to_hide = './tests/sample-files/lorem_ipsum.txt' + text_file_to_hide = "./tests/sample-files/lorem_ipsum.txt" with open(text_file_to_hide) as f: message = f.read() secret = lsb.hide("./tests/sample-files/Lenna.png", message) @@ -53,7 +52,7 @@ class TestSteganalysis(unittest.TestCase): def test_parity_rgba(self): """ Test that stegano.steganalysis.parity works with RGBA images """ - img = Image.open('./tests/sample-files/transparent.png') + img = Image.open("./tests/sample-files/transparent.png") analysis = parity.steganalyse(img) target = Image.open("./tests/expected-results/parity_rgba.png") diff = ImageChops.difference(target, analysis).getbbox() @@ -63,12 +62,12 @@ class TestSteganalysis(unittest.TestCase): """ Test stegano.steganalysis.statistics """ image = Image.open("./tests/sample-files/Lenna.png") - stats = str(statistics.steganalyse(image)) + '\n' + stats = str(statistics.steganalyse(image)) + "\n" file = open("./tests/expected-results/statistics") target = file.read() file.close() self.assertEqual(stats, target) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() diff --git a/tests/test_tools.py b/tests/test_tools.py index 9579a2b..c16bec2 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -31,48 +31,61 @@ import io from stegano import tools -class TestTools(unittest.TestCase): +class TestTools(unittest.TestCase): def test_a2bits(self): bits = tools.a2bits("Hello World!") - self.assertEqual(bits, '010010000110010101101100011011000110111100100000010101110110111101110010011011000110010000100001') + self.assertEqual( + bits, + "010010000110010101101100011011000110111100100000010101110110111101110010011011000110010000100001", + ) def test_a2bits_list_UTF8(self): list_of_bits = tools.a2bits_list("Hello World!") - self.assertEqual(list_of_bits, ['01001000', - '01100101', - '01101100', - '01101100', - '01101111', - '00100000', - '01010111', - '01101111', - '01110010', - '01101100', - '01100100', - '00100001']) + self.assertEqual( + list_of_bits, + [ + "01001000", + "01100101", + "01101100", + "01101100", + "01101111", + "00100000", + "01010111", + "01101111", + "01110010", + "01101100", + "01100100", + "00100001", + ], + ) def test_a2bits_list_UTF32LE(self): - list_of_bits = tools.a2bits_list("Hello World!", 'UTF-32LE') - self.assertEqual(list_of_bits, ['00000000000000000000000001001000', - '00000000000000000000000001100101', - '00000000000000000000000001101100', - '00000000000000000000000001101100', - '00000000000000000000000001101111', - '00000000000000000000000000100000', - '00000000000000000000000001010111', - '00000000000000000000000001101111', - '00000000000000000000000001110010', - '00000000000000000000000001101100', - '00000000000000000000000001100100', - '00000000000000000000000000100001']) + list_of_bits = tools.a2bits_list("Hello World!", "UTF-32LE") + self.assertEqual( + list_of_bits, + [ + "00000000000000000000000001001000", + "00000000000000000000000001100101", + "00000000000000000000000001101100", + "00000000000000000000000001101100", + "00000000000000000000000001101111", + "00000000000000000000000000100000", + "00000000000000000000000001010111", + "00000000000000000000000001101111", + "00000000000000000000000001110010", + "00000000000000000000000001101100", + "00000000000000000000000001100100", + "00000000000000000000000000100001", + ], + ) def test_n_at_a_time(self): - result = tools.n_at_a_time([1, 2, 3, 4, 5], 2, 'X') - self.assertEqual(list(result), [(1, 2), (3, 4), (5, 'X')]) + result = tools.n_at_a_time([1, 2, 3, 4, 5], 2, "X") + self.assertEqual(list(result), [(1, 2), (3, 4), (5, "X")]) def test_binary2base64(self): - with open('./tests/expected-results/binary2base64', 'r') as f: - expected_value = f.read() - value = tools.binary2base64('tests/sample-files/free-software-song.ogg') + with open("./tests/expected-results/binary2base64", "r") as f: + expected_value = f.read() + value = tools.binary2base64("tests/sample-files/free-software-song.ogg") self.assertEqual(expected_value, value) diff --git a/tools/run_mypy.py b/tools/run_mypy.py index 7a1efc2..e3d2773 100644 --- a/tools/run_mypy.py +++ b/tools/run_mypy.py @@ -1,21 +1,29 @@ import subprocess import sys -modules = ['stegano/tools.py', - 'stegano/lsb/lsb.py', - 'stegano/lsbset/lsbset.py', - 'stegano/lsbset/generators.py', - 'stegano/red/red.py', - 'stegano/exifHeader/exifHeader.py', - 'stegano/steganalysis/parity.py', - 'stegano/steganalysis/statistics.py'] +modules = [ + "stegano/tools.py", + "stegano/lsb/lsb.py", + "stegano/lsbset/lsbset.py", + "stegano/lsbset/generators.py", + "stegano/red/red.py", + "stegano/exifHeader/exifHeader.py", + "stegano/steganalysis/parity.py", + "stegano/steganalysis/statistics.py", +] exit_codes = [] for module in modules: - rc = subprocess.call(['mypy', '--ignore-missing-imports', - '--check-untyped-defs', - '--follow-imports', 'skip', module], - ) + rc = subprocess.call( + [ + "mypy", + "--ignore-missing-imports", + "--check-untyped-defs", + "--follow-imports", + "skip", + module, + ], + ) exit_codes.append(rc) sys.exit(max(exit_codes))