173 lines
4.9 KiB
Python
173 lines
4.9 KiB
Python
import gzip
|
|
import os
|
|
from pathlib import Path
|
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
from cryptography.hazmat.backends import default_backend
|
|
from cryptography.hazmat.primitives import padding
|
|
from argparse import ArgumentParser
|
|
from enum import Enum
|
|
import binascii
|
|
|
|
|
|
class Keys(Enum):
|
|
Datatable = "" # Add datatable key here
|
|
Fumen = "" # Add Fumen key here
|
|
|
|
|
|
def read_iv_from_file(file_path):
|
|
with open(file_path, "rb") as f:
|
|
iv = f.read(16)
|
|
if len(iv) != 16:
|
|
raise Exception("Invalid file")
|
|
return iv
|
|
|
|
|
|
def pad_data(data):
|
|
padder = padding.PKCS7(128).padder()
|
|
return padder.update(data) + padder.finalize()
|
|
|
|
|
|
def remove_pkcs7_padding(data):
|
|
unpadder = padding.PKCS7(128).unpadder()
|
|
return unpadder.update(data) + unpadder.finalize()
|
|
|
|
|
|
def decrypt_file(input_file, key_type: Keys = Keys(Keys.Datatable)):
|
|
# Convert the key from hex to bytes
|
|
key = binascii.unhexlify(Keys(key_type.value).value)
|
|
|
|
# Read the IV from the first 16 bytes of the input file
|
|
iv = read_iv_from_file(input_file)
|
|
|
|
# Create an AES cipher object with CBC mode
|
|
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
|
|
decryptor = cipher.decryptor()
|
|
|
|
with open(input_file, "rb") as infile:
|
|
# Skip the IV in the input file
|
|
infile.seek(16)
|
|
|
|
# Decrypt the file
|
|
decrypted_data = b"" + decryptor.update(infile.read())
|
|
|
|
# Remove PKCS7 padding
|
|
unpadded_data = remove_pkcs7_padding(decrypted_data)
|
|
|
|
# Gzip decompress the data
|
|
decompressed_data = gzip.decompress(unpadded_data)
|
|
|
|
# return the decompressed data
|
|
return decompressed_data
|
|
|
|
|
|
def encrypt_file(input_file, key_type: Keys = Keys(Keys.Datatable)):
|
|
# Convert the key from hex to bytes
|
|
key = binascii.unhexlify(Keys(key_type.value).value)
|
|
|
|
# Generate a random 128-bit IV
|
|
iv = os.urandom(16)
|
|
|
|
# Create an AES cipher object with CBC mode
|
|
try:
|
|
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
|
|
encryptor = cipher.encryptor()
|
|
except Exception as error:
|
|
print(error)
|
|
print("You need to set the right AES keys in the encryption.py file")
|
|
exit(0)
|
|
|
|
with open(input_file, "rb") as infile:
|
|
# Read the entire file into memory
|
|
data = infile.read()
|
|
|
|
# Gzip compress the data
|
|
compressed_data = gzip.compress(data)
|
|
|
|
# Pad the compressed data, encrypt it, and return the encrypted result
|
|
encrypted_data = (
|
|
encryptor.update(pad_data(compressed_data)) + encryptor.finalize()
|
|
)
|
|
|
|
return iv + encrypted_data
|
|
|
|
|
|
def save_file(file: bytes, outdir: str, encrypt: bool):
|
|
try:
|
|
fileContent = (
|
|
decrypt_file(input_file=file, key_type=type)
|
|
if not encrypt
|
|
else encrypt_file(input_file=file, key_type=type)
|
|
)
|
|
|
|
print("Decrypting" if not encrypt else "Encrypting", file, "to", outdir)
|
|
|
|
with open(outdir, "wb") as outfile:
|
|
outfile.write(fileContent)
|
|
except Exception as error:
|
|
print(
|
|
file, "couldn't be", "decrypted :" if not encrypt else "encrypted :", error
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = ArgumentParser()
|
|
parser.add_argument(
|
|
"-i",
|
|
"--input",
|
|
help="Input file / folder",
|
|
)
|
|
parser.add_argument(
|
|
"-o",
|
|
"--output",
|
|
help="Output file / folder",
|
|
)
|
|
parser.add_argument(
|
|
"-e",
|
|
"--enc",
|
|
action="store_true",
|
|
default=False,
|
|
help="Use this flag to encrypt a file",
|
|
)
|
|
parser.add_argument(
|
|
"-t",
|
|
"--fumen",
|
|
action="store_true",
|
|
default=False,
|
|
help="Datatable is default, use this flag for Fumen",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
if not args.input:
|
|
print("Missing input file, pass the argument --help for help")
|
|
exit(0)
|
|
|
|
if not args.output:
|
|
print("Missing output file, pass the argument --help for help")
|
|
exit(0)
|
|
|
|
type = Keys.Datatable if not args.fumen else Keys.Fumen
|
|
|
|
if os.path.isdir(args.input):
|
|
for path, subdirs, files in os.walk(args.input):
|
|
for name in files:
|
|
full_path = os.path.join(path, name)
|
|
relative_path = os.path.relpath(full_path, args.input)
|
|
outpath = os.path.join(args.output, relative_path)
|
|
outdir = os.path.dirname(outpath)
|
|
|
|
Path(outdir).mkdir(parents=True, exist_ok=True)
|
|
|
|
if os.path.isfile(full_path):
|
|
save_file(
|
|
file=full_path,
|
|
outdir=outpath,
|
|
encrypt=False if not args.enc else True,
|
|
)
|
|
|
|
else:
|
|
save_file(
|
|
file=args.input,
|
|
outdir=args.output,
|
|
encrypt=False if not args.enc else True,
|
|
)
|