diff --git a/stegano/console/wav.py b/stegano/console/wav.py
deleted file mode 100644
index 40cd29d..0000000
--- a/stegano/console/wav.py
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/env python
-# Stegano - Stegano is a pure Python steganography module.
-# Copyright (C) 2010-2025 Cédric Bonhomme - https://www.cedricbonhomme.org
-#
-# For more information : https://github.com/cedricbonhomme/Stegano
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see
-
-__author__ = "Cedric Bonhomme"
-__version__ = "$Revision: 0.7 $"
-__date__ = "$Date: 2016/03/18 $"
-__revision__ = "$Date: 2019/06/04 $"
-__license__ = "GPLv3"
-
-try:
- from stegano import wav
-except Exception:
- print("Install stegano: pipx install Stegano")
-
-import argparse
-
-from stegano import tools
-
-def main():
- parser = argparse.ArgumentParser(prog="stegano-lsb")
- subparsers = parser.add_subparsers(
- help="sub-command help", dest="command", required=True
- )
-
- # Subparser: Hide
- parser_hide = subparsers.add_parser("hide", help="hide help")
- # Original audio
- parser_hide.add_argument(
- "-i",
- "--input",
- dest="input_audio_file",
- required=True,
- help="Input audio file.",
- )
- parser_hide.add_argument(
- "-e",
- "--encoding",
- dest="encoding",
- choices=tools.ENCODINGS.keys(),
- default="UTF-8",
- help="Specify the encoding of the message to hide."
- " UTF-8 (default) or UTF-32LE.",
- )
-
- group_secret = parser_hide.add_mutually_exclusive_group(required=True)
- # Non binary secret message to hide
- group_secret.add_argument(
- "-m", dest="secret_message", help="Your secret message to hide (non binary)."
- )
- # Binary secret message to hide
- group_secret.add_argument(
- "-f", dest="secret_file", help="Your secret to hide (Text or any binary file)."
- )
-
- # Audio containing the secret
- parser_hide.add_argument(
- "-o",
- "--output",
- dest="output_audio_file",
- required=True,
- help="Output audio containing the secret.",
- )
-
- # Subparser: Reveal
- parser_reveal = subparsers.add_parser("reveal", help="reveal help")
- parser_reveal.add_argument(
- "-i",
- "--input",
- dest="input_audio_file",
- required=True,
- help="Input audio file.",
- )
- parser_reveal.add_argument(
- "-e",
- "--encoding",
- dest="encoding",
- choices=tools.ENCODINGS.keys(),
- default="UTF-8",
- help="Specify the encoding of the message to reveal."
- " UTF-8 (default) or UTF-32LE.",
- )
-
- arguments = parser.parse_args()
-
- if arguments.command == "hide":
- if arguments.secret_message is not None:
- secret = arguments.secret_message
- elif arguments.secret_file != "":
- secret = tools.binary2base64(arguments.secret_file)
-
- wav.hide(
- input_file=arguments.input_audio_file,
- message=secret,
- encoding=arguments.encoding,
- output_file=arguments.output_audio_file
- )
-
- elif arguments.command == "reveal":
- try:
- secret = wav.reveal(
- encoded_wav=arguments.input_audio_file,
- encoding=arguments.encoding
- )
- except IndexError:
- print("Impossible to detect message.")
- exit(0)
- if arguments.secret_binary is not None:
- data = tools.base642binary(secret)
- with open(arguments.secret_binary, "wb") as f:
- f.write(data)
- else:
- print(secret)
diff --git a/stegano/exifHeader/exifHeader.py b/stegano/exifHeader/exifHeader.py
index 1fefa93..33fec99 100644
--- a/stegano/exifHeader/exifHeader.py
+++ b/stegano/exifHeader/exifHeader.py
@@ -40,7 +40,7 @@ def hide(
from zlib import compress
if secret_file is not None:
- with open(secret_file, "rb") as f:
+ with open(secret_file) as f:
secret_message = f.read()
try:
diff --git a/stegano/wav/__init__.py b/stegano/wav/__init__.py
deleted file mode 100644
index e2529fe..0000000
--- a/stegano/wav/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/usr/bin/env python
-
-from .wav import hide, reveal
-
-__all__ = ["hide", "reveal"]
diff --git a/stegano/wav/wav.py b/stegano/wav/wav.py
deleted file mode 100644
index 0593257..0000000
--- a/stegano/wav/wav.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-# Stegano - Stéganô is a basic Python Steganography module.
-# Copyright (C) 2010-2024 Cédric Bonhomme - https://www.cedricbonhomme.org
-#
-# For more information : https://github.com/cedricbonhomme/Stegano
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see
-
-__author__ = "Cedric Bonhomme"
-__version__ = "$Revision: 0.2 $"
-__date__ = "$Date: 2010/10/01 $"
-__revision__ = "$Date: 2017/02/06 $"
-__license__ = "GPLv3"
-
-import wave
-from typing import IO, Union
-from stegano import tools
-
-def hide(
- input_file: Union[str, IO[bytes]],
- message: str,
- output_file: Union[str, IO[bytes]],
- encoding: str = "UTF-8"
-):
- """
- Hide a message (string) in a .wav audio file.
-
- Use the lsb of each PCM encoded sample to hide the message string characters as ASCII values.
- The first eight bits are used for message_length of the string.
- """
- message_length = len(message)
- assert message_length != 0, "message message_length is zero"
- assert message_length < 255, "message is too long"
-
- output = wave.open(output_file, "wb")
- with wave.open(input_file, "rb") as input:
- # get .wav params
- nchannels, sampwidth, framerate, nframes, comptype, _ = input.getparams()
- assert comptype == "NONE", "only uncompressed files are supported"
-
- nsamples = nframes * nchannels
-
- message_bits = f"{message_length:08b}" + "".join(tools.a2bits_list(message, encoding))
- assert len(message_bits) <= nsamples, "message is too long"
-
- # copy over .wav params to output
- output.setnchannels(nchannels)
- output.setsampwidth(sampwidth)
- output.setframerate(framerate)
-
- # encode message in frames
- frames = bytearray(input.readframes(nsamples))
- for i in range(nsamples):
- if i < len(message_bits):
- if message_bits[i] == "0":
- frames[i] = frames[i] & ~1
- else:
- frames[i] = frames[i] | 1
-
- # write out
- output.writeframes(frames)
-
-
-def reveal(input_file: Union[str, IO[bytes]], encoding: str = "UTF-8"):
- """
- Find a message in an image.
-
- Check the lsb of each PCM encoded sample for hidden message characters (ASCII values).
- The first eight bits are used for message_length of the string.
- """
- message = ""
- encoding_len = tools.ENCODINGS[encoding]
- with wave.open(input_file, "rb") as input:
- nchannels, _, _, nframes, comptype, _ = input.getparams()
- assert comptype == "NONE", "only uncompressed files are supported"
-
- nsamples = nframes * nchannels
- frames = bytearray(input.readframes(nsamples))
-
- # Read first 8 bits for message length
- length_bits = ""
- for i in range(8):
- length_bits += str(frames[i] & 1)
- message_length = int(length_bits, 2)
-
- # Read message bits
- message_bits = ""
- for i in range(8, 8 + message_length * encoding_len):
- message_bits += str(frames[i] & 1)
-
- # Convert bits to string
- chars = [chr(int(message_bits[i:i+encoding_len], 2)) for i in range(0, len(message_bits), encoding_len)]
- message = "".join(chars)
- return message
diff --git a/tests/sample-files/free-software-song.wav b/tests/sample-files/free-software-song.wav
deleted file mode 100644
index 405684a..0000000
Binary files a/tests/sample-files/free-software-song.wav and /dev/null differ
diff --git a/tests/test_wav.py b/tests/test_wav.py
deleted file mode 100644
index 86276d0..0000000
--- a/tests/test_wav.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-# Stegano - Stegano is a pure Python steganography module.
-# Copyright (C) 2010-2025 Cédric Bonhomme - https://www.cedricbonhomme.org
-#
-# For more information : https://github.com/cedricbonhomme/Stegano
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see
-
-__author__ = "Cedric Bonhomme"
-__version__ = "$Revision: 0.1 $"
-__date__ = "$Date: 2016/05/19 $"
-__license__ = "GPLv3"
-
-import os
-import unittest
-
-from stegano import wav
-
-
-class TestWav(unittest.TestCase):
- def test_hide_empty_message(self):
- """
- Test hiding the empty string.
- """
- with self.assertRaises(AssertionError):
- wav.hide("./tests/sample-files/free-software-song.wav", "", "./audio.wav")
-
- def test_hide_and_reveal(self):
- messages_to_hide = ["a", "foo", "Hello World!", ":Python:"]
-
- for message in messages_to_hide:
- wav.hide("./tests/sample-files/free-software-song.wav", message, "./audio.wav")
- clear_message = wav.reveal("./audio.wav")
-
- self.assertEqual(message, clear_message)
-
- def test_with_too_long_message(self):
- with open("./tests/sample-files/lorem_ipsum.txt") as f:
- message = f.read()
- with self.assertRaises(AssertionError):
- wav.hide("./tests/sample-files/free-software-song.wav", message, "./audio.wav")
-
- def tearDown(self):
- try:
- os.unlink("./audio.wav")
- except Exception:
- pass
-
-
-if __name__ == "__main__":
- unittest.main()