feat(cipher): add manual OTP decryption instructions and pad generator

- Expand instructions.md with step-by-step manual encryption/decryption example using modular addition.
- Add padgen.py script to generate random one-time pads from /dev/urandom, formatted in groups.
- Add cleanup of temporary audio file in numbers_station.sh.
- Minor title update in site/index.html for clarity.
This commit is contained in:
Gregory Gauthier 2026-04-28 17:20:40 +01:00
parent 33c9b16267
commit 135cf1ff01
4 changed files with 75 additions and 4 deletions

View File

@ -1,6 +1,41 @@
## HOW TO DECRYPT — STEP BY STEP (using your 8-bit machine)
### HOW TO DECRYPT — STEP BY STEP (by hand)
1. Type in the NERDLETTER DECRYPTOR BASIC program (see below)
1. **Key Generation**
- You generate a **truly random key** that is **exactly as long as the plaintext message**.
- The key must be purely random (each bit or character has equal probability and no patterns).
- The key is shared securely between sender and receiver **in advance** (this is the hard part in practice).
2. **Encryption**
- Take the plaintext message.
- Combine it with the key using a reversible operation. The two most common methods are:
- **Bitwise XOR** (for binary data — the standard modern way)
- **Modular addition** (for letters, e.g., A=0, B=1, ..., Z=25 — the classic "pad" method)
**Example with letters (Vigenère-style addition mod 26):**
Plaintext: `H E L L O`
→ Numbers: `7 4 11 11 14`
One-time pad: `X M C K L`
→ Numbers: `23 12 2 10 11`
Ciphertext: `(7+23) (4+12) (11+2) (11+10) (14+11) mod 26`
`4 16 13 21 25`
→ Letters: `E Q N V Z`
3. **Decryption**
- The receiver does the **inverse operation** with the same key.
- For modular addition: subtract the key (mod 26).
- For XOR: XOR the ciphertext with the key again (XOR is its own inverse).
Ciphertext: `E Q N V Z`
Key: `X M C K L`
Plaintext: `H E L L O`
### HOW TO DECRYPT — STEP BY STEP (using your 8-bit machine)
1. Type in the NERDLETTER DECRYPTOR BASIC program (provided with your subscription)
2. RUN
3. When it asks, type the PAD groups from the appropriate page:
@ -12,7 +47,7 @@
5. The machine will instantly print the plaintext!
## RESULT YOU SHOULD SEE:
#### RESULT YOU SHOULD SEE:
```
MARYHADALITTLELAMB

34
cipher/padgen.py Normal file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
"""Generate a one-time pad of uppercase letters from /dev/urandom."""
import sys
def generate_daybook(weeks: int = 52):
for week in range(1, weeks + 1):
with open(f"daybook_week_{week:02d}.txt", "w") as f:
f.write(f"WEEK {week:02d}\n\n")
f.write(format_pad(generate_pad(500)))
def generate_pad(num_letters: int) -> str:
"""Read raw bytes from /dev/urandom and map them uniformly to A-Z."""
letters = []
with open("/dev/urandom", "rb") as f:
while len(letters) < num_letters:
b = f.read(1)[0]
# Reject bytes >= 234 to avoid modulo bias.
# 234 = 9 * 26, so bytes 0..233 map uniformly to 0..25.
if b < 234:
letters.append(chr((b % 26) + 65))
return "".join(letters)
def format_pad(text: str, group_size: int = 5, groups_per_line: int = 10) -> str:
"""Format as 5-letter groups, 10 groups per line — classic OTP layout."""
groups = [text[i:i + group_size] for i in range(0, len(text), group_size)]
lines = [" ".join(groups[i:i + groups_per_line])
for i in range(0, len(groups), groups_per_line)]
return "\n".join(lines)
if __name__ == "__main__":
n = int(sys.argv[1]) if len(sys.argv) > 1 else 500
print(format_pad(generate_pad(n)))

View File

@ -119,4 +119,6 @@ drawtext=font='Courier':fontsize=44:fontcolor=lime@0.95:text='${MESSAGE}':x=(w-t
drawtext=font='Courier':fontsize=30:fontcolor=green@0.75:text='DESTROY PAGE AFTER USE — SUBSCRIBERS ONLY':x=(w-text_w)/2:y=640" \
-c:v libx264 -pix_fmt yuv420p -c:a aac -shortest "$OUTFILE" -y
rm "${TMPDIR}/final_audio.wav"
echo "Done: ${OUTFILE}"

View File

@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Nerdletter • Retro-Modern Fusion</title>
<title>The Nerdletter • Retro-Modern Fusion Newsletter</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=VT323&display=swap'); /* Perfect CRT font */
body {