# Cryptography

## القيصر الصغير

This challenge is a Caesar Cipher with a small twist, Handout:

```python
from egypt import محمد_رمضان
def التشفير(النص):
    النص_المشفر = ""
    for حرف in النص:
        النص_المشفر += chr(((حرف) + محمد_رمضان * 5) % 256)
    return النص_المشفر

النص = b"REDACTED"
النص_المشفر = (التشفير(النص))

print(النص_المشفر)
```

Since we all know that Mohammad Ramadan = 1, our solver should look something like this:

```python
ct = b'Uqf~lwtzsixHYKYm9spd~5zdk5wd~5zwdu9wy6h6u9y65s'
flag = ''
for i in ct:
    flag += chr(i  - 5)
    
print(flag)

# PlaygroundsCTF{Th4nk_y0u_f0r_y0ur_p4rt1c1p4t10n}
```

## NotSoBabyRSA

This is an RSA challenge that tests the competitors knowledge in modular arithmetic and the RSA cipher

```python
from Crypto.PublicKey import RSA
from Crypto.Util.number import bytes_to_long
from random import randint

FLAG = b"REDACTED"
key = RSA.generate(2048)
n = key.n
e = key.e
p = key.p
q = key.q
phi = (p-1)*(q-1)
coeff = randint(1,2**1024)

ct = pow(bytes_to_long(FLAG), e, n)

with open("out.txt", "w") as f:
    f.write(f"e = {e}\\n")
    f.write(f"phi = {phi}\\n")
    f.write(f"ct = {ct}\\n")
    f.write(f"hint = {coeff * phi + p}\\n")
```

We have, e and phi so we can find d easily, but our bottleneck is that we don’t have N. This is what the hint is for, let’s work out the math behind it.

$$
hint = coeff \times phi + p \newline \to hint \mod phi \equiv coeff \*phi + p \mod phi \newline \equiv (coeff \* phi) \mod phi + p \mod phi \newline \text {Since phi > p, p mod phi = p} \newline \equiv 0 + p \mod phi = p
$$

So we have found p by taking hint % phi, now what we have p we can find q through phi thus finding N and breaking the encryption.

```python
from Crypto.Util.number import *
e = 65537
phi = 22252059767191628213686269923550918466514556095718454355165487876212210042902512235466879654483456946425339939630332123373070610861978032641036769394687306065133457782047000737646012734574708243779878702796676880304773026331970265865563482201902213773401935525070342789630609249451297138419324527417706432939161831004010945981262204111549579591136851462878110040834628052606282279600752492602268142909665311586670088584877305808427995341132871133590702019242934894841646820641963380844193501147607394477559133105115605676776453120545196783998160115109245212957419072332329260204681158981943471613299096279320611901408
ct = 7487513392805281320020821228815838530393100681899722996521156929013128981749267847123083927473474437250065101826145882598964943701979376229164252243817179617956750851638734244561560870851434791870329947587761957799492071466293409788488637493888696552782176278479158234684156806503441826814543070260882338383602524028033304423497625264097614619892750908454123706980227808652116205222826719696074660729984587075966039537626371869181798938672291276714789617761108485432749493055410057969359775648166786267549750149259376009480247197369418823946423245660938830554461992596618289629818521468132029008837658517200600182974
hint = 3102549700716471604272133991221428061037218505949681857660761386956318993188444305199487096163182871844881676763785930672696384950415479206532153456120236817518735946946222300270351409770921866514521764852504710727970233542767784601619718425279440489928938729445426772743151497970269749153857242373473563340064158698310177980068817462081355409876988043237956275853736714781629878899944397243489362768101056010339642071758090894192048533914459938764491819929178335815241575412994798094315675694615947077837861137354498632529849072889450466768115902839785739215182722766750875909398546046941230273782994128087501747209927811284914059323448695154033832341124961310708853098254914025220329858403824553264283752892117512171230868825247975542010780862495154205819873946988892354419134743650520241834006924095813697810698021188119648594802353096693251516258098009853570474710354666561151603069384594968449769633717489801331476901035

p = hint % phi
q = phi // (p-1) + 1
n = p*q
d = inverse(e, phi)
m = pow(ct, d, n)
print(long_to_bytes(m))
# PlaygroundsCTF{P3n_and_P4p3r_4r3_4ll_y0u_n33d_t0_cr4ck_RSA}
```

## Building Pyramids

Handout:

```python
from math import sin
from Crypto.Util.number import getRandomInteger
from Crypto.Cipher import AES
from hashlib import sha256
from Crypto.Util.Padding import pad
Flag = b"REDACTED"
x = getRandomInteger(1024)

key = float(str(sin(x) + 1)[:6])

# print(key)

def encrypt_flag(flag, key=key):
    key = sha256(str(key).encode()).digest() [:16]
    cipher = AES.new(key, AES.MODE_ECB)
    return cipher.encrypt(flag)

with open("out.txt", "w") as f:
    f.write(str(encrypt_flag(pad(Flag, 16))))
```

