# HalfTimePad
## Desc
There is a hidden message in this service that contains flag.
Here is the leaked source code of program: [cipher.go]()
ez pz!
```bashcurl halftimepad.roboepics.com```
## Solution
This is what leaked `cipher.go` does: it has a function called `HalfTimePad` which its objective is to encrypt global `plain` variable by XORing it with a genereted byte string for each request. The byte string is being generated by choosing random bytes for random length (between 20 and 100) and cycling it until it has same length as the plain text.
```           ----------------------------------------            |             Plain Text               |           ----------------------------------------            ----------------------------------------            | key | key | key | key | key | key | k|           ----------------------------------------      (XOR) ========================================            ----------------------------------------            |             Cipher Text              |           ---------------------------------------- ```
Notice that we know the plain text contains the flag and the flag contains `xeroctf{` and if we know the length of the key (`l`) and index of `xeroctf{` we could obtain a part of the key by XORing cipher text with `xeroctf{`, hence we could obtain parts of plain text. These parts should be meaningful and of course printable. So we can find `l` and `i` by bruteforcing all possible cases.
```                             ,_ i _,                                                `v'                             ----------------------------------------   Plain:   |                    xeroctf{          |           ----------------------------------------            ----------------------------------------   Key:     |    #found##   |    #found##   |   ###|           ----------------------------------------      (XOR) ========================================            ----------------------------------------   Cipher:  |    #found##        #found##       #fo|           ---------------------------------------- ```
Here is a python script for finding candidate `(l, i)`s:
```pythonimport base64import string
# Sample ciphercipher = """"x2jJ4MpMB7EwWkl61QHoywcmK5V0TrxsbZykIyHZB6FCWv07K01lTZWgNczh6Gv0uaICnV3Yn4MVk3Fvl5AQPpBaecutA9ddc8EV0ytvUPCpt50AFYHtz9K+/hDLgFs2/PKvMoz/8A8MujZaCGiJYuXAETAl9nMGoG1tk7tiJ8NUuEpY/j1/Wy8xmaJ5143WTZ2dgiLua//NgFScXGPEvRJojR12hb0+4XEAviP4VF1Im+nqkxRbhKHR0qvpSZ+QUHnj+K84l7+OBQ2hNAgddM4brdEGLXG/YQa5djmBu2Zgmx20D0f+LG4TXhaX7nyYpvh2urPsD8lHntqYWodkYpboKnWzXHiP+SfLTTTLI61VXWrOmQ=="""cipher = base64.b64decode(cipher)
flag_header = b"xeroctf{"
def wrapping(lst, n):    return [lst[i:i+n] for i in range(0, len(lst), n)]
def decipher(key, cipher):    d = b''    for i in range(len(cipher)):        d += bytes([cipher[i] ^ key[i%len(key)]])    return d
def isprintable(s):    return all(c < 127 and chr(c) in string.printable for c in s)
for n in range(20, 101):    for i in range(len(cipher)-len(flag_header)):        part = cipher[i:i+len(flag_header)]        dekey = bytes([part[j] ^ flag_header[j] for j in range(len(part))])
        key = [0] * n        ikey = set([])        for j in range(len(dekey)):            index = (j + i) % n            key[index] = dekey[j]            ikey.add(index)
        txt = decipher(key, cipher)        ws = wrapping(txt, n)
        f = True        for w in ws:            for k in ikey:                if not isprintable(w[k:k+1]):                    f = False        if f:            for w in ws:                s = "".join([chr(w[i]) for i in ikey if i < len(w)])                print(s)
```
By checking candidates, we will find that `i = 129`.
Now considering `crypto.go` chooses random `l` between 20 and 100, for every `l` we can extract distinct places of the plain text by almost the same process:
```                             ,_ i _,                                                `v'                             ----------------------------------------   Plain:   |#found2#nd1#        xeroctf{       #fo|           ----------------------------------------            ----------------------------------------   Key1:    |    #found1#   |    #found1#   |   ###|           ----------------------------------------            ----------------------------------------   Key2:    |#found2#           |#found2#          |           ----------------------------------------            .                 .                    .           .                 .                    .           .                 .                    .
```
```pythonplain = Nonewhile True:    cipher = input().strip()    cipher = base64.b64decode(cipher)    if plain is None:        plain = ['?'] * len(cipher)
    for n in range(20, 100):        i = 129        part = cipher[i:i+len(flag_header)]        dekey = bytes([part[j] ^ flag_header[j] for j in range(len(part))])
        key = [0] * n        ikey = set([])        for j in range(len(dekey)):            index = (j + i) % n            key[index] = dekey[j]            ikey.add(index)         txt = decipher(key, cipher)        ws = wrapping(txt, n)        f = True        for w in ws:            for k in ikey:                if not isprintable(w[k:k+1]):                    f = False        if not f:            continue
        changed = False        pplain = plain[:]        for j in range(len(pplain)):            if pplain[j] != '?':                continue            if j % n in ikey:                pplain[j] = chr(txt[j])                changed = True        if changed:            print("".join(pplain))            print("Accept?")            if input() in ["y", "Y"]:                plain = pplain```
It's enough to extract the first 100 bytes of the plain text, so we can reveal the key completely.