Skip to content

Commit fbfad71

Browse files
authored
Implemented Audio steganography (avinashkranjan#991)
1 parent feeb243 commit fbfad71

File tree

8 files changed

+268
-0
lines changed

8 files changed

+268
-0
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import os
2+
import wave
3+
import simpleaudio as sa
4+
import numpy as np
5+
from scipy.io import wavfile
6+
import binascii
7+
8+
"""
9+
10+
[NOTE] In this decryption algorithm we simply read the path of the audio from the user and we
11+
get a numpy array from the same. We then read the LSB of the binary representation of the data and get a string
12+
of binary data. Finally we convert this string to ascii charecters and write it to a file.
13+
14+
"""
15+
16+
17+
class Decrypt:
18+
19+
def __init__(self, audio_path):
20+
self.audio_path = audio_path
21+
self.audio_wave_obj = wave.open(audio_path)
22+
23+
"""
24+
This function is there for playing audio.
25+
"""
26+
27+
def play_audio(self) -> None:
28+
29+
playing = sa.WaveObject.from_wave_read(self.audio_wave_obj)
30+
obj = playing.play()
31+
32+
if obj.is_playing():
33+
print(f"Playing audio")
34+
35+
obj.wait_done()
36+
37+
"""
38+
The decryption is done here.
39+
"""
40+
41+
def decrypt_audio(self, output_dir: str, file_name: str, gen_file_status: bool) -> (str, bool):
42+
if gen_file_status:
43+
curr_dir_path = os.getcwd()
44+
output_dir_path = os.path.join(curr_dir_path, output_dir)
45+
46+
try:
47+
os.mkdir(output_dir_path)
48+
except:
49+
pass
50+
51+
print(f"This might take some while if your secret message is big and might contain some rubbish data.")
52+
53+
# Reading the data from the wav file
54+
samplerate, data = wavfile.read(self.audio_path)
55+
m, n = data.shape
56+
# Reshaping it to make the data easier to handle
57+
data_reshaped = data.reshape(m*n, 1)
58+
59+
s = ""
60+
zeros = 0
61+
62+
# Getting the LSB from each number
63+
for i in range(m*n):
64+
t = str(data_reshaped[i][0] & 1)
65+
if zeros < 9:
66+
s += t
67+
else:
68+
break
69+
if t == '0':
70+
zeros += 1
71+
if t == '1':
72+
zeros = 0
73+
74+
# Making sure the bit-string is of length divisible by 8 as we have stored the input-secret as 8-bits only
75+
s = s[:((len(s)//8)*8)]
76+
77+
# Converting bbinary string to utf-8
78+
in_bin = int(s, 2)
79+
byte_num = in_bin.bit_length() + 7 // 8
80+
bin_arr = in_bin.to_bytes(byte_num, "big")
81+
result = bin_arr.decode("utf-8", "ignore")
82+
83+
# Writing to output file if status was given true
84+
if gen_file_status:
85+
try:
86+
with open(os.path.join(output_dir_path, file_name), "w", encoding="utf-8") as f:
87+
f.write(result)
88+
print("Success !!!")
89+
return result, True
90+
except:
91+
print(("Error !!!"))
92+
pass
93+
return None, False
94+
else:
95+
return result, True
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import os
2+
import wave
3+
import simpleaudio as sa
4+
import numpy as np
5+
from scipy.io import wavfile
6+
7+
8+
"""
9+
[NOTE] In this algorithm we make use of LSB Steganographic method of encoding. In this algorithm we have converted each charecter
10+
of the secret text into 8-bit binary string and then we have stored it to a numpy array of size x*8 where x = no. of charecters.
11+
After that we have copied the same into the LSB of the binary form of the audio file we have read.
12+
"""
13+
14+
15+
class Encrypt:
16+
17+
def __init__(self, message_audio_file_path: str, secret_message: str):
18+
self.message_audio_file_path = message_audio_file_path
19+
self.secret_message = secret_message
20+
21+
# For getting name of the file
22+
self.message_filename = message_audio_file_path.split(os.sep)[-1]
23+
24+
# Reading the .wav audio file as a Wave obj - to be used later
25+
self.message_audio = wave.open(message_audio_file_path)
26+
27+
# Getting the numpy array from the secret string.
28+
self.secret_as_nparr = self.get_bin_npapp_from_path(
29+
secret_message)
30+
31+
self.mess_as_nparr = None
32+
33+
"""
34+
This function is used as a helper function
35+
"""
36+
37+
def get_bin_npapp_from_path(self, secret: str) -> np.ndarray:
38+
39+
strings = ' '.join('{0:08b}'.format(ord(word), 'b')
40+
for word in secret)
41+
lst = []
42+
for word in strings.split(" "):
43+
# arr = np.fromstring(word, dtype="u1")-ord('0')
44+
temp_lst = [int(i) for i in word]
45+
lst.append(np.array(temp_lst))
46+
47+
return np.array(lst)
48+
49+
"""
50+
This function is there for playing audio.
51+
"""
52+
53+
def play_audio(self) -> None:
54+
55+
playing = sa.WaveObject.from_wave_read(self.message_audio)
56+
obj = playing.play()
57+
58+
if obj.is_playing():
59+
print(f"Playing audio : {self.message_filename}")
60+
61+
obj.wait_done()
62+
63+
"""
64+
This function is for encryption
65+
"""
66+
67+
def encrypt_using_lsb(self, output_dir: str, file_name: str) -> (np.ndarray, bool):
68+
69+
# Getting the ouput path
70+
curr_dir_path = os.getcwd()
71+
output_dir_path = os.path.join(curr_dir_path, output_dir)
72+
73+
try:
74+
os.mkdir(output_dir_path)
75+
except:
76+
pass
77+
78+
print(f"This might take some while if either your audio file or your secret message is big")
79+
80+
# Reading shape of secret message and reshaping
81+
m1, n1 = self.secret_as_nparr.shape
82+
secret_reshape = self.secret_as_nparr.reshape(m1*n1, 1)
83+
84+
# Reading the .wav file
85+
samplerate, self.mess_as_nparr = wavfile.read(
86+
self.message_audio_file_path)
87+
88+
# Reading the shape of .wav file and reshaping
89+
m2, n2 = self.mess_as_nparr.shape
90+
message_reshape = self.mess_as_nparr.reshape(m2*n2, 1)
91+
92+
# Edge case
93+
if m1*n1 > m2*n2:
94+
print("Coudn't be done")
95+
quit()
96+
97+
# Encryption part
98+
k = 0
99+
for i in range(m2*n2):
100+
if k < m1*n1:
101+
# This line is for copying the bit off the secret message to the LSB of the audio
102+
message_reshape[i][0] = message_reshape[i][0] & 0xFE | secret_reshape[k][0]
103+
k += 1
104+
else:
105+
message_reshape[i][0] = 0
106+
break
107+
108+
# Reshaping back again
109+
message_reshape = message_reshape.reshape(m2, n2)
110+
111+
try:
112+
# Writing into ouput file
113+
p = wavfile.write(os.path.join(output_dir_path, file_name),
114+
samplerate, message_reshape.astype(message_reshape.dtype))
115+
print("Success !!!")
116+
return message_reshape, True
117+
except:
118+
print("Error !!!")
119+
pass
120+
return None, False

Audio_Steganography/Algos/__init__.py

Whitespace-only changes.
134 KB
Loading
68.3 KB
Loading

Audio_Steganography/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Audio Steganography
2+
This is a package to encrypt a given message into a .wav audio file. It can decrypt from audio as well.
3+
- Encrypt : This is used for the encryption part. Can play the audio as well.
4+
- Decrypt : This is used for decryption part. Can play audio as well.
5+
6+
## Setup instructions
7+
- It is recommended to install a virtualenv before you proceed. This can be done by ```virtualenv {name_of_virtualenv}```
8+
- Do
9+
```python3
10+
pip install -r requirements.txt
11+
```
12+
- You can import Encrypt from Algos.Encrypt and decrypt from Algos.Decrpyt
13+
- The TestingCode.py file has an example implementation. Please refer to it if you face any issue.
14+
15+
## Output
16+
- The code in TestingCode.py will produce 2 Directories as well as produce sound that is inside the .wav files that you have passed as a parameter to ```Encrypt```.
17+
- The Encryption and Decryption parts each will produce a directory with a name of your choice as well as file inside it containing the encrypted audio file or decrypted text file .
18+
- An Example of what you might expect :
19+
- Before
20+
![Before](Images/Before.jpg)
21+
- After
22+
![After](Images/After.jpg)
23+
24+
- Dont worry if your decrypted sentence looks a bit funky-it is to be expected.
25+
26+
## Author(s)
27+
[Trisanu Bhar](https://github.com/Trisanu-007)

Audio_Steganography/TestingCode.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from Algos.Encrypt import Encrypt
2+
from Algos.Decrypt import Decrypt
3+
4+
"""
5+
[NOTE] Here we demostrate an use of the Encrypt and Decrypt algorithms
6+
We also play the audio file as well.
7+
"""
8+
# You can try with Forest.wav as well
9+
message_path = input("Enter path of Audio file: ")
10+
secret = input("Enter secret message: ")
11+
12+
# Using Encrypt
13+
en = Encrypt(message_path, secret)
14+
en.play_audio()
15+
res, status = en.encrypt_using_lsb("Encrypted", "encrypted.wav")
16+
17+
if status:
18+
print(res)
19+
20+
# Using Decrypt
21+
dec = Decrypt("Encrypted\encrypted.wav")
22+
dec.play_audio()
23+
res, status = dec.decrypt_audio("Decrypted", "decrypted.txt", False)
24+
25+
if status:
26+
print(res)
224 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)