คลัง
crypto

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 ที่พบบ่อย

Beginner#caesar#rot#rot13#rot47#classical#cipher#crypto#substitution

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)
ความสัมพันธ์ ROT13Caesar ที่ 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 (ตัวเลข เว้นวรรค สัญลักษณ์) มักถูกปล่อยไว้ตามเดิม

Caesar shift wheel (k = 3)
k = 3 A -> D AD BE CF DG EH FI GJ HK IL JM KN LO วงนอก = plaintext, วงใน = ciphertext (หมุนทวนตาม k)
Caesar เป็นกรณีพิเศษของ Vigenère ที่ key ยาว 1 ตัวอักษร และเป็นกรณีพิเศษของ substitution ทั่วไป ที่การ map ถูกบังคับให้เป็นการเลื่อนคงที่ ถ้า brute Caesar แล้วไม่อ่านออก ให้ขยับไปทาง Vigenère หรือ substitution แบบอิสระ (ดูหัวข้อ vigenere)

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 ธรรมดา
Caesar รักษา 'รูปทรง histogram' ของภาษาไว้ เพราะแค่เลื่อนแกน x ทั้งอัน — ต่างจาก substitution แบบสุ่มที่สลับตำแหน่งกระจาย ดังนั้นถ้า histogram ดูเป็นภาษาอังกฤษแต่ยอดสูงสุดไม่อยู่ที่ E ให้เดา shift = ระยะจากยอดนั้นกลับมา E

3. Brute force ทั้ง 25 shift

เพราะ key space มีแค่ 25 ค่า วิธีที่เร็วและชัวร์ที่สุดคือพิมพ์ผลลัพธ์ทั้ง 25 shift ออกมาแล้วกวาดสายตาหา flag / คำที่อ่านออก ไม่ต้องคิดมาก

Brute force ทุก shift (Python)
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{
ใช้ -k เพื่อ 'ถอด' (เลื่อนกลับ) — วน k 1..25 ครอบคลุมทุกความเป็นไปได้
Brute force ด้วย bash + tr (ไล่ทีละ shift)Linux
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")"
done
sed หมุน alphabet ทีละ k ตำแหน่ง แล้ว tr แทนที่ — เหมาะเวลาไม่มี Python
CyberChef มี operation ROT13 Brute Force และ ROT47 Brute Force ที่พ่นทุก shift ออกมาในหน้าเดียว ลากวางเสร็จใน 3 วินาที — เป็นวิธีที่เร็วสุดสำหรับข้อความสั้น

4. Frequency analysis (หา shift อัตโนมัติ)

เมื่อข้อความยาวพอ (หลายสิบตัวอักษรขึ้นไป) สามารถหา shift ได้โดยไม่ต้องกวาดตา — ใช้ข้อเท็จจริงว่าในภาษาอังกฤษ E คือตัวที่พบบ่อยที่สุด สมมติตัวที่พบบ่อยสุดใน ciphertext คือ plaintext E แล้วคำนวณ shift ย้อนกลับ วิธีที่แม่นกว่าคือ chi-squared เทียบ histogram ของผลลัพธ์แต่ละ shift กับความถี่มาตรฐานภาษาอังกฤษ แล้วเลือก shift ที่ค่าต่ำสุด

หา shift ด้วย chi-squared scoring (Python)
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))
chi-squared ยิ่งต่ำยิ่งใกล้ภาษาอังกฤษ — เลือก shift ที่ให้ค่าต่ำสุดเป็นคำตอบ
frequency analysis ต้องการข้อความยาวพอสมควรจึงจะแม่น สำหรับ flag สั้นๆ (เช่น 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 ตัว) ครอบคลุมตัวเลขและสัญลักษณ์ด้วย

ช่วงที่หมุนshiftself-inverse
Caesar (k)a-z A-Z1–25เฉพาะ k=13
ROT13a-z A-Z13ใช่
ROT47ASCII 33–126 (94 ตัว)47ใช่ (47 = 94/2)
ถ้าข้อความมีแต่ a-z → ลอง ROT13 ก่อน แล้วค่อย brute 25; ถ้ามีตัวเลข/สัญลักษณ์ปนเยอะ → ลอง ROT47 รายละเอียด ROT ทุกแบบดูหัวข้อ rot

6. เครื่องมือ & 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 ด้วย tr + คำสั่งลัดที่ใช้บ่อย
# 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 เอง) หรือใช้เว็บ
tr 'A-Za-z' 'N-ZA-Mn-za-m' คือ ROT13 มาตรฐาน จำไว้ได้เลย
เจอข้อความน่าสงสัย — ไล่ตามนี้
ตัวอักษรล้วน a-z? ความยาวคงที่?
ยืนยัน substitution ก่อน
มีตัวเลข/สัญลักษณ์ปนเยอะลอง ROT47
a-z ล้วนไปขั้นถัดไป
ยังไม่ออก → brute ทั้ง 25 shift
Python loop หรือ CyberChef Brute Force
ข้อความยาว → frequency / chi-squared
หา shift อัตโนมัติ
brute แล้วยังอ่านไม่ออก?
histogram เหมือนอังกฤษแต่กระจายsubstitution ทั่วไป → quipqiup
แต่ละส่วนใช้ shift ต่างกันVigenère
เจอ flag / ข้อความอ่านออก

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. 1ดูข้อความก่อน: `cat chal.txt` — เป็นตัวอักษร a-z/A-Z ล้วนไหม ความยาวเท่าเดิม (ไม่ขยาย/บีบ) ถ้าใช่ ให้สงสัยว่าเป็น substitution cipher แบบ Caesar
  2. 2ลอง ROT13 ก่อนเสมอ (พบบ่อยสุดใน CTF): `echo 'ข้อความ' | tr 'A-Za-z' 'N-ZA-Mn-za-m'` — ถ้าเห็น flag{ หรืออ่านออกเป็นภาษาอังกฤษ = จบเลย
  3. 3ไม่ออก → brute ทั้ง 25 shift ด้วย python loop (ดูโค้ดหัวข้อด้านบน) แล้วกวาดตาหา flag{ หรือคำที่อ่านออก
  4. 4ขี้เกียจเขียนโค้ด → เปิดเบราว์เซอร์ไป https://gchq.github.io/CyberChef วาง ciphertext ใน Input แล้วลาก operation 'ROT13 Brute Force' มาวางที่ Recipe — เห็นทั้ง 25 ผลลัพธ์พร้อมกัน
  5. 5ยังไม่เจอ → ลอง https://www.dcode.fr/caesar-cipher ใส่ ciphertext แล้วกด Automatic ให้มันให้คะแนนความน่าจะเป็นภาษาอังกฤษเอง
  6. 6เช็คว่ามีตัวเลข/สัญลักษณ์ปนเยอะไหม (`!@#{}` เยอะผิดปกติ) ถ้ามี ให้สงสัยว่าเป็น ROT47 แทน — ลองที่ CyberChef operation 'ROT47'
  7. 7ทำ histogram คร่าวๆ ด้วย python (`from collections import Counter; Counter(ct)`) — ถ้าเห็น peak เดียวเด่นชัด (น่าจะคือ E ที่ถูกเลื่อน) ให้ลอง chi-squared scoring หา shift อัตโนมัติ
  8. 8histogram แบนเรียบ ไม่มี peak ชัด (หรือ brute 25 ไม่มีอันไหนอ่านออกเลย) → มีโอกาสเป็น substitution ทั่วไป (ไม่ใช่แค่เลื่อนคงที่) → ลอง https://quipqiup.com ใส่ ciphertext ให้มันเดา mapping
  9. 9ถ้าดูเหมือนแต่ละช่วงของข้อความถูกเลื่อนไม่เท่ากัน (ไม่ใช่ shift เดียวทั้งข้อความ) → นี่คือ Vigenère (key ยาวกว่า 1 ตัวอักษร) → ไปทำตามหัวข้อ Vigenère
  10. 10ได้ผลลัพธ์อ่านออกแล้ว → เช็ค flag format ให้ตรงกับที่โจทย์กำหนด (เช่น flag{...} หรือ CTF{...}) แล้วส่งคำตอบ
เจอข้อความน่าสงสัย มีแค่ Kali — ไล่ตามนี้
cat chal.txt — เป็น a-z ล้วน? ความยาวเท่าเดิม?
ยืนยันว่าน่าจะเป็น substitution/Caesar
ลอง ROT13 ก่อน (tr 'A-Za-z' 'N-ZA-Mn-za-m')
✅ อ่านออก / เจอ flag{→ จบ ส่ง flag
❌ ไม่ออก→ brute ทั้ง 25 shift ต่อ
brute 25 shift (python loop หรือ CyberChef 'ROT13 Brute Force')
✅ เจอบรรทัดที่อ่านออก→ จบ ส่ง flag
❌ ไม่มีบรรทัดไหนอ่านออกเลย→ เช็ค charset อีกที
มีตัวเลข/สัญลักษณ์ปนเยอะไหม?
✅ มีปนเยอะ→ ลอง ROT47
❌ a-z ล้วน→ ทำ histogram ดูต่อ
histogram มี peak เดียวชัดไหม (เหมือนอังกฤษ)?
✅ มี peak ชัด→ chi-squared หา shift อัตโนมัติแล้วถอด
❌ แบนเรียบ / brute 25 ไม่ออกเลย→ สงสัย substitution ทั่วไปหรือ Vigenère
ลอง quipqiup.com (substitution solver)
✅ ได้ mapping อ่านออก→ จบ
❌ ไม่ได้ / ข้อความสั้นเกินไป→ สงสัยว่าเป็น Vigenère (shift ไม่เท่ากันทั้งข้อความ)
ขั้นตอน/งานเครื่องมือใน Kaliติดตั้งเพิ่ม (ถ้าไม่มี)เครื่องมือออนไลน์
ดูไฟล์/ข้อความเบื้องต้นcat, file, xxd--
ถอด ROT13 เร็วๆtr-gchq.github.io/CyberChef (ROT13)
brute Caesar ทุก shiftpython3-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)
🚑 ถ้าตันสนิท ลองท่าถัดไป: Vigenère — ถ้า brute Caesar 25 ค่าไม่ออกเลยและ histogram แบนเรียบ (shift ไม่คงที่ทั้งข้อความ) · ROT13/ROT47 — ถ้ายังไม่ได้ลอง ROT47 กับข้อความที่มีตัวเลข/สัญลักษณ์ปน · XOR — ถ้าข้อมูลเป็น hex/base64 ที่ decode ออกมาไม่ใช่ตัวอักษรแต่เป็น byte กระจายไม่มีแพทเทิร์น · Hash Cracking — ถ้าสิ่งที่ได้มาจริงๆ คือ hash (ความยาวคงที่ เช่น 32/40/64 hex ไม่ขยับตามข้อความ)

โน้ตของฉัน

ยังไม่มีโน้ตสำหรับหัวข้อนี้