|
| 1 | +<?php |
| 2 | + |
| 3 | +// This script attempts to decrypt an urlencoded & base64 encoded string that |
| 4 | +// was generated using Construct 3's Cryptography plugin using password-based |
| 5 | +// AES 256 encryption. |
| 6 | +// The decrypt_c3_aes_gcm function takes a base64 encoded string as an input. |
| 7 | +// The script expects the payload in the "data" GET parameter; since base64 |
| 8 | +// strings are not URL safe, the payload must be urlencoded as well. |
| 9 | + |
| 10 | +define('PASSWORD', 'hackerman'); // enter the same password you specified in C3 |
| 11 | + |
| 12 | +function decrypt_c3_aes_gcm($encrypted_base64, $password) { |
| 13 | + |
| 14 | + // Base64 decode the input |
| 15 | + $encrypted_data = base64_decode($encrypted_base64); |
| 16 | + |
| 17 | + if ($encrypted_data === false) { |
| 18 | + return false; // Return false if Base64 decoding fails |
| 19 | + } |
| 20 | + |
| 21 | + // Extract parts from the binary data based on the format described here: |
| 22 | + // https://www.construct.net/en/make-games/manuals/construct-3/plugin-reference/cryptography#internalH1Link4 |
| 23 | + |
| 24 | + $reserved = ord($encrypted_data[0]); // Reserved byte (should be 0) |
| 25 | + $salt = substr($encrypted_data, 1, 16); // Salt (16 bytes) |
| 26 | + $iv = substr($encrypted_data, 17, 12); // Initialization Vector (12 bytes) |
| 27 | + $iterations = unpack('N', substr($encrypted_data, 29, 4))[1]; // Iterations (4 bytes, uint32) |
| 28 | + $ciphertext = substr($encrypted_data, 33); // Ciphertext starts from byte 33 onwards |
| 29 | + // Validate the reserved byte is zero |
| 30 | + if ($reserved !== 0) { |
| 31 | + return false; // Invalid format (reserved byte is not 0) |
| 32 | + } |
| 33 | + |
| 34 | + // Derive the encryption key using PBKDF2 with the provided password, salt, and iterations |
| 35 | + $key = hash_pbkdf2('sha256', $password, $salt, $iterations, 32, true); // 256-bit (32-byte) key |
| 36 | + // Separate the encrypted payload and the GCM authentication tag |
| 37 | + $tag = substr($ciphertext, -16); // GCM authentication tag (16 bytes at the end) |
| 38 | + $encrypted_payload = substr($ciphertext, 0, -16); // Encrypted data (without tag) |
| 39 | + // Decrypt the payload |
| 40 | + $decrypted_data = openssl_decrypt( |
| 41 | + $encrypted_payload, // Ciphertext |
| 42 | + 'aes-256-gcm', // Cipher method |
| 43 | + $key, // Key derived from password |
| 44 | + OPENSSL_RAW_DATA, // Output raw data |
| 45 | + $iv, // Initialization vector (IV) |
| 46 | + $tag // GCM tag |
| 47 | + ); |
| 48 | + |
| 49 | + // Return the decrypted text if successful, or false if decryption failed |
| 50 | + return $decrypted_data !== false ? $decrypted_data : false; |
| 51 | +} |
| 52 | + |
| 53 | +// Get the encrypted data from the "data" GET parameter and urldecode it |
| 54 | +$encrypted_data_base64 = urldecode(filter_input(INPUT_GET, 'data')); |
| 55 | + |
| 56 | +// Try to decrypt the data |
| 57 | +$decrypted_text = decrypt_c3_aes_gcm($encrypted_data_base64, PASSWORD); |
| 58 | + |
| 59 | +if ($decrypted_text !== false) { |
| 60 | + echo 'Decrypted Text: ' . $decrypted_text; |
| 61 | +} else { |
| 62 | + echo 'Decryption failed!'; |
| 63 | +} |
0 commit comments