---
# System prepended metadata

title: Team 19 "Vigenere + CTR" writeup

---

After understanding the challenge script, I know that
1) `add()` and `sub()` is from Vigenere Cipher
2) how `ctf()` change the nonce is first adding 1 to the last character, then flip the string. 
The details are not important, I am just interested in knowing that the process doesn't involve any random component, so the changes to the nonce is reproducible
3) in `vigenere_ctr_enc()`, first two steps in the for loop can be combined to ctxt += (b + nonce + key), where the addition here is the Vigenere Cipher's addition
4) the value of `nonce` is given in the first block in `CTXT`
5) the value of `KEY` is constant

Then, I start solving it.
1. From the challenge script, I know that except the first block in `CTXT`, `CTXT_blocks[i] = message_blocks[i - 1] + current nonce + KEY`. As mentioned, the change to `nonce` is reproducible, therefore I can easily remove the value of `current nonce` from `CTXT_blocks[i]`.What remained in each block `i` will be `message_blocks[i - 1] + KEY`, which is simply `message_blocks[i - 1] + a constant`.

    ```python
    def get_blocks(s):
        blocks = []
        i = 0
        while(i + BLOCKLENGTH<len(s)):
            blocks.append(s[i:i+BLOCKLENGTH])
            i = i + BLOCKLENGTH
        blocks.append(s[i:len(s)])
        return(blocks)

    def ctr(num):
        decimal_num = 0
        power = len(num) - 1 
        for digit in num:
            decimal_num += (ord(digit) - ord('A')) * (MOD ** power)
            power -= 1

        decimal_num += 1

        result = ""
        while decimal_num > 0: 
            remainder = decimal_num % MOD
            result = chr(remainder + ord('A')) + result 
            decimal_num //= MOD

        return(result)

    def add(block1,block2):
        assert(len(block1)<= len(block2))
        assert(len(block2)<= BLOCKLENGTH)
        b1upper = block1.upper()
        b2upper = block2.upper()
        b1 = [ ord(b1upper[i])-SHIFT for i in range(len(block1))]
        b2 = [ ord(b2upper[i])-SHIFT for i in range(len(block1))]
        s = [ (b1[i] + b2[i]) % MOD for i in range(len(block1))]
        slist = [ chr(s[i]+SHIFT) for i in range(len(block1))]
        sum = ''.join(slist)
        return(sum)

    def sub(block1,block2):
        assert(len(block1)<= len(block2))
        assert(len(block2)<= BLOCKLENGTH)
        b1upper = block1.upper()
        b2upper = block2.upper()
        b1 = [ ord(b1upper[i])-SHIFT for i in range(len(block1))]
        b2 = [ ord(b2upper[i])-SHIFT for i in range(len(block1))]
        s = [ (b1[i] - b2[i]) % MOD for i in range(len(block1))]
        slist = [ chr(s[i]+SHIFT) for i in range(len(block1))]
        sum = ''.join(slist)
        return(sum)


    SHIFT = 65
    MOD = 26
    BLOCKLENGTH = 20
    CTXT = "ULDGWMFOXRNTKTVECMMNPQPAJYLJPIXJQUTYRQIQLQSURMZGYUTTPMHOHJAKNQKFFYGTPWXTMFWKHELLZYYFSUDNFKHOZAQIFQDPLUEFFPAILDTXQWWWKIGSVPPTMMWQMODAIBCODZTDSYUQBFSMLSILAZZHVXNTHPUASMZQBBSQZIKHQCLQFQXQAUJGMKACTYBBVMCXUMJOC"

    # everything above is direcly copied from the challenge script
    def RemoveNonce(ctxt):
        blocks = get_blocks(ctxt)
        nonce = blocks[0]
        ptxt = ""
        for i in range(1, len(blocks)):
            ptxt += sub(blocks[i], nonce)
            nonce = ctr(nonce)
        return(ptxt)

    CTXT_without_nonce = RemoveNonce(CTXT)
    print(''.join(get_blocks(CTXT_without_nonce)))

    ```
    Then, we will get the output string 
    ```
    VFMUNMGVSRKQGBYUPEWDRFPOVAUSBDGAFTMKFXOWTFHZJMBFSFKACMBGFSZWFNVZWIYZITUVPHVEDERZRJBZJDVUOMGEGDBSIWUBBEMNQARCPXQHYIHKBNHLYNRKFTNYOBVSQGEDTLBANERUWAUCEKFXPPPDOQZWLFUKEIESPTNJJFGXTAQCABGIG
    ```
    Block `i` in this string is `message_blocks[i] + KEY`. As the `KEY` is a constant value, what we get is a simple Vigenere Cipher.
2. We can break the Vigenere Cipher using online tool, e.g. https://guballa.de/vigenere-solver.
![image](https://hackmd.io/_uploads/Byu5535Ka.png)

    Then we will get
    ```
    ISTOLETHISIDEAFROMTHESWITSHEREENDSTHEFLAGSOTHEORIGINALIDEAWASACTUALLYUSINGCBCMODEWITHVIGENERECIPHERFORTHOSEOFYOUWHOHAVEPLAYEDLAKECTFOFLASTYEARYOUSHOULDKNOWANYWAYSBECAREFULWHENUSINGNONCE
    ```

    Reading the message, we will see `"HERE ENDS THE FLAG"`, so we stop right before it.
    
    flag: `firebird{ISTOLETHISIDEAFROMTHESWITS}`