Cryptography

Challenge
Link

Jank File Encryptor (315 pts)

Copper Crypto (328 pts)

Jank File Encryptor (315 pts)

Description

They say you shouldn't roll your own encryption code, but I think all those naysayers are just gatekeeping!

Solution

Given source code below

import random

# File to encrypt
file_name = input("Please input the filename: ")

# Choose whether to encrypt or decrypt the file
choice = input("Enter 'encrypt' or 'decrypt' to preform the respective operation on the selected file: ")

# Open the file
f = open(file_name, mode="rb")

# Read the file
data = f.read()

if choice == "encrypt":
    # Generate random numbers for the LCG
    seed = random.randint(1, 256)
    a = random.randint(1, 256)
    c = random.randint(1, 256)
    modulus = random.randint(1, 256)

    print(f"Seed: {seed}")
    print(f"A: {a}")
    print(f"C: {c}")
    print(f"Modulus: {modulus}")

    # Pad the file out with some filler bytes to obscure it's size
    arr = bytearray(data)
    arr += bytearray([0x41] * 1000)

    save = bytearray()

    # Encrypt the files contents with the LCG
    for i in arr:
        seed = (a * seed + c) % modulus
        save.append(i ^ seed)

    f.close()

    # Write the encrypted file back to the disk
    with open(f"{file_name}.enc", "wb") as binary_file:
        binary_file.write(save)

elif choice == "decrypt":
    seed = int(input("Seed: "))
    a = int(input("A: "))
    c = int(input("C: "))
    modulus = int(input("Modulus: "))

    # Remove the padding bytes
    arr = bytearray(data[:len(data)-1000])

    save = bytearray()

    # Decrypt the files contents with the LCG
    for i in arr:
        seed = (a * seed + c) % modulus
        save.append(i ^ seed)

        # Write the encrypted file back to the disk
        with open(f"{file_name}.dec", "wb") as binary_file:
            binary_file.write(save)
  • Plaintext padded with 1000 bytes 0x41

  • Seed, a, c, and modulus used in LCG generated with random integer 1-256

We can leak 1000 bytes last seed by xor last 1000 bytes ciphertext with 0x41. Because a, c, and modulus only 1 byte (1-256) it is possible to do bruteforce (total 3 bytes). After getting valid a,c, and modulus value just reverse the flow to get previous seed.

si=(aβˆ—siβˆ’1+c)β€Šmodβ€Šmsiβˆ’1=((siβˆ’c)βˆ—aβˆ’1)β€Šmodβ€Šms_i = (a * s_{i-1} + c) \bmod m\\ s_{i-1} = ((s_i - c)*a^{-1}) \bmod m

Here is my solver

Flag: swampCTF{d0nt_l3ak_ur_k3ystr3am5}

Copper Crypto (328 pts)

Description

I've been learning the new pycryptodome library! I don't know much yet though. Here's my first code to encrypt some text:

Solution

Given source code below

  • Flag are padded, so pad(m)^e > n

    • null byte padding same as multiplication with 256^i with i = padding length

  • e is 3, if m^e < n , so we can get m by doing nth root

So the idea is finding m^e by removing the padding. Because the padded m is m*256^i we can remove the padding by doing multiplication inverse with 256^-i. After that just do nthroot.

ct=(mβˆ—256i)eβ€Šmodβ€Šnctβˆ—(256βˆ’i)e=meβ€Šmodβ€Šnct = (m*256^i)^e \bmod n\\ ct * (256^{-i})^e = m^e \bmod n

Here is my solver

Flag: swampCTF{pycryp70d0m3_h45_4_p4dd1n6_func}

Last updated