This article provides a practical, hands-on guide to programmatically processing Swank AES hard drives using Python. The previous article, "Getting Started: A Guide to Processing Swank AES Encrypted Hard Drives," explained the concepts and file structure. Here, we will translate that logic into functional code.
While these examples are in Python, the core cryptographic principles can be applied to any modern programming language like C#, Java, or Go.
1. Setup & Prerequisites
Before you begin, ensure you have the following:
- Python Environment: This code is written for modern Python (e.g., Python 3.8+).
- PyCryptodome Library: This is a required third-party library for performing the AES decryption. It is a replacement for the older, unmaintained PyCrypto library.
You can install pycryptodome using pip:
Shell
pip install pycryptodome
Let's start by creating a Python script and defining the essential configuration variables.
process_drive.py
Python
import os
import json
import base64
from Crypto.Cipher import AES
# --- CONFIGURATION: SET THESE VALUES ---
# The root path to the Swank hard drive.
DRIVE_ROOT_PATH = "E:\\" # Example: "E:\\" on Windows or "/media/swankdrive/" on Linux
# Your unique Customer Encryption Key provided by Swank, as a Base64 string.
CUSTOMER_ENCRYPTION_KEY_BASE64 = "YOUR_BASE64_CUSTOMER_ENCRYPTION_KEY_HERE"
# -----------------------------------------
def main():
"""
Main function to process the Swank AES drive.
"""
print("Starting Swank Drive Processing...")
# The rest of our logic will go here.
print("Processing complete.")
if __name__ == "__main__":
main()
2. The Decryption Engine
The core of the solution is a reusable decryption function. The process is identical for decrypting both the Content Key and the main content file.
The critical steps are:
- Extract the first 16 bytes of the encrypted data as the Initialization Vector (IV).
- Use the remaining bytes as the encrypted payload.
- Perform AES-256-CBC decryption.
- Remove the PKCS7 padding from the decrypted result.
Here is the helper function for this process.
process_drive.py (add this function)
Python
def unpad_pkcs7(data):
"""
Removes PKCS7 padding from a byte string.
"""
padding_len = data[-1]
return data[:-padding_len]
def decrypt_data(encrypted_data_with_iv, key):
"""
Decrypts data using AES-256-CBC with PKCS7 padding.
The IV is expected to be the first 16 bytes of the encrypted_data_with_iv.
"""
# 1. Extract the IV (first 16 bytes)
iv = encrypted_data_with_iv[:16]
# 2. Extract the encrypted content (the rest of the data)
encrypted_data = encrypted_data_with_iv[16:]
# 3. Create the AES cipher
cipher = AES.new(key, AES.MODE_CBC, iv)
# 4. Decrypt and unpad the data
decrypted_padded_data = cipher.decrypt(encrypted_data)
decrypted_data = unpad_pkcs7(decrypted_padded_data)
return decrypted_data
3. Putting It All Together: The Main Process
Now, let's update our main function to read the manifest, loop through each title, and perform the decryption and file handling.
process_drive.py (update the main function)
Python
def main():
"""
Main function to process the Swank AES drive.
"""
print("Starting Swank Drive Processing...")
# 1. Validate configuration
if "YOUR_BASE64" in CUSTOMER_ENCRYPTION_KEY_BASE64:
print("\033[91mERROR: Please set your 'CUSTOMER_ENCRYPTION_KEY_BASE64' in the script.\033[0m")
return
customer_encryption_key = base64.b64decode(CUSTOMER_ENCRYPTION_KEY_BASE64)
# 2. Read and parse Manifest.json
manifest_path = os.path.join(DRIVE_ROOT_PATH, "Manifest.json")
try:
with open(manifest_path, 'r') as f:
manifest = json.load(f)
except FileNotFoundError:
print(f"ERROR: Manifest.json not found at '{manifest_path}'")
return
except json.JSONDecodeError:
print(f"ERROR: Could not parse Manifest.json. Ensure it is valid JSON.")
return
content_items = manifest.get('ContentItems', [])
print(f"Found {len(content_items)} title(s) to process.")
# 3. Loop through each title in the manifest
for title in content_items:
film_number = title['Identifiers']['FilmNumber']
title_name = title['Title']
print(f"\n--- Processing Title: {title_name} ({film_number}) ---")
try:
# STEP A: Decrypt the Content Key
print("Step A: Decrypting Content Key...")
encrypted_content_key_b64 = title['DRMKeyInfo'][0]['Key']
encrypted_content_key_with_iv = base64.b64decode(encrypted_content_key_b64)
# Decrypt it using our Customer Key
decrypted_content_key = decrypt_data(encrypted_content_key_with_iv, customer_encryption_key)
print("Content Key decrypted successfully.")
# STEP B: Decrypt the Content File
print("Step B: Decrypting Content File...")
# Per the documentation, the filename is the FilmNumber with an extension
content_file_name = f"{film_number}.MP4"
asset_location = title['Asset']['Location']
encrypted_file_path = os.path.join(DRIVE_ROOT_PATH, asset_location, content_file_name)
with open(encrypted_file_path, 'rb') as f:
encrypted_file_with_iv = f.read()
# Decrypt the file using the decrypted Content Key from Step A
decrypted_file_data = decrypt_data(encrypted_file_with_iv, decrypted_content_key)
# Save the decrypted file
output_directory = os.path.join(os.getcwd(), "DecryptedOutput", film_number)
os.makedirs(output_directory, exist_ok=True)
decrypted_file_path = os.path.join(output_directory, content_file_name)
with open(decrypted_file_path, 'wb') as f:
f.write(decrypted_file_data)
print(f"Content file decrypted and saved to: {decrypted_file_path}")
# STEP C & D: Locate Metadata and Publicity Assets
print("Step C/D: Locating metadata and publicity assets...")
publicity_metadata_path = os.path.join(DRIVE_ROOT_PATH, title['PublicityMetadataLocation'])
media_info_path = os.path.join(DRIVE_ROOT_PATH, title['Asset']['MediaFileInfoLocation'])
print(f"Publicity Metadata is at: {publicity_metadata_path}")
print(f"Media File Info is at: {media_info_path}")
# In a real application, you would parse these JSON files and copy publicity assets.
except Exception as e:
print(f"\033[91mAn error occurred while processing title {title_name}: {e}\033[0m")
print("\nProcessing complete.")
Conclusion
This guide provides a complete, functional Python script for processing Swank AES drives. By following this structure, you can automate the ingestion of content and metadata into your systems.
Key Takeaways:
-
The
Manifest.jsondrives everything: It is the single source of truth for all file locations on the drive. - The Decryption pattern is consistent: The process of separating the 16-byte IV from the data and using AES-256-CBC decryption is the same for both the Content Key and the Content File. Remember to handle the PKCS7 unpadding after decryption.
- Production Code: This example omits robust logging, configuration management, and more advanced error handling that would be necessary for a production environment. Please adapt it to fit your production standards.
Comments
0 comments
Please sign in to leave a comment.