If we try adding a print line to see what our key tends to look like, and we notice its either `0.xxxx` or `1.xxxx` so basically in the range of `sin(x) + 1` with rounding to the 4th decimal point, this means we have 20,000 possible keys. bruteforcable.

```python
from Crypto.Cipher import AES
from hashlib import sha256
from Crypto.Util.Padding import unpad

ct = b'\\xd9\\xa1:m\\xad\\x02\\xd9j\\x04\\n_h\\x81}\\r\\x8e\\xe1\\xc4}\\x86\\xad1\\x83\\xad\\xbaPo\\xaa\\x9e\\xd6\\x03n\\x8ek\\xa1\\xea3\\xdf\\xf4\\xe5\\xc9\\xc8\\t\\x04\\xc7\\xc2\\xe6\\xdbT\\xbdTq\\x0ed\\x08F\\xf8\\xcc6&\\x03\\xc0\\xc0\\xb1'

def decrypt_flag(ciphertext, key):
    key = sha256(str(key).encode()).digest()[:16]
    cipher = AES.new(key, AES.MODE_ECB)
    return cipher.decrypt(ciphertext)
from numpy import arange

for i in range(0, 2, 0.0001):
    key = i.round(4)
    if b"Play" in decrypt_flag(ct, key):
        print(unpad(decrypt_flag(ct, key),16).decode())
        break
        
# PlaygroundsCTF{3L_H4R4M_15_PR0ud_0f_Y0u}
```

## Simple RSA

Classic RSA challenge, encrypting char by char

```python
from Crypto.Util.number import *

Flag = b"REDACTED"

p = getPrime(1024)
q = getPrime(1024)

assert p != q

n = p*q

e = 0x10001

ct = []
for c in Flag:
    ct.append((pow((c), e, n)))

with open("out.txt", "w") as f:
    f.write(f'ct = {str(ct)}\\n')
    f.write(f'n = {str(n)}')
```

This challenge is similar to `Giza Cipher` except you’ll have to generate the table by encrypting all printable characters with the public key and comparing with the given ciphertext list

```python
from Crypto.Util.number import * 
import string

ct = [..,..
n = ..

printables = string.printable
enc_printables = [pow(ord(c), 0x10001, n) for c in printables]

for c in ct:
    if c in enc_printables:
        print(printables[enc_printables.index(c)], end='')
    else:
        print(c, end='')
print()
# PlaygroundsCTF{S1mpl3_5ub5717u710n:3}
```

## Calc 101

Let’s look at our source

```python
import sys
import sympy as sp
from random import randint
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from hashlib import sha256
import os 

flag = "PlaygroundsCTF{FAKE_FLAG_FOR_TESTING}".encode()

sys.set_int_max_str_digits(1000000)
x = sp.symbols('x')

poly = x**70 - 100*x**8 + 99*x**169 - 100*x**2 + 1

def encrypt(pt, key):
    key = sha256(key).digest()[:16]
    cipher = AES.new(key, AES.MODE_ECB)
    return cipher.encrypt(pad(pt, 16))

def get_derivative(n,inp,poly=poly):
    for i in range(n):
        poly = sp.diff(poly)

    return poly.subs(x,inp)

def main():
    randx = randint(1, 2**1024)
    n = abs(int(input("enter a positive integer: ")))
    key = get_derivative(n,randx)
    ct = encrypt(flag, str(key).encode())
    print(f"Here is the ciphertext: {ct.hex()}")    

if __name__ == "__main__":
    main()
```

Usually in these challenges we try to look for ways to make our key predictable, since we can differentiate the polynomial as many times as we want, we can differentiate it so many times it becomes 0, making any random input into the function output a 0 as the encryption key.

```python
from pwn import * 
from Crypto.Cipher import AES
from hashlib import sha256
from Crypto.Util.Padding import unpad

r = remote("URL",00000)

r.recvuntil(b"integer: ")

r.sendline(b"10000") # or any number > 169

r.recvuntil(b"text: ")

ct = r.recvline().strip()
r.close()

ct = bytes.fromhex(ct.decode())

def decrypt(ct, k):
    key = sha256(k).digest()[:16]
    cipher = AES.new(key, AES.MODE_ECB)
    return cipher.decrypt(ct)

    
pt = decrypt(ct, str(0).encode())
print(unpad(pt, 16).decode())
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://l0mb4rd.gitbook.io/home/ctf-stuff/playgroundsctf-24-writeups/cryptography.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
