🧙‍♂️ Enchanted Cipher — Write-Up | Cyber Apocalypse 2025

Details
URL [Hack The Box :: Enchanted Cipher
Difficulty Easy
Team Rank 541 / 8129
CTF Date 26 Mar, 13:00

📖 Challenge Summary

The Grand Arcane Codex has been corrupted. To restore historical records, each entry must be deciphered from an Enchanted Shifting Cipher. This cipher encrypts messages using a Caesar-style shift, but with a twist:

🧩 Cipher Rules

  • Only alphabetic characters are encrypted; all other characters (e.g., spaces) are ignored during encryption.
  • Characters are grouped into chunks of 5 letters.
  • Each group is encrypted with a random Caesar shift (between 1 and 25).
  • The input ends with:
    1. The number of shift groups.
    2. A list of Caesar shift values, one for each group.

Your task is to reverse the cipher, restoring the original plaintext while preserving the formatting (spaces, punctuation, etc.).


🛠️ Decryption Approach

  1. Extract all alphabetic characters, ignoring any spaces or symbols.
  2. Group these characters into chunks of 5.
  3. Decrypt each group using the corresponding shift from the provided list.
  4. Reconstruct the original message by re-inserting non-alphabetic characters at their original positions.

🔮 Final Challenge Input

jqccqa rsfbhwl wzafbqy hpnbqo qfcicn

💡 Takeaways

  • When solving multi-shift ciphers, group tracking and precise indexing are crucial.
  • Caesar shifts can be reversed easily using modular arithmetic:
decrypted = (ord(c) - ord('a') - shift) % 26 + ord('a')

import string

ciphertext = input().strip()
group_count = int(input().strip())
shifts = eval(input().strip())

alpha_chars = []
non_alpha_positions = {}

for i, c in enumerate(ciphertext):
    if c.isalpha():
        alpha_chars.append(c.lower())
    else:
        non_alpha_positions[i] = c  

groups = [alpha_chars[i:i+5for i in range(0, len(alpha_chars), 5)]

def decrypt_char(c, shift):
    return chr((ord(c) - ord('a'- shift) % 26 + ord('a'))

decrypted_chars = []

for i, group in enumerate(groups):
    shift = shifts[i]
    decrypted_group = [decrypt_char(c, shift) for c in group]
    decrypted_chars.extend(decrypted_group)  

final_output = []
alpha_index = 0

for i in range(len(ciphertext)):
    if i in non_alpha_positions:
        final_output.append(non_alpha_positions[i])
    else:
        final_output.append(decrypted_chars[alpha_index])
        alpha_index += 1

print(''.join(final_output))

🏁 Flag

‘‘HTB{3NCH4NT3D_C1PH3R_D3C0D3D_33e4f8554a8de74dbe70c5d34852dbfd}’’