Moved sample files and updated documentation.
10
README.rst
|
@ -23,8 +23,6 @@ Usage
|
||||||
|
|
||||||
A `tutorial <https://stegano.readthedocs.io>`_ is available.
|
A `tutorial <https://stegano.readthedocs.io>`_ is available.
|
||||||
|
|
||||||
There are also some examples in the folder
|
|
||||||
`examples <https://github.com/cedricbonhomme/Stegano/tree/master/examples>`_.
|
|
||||||
|
|
||||||
Use Stéganô as a library in your Python program
|
Use Stéganô as a library in your Python program
|
||||||
'''''''''''''''''''''''''''''''''''''''''''''''
|
'''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
@ -34,8 +32,8 @@ appropriate steganography technique. For example:
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
>>> from stegano import slsb
|
>>> from stegano import lsb
|
||||||
>>> secret = slsb.hide("./pictures/Lenna.png", "Hello World")
|
>>> secret = slsb.hide("./tests/sample-files/Lenna.png", "Hello World")
|
||||||
>>> secret.save("./Lenna-secret.png")
|
>>> secret.save("./Lenna-secret.png")
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,13 +42,13 @@ Use Stéganô as a program
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
$ slsb --hide -i ../examples/pictures/Lenna.png -o Lena1.png -m "Secret Message"
|
$ lsb --hide -i ./tests/sample-files/Lenna.png -o Lena1.png -m "Secret Message"
|
||||||
|
|
||||||
Hide the message with Sieve of Eratosthenes:
|
Hide the message with Sieve of Eratosthenes:
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
$ slsb-set --hide -i ../examples/pictures/Lenna.png -o Lena2.png --generator eratosthenes -m 'Secret Message'
|
$ lsb-set --hide -i ./tests/sample-files/Lenna.png -o Lena2.png --generator eratosthenes -m 'Secret Message'
|
||||||
|
|
||||||
|
|
||||||
Running the tests
|
Running the tests
|
||||||
|
|
|
@ -29,7 +29,7 @@ LSB method
|
||||||
[GCC 4.9.2] on linux
|
[GCC 4.9.2] on linux
|
||||||
Type "help", "copyright", "credits" or "license" for more information.
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
>>> from stegano import slsb
|
>>> from stegano import slsb
|
||||||
>>> secret = slsb.hide("./examples/pictures/Lenna.png", "Hello world!")
|
>>> secret = slsb.hide("./tests/sample-files/Lenna.png", "Hello world!")
|
||||||
>>> secret.save("./Lenna-secret.png")
|
>>> secret.save("./Lenna-secret.png")
|
||||||
>>> print(slsb.reveal("./Lenna-secret.png"))
|
>>> print(slsb.reveal("./Lenna-secret.png"))
|
||||||
Hello world!
|
Hello world!
|
||||||
|
@ -45,7 +45,7 @@ For JPEG and TIFF images.
|
||||||
[GCC 4.9.2] on linux
|
[GCC 4.9.2] on linux
|
||||||
Type "help", "copyright", "credits" or "license" for more information.
|
Type "help", "copyright", "credits" or "license" for more information.
|
||||||
>>> from stegano import exifHeader
|
>>> from stegano import exifHeader
|
||||||
>>> secret = exifHeader.hide("./examples/pictures/20160505T130442.jpg",
|
>>> secret = exifHeader.hide("./tests/sample-files/20160505T130442.jpg",
|
||||||
"./image.jpg", secret_message="Hello world!")
|
"./image.jpg", secret_message="Hello world!")
|
||||||
>>> print(exifHeader.reveal("./image.jpg"))
|
>>> print(exifHeader.reveal("./image.jpg"))
|
||||||
|
|
||||||
|
@ -80,13 +80,13 @@ Display help
|
||||||
Output for the binary secret (Text or any binary
|
Output for the binary secret (Text or any binary
|
||||||
file).
|
file).
|
||||||
|
|
||||||
Hide and reveal a text message
|
Hide and reveal a text message with the LSB method
|
||||||
------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ slsb --hide -i ./pictures/Lenna.png -o ./pictures/Lenna_enc.png -m HelloWorld!
|
$ lsb --hide -i ./tests/sample-files/Lenna.png -o ./Lenna_enc.png -m HelloWorld!
|
||||||
$ slsb --reveal -i ./pictures/Lenna_enc.png
|
$ lsb --reveal -i ./Lenna_enc.png
|
||||||
HelloWorld!
|
HelloWorld!
|
||||||
|
|
||||||
Hide and reveal a binary file
|
Hide and reveal a binary file
|
||||||
|
@ -95,21 +95,72 @@ Hide and reveal a binary file
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ wget http://www.gnu.org/music/free-software-song.ogg
|
$ wget http://www.gnu.org/music/free-software-song.ogg
|
||||||
$ slsb --hide -i ./pictures/Montenach.png -o ./pictures/Montenach_enc.png -f ./free-software-song.ogg
|
$ lsb --hide -i ./tests/sample-files/Montenach.png -o ./Montenach_enc.png -f ./free-software-song.ogg
|
||||||
$ rm free-software-song.ogg
|
$ rm free-software-song.ogg
|
||||||
$ slsb --reveal -i ./pictures/Montenach_enc.png -b ./song.ogg
|
$ lsb --reveal -i ./Montenach_enc.png -b ./song.ogg
|
||||||
|
|
||||||
Hide and reveal a message by using the description field of the image
|
Hide and reveal a text message with the LSB method and generated sets
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
|
|
||||||
|
Sets are used in order to select the pixels where the message will be hidden.
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ ./exif-header.py --hide -i ./Elisha-Cuthbert.jpg -o ./Elisha-Cuthbert_enc.jpg -f ./fileToHide.txt
|
echo "Hide the message with the Sieve of Eratosthenes..."
|
||||||
$ ./exif-header.py --reveal -i ./Elisha-Cuthbert_enc.jpg
|
lsb-set --hide -i ./tests/sample-files/Montenach.png -o ./surprise.png --generator eratosthenes -m 'Joyeux Noël!'
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Try to reveal with Mersenne numbers..."
|
||||||
|
lsb-set --reveal --generator mersenne -i ./surprise.png
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Try to reveal with fermat numbers..."
|
||||||
|
lsb-set --reveal --generator fermat -i ./surprise.png
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Try to reveal with carmichael numbers..."
|
||||||
|
lsb-set --reveal --generator carmichael -i ./surprise.png
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Try to reveal with Sieve of Eratosthenes..."
|
||||||
|
lsb-set --reveal --generator eratosthenes -i ./surprise.png
|
||||||
|
|
||||||
|
|
||||||
|
An other example:
|
||||||
|
|
||||||
|
.. code-block:: bash
|
||||||
|
|
||||||
|
# Hide the message - LSB with a set defined by the identity function (f(x) = x).
|
||||||
|
lsb-set --hide -i ./tests/sample-files/Montenach.png -o ./enc-identity.png --generator identity -m 'I like steganography.'
|
||||||
|
|
||||||
|
# Hide the message - LSB only.
|
||||||
|
lsb --hide -i ./tests/sample-files/Montenach.png -o ./enc.png -m 'I like steganography.'
|
||||||
|
|
||||||
|
# Check if the two generated files are the same.
|
||||||
|
sha1sum ./enc-identity.png ./enc.png
|
||||||
|
|
||||||
|
# The output of lsb is given to lsb-set.
|
||||||
|
lsb-set --reveal -i ./enc.png --generator identity
|
||||||
|
|
||||||
|
# The output of lsb-set is given to lsb.
|
||||||
|
lsb --reveal -i ./enc-identity.png
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Steganalysis
|
Steganalysis
|
||||||
------------
|
============
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
$ steganalysis-parity -i ./pictures./Lenna_enc.png -o ./pictures/Lenna_enc_st.png
|
# Hide the message with Sieve of Eratosthenes
|
||||||
|
lsb-set --hide -i ./tests/sample-files/Ginnifer-Goodwin.png -o ./surprise.png --generator eratosthenes -m 'Very important message.'
|
||||||
|
|
||||||
|
# Steganalysis of the original photo
|
||||||
|
steganalysis-parity -i ./tests/sample-files/Ginnifer-Goodwin.png -o ./surprise_st_original.png
|
||||||
|
|
||||||
|
# Steganalysis of the secret photo
|
||||||
|
steganalysis-parity -i ./surprise.png -o ./surprise_st_secret.png
|
||||||
|
|
||||||
|
# Reveal with Sieve of Eratosthenes
|
||||||
|
lsb-set --reveal --generator eratosthenes -i ./surprise.png
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
wget http://www.gnu.org/music/free-software-song.ogg
|
|
||||||
lsb --hide -i ./pictures/Montenach.png -o ./pictures/Montenach_enc.png -f ./free-software-song.ogg
|
|
||||||
rm free-software-song.ogg
|
|
||||||
lsb --reveal -i ./pictures/Montenach_enc.png -b ./zik.ogg
|
|
|
@ -1,26 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test the LSB method with sets.
|
|
||||||
#
|
|
||||||
|
|
||||||
echo "We're going to test a little Stéganô..."
|
|
||||||
|
|
||||||
echo "Hide the message with the Sieve of Eratosthenes..."
|
|
||||||
lsb-set --hide -i ./pictures/Montenach.png -o ./surprise.png --generator eratosthenes -m 'Joyeux Noël!'
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Try to reveal with Mersenne numbers..."
|
|
||||||
lsb-set --reveal --generator mersenne -i ./surprise.png
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Try to reveal with fermat numbers..."
|
|
||||||
lsb-set --reveal --generator fermat -i ./surprise.png
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Try to reveal with carmichael numbers..."
|
|
||||||
lsb-set --reveal --generator carmichael -i ./surprise.png
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Try to reveal with Sieve of Eratosthenes..."
|
|
||||||
lsb-set --reveal --generator eratosthenes -i ./surprise.png
|
|
|
@ -1,22 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
# Some tests of the LSB method which uses sets (slsb-set). Sets are used in order to select the pixels where the
|
|
||||||
# message will be hidden.
|
|
||||||
|
|
||||||
|
|
||||||
# Hide the message - LSB with a set defined by the identity function (f(x) = x).
|
|
||||||
lsb-set --hide -i examples/pictures/Montenach.png -o ~/enc-identity.png --generator identity -m 'I like steganography.'
|
|
||||||
|
|
||||||
# Hide the message - LSB only.
|
|
||||||
lsb --hide -i examples/pictures/Montenach.png -o ~/enc.png -m 'I like steganography.'
|
|
||||||
|
|
||||||
|
|
||||||
# Check if the two generated files are the same.
|
|
||||||
sha1sum ~/enc-identity.png ~/enc.png
|
|
||||||
|
|
||||||
|
|
||||||
# The output of slsb is given to slsb-set.
|
|
||||||
lsb-set --reveal -i ~/enc.png --generator identity
|
|
||||||
|
|
||||||
# The output of slsb-set is given to slsb.
|
|
||||||
lsb --reveal -i ~/enc-identity.png
|
|
|
@ -1,21 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Test the LSB method with sets.
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
echo "Hide the message with Sieve of Eratosthenes..."
|
|
||||||
lsb-set --hide -i ./pictures/Ginnifer-Goodwin.png -o ./surprise.png --generator eratosthenes -m 'Probably the most beautiful woman in the world.'
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Steganalysis of the original photo..."
|
|
||||||
steganalysis-parity -i ./pictures/Ginnifer-Goodwin.png -o ./surprise_st_original.png
|
|
||||||
|
|
||||||
echo "Steganalysis of the secret photo..."
|
|
||||||
steganalysis-parity -i ./surprise.png -o ./surprise_st_secret.png
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
echo "Reveal with Sieve of Eratosthenes..."
|
|
||||||
echo "The secret is:"
|
|
||||||
lsb-set --reveal --generator eratosthenes -i ./surprise.png
|
|
Before Width: | Height: | Size: 5.4 MiB After Width: | Height: | Size: 5.4 MiB |
Before Width: | Height: | Size: 373 KiB After Width: | Height: | Size: 373 KiB |
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
Before Width: | Height: | Size: 464 KiB After Width: | Height: | Size: 464 KiB |
Before Width: | Height: | Size: 3.8 MiB After Width: | Height: | Size: 3.8 MiB |
|
@ -35,7 +35,7 @@ class TestEXIFHeader(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Test hiding the empty string.
|
Test hiding the empty string.
|
||||||
"""
|
"""
|
||||||
secret = exifHeader.hide("./examples/pictures/20160505T130442.jpg",
|
secret = exifHeader.hide("./tests/sample-files/20160505T130442.jpg",
|
||||||
"./image.jpg", secret_message="")
|
"./image.jpg", secret_message="")
|
||||||
#secret.save(""./image.png"")
|
#secret.save(""./image.png"")
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class TestEXIFHeader(unittest.TestCase):
|
||||||
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 = exifHeader.hide("./examples/pictures/20160505T130442.jpg",
|
secret = exifHeader.hide("./tests/sample-files/20160505T130442.jpg",
|
||||||
"./image.jpg", secret_message=message)
|
"./image.jpg", secret_message=message)
|
||||||
|
|
||||||
clear_message = exifHeader.reveal("./image.jpg")
|
clear_message = exifHeader.reveal("./image.jpg")
|
||||||
|
@ -55,7 +55,7 @@ class TestEXIFHeader(unittest.TestCase):
|
||||||
self.assertEqual(message, message)
|
self.assertEqual(message, message)
|
||||||
|
|
||||||
def test_with_image_without_exif_data(self):
|
def test_with_image_without_exif_data(self):
|
||||||
secret = exifHeader.hide("./examples/pictures/Elisha-Cuthbert.jpg",
|
secret = exifHeader.hide("./tests/sample-files/Elisha-Cuthbert.jpg",
|
||||||
"./image.jpg", secret_message="")
|
"./image.jpg", secret_message="")
|
||||||
#secret.save(""./image.png"")
|
#secret.save(""./image.png"")
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ class TestEXIFHeader(unittest.TestCase):
|
||||||
self.assertEqual(b"", clear_message)
|
self.assertEqual(b"", clear_message)
|
||||||
|
|
||||||
def test_with_png_image(self):
|
def test_with_png_image(self):
|
||||||
secret = exifHeader.hide("./examples/pictures/Lenna.png",
|
secret = exifHeader.hide("./tests/sample-files/Lenna.png",
|
||||||
"./image.png", secret_message="Secret")
|
"./image.png", secret_message="Secret")
|
||||||
#secret.save(""./image.png"")
|
#secret.save(""./image.png"")
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ class TestLSB(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Test hiding the empty string.
|
Test hiding the empty string.
|
||||||
"""
|
"""
|
||||||
secret = lsb.hide("./examples/pictures/Lenna.png", "")
|
secret = lsb.hide("./tests/sample-files/Lenna.png", "")
|
||||||
secret.save("./image.png")
|
secret.save("./image.png")
|
||||||
|
|
||||||
clear_message = lsb.reveal("./image.png")
|
clear_message = lsb.reveal("./image.png")
|
||||||
|
@ -46,7 +46,7 @@ class TestLSB(unittest.TestCase):
|
||||||
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("./examples/pictures/Lenna.png", message)
|
secret = lsb.hide("./tests/sample-files/Lenna.png", message)
|
||||||
secret.save("./image.png")
|
secret.save("./image.png")
|
||||||
|
|
||||||
clear_message = lsb.reveal("./image.png")
|
clear_message = lsb.reveal("./image.png")
|
||||||
|
@ -54,20 +54,20 @@ class TestLSB(unittest.TestCase):
|
||||||
self.assertEqual(message, clear_message)
|
self.assertEqual(message, clear_message)
|
||||||
|
|
||||||
def test_with_long_message(self):
|
def test_with_long_message(self):
|
||||||
with open("./examples/lorem_ipsum.txt") as f:
|
with open("./tests/sample-files/lorem_ipsum.txt") as f:
|
||||||
message = f.read()
|
message = f.read()
|
||||||
secret = lsb.hide("./examples/pictures/Lenna.png", message)
|
secret = lsb.hide("./tests/sample-files/Lenna.png", message)
|
||||||
secret.save("./image.png")
|
secret.save("./image.png")
|
||||||
|
|
||||||
clear_message = lsb.reveal("./image.png")
|
clear_message = lsb.reveal("./image.png")
|
||||||
self.assertEqual(message, clear_message)
|
self.assertEqual(message, clear_message)
|
||||||
|
|
||||||
def test_with_too_long_message(self):
|
def test_with_too_long_message(self):
|
||||||
with open("./examples/lorem_ipsum.txt") as f:
|
with open("./tests/sample-files/lorem_ipsum.txt") as f:
|
||||||
message = f.read()
|
message = f.read()
|
||||||
message += message*2
|
message += message*2
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
lsb.hide("./examples/pictures/Lenna.png", message)
|
lsb.hide("./tests/sample-files/Lenna.png", message)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -35,7 +35,7 @@ class TestLSBSet(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Test hiding the empty string.
|
Test hiding the empty string.
|
||||||
"""
|
"""
|
||||||
secret = lsbset.hide("./examples/pictures/Lenna.png", "",
|
secret = lsbset.hide("./tests/sample-files/Lenna.png", "",
|
||||||
"eratosthenes")
|
"eratosthenes")
|
||||||
secret.save("./image.png")
|
secret.save("./image.png")
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class TestLSBSet(unittest.TestCase):
|
||||||
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 = lsbset.hide("./examples/pictures/Lenna.png", message,
|
secret = lsbset.hide("./tests/sample-files/Lenna.png", message,
|
||||||
"eratosthenes")
|
"eratosthenes")
|
||||||
secret.save("./image.png")
|
secret.save("./image.png")
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ class TestLSBSet(unittest.TestCase):
|
||||||
def test_hide_and_reveal_with_bad_generator(self):
|
def test_hide_and_reveal_with_bad_generator(self):
|
||||||
message_to_hide = "Hello World!"
|
message_to_hide = "Hello World!"
|
||||||
|
|
||||||
secret = lsbset.hide("./examples/pictures/Lenna.png", message_to_hide,
|
secret = lsbset.hide("./tests/sample-files/Lenna.png", message_to_hide,
|
||||||
"eratosthenes")
|
"eratosthenes")
|
||||||
secret.save("./image.png")
|
secret.save("./image.png")
|
||||||
|
|
||||||
|
|
|
@ -36,13 +36,13 @@ class TestRed(unittest.TestCase):
|
||||||
Test hiding the empty string.
|
Test hiding the empty string.
|
||||||
"""
|
"""
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(AssertionError):
|
||||||
secret = red.hide("./examples/pictures/Lenna.png", "")
|
secret = red.hide("./tests/sample-files/Lenna.png", "")
|
||||||
|
|
||||||
def test_hide_and_reveal(self):
|
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:
|
for message in messages_to_hide:
|
||||||
secret = red.hide("./examples/pictures/Lenna.png", message)
|
secret = red.hide("./tests/sample-files/Lenna.png", message)
|
||||||
secret.save("./image.png")
|
secret.save("./image.png")
|
||||||
|
|
||||||
clear_message = red.reveal("./image.png")
|
clear_message = red.reveal("./image.png")
|
||||||
|
@ -50,10 +50,10 @@ class TestRed(unittest.TestCase):
|
||||||
self.assertEqual(message, clear_message)
|
self.assertEqual(message, clear_message)
|
||||||
|
|
||||||
def test_with_too_long_message(self):
|
def test_with_too_long_message(self):
|
||||||
with open("./examples/lorem_ipsum.txt") as f:
|
with open("./tests/sample-files/lorem_ipsum.txt") as f:
|
||||||
message = f.read()
|
message = f.read()
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(AssertionError):
|
||||||
red.hide("./examples/pictures/Lenna.png", message)
|
red.hide("./tests/sample-files/Lenna.png", message)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
try:
|
try:
|
||||||
|
|