Tags: random crypto seed 

Rating:

Source code:
```
import random, time
import string
import base64
import os

def otp(a, b):
r = ""
for i, j in zip(a, b):
r += chr(ord(i) ^ ord(j))
return r

def genSample():
p = ''.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for _ in range(random.randint(1, 30))])
k = ''.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for _ in range(len(p))])

x = otp(p, k)

return x, p, k

random.seed(int(time.time()))

print("Welcome to my one time pad service!\nIt's so unbreakable that *if* you do manage to decrypt my text, I'll give you a flag!")
print("You will be given the ciphertext and key for samples, and the ciphertext for when you try to decrypt. All will be given in base 64, but when you enter your answer, give it in ASCII.")
print("Enter:")
print("\t1) Request sample")
print("\t2) Try your luck at decrypting something!")

while True:
choice = int(input("> "))
if choice == 1:
x, p, k = genSample()
print(base64.b64encode(x.encode()).decode(), "with key", base64.b64encode(k.encode()).decode())

elif choice == 2:
x, p, k = genSample()
print(base64.b64encode(x.encode()).decode())
a = input("Your answer: ").strip()
if a == p:
print(os.environ.get("FLAG"))
break

else:
print("Wrong! The correct answer was", p, "with key", k)
```

After analysis of the source code, we can notice that seed for the random is the time of the connection to the server:
`random.seed(int(time.time()))`

Since we can get the sample, we can easily bruteforce the seed and decrypt the message to get the flag.

The script we use is the following:

```
import random, time
import string
import base64
import os

def otp(a, b):
r = ""
for i, j in zip(a, b):
r += chr(ord(i) ^ ord(j))
return r

def genSample():
p = ''.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for _ in range(random.randint(1, 30))])
k = ''.join([string.ascii_letters[random.randint(0, len(string.ascii_letters)-1)] for _ in range(len(p))])

x = otp(p, k)

return x, p, k

times = [int(time.time()) - x for x in range(0, 60)]

x_ = input("x: ")
k_ = input("k: ")

print(f"x_: {x_}")
print(f"k_: {k_}")

for t in times:
random.seed(int(t))

x, p, k = genSample()

if x_ == base64.b64encode(x.encode()).decode() and k_ == base64.b64encode(k.encode()).decode():
print(f"seed: {t}")
break

x, p, k = genSample()
print(p)
```

`otp` and `genSample` functions are copied from the source code of the server, and we just try to bruteforce the seed by giving the sample encryption as an input.
Once we get the same result of encryption as one from the server, we have found the seed, so we can easily print the next encryption and type it in the server to get the flag:
actf{one_time_pad_more_like_i_dont_like_crypto-1982309}

P.S. Of course we could have used `pwntools` or `requests` or any other module to make everything automated, but we didn't care about it :3