Last active
August 27, 2024 15:28
-
-
Save UserUnknownFactor/c5b63960016f3cf8bc9c060644aebb9c to your computer and use it in GitHub Desktop.
Tool to decrypt/encrypt CryptoJS encrypted files in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Tool to decrypt/encrypt CryptoJS encrypted files in Python | |
import os, base64, glob | |
from hashlib import md5 | |
from Crypto.Cipher import AES # requires: pip install pycryptodome | |
from Crypto import Random | |
STREAM_PREFIX = b"Salted__" | |
def pad(s): | |
padding = 16 - len(s) % 16 | |
return s + padding * chr(padding).encode() | |
def unpad(s): | |
return s[0:-ord(s[-1:])] | |
def bytes_to_key(data, salt, output=32+16): | |
assert len(salt) == 8, f"salt's length must be 8, {len(salt)} provided" | |
data += salt | |
key = md5(data).digest() | |
final_key = key | |
while len(final_key) < output: | |
key = md5(key + data).digest() | |
final_key += key | |
return final_key[:output] | |
def encrypt_cryptojs(data, password): | |
salt = Random.new().read(8) | |
key_iv = bytes_to_key(password, salt) | |
key, iv = key_iv[:32], key_iv[32:] | |
aes = AES.new(key, AES.MODE_CBC, iv) | |
return base64.b64encode(STREAM_PREFIX + salt + aes.encrypt(pad(data))) | |
def decrypt_cryptojs(data, password): | |
data = base64.b64decode(data) | |
assert data[:8] == STREAM_PREFIX, f"data must start with {STREAM_PREFIX}, found {data[:8]}" | |
salt = data[8:16] | |
key_iv = bytes_to_key(password, salt, 32+16) | |
key, iv = key_iv[:32], key_iv[32:] | |
return unpad( AES.new(key, AES.MODE_CBC, iv).decrypt(data[16:]) ) | |
def process_files(input_mask, output_dir, decrypt, key): | |
for filename in glob.glob(input_mask, recursive=True): | |
print(f"{'De' if decrypt else 'En'}crypting {filename}...", end='') | |
filepath = os.path.relpath(filename) | |
output_filepath = os.path.join(output_dir, filename) | |
with open(filepath, "rb") as f: | |
data = f.read() | |
try: | |
if decrypt: | |
processed_data = decrypt_cryptojs(data, key) | |
else: | |
processed_data = encrypt_cryptojs(data, key) | |
os.makedirs(os.path.dirname(output_filepath), exist_ok=True) | |
with open(output_filepath, "wb") as f: | |
f.write(processed_data) | |
print(f" OK ({os.path.relpath(output_filepath)})") | |
except Exception as e: | |
print(f" SKIPPED")# ({str(e)})") | |
def main(): | |
import argparse | |
parser = argparse.ArgumentParser(description="Tool to decrypt/encrypt CryptoJS format files") | |
parser.add_argument("--input", "-i", default=".\\**\\*.json", help="Input file mask (default to JSON files)") | |
parser.add_argument("--output", "-o", default="processed", help="Output directory") | |
parser.add_argument("--decrypt", "-d", action="store_true", help="Decrypt the files (default)") | |
parser.add_argument("--encrypt", "-e", action="store_true", help="Encrypt the files") | |
parser.add_argument("--key", "-k", default=b"_myJSkey16bytes_", help="Encryption/decryption key") | |
args = parser.parse_args() | |
if args.encrypt and args.decrypt: | |
parser.error("Please specify either --decrypt or --encrypt.") | |
process_files(input_mask=args.input, output_dir=args.output, decrypt=not args.encrypt, key=args.key) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment