# QUICK START GUIDE

## Challenge: Fl1pper Zer0 - Signing Service

### The Bug
The challenge reuses the same AES-GCM nonce for multiple encryptions. This is **catastrophic**!

### Quick Test

1. **Install dependencies:**
   ```bash
   pip install pycryptodome ecdsa
   ```

2. **Run the challenge:**
   ```bash
   python chall_ecdsa.py
   ```

3. **Run the solution:**
   ```bash
   python solution.py
   ```

### What The Solution Does

1. **Identifies the vulnerability:** AES-GCM nonce reuse
2. **Collects encrypted keys:** Multiple keys encrypted with same nonce
3. **Demonstrates XOR attack:** Shows that CT1 ⊕ CT2 = PT1 ⊕ PT2
4. **Explains recovery methods:** How to get the private key
5. **Shows flag decryption:** How to decrypt once you have the key

### The Vulnerability Explained

```python
# In SignService.__init__():
self.key = os.urandom(16)  # Generated ONCE
self.iv = os.urandom(16)   # Generated ONCE

# In generate_key():
self.privkey = random.randrange(1, self.order - 1)  # Only this changes!
# The AES key and IV DON'T change! ← THE BUG
```

**Result:** Every `generate_key()` call creates a new private key but encrypts it with the **SAME** AES key and nonce.

### Why This Breaks Everything

In GCM mode:
- **Ciphertext = Plaintext ⊕ Keystream(key, nonce)**
- Same (key, nonce) → Same keystream
- Therefore: **CT₁ ⊕ CT₂ = PT₁ ⊕ PT₂**

If you recover one plaintext, you recover them all!

### Files Overview

| File | Purpose |
|------|---------|
| `chall_ecdsa.py` | Challenge server (working version) |
| `solution.py` | **Main solver - run this!** |
| `secret.py` | Contains the flag |
| `README.md` | Full documentation |
| `QUICKSTART.md` | This file |

### Expected Output

```
[+] Collected 3 encrypted signing keys
[*] All encrypted with SAME AES key and nonce!

[*] XOR Analysis:
    signkey1 (ct): 0c2f51c043ec7bc99971bfcebbe7a14e...
    signkey2 (ct): 741c2266fe42cacc561cf496bd5945b2...
    XOR result:    783373a6bdaeb105cf6d4b5806bee4fc...

[!] This XOR equals: privkey1 XOR privkey2
[!] If we recover one private key, we get both!
```

### Next Steps to Get The Flag

The solution demonstrates the vulnerability. To actually decrypt the flag:

1. **Recover the private key** using:
   - Brute force (if key is small)
   - Baby-step Giant-step algorithm
   - Pollard's rho
   - Weak RNG exploitation

2. **Decrypt the flag:**
   ```python
   flag_key = SHA256(privkey)[:16]
   cipher = AES.new(flag_key, AES.MODE_ECB)
   flag = cipher.decrypt(encrypted_flag)
   ```

### Key Takeaway

**NEVER reuse nonces in GCM mode!** Each encryption must use a unique nonce, or the entire scheme is broken.
