│ Category: Cryptography
│ Author: Imattas aka Zemi
│ Flag: byuctf{cryptonerdsgobrrrrrrweneedmoreofthem}
│ Source Path: crypto/anaken21sec2
────────────────────────────────────────────────────────────────────────────────
--[ Challenge Description ]--
-- text --
I made this custom encryption algorithm for my crypto class and decided to share it with you guys! Let's see if you can break it without knowing the key...
*Note - wrap the flag in `byuctf{}`*
`nc anaken21sec2.chal.cyberjousting.com 1347`
[encrypt.py] [break.py]
────────────────────────────────────────────────────────────────────────────────
--[ Provided Materials ]--
- Repository folder
https://github.com/BYU-CSA/BYUCTF-2025/tree/main/crypto/anaken21sec2
- crypto/anaken21sec2/README.md
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/crypto/anaken21sec2/README.md
- crypto/anaken21sec2/break.py
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/crypto/anaken21sec2/break.py
- crypto/anaken21sec2/solve.py
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/crypto/anaken21sec2/solve.py
────────────────────────────────────────────────────────────────────────────────
--[ Recon / Initial Analysis ]--
This page imports the BYUCTF 2025 source material for the Cryptography challenge
Anaken21sec2. The prompt is kept separate from the solve notes, and upstream
artifacts are linked so the challenge can be replayed from the original
repository.
────────────────────────────────────────────────────────────────────────────────
--[ Vulnerability / Observation ]--
The useful observation comes from the imported solve notes below. I kept the
original technical path intact while normalizing the page metadata, challenge
grouping, and author attribution for the Volume 2 writeup archive.
────────────────────────────────────────────────────────────────────────────────
--[ Exploitation / Solution ]--
Source: crypto/anaken21sec2/README.md
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/crypto/anaken21sec2/README.md
To break the encryption, you can exploit the fact that the same key is used to
mix up the 6x6 box as is used to shuffle the letters at the end. This leaves the
encryption vulnerable to a chosen plaintext attack. By using a chosen plaintext
attack, you can figure out the alphabetical order of the key. Then, you can use
that to reduce the brute force space to a matter of minutes instead of days. You
can do this as follows:
1. Encrypt several (at least 10) different 12-letter plaintexts and keep track
of their encryptions
2. Encrypt the concatenation of the plaintexts
3. Using the output of the long plaintext and comparing it to the short outputs,
you can deduce the alphabetical order of the key.
4. Using the alphabetical order of the key, you can brute force the key much
faster than trying all 25^11 combinations.
Here is an example. We start by encrypting the following plaintexts on the left
and we get the ciphertexts on the right.
aaaaaaaaaaaa frqccahtwirw
rrrrrrrrrrrr gjmfkputacxz
zzzzzzzzzzzz qxkonxnjghvf
dddddddddddd fehu0hztzrlm
uuuuuuuuuuuu gudxqnltdlip
llllllllllll yunrvnt0ivzj
gggggggggggg fpzlfcqtt0fc
tttttttttttt qbbfkvejaqpz
cccccccccccc puuu0ngjzedm
yyyyyyyyyyyy xpfoncv0gjnf
Then we encrypt the concatenation and get the following ciphertext.
aaaaaaaaaaaarrrrrrrrrrrrzzzzzzzzzzzzdddddddddddduuuuuuuuuuuullllllllllllggggggggggggttttttttttttccccccccccccyyyyyyyyyyyy
frfjhiv0ezcqxnrliczpuoctklqvqanfccnznjfpfjfazqxutnfkevhaxmgurtbdntmv0lttvmxpwpffex0zp0jiughpyuljunrkhzdncqbu0wgjotdzfqgg
We can split up the cipher text by the letters in the first plaintext (each
split should be with in 1 letter of length from the others)
frfjhiv0ezc qxnrliczpuo ctklqvqanf ccnznjfpfjf azqxutnfkev haxmgurtbdn tmv0lttvmxp wpffex0zp0j iughpyuljun rkhzdncqbu0 wgjotdzfqgg
From here we can split each of the chunks into letters based off the
ciphertexts. Note that each line represents a letter of the key. Since each
message is 11 letters long and the cipher is done in blocks of 12, each letter
will take 1 or 2 letters (but usually 1) from each of the individual
ciphertexts. We can use this to discover the order of the key. For example, the
first line has 2 letters from the first ciphertext. Thus, it is the first to
come alphabetically from the key. The last letter comes next alphabetically and
so on. (Sometimes it gives ambiguous results, but it usually causes errors later
on so you can go back and check your work)
1 fr f j h i v 0 e z c
2 q x n r l i c z pu o
3 c t k l q v q a n f
4 c c n z n j fp f j f
5 a z qx u t n f k e v
6 h a x m gu r t b d n
7 t m v 0 l t t v m xp
8 w p f fe x 0 z p 0 j
9 i u g h p yu l j u n
10 r k h z d n c qb u 0
11 w gj o t d z f q g g
From this we know that the order must go
1 11 5 8 6 9 4 10 2 7 3
Now, we can use this to brute force any plaintext. My code to brute force is in
brute.py. I used the plaintext "abcdefghijkl" with corresponding ciphertext
"gsswpplcfyjn". This yields 2 potential keys in less than 12 minutes:
cxjqksgwdlf
cxjqkriwdlf
These are actually both valid keys that perform the same encryption (on every
plaintext that I tried at least). Using either key, we can now decrypt the
ciphertext to find the flag.
Flag - byuctf{cryptonerdsgobrrrrrrweneedmoreofthem}
────────────────────────────────────────────────────────────────────────────────
--[ Full Exploit Script ]--
Source: crypto/anaken21sec2/break.py
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/crypto/anaken21sec2/break.py
-- python --
#!/usr/local/bin/python
import encrypt
key = encrypt.getRandomKey()
flag = open("flag.txt").read().strip().split("byuctf{")[1].split("}")[0]
flag = [letter.lower() for letter in flag if letter.isalpha()]
print(encrypt.encrypt(flag, key))
for _ in range(20):
plaintext = input("What to encrypt:\n")
plaintext = [letter.lower() for letter in plaintext if letter.isalpha()]
if plaintext == "":
break
print(encrypt.encrypt(plaintext, key))
────────────────────────────────────────────────────────────────────────────────
Source: crypto/anaken21sec2/solve.py
https://github.com/BYU-CSA/BYUCTF-2025/blob/main/crypto/anaken21sec2/solve.py
-- python --
import encrypt
from itertools import combinations
from time import time
plaintext = input("What is the plaintext?\n")
ciphertext = input("What is ciphertext?\n")
order = input("what is the order of the 11-digit key\n").split(" ")
order = [int(i)-1 for i in order]
numbers = [chr(i) for i in range(97, 97+25)]
start = time()
for comb in combinations(numbers, 11):
key = ""
for i in range(11):
key += comb[order[i]]
if encrypt.encrypt(plaintext, key) == ciphertext:
print(key, time()-start)
print("complete", time()-start)
────────────────────────────────────────────────────────────────────────────────
--[ Key Takeaways ]--
- The BYUCTF 2025 challenge material is preserved with local archive formatting.
- The page author is normalized to Imattas aka Zemi.
- The source repository remains linked for handouts, services, and solve
artifacts.