Example file: [[selfdec.html]] -- passphrase is `hello` Generated by ```bash python encode.py cover.html payload.html PassPhrase output.html ``` Python source ```py import base64 import os import sys import urllib.request from cryptography.hazmat.primitives import hashes, padding from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC CRYPTOJS_FILENAME = "crypto-js.min.js" CRYPTOJS_URL = "https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js" def get_cryptojs_source(): """Fetches CryptoJS once from CDN and caches it locally for offline inlining.""" if not os.path.exists(CRYPTOJS_FILENAME): print("[*] Downloading CryptoJS library for offline embedding (requires internet once)...") try: urllib.request.urlretrieve(CRYPTOJS_URL, CRYPTOJS_FILENAME) except Exception as e: print(f"[-] Error downloading CryptoJS: {e}") sys.exit(1) with open(CRYPTOJS_FILENAME, "r", encoding="utf-8") as f: return f.read() def derive_key(passphrase: str, salt: bytes) -> bytes: """Derive a 256-bit AES key from the passphrase and salt using PBKDF2-HMAC-SHA256.""" kdf = PBKDF2HMAC( algorithm=hashes.SHA256(), length=32, salt=salt, iterations=100_000 ) return kdf.derive(passphrase.encode('utf-8')) def encrypt_html(cover_path: str, payload_path: str, passphrase: str, output_path: str): # 1. Read files with open(payload_path, "r", encoding="utf-8") as f: payload_html = f.read() with open(cover_path, "r", encoding="utf-8") as f: cover_html = f.read() # Get the inlineable CryptoJS source code cryptojs_code = get_cryptojs_source() # 2. Generate cryptographic parameters salt = os.urandom(16) iv = os.urandom(16) # AES block size is 16 bytes for CBC key = derive_key(passphrase, salt) # 3. Apply PKCS7 Padding and Encrypt using AES-CBC padder = padding.PKCS7(128).padder() padded_data = padder.update(payload_html.encode('utf-8')) + padder.finalize() cipher = Cipher(algorithms.AES(key), modes.CBC(iv)) encryptor = cipher.encryptor() ciphertext = encryptor.update(padded_data) + encryptor.finalize() # Pack salt, iv, and ciphertext together, then base64 encode blob = salt + iv + ciphertext b64_blob = base64.b64encode(blob).decode('utf-8') # 4. Generate the fully offline, self-contained HTML wrapper template = """
Please enter the passphrase to view this page.