チームpapipupepoで参加し、全体30位、日本学生10位でした!

https://x.com/PotyaExe/status/1918866193638641980

a8tsukuctf

問題

適当な KEY を作って暗号化したはずが、 tsukuctf の部分が変わらないなぁ...

解法

ヴィジュネル暗号の問題ってことはわかったので、AIに投げたらできました。

AI最高

ただ、理解をしないといけないので、ちゃんと解きます。

今回は

$$ C_i \equiv (P_i + K_i) \bmod 26
$$

で暗号化されています。つまり、復号化する場合はKeyだけ引いてあげたら良いです。

$$ C_i \equiv (P_i - K_i) \bmod 26
$$

後は、暗号化コードに従って、同じ操作をしてあげたら元の文章が出てくるでしょう。

import string

ciphertext = "ayb wpg uujmz pwom jaaaaaa aa tsukuctf, hj vynj? mml ogyt re ozbiymvrosf bfq nvjwsum mbmm ef ntq gudwy fxdzyqyc, yeh sfypf usyv nl imy kcxbyl ecxvboap, epa 'avb' wxxw unyfnpzklrq."

def f_inv(c, k):
    c = ord(c) - ord('a')
    k = ord(k) - ord('a')
    ret = (c - k + 26) % 26
    return chr(ord('a') + ret)

def decrypt(c, position):
    # 1) Extract only lowercase letters for keystream calculation
    cipher_without_symbols = [c for c in ciphertext if c in string.ascii_lowercase]

    # 2) Recover the initial keystream using the known plaintext "tsukuctf"
    known_plain = 'tsukuctf'
    init_key = []
    for i in range(len(known_plain)):
        c = cipher_without_symbols[position + i]
        p = known_plain[i]
        # keystream = (cipher - plain) mod 26
        k = (ord(c) - ord(p)) % 26
        k = chr(ord('a') + k)
        init_key.append(k)

    # 3) Decrypt full message using an autokey Vigenere cipher:
    #    - First use the recovered initial keystream
    #    - Then append each decrypted plaintext to the keystream
    plain = []
    idx = 0
    key = init_key
    for c in ciphertext:
        if c in string.ascii_lowercase:
            # Choose the keystream character:
            #    - For the first len (init_key) letters, use the recovered initial key
            #    - Afterwards, use previous ciphertext letters as the autokey
            if idx < len(key):
                k = key[idx]
            else:
                k = cipher_without_symbols[idx - len(key)]
            p = f_inv(c, k)
            plain.append(p)
            idx += 1
        else:
            plain.append(c)

    return ''.join(plain), ''.join(init_key)

plaintext, key = decrypt(ciphertext, 30)

print("key:", key)
print("m:", plaintext)
key: annzbwue
m: alo xok aqjoy this problem or tsukuctf, or both? the flag is concatenate the seventh word in the first sentence, the third word in the second sentence, and 'fun' with underscores.