If you want to use a previous version (1.0.2 or lower), where you needed the original image to extract the file, you can download it here.
- 1. Description
- 2. Getting Started
- 3. Results
- 4. Examples of use
- 5. Configuration
- 6. What it does
- 7. How it works
File Injector is a script that allows you to store any file (.zip
, .png
, .txt
, .gba
...) and its filename in an image/audio as noise, using steganography.
You can also choose to encrypt the input file before storing it.
Then, to extract the file from the modified image/audio, you DON'T need the original image/audio, just the encryption key if the file has been encrypted.
python3 -m pip install -r requirements.txt
If that doesn't work, you can try:
py -m pip install -r requirements.txt
python3 main.py
Choose a base image/audio for storing the file from the files/base
folder.
You can also add your own images/audios to this folder.
- The images can be
.png
or (.jpg
/.jpeg
), but they will be converted to.png
when the script is run. - The audios have to be
.mp3
or.wav
, but they will be converted to.mp3
when the script is run.
Choose a file to be stored in the image/audio from the files/input
folder.
You can add your own files to this folder. They can be any type of files.
Choose a modified image/audio for extracting the file from the files/modified
folder.
You can also add your own modified images/audios to this folder.
You can choose a key from the files/$encryption-keys
folder or generate one there.
The key file must have the .key
extension
You don't need to choose a particular one when decrypting a file, it will be selected automatically from the folder.
This 17.1MP image contains an encrypted 9MB .zip
file and its filename stored as noise.
This 1.7MP image contains an encrypted 0.93MB .zip
file and its filename stored as noise.
This 42MB audio file contains an encrypted 9MB .zip
file and its filename stored as noise.
winter-vivaldi_mod.mp4
... File-Injector % python3 main.py
[0] EXIT
[1] Inject file
[2] Extract file
Option: 1
File to be stored: images.zip
Filename of the base image: 2'2MP
Encrypt the file? (y/n): y
Do you want to use an existing key or generate a new one?
[0] Existing key
[1] New key
Option: 1
Filename of the new key file (blank for default):
Key generated and saved to files/$encryption-keys/key9.key
Preparing...
Modified bits per channel: 2
Image modification: 1.56%
✅ Storing... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ [100.0%]
Generating random values...
Storing random values...
Reshaping...
Modified image saved in files/modified-images/2'2MP_mod.png
Done in 7.5892 seconds
... File-Injector % python3 main.py
[0] EXIT
[1] Inject file
[2] Extract file
Option: 2
Filename of the modified image: 2'2MP_mod
Preparing...
Retrieving filename...
Retrieving input file...
Decrypted with "files/$encryption-keys/key2.key"
Output file saved in files/output-files/images.zip
Done in 1.4083 seconds
You can change the configuration in the config.py file.
Constant | Description | Default value |
---|---|---|
MOD_PREFIX |
Prefix the modified image/audio will have | "" |
MOD_SUFFIX |
Suffix the modified image/audio will have | "_mod" |
STORE_RANDOM |
Store random data in the modified image so that the limit between the part with the stored data and the part without is not so obvious | True |
TEST_MODE |
Enables/Disables Test Mode: Test with predefined images/audios and files | True |
The injection is done by storing the file in the X less significant bits of each element of the array created by flattening the array of image/audio.
- Each element has 8 bits (if the base file is an image) or 16 bits (if the base file is an audio)
- This script changes from 1 to all the bits of each element, depending on the size of the file to be stored compared to the base image/audio.
- If you store a bigger file or if the base image/audio is smaller, more bits will be changed and the changes will be more noticeable.
- If you store a smaller file or if the base image/audio is bigger, less bits will be changed and the changes will be less noticeable.
- If the base image/audio is too small to store the file, the script will stop and warn you.
- If you choose to encrypt the file, its size will increase by ≈1/3.
Option | Description |
---|---|
[0] EXIT | Exit the script |
[1] Inject file | Calls inject_file_func() |
[2] Extract file | Calls extract_file_func() |
- If
TEST_MODE
==True
, it will use the predefined base image/audio and input file. Otherwise, it will ask for the base image/audio and input file. - Read the file (in bytes)
- Read the image/audio and store it in a numpy array
- Read the filename (in bytes)
- If the user wants to encrypt the file:
- Get the key with
get_fernet()
- Encrypt the file and filename
- Get the key with
- Try to inject the file and filename in the image/audio with
inject_file()
.- If the image/audio is too small to store the file, raise an error
- Else, return the modified image/audio.
- Save the modified image/audio
- If
TEST_MODE
==True
, it will use the predefined modified image/audio. Otherwise, it will ask for the modified image/audio. - Read the modified image/audio
- Extract file and filename as bytes with
extract_file()
- If the file and filename have been encrypted (they start with
gAAAAA
), decrypt them withdecrypt_content
- Decode the filename to UTF-8
- Save the file with the decoded filename
Option | Description |
---|---|
[0] Existing key | Use an existing key |
[1] New key | Generate a new key |
[0] Existing key
- Choose a key to use from the
files/$encryption-keys
folder
[1] New key
- Choose a filename for the new key (or leave it blank for the default one (e.g. key8.key))
- Generate a new key and save it with the chosen filename
- Return the Fernet object with the new key
- For each key in the
files/$encryption-keys
folder:- Try to decrypt the file and filename with it
- If InvalidToken is raised:
- It means that the key is not the right one
- Try with other key
- Else, return the key
- If no key is found, raise an Exception
Parameter | Type | Description |
---|---|---|
arr |
np.ndarray |
Image/audio as a numpy array |
file |
bytes |
File as bytes |
filename |
bytes |
Filename as bytes |
store_random |
boolean |
Whether or not to store random data in the modified image/audio |
Returns the modified image/audio array (np.ndarray
, with same shape as arr
)
Parameter | Type | Description |
---|---|---|
mod_arr_flat |
np.ndarray |
Flattened modified image/audio |
Returns a dictionary with the extracted file and filename, both in (bytes
) format