File size: 2,848 Bytes
82f2823
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44a69a7
82f2823
 
 
 
 
44a69a7
82f2823
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44a69a7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
82f2823
44a69a7
82f2823
44a69a7
 
 
 
 
82f2823
 
 
 
44a69a7
82f2823
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import os
import base64
import hashlib
import gradio as gr
from pathlib import Path
from Crypto.Cipher import AES
from Crypto.Util import Counter

ROOT = Path(__file__).parent
ASSET_IMG = ROOT / "mascot.png"
REQUIREMENTS = ROOT / "requirements.txt"

def _key_and_nonce():
    # Key = SHA256 of mascot.png bytes
    img_bytes = (ASSET_IMG.read_bytes() if ASSET_IMG.exists() else b"")
    key = hashlib.sha256(img_bytes).digest()  # 32 bytes (AES-256)

    # Nonce (8 bytes) derived from first line of requirements.txt
    rl = ""
    if REQUIREMENTS.exists():
        with REQUIREMENTS.open("r", encoding="utf-8", errors="ignore") as f:
            rl = (f.readline() or "").strip()
    nonce_src = hashlib.sha1(rl.encode("utf-8")).digest()
    nonce = nonce_src[:8] if nonce_src else b"\x00" * 8

    return key, nonce

def _encrypt_flag(flag: str) -> str:
    key, nonce = _key_and_nonce()
    ctr = Counter.new(64, prefix=nonce, initial_value=0)
    cipher = AES.new(key, AES.MODE_CTR, counter=ctr)
    ct = cipher.encrypt(flag.encode("utf-8"))
    return base64.b64encode(ct).decode("ascii")

def get_ciphertext():
    flag = (os.environ.get("FLAG") or "").strip()
    if not flag:
        return "⚠️ FLAG not set."
    return _encrypt_flag(flag)

def verify(candidate: str):
    flag = (os.environ.get("FLAG") or "").strip()
    if not flag:
        return ("⚠️ FLAG not set.", "")
    candidate = (candidate or "").strip()
    if not candidate:
        return ("No input provided.", "")
    if candidate == flag:
        # Always return the official flag from env (not user input)
        return ("✅ Correct.", flag)
    return ("❌ Incorrect.", "")

custom_css = """
#hero { display: flex; gap: 16px; align-items: center; }
#hero .title h1 { margin: 0; }
"""

with gr.Blocks(title="ENUSEC Freshers – Decrypter 2025", css=custom_css) as demo:
    # Hero row with mascot + title
    with gr.Row(elem_id="hero"):
        gr.Image(
            value=str(ASSET_IMG) if ASSET_IMG.exists() else None,
            show_label=False,
            interactive=False,
            height=160,
            visible=ASSET_IMG.exists()
        )
        gr.Markdown(
            """
# Decrypter 2025
Click **Get Encrypted Blob** to receive a Base64 string.  
Submit the flag when you have it.
            """,
            elem_classes=["title"]
        )

    # Ciphertext section
    b = gr.Button("Get Encrypted Blob")
    blob = gr.Textbox(label="Ciphertext (Base64)", interactive=False)
    b.click(get_ciphertext, None, blob)

    # Submission section
    gr.Markdown("## Submit Flag")
    guess = gr.Textbox(label="freshers{...}")
    submit = gr.Button("Submit")
    msg = gr.Markdown()
    out = gr.Textbox(label="Official Flag", interactive=False)
    submit.click(verify, guess, [msg, out])

if __name__ == "__main__":
    demo.launch()