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 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, you DON'T need the original image, 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 for storing/retrieving the file from the files/base-images
folder.
You can add your own images to this folder. They can be .png
or (.jpg
/.jpeg
), but they will be converted to .png
when the script is run.
Choose a file to be stored in the image from the files/input-files
folder.
You can add your own files to this folder. It can be any file type.
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.
... 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 will have | "" |
MOD_SUFFIX |
Suffix the modified image 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 and files | True |
The injection is done by storing the information in the X less significant bits of the image's channels
- Each channel (R, G and B) has 8 bits, and this script changes from 1 to 4 bits of each channel, depending on the size of the file to be stored.
- If you store a bigger file, more bits will be changed and the changes will be more noticeable.
- If you store a smaller file, less bits will be changed and the changes will be less noticeable.
- If you choose to encrypt the file, its size will increase by ≈1/3.
Changed bits | ≈Image size (MP) | ≈Max file size (MB) |
---|---|---|
1 | 1 | 0.375 |
2 | 1 | 0.5 |
3 | 1 | 0.75 |
4 | 1 | 1.5 |
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 and file. Otherwise, it will ask for the input file and the base image. - Read the file
- Read the image and store it in a numpy array
- If the user wants to encrypt the file:
- Get the key with
get_fernet()
- Encrypt the file and filename
- Get the key with
- Convert the file and filename to hexadecimal
- Try to inject the hexadecimal file and filename in the image with
inject_file()
.- If the image is too small to store the file, raise an error
- Else, return the modified image.
- Save the modified image
- If
TEST_MODE
==True
, it will use the predefined modified image. Otherwise, it will ask for the modified image. - Flatten the modified image
- Extract the hexadecimal file and filename 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 |
---|---|---|
img_arr |
np.ndarray |
Image as a numpy array |
file |
str |
File in hexadecimal |
filename |
str |
Filename in hexadecimal |
store_random |
boolean |
Whether or not to store random data in the modified image |
returns the modified image array (not flattened np.ndarray
)
Parameter | Type | Description |
---|---|---|
mod_img_arr_flat |
np.ndarray |
Flattened modified image |
returns a dictionary with the extracted file and filename, both in (bytes
) format