Caesar Cipher
Caesar cipher คือรหัสแทนที่ (monoalphabetic substitution) ที่เลื่อนตัวอักษรทุกตัวไปด้วยจำนวนคงที่ (shift k) เช่น k=3 ให้ A→D, B→E ด้วย key space เพียง 25 ค่า จึง brute force ได้ทันที บทนี้ไล่ตั้งแต่คณิตศาสตร์ของการเลื่อน (mod 26), การ brute ทั้ง 25 shift, frequency analysis เมื่อ shift ไม่รู้, ความสัมพันธ์กับ ROT13/ROT47, เครื่องมือ (tr / Python / CyberChef / quipqiup) และรูปแบบโจทย์ CTF ที่พบบ่อย
1. Caesar ทำงานอย่างไร
Caesar cipher แทนตัวอักษรแต่ละตัวด้วยตัวที่อยู่ห่างไป k ตำแหน่งใน alphabet แบบวนรอบ (modulo 26) โดย k เดียวใช้กับทุกตัวอักษรตลอดข้อความ — นี่คือสาเหตุที่เรียกว่า monoalphabetic (map ตัวอักษรแบบ 1-1 ทั้งข้อความ) key มีแค่ค่าเดียวคือจำนวน shift ทำให้ key space เล็กมากเพียง 25 ค่าที่มีความหมาย (k=0 คือไม่เปลี่ยน, k=26 วนกลับที่เดิม)
| การดำเนินการ | สูตร (ให้ A=0..Z=25) |
|---|---|
| เข้ารหัส | C = (P + k) mod 26 |
| ถอดรหัส | P = (C − k) mod 26 |
| ถอดโดยไม่รู้ k | ลองทุก k = 1..25 (brute force) |
| ความสัมพันธ์ ROT13 | Caesar ที่ k = 13 |
ตัวอย่าง: plaintext HELLO เลื่อน k=3 → H(7)+3=10=K, E(4)+3=7=H, L(11)+3=14=O, L→O, O(14)+3=17=R ได้ ciphertext KHOOR การถอดคือเลื่อนกลับ 3 ตำแหน่ง สังเกตว่าความยาวข้อความไม่เปลี่ยน และตัวอักษรที่ไม่ใช่ a-z (ตัวเลข เว้นวรรค สัญลักษณ์) มักถูกปล่อยไว้ตามเดิม
2. สังเกตอย่างไรว่าเป็น Caesar
- ciphertext เป็นตัวอักษร a-z/A-Z เกือบล้วน ความยาวเท่ากับ plaintext (ไม่ขยาย/บีบ) — บ่งชี้ substitution
- การกระจายความถี่ตัวอักษร (histogram) มี 'รูปทรง' เหมือนภาษาอังกฤษแต่ถูกเลื่อนตำแหน่ง — ตัวที่พบบ่อยสุดมักคือ E ที่ถูกเลื่อน
- โจทย์ใบ้คำว่า shift, rotate, Caesar, ROT, 'Et tu', 'legion', หรือเลข 13/47
- flag format คุ้นเคย (เช่น flag{ / CTF{) โผล่มาชัดเมื่อลอง shift บางค่า
- ถ้ามีตัวเลข/สัญลักษณ์ ASCII printable ปนเยอะ (ไม่ใช่แค่ a-z) → น่าจะเป็น ROT47 มากกว่า Caesar ธรรมดา
3. Brute force ทั้ง 25 shift
เพราะ key space มีแค่ 25 ค่า วิธีที่เร็วและชัวร์ที่สุดคือพิมพ์ผลลัพธ์ทั้ง 25 shift ออกมาแล้วกวาดสายตาหา flag / คำที่อ่านออก ไม่ต้องคิดมาก
ct = "KHOOR ZRUOG"
def shift(text, k):
out = []
for c in text:
if c.isupper():
out.append(chr((ord(c) - 65 - k) % 26 + 65))
elif c.islower():
out.append(chr((ord(c) - 97 - k) % 26 + 97))
else:
out.append(c) # เก็บอักขระที่ไม่ใช่ตัวอักษรไว้เดิม
return "".join(out)
for k in range(1, 26):
print(f"{k:2d}: {shift(ct, k)}")
# มองหาบรรทัดที่อ่านออก / มี flag{ct="KHOOR ZRUOG"
for k in $(seq 1 25); do
from=$(printf '%s' {A..Z})
# สร้าง alphabet ที่หมุนไป k ตำแหน่งสำหรับถอด
to=$(printf '%s' {A..Z} | sed -E "s/(.{$k})(.*)/\2\1/")
echo "$k: $(echo "$ct" | tr "$from" "$to")"
doneROT13 Brute Force และ ROT47 Brute Force ที่พ่นทุก shift ออกมาในหน้าเดียว ลากวางเสร็จใน 3 วินาที — เป็นวิธีที่เร็วสุดสำหรับข้อความสั้น4. Frequency analysis (หา shift อัตโนมัติ)
เมื่อข้อความยาวพอ (หลายสิบตัวอักษรขึ้นไป) สามารถหา shift ได้โดยไม่ต้องกวาดตา — ใช้ข้อเท็จจริงว่าในภาษาอังกฤษ E คือตัวที่พบบ่อยที่สุด สมมติตัวที่พบบ่อยสุดใน ciphertext คือ plaintext E แล้วคำนวณ shift ย้อนกลับ วิธีที่แม่นกว่าคือ chi-squared เทียบ histogram ของผลลัพธ์แต่ละ shift กับความถี่มาตรฐานภาษาอังกฤษ แล้วเลือก shift ที่ค่าต่ำสุด
ct = "WKLV LV D VHFUHW PHVVDJH"
# ความถี่ตัวอักษรอังกฤษ (%) A..Z
ENG = [8.2,1.5,2.8,4.3,12.7,2.2,2.0,6.1,7.0,0.15,0.77,4.0,2.4,
6.7,7.5,1.9,0.095,6.0,6.3,9.1,2.8,0.98,2.4,0.15,2.0,0.074]
def decrypt(text, k):
return "".join(chr((ord(c)-65-k)%26+65) if c.isupper()
else c for c in text)
def chi2(text):
letters = [c for c in text if c.isupper()]
n = len(letters) or 1
score = 0.0
for i in range(26):
obs = letters.count(chr(65+i))
exp = ENG[i]/100*n
score += (obs-exp)**2/exp if exp else 0
return score
best = min(range(26), key=lambda k: chi2(decrypt(ct, k)))
print("shift =", best)
print(decrypt(ct, best))synt{...}) การ brute 25 ค่าแล้วมองหา flag{/CTF{ ตรงๆ ได้ผลเร็วและชัวร์กว่า5. ความสัมพันธ์กับ ROT13 / ROT47
ROT13 คือ Caesar ที่ k = 13 พอดี ความพิเศษคือ 13 = 26/2 ทำให้เข้ารหัสและถอดรหัสเป็นการดำเนินการเดียวกัน (self-inverse): ROT13(ROT13(x)) = x เพราะเลื่อนไป 13 แล้วอีก 13 ครบ 26 พอดี ส่วน ROT47 ไม่ใช่ Caesar บน a-z แต่หมุน 47 ตำแหน่งบนช่วง ASCII printable 33–126 (94 ตัว) ครอบคลุมตัวเลขและสัญลักษณ์ด้วย
| ช่วงที่หมุน | shift | self-inverse | |
|---|---|---|---|
| Caesar (k) | a-z A-Z | 1–25 | เฉพาะ k=13 |
| ROT13 | a-z A-Z | 13 | ใช่ |
| ROT47 | ASCII 33–126 (94 ตัว) | 47 | ใช่ (47 = 94/2) |
rot6. เครื่องมือ & auto-solver
- CyberChef — operation
ROT13(ปรับ amount ได้),ROT13 Brute Force,ROT47ลากวางทดสอบเร็ว - quipqiup.com — auto-solver สำหรับ substitution/Caesar ใส่ ciphertext แล้วมันเดา mapping จากพจนานุกรม เหมาะเมื่อไม่แน่ใจว่าเป็น Caesar หรือ substitution ทั่วไป
- dcode.fr/caesar-cipher — ลองทุก shift + ให้คะแนนความอ่านออกอัตโนมัติ
- tr (Unix) — ถอด ROT13 ในบรรทัดเดียว ไม่ต้องติดตั้งอะไร
- Python — เขียนเองเมื่อต้องคุม scoring หรือจัดการ format แปลกๆ
# ROT13 (self-inverse: ใช้ถอดและเข้าได้ด้วยคำสั่งเดียว)
echo 'Uryyb Jbeyq' | tr 'A-Za-z' 'N-ZA-Mn-za-m'
# เลื่อน k ค่าอื่น เช่น decrypt shift 3 (ตัวพิมพ์ใหญ่)
echo 'KHOOR' | tr 'A-Z' 'X-ZA-W'
# ส่งไฟล์เข้า CyberChef ผ่าน curl (ถ้า host เอง) หรือใช้เว็บ7. ตัวอย่างโจทย์ CTF
โจทย์ A (ROT13 ตรงๆ): ได้ synt{pnrfne_vf_rnfl} — ตัวอักษรล้วน ลอง ROT13 ทันทีได้ flag{caesar_is_easy} ไม่ต้องคิดมาก เพราะ synt คือ flag ที่ผ่าน ROT13
โจทย์ B (shift ไม่ใช่ 13): ได้ MFLES{corryd_ho_gcurrent} ที่ ROT13 ไม่ออก — brute 25 shift พบว่า shift 8 ให้ EXPD...... จริงๆ ต้องไล่จนเจอบรรทัดที่ prefix ตรง flag format เช่นเจอ flag{ ที่ shift ค่าหนึ่ง คำตอบคือ shift นั้น
โจทย์ C (ROT47): ได้ u=B8mtem02c0j:D0967g ที่มีตัวเลข/สัญลักษณ์ปน — ลอง ROT47 (หมุน 47 บน ASCII printable) ได้ flag ที่อ่านออก สังเกตจากการมีสัญลักษณ์ปนว่าไม่ใช่ Caesar a-z ธรรมดา
โจทย์ D (ซ้อนชั้น): ข้อความ base64 → ถอดได้ ciphertext ที่ยังอ่านไม่ออก → ROT13 → ได้ flag การซ้อนชั้น encoding + Caesar เป็นแพทเทิร์นคลาสสิก ลองไล่ decode ทีละชั้น (base64 → ROT → hex ...) ด้วย CyberChef 'Magic'
8. ข้อผิดพลาดที่พบบ่อย
- ลืมว่าตัวพิมพ์ใหญ่/เล็กต้อง wrap แยกกัน (ฐาน 65 กับ 97 ต่างกัน)
- ลืมเก็บอักขระที่ไม่ใช่ตัวอักษร (ตัวเลข/เว้นวรรค/สัญลักษณ์) ไว้ตามเดิม → flag เพี้ยน
- สับสนทิศ shift: เข้ารหัส +k แต่ถอด −k (ถ้า loop ทั้ง 25 ก็ครอบคลุมทั้งสองทิศอยู่แล้ว)
- หยุดที่ ROT13 ทั้งที่โจทย์ใช้ shift อื่น — ต้อง brute ให้ครบ 25
- เห็นสัญลักษณ์ปนแล้วยังดัน brute Caesar a-z ทั้งที่ควรลอง ROT47
- ข้อความสั้นแล้วไปพึ่ง frequency analysis (ไม่แม่น) แทนที่จะ brute + มองหา flag format
9. Quick Reference
C = (P + k) mod 26· ถอดP = (C − k) mod 26- key space แค่ 25 → brute force ได้เสมอ
- ลอง ROT13 ก่อน:
tr 'A-Za-z' 'N-ZA-Mn-za-m' - brute 25 แล้วมองหา flag format / คำอ่านออก
- ข้อความยาว → frequency / chi-squared หา shift
- มีตัวเลข/สัญลักษณ์ปน → ROT47 (ดูหัวข้อ rot)
- brute แล้วไม่ออก → substitution ทั่วไป (quipqiup) หรือ Vigenère
- auto-solver: CyberChef Brute Force, quipqiup.com, dcode.fr
🧭 จับมือทำทีละขั้น (มีแค่ Kali) + ถ้าติดไปไหนต่อ
สมมติเปิดโจทย์มาเจอข้อความประหลาดๆ แบบนี้ และมีแค่เครื่อง Kali เปล่าๆ ไม่มีปลั๊กอินพิเศษอะไร ทำตามขั้นตอนด้านล่างทีละสเต็ป ไม่ต้องคิดเยอะ ไล่ไปเรื่อยๆ ตามลำดับ
- 1ดูข้อความก่อน: `cat chal.txt` — เป็นตัวอักษร a-z/A-Z ล้วนไหม ความยาวเท่าเดิม (ไม่ขยาย/บีบ) ถ้าใช่ ให้สงสัยว่าเป็น substitution cipher แบบ Caesar
- 2ลอง ROT13 ก่อนเสมอ (พบบ่อยสุดใน CTF): `echo 'ข้อความ' | tr 'A-Za-z' 'N-ZA-Mn-za-m'` — ถ้าเห็น flag{ หรืออ่านออกเป็นภาษาอังกฤษ = จบเลย
- 3ไม่ออก → brute ทั้ง 25 shift ด้วย python loop (ดูโค้ดหัวข้อด้านบน) แล้วกวาดตาหา flag{ หรือคำที่อ่านออก
- 4ขี้เกียจเขียนโค้ด → เปิดเบราว์เซอร์ไป https://gchq.github.io/CyberChef วาง ciphertext ใน Input แล้วลาก operation 'ROT13 Brute Force' มาวางที่ Recipe — เห็นทั้ง 25 ผลลัพธ์พร้อมกัน
- 5ยังไม่เจอ → ลอง https://www.dcode.fr/caesar-cipher ใส่ ciphertext แล้วกด Automatic ให้มันให้คะแนนความน่าจะเป็นภาษาอังกฤษเอง
- 6เช็คว่ามีตัวเลข/สัญลักษณ์ปนเยอะไหม (`!@#{}` เยอะผิดปกติ) ถ้ามี ให้สงสัยว่าเป็น ROT47 แทน — ลองที่ CyberChef operation 'ROT47'
- 7ทำ histogram คร่าวๆ ด้วย python (`from collections import Counter; Counter(ct)`) — ถ้าเห็น peak เดียวเด่นชัด (น่าจะคือ E ที่ถูกเลื่อน) ให้ลอง chi-squared scoring หา shift อัตโนมัติ
- 8histogram แบนเรียบ ไม่มี peak ชัด (หรือ brute 25 ไม่มีอันไหนอ่านออกเลย) → มีโอกาสเป็น substitution ทั่วไป (ไม่ใช่แค่เลื่อนคงที่) → ลอง https://quipqiup.com ใส่ ciphertext ให้มันเดา mapping
- 9ถ้าดูเหมือนแต่ละช่วงของข้อความถูกเลื่อนไม่เท่ากัน (ไม่ใช่ shift เดียวทั้งข้อความ) → นี่คือ Vigenère (key ยาวกว่า 1 ตัวอักษร) → ไปทำตามหัวข้อ Vigenère
- 10ได้ผลลัพธ์อ่านออกแล้ว → เช็ค flag format ให้ตรงกับที่โจทย์กำหนด (เช่น flag{...} หรือ CTF{...}) แล้วส่งคำตอบ
| ขั้นตอน/งาน | เครื่องมือใน Kali | ติดตั้งเพิ่ม (ถ้าไม่มี) | เครื่องมือออนไลน์ |
|---|---|---|---|
| ดูไฟล์/ข้อความเบื้องต้น | cat, file, xxd | - | - |
| ถอด ROT13 เร็วๆ | tr | - | gchq.github.io/CyberChef (ROT13) |
| brute Caesar ทุก shift | python3 | - | CyberChef 'ROT13 Brute Force', dcode.fr/caesar-cipher |
| ROT47 (มีสัญลักษณ์ปน) | python3, tr | - | CyberChef (ROT47) |
| หา shift อัตโนมัติ (frequency) | python3 (chi-squared) | - | dcode.fr (ปุ่ม Automatic) |
| substitution ทั่วไป (ไม่ใช่ shift คงที่) | python3 | - | quipqiup.com |
| decode ซ้อนชั้น (base64/hex ก่อนถึง cipher) | base64, xxd | - | CyberChef (operation Magic) |
โน้ตของฉัน
ยังไม่มีโน้ตสำหรับหัวข้อนี้