Skip to content

Commit

Permalink
crypto(diffie-helman): add beginner challenge
Browse files Browse the repository at this point in the history
  • Loading branch information
atsouloupas committed Jul 4, 2024
1 parent e7dc9ce commit b6597bf
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 0 deletions.
35 changes: 35 additions & 0 deletions crypto/diffie-hellman/challenge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: "Diffie-Hellman"
author: "feltf"
category: crypto

description: |
Play the role of Bob (one of the two parties) in the Diffie-Hellman key
exchange algorithm to obtain the shared secret!
Then decrypt the encrypted flag that Alice will send to you!
You don't have to implement the cryptographic algorithms from scratch. Take a look at the
python crypto library [PyCryptodome](https://pycryptodome.readthedocs.io/en/latest/),
it will help you to decrypt the flag.
value: 500
type: dynamic_docker
extra:
initial: 500
minimum: 100
decay: 25
redirect_type: direct
compose_stack: !filecontents docker-compose.yml

flags:
- GTBQ{d1ff1e_h3llm4n_key_exchang3_and_bas1c_crypt0}

files:
- public/server.py

tags:
- crypto
- beginner

state: visible
version: "0.1"
7 changes: 7 additions & 0 deletions crypto/diffie-hellman/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: '3'
services:
casino:
build: ./setup/
image: ghcr.io/cybermouflons/gtbq-2024/diffie-hellman:latest
ports:
- 1337:1337
1 change: 1 addition & 0 deletions crypto/diffie-hellman/public/server.py
15 changes: 15 additions & 0 deletions crypto/diffie-hellman/setup/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
FROM ubuntu:22.04

RUN apt-get update && apt-get install -y socat python3 python3-pip

RUN mkdir /app
WORKDIR /app

COPY requirements.txt /app/
RUN pip install -r requirements.txt

COPY secret.py/ /app/
COPY server.py/ /app/

EXPOSE 1337
CMD ["socat", "-v","TCP-LISTEN:1337,reuseaddr,fork", "EXEC:'python3 /app/server.py'"]
1 change: 1 addition & 0 deletions crypto/diffie-hellman/setup/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pycryptodome==3.20.0
1 change: 1 addition & 0 deletions crypto/diffie-hellman/setup/secret.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
FLAG = b"GTBQ{d1ff1e_h3llm4n_key_exchang3_and_bas1c_crypt0}"
79 changes: 79 additions & 0 deletions crypto/diffie-hellman/setup/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import secrets
from secret import FLAG
from Crypto.Protocol.KDF import HKDF
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Hash import SHA256
from Crypto.Util.number import long_to_bytes

class DiffieHellman:
def __init__(self) -> None:
# Diffie-Hellman group (2048-bit MODP Group)
self.p = 0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF
self.q = (self.p-1)//2 # group order
self.g = 2 # group generator

def start(self):
print("""
=============================================================
| |
| Diffie-Hellman Key Exchange: |
| Derive a secret to decrypt the flag |
| |
=============================================================
| (p,q,g) |
| |
| Alice Bob (you) |
| O O |
| /|\ /|\ |
| / \ / \ |
| flag |
| |
| chose random a in [1,q] |
| A = g^a mod p |
| |
| A |
| ----------------------> |
| |
| chose random b in [1,q] |
| S = A^b mod p |
| B = g^b mod p |
| |
| B |
| <---------------------- |
| |
| S = B^a mod p |
| K = HKDF-SHA256(S, 16, "") |
| |
| c, IV = AES-CBC(K, flag) |
| ----------------------> |
=============================================================""")

print(f"(Info) p={self.p}")
print(f"(Info) q={self.q}")
print(f"(Info) g={self.g}")

a = secrets.randbelow(self.q) + 1 # Alice's secret value
A = pow(self.g, a, self.p) # Alice's public group member
print(f"(Alice) Bob A is {A}")
try:
B = int(input("(Bob) Alice B is "))
except:
print("(Error) B is an integer value member of the group (mod p)")
return

if pow(B, self.q, self.p) != 1:
print("(Error) B is not in the group (mod p)")
return

S = pow(B, a, self.p)
K = HKDF(long_to_bytes(S), 16, "", SHA256)

cipher = AES.new(K, AES.MODE_CBC)
c = cipher.encrypt(pad(FLAG, AES.block_size))

print(f"(Alice) Bob the encrypted flag (in hex) is {c.hex()} with IV {cipher.iv.hex()}")


dhke = DiffieHellman()
dhke.start()
62 changes: 62 additions & 0 deletions crypto/diffie-hellman/sol/solve.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
import os
import secrets

from telnetlib import Telnet

from Crypto.Protocol.KDF import HKDF
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from Crypto.Hash import SHA256
from Crypto.Util.number import long_to_bytes


def solve(tn: Telnet):
# Read p
tn.read_until(b"p=")
p = int((tn.read_until(b"\n")[:-1]))

# Read q
tn.read_until(b"q=")
q = int((tn.read_until(b"\n")[:-1]))

# Read g
tn.read_until(b"g=")
g = int((tn.read_until(b"\n")[:-1]))

# Read Alice's public A
tn.read_until(b"Bob A is ")
A = int((tn.read_until(b"\n")[:-1]))

# chose random b
b = secrets.randbelow(q) + 1
# compute Bob's public B
B = pow(g, b, p)
# send public B
tn.read_until(b"Alice B is ")
tn.write(str(B).encode() + b"\n")

# Read encrypted flag
tn.read_until(b"Bob the encrypted flag (in hex) is ")
c = bytes.fromhex(tn.read_until(b" ")[:-1].decode())

# Read IV
tn.read_until(b"with IV ")
IV = bytes.fromhex(tn.read_until(b"\n")[:-1].decode())

# Until here it can be done manually, i.e., extract info from server responses
S = pow(A, b, p)
K = HKDF(long_to_bytes(S), 16, "", SHA256)

cipher = AES.new(K, AES.MODE_CBC, IV)
flag = unpad(cipher.decrypt(c), AES.block_size)
print(flag)

if __name__ == "__main__":
if "REMOTE" in os.environ:
HOSTNAME = ""
else:
HOSTNAME = "localhost"
PORT = 1337
with Telnet(HOSTNAME, PORT) as tn:
solve(tn)

0 comments on commit b6597bf

Please sign in to comment.