Nov 21, 2010

Cryptography ตอนที่ 4 การเข้ารหัสลับแบบสัมพรรค

จากสองตอนที่ผ่านมา เราได้เห็นว่าการเข้ารหัสลับแบบเลื่อนนั้น เป็นกรณีพิเศษกรณีหนึ่งในการเข้ารหัสลับแบบจับคู่
แต่อาจเนื่องด้วยความยุ่งยากของการต้องใช้กุญแจขนาดใหญ่เพื่อไขรหัสให้ได้ บวกกับความง่ายเกินไปของการเข้ารหัสแบบเลื่อน
ทำให้เกิดการเข้ารหัสแบบสัมพรรค หรือ Affine Cipher ซึ่งดัดแปลงเพิ่มเติมจากการเข้ารหัสลับแบบเลื่อนขึ้นมา
เขียนอธิบายเป็นภาษาทั่วไปยากหน่อย วิธีนี้ดูสมการแล้วน่าจะเข้าใจง่ายกว่าจริงๆ

ให้ P = C = Z26 และให้ K = {(a, b) ใน Z26 | gcd(a, 26) = 1}
สำหรับ K = (a, b) จะกล่าวว่า
eK(x) = (ax + b) mod 26 และ dK(y) = a-1(y - b) mod 26 สำหรับ x, y ที่เป็นสมาชิกของ Z26

อย่างที่บอกไว้ว่าวิธีนี้ดัดแปลงเพิ่มเติมจากการเข้ารหัสแบบเลื่อนแค่นิดเดียว
ลองมองผ่านๆ จะเห็นว่าวิธีการนี้เพียงแค่เพิ่ม a เข้าไปคูณกับ x ก่อนที่จะบวกด้วย b เท่านั้นเอง
รู้แค่นี้ก็เอาไปใช้ได้แล้ว แต่ถ้าอยากใช้อย่างไม่ผิดพลาด ลองมาวิเคราะห์อะไรที่มันยากๆ ในนั้นกัน

เริ่มจาก K = {(a, b) ใน Z26 | gcd(a, 26) = 1} หมายความว่ากุญแจที่ใช้นี้ ต้องการตัวแปรเพื่อใช้เข้ารหัส 2 ค่า อันนี้ไม่ยากๆ
แต่จะยากตั้งแต่ตรงนี้ไปคือ gcd(a, 26) = 1 หรือห.ร.ม.ของ a กับ 26 ต้องเป็น 1 เท่านั้น
นั่นก็เพราะว่า ถ้าห.ร.ม.ไม่เท่ากับ 1 แล้ว ฟังก์ชัน eK จะไม่เป็น 1-1 ส่งผลให้ไม่สามารถใช้ dK หาข้อความที่ถูกต้องได้
ลองพิจรณาตัวอย่าง สมมติให้ a = 2, b = 0 ข้อความ iamaboy จะแปลงได้เป็น QAYACCW
ซึ่งเห็นได้ว่า b, o ทั้งสองตัวแปลงเป็น C ทำให้แปลง QAYACCW กลับเป็น iamaboy ไม่ได้แล้ว

และเขียนเป็นทฤษฎีบทได้คือ ax = b (mod m) จะมีคำตอบเฉพาะสำหรับ x ที่อยู่ใน Zm เมื่อ b ใน Zm ก็ต่อเมื่อ gcd(a, m) = 1
สำหรับวิธีพิสูจน์จะขอละไว้ก่อน เนื่องจากมันค่อนข้างยาวและใช้ความรู้ด้าน Number theory ที่ผมยังไม่ค่อยถนัดนัก

ขั้นต่อไปที่เราะพิจรณาคือ จะมี a ใดบ้างที่เหลือให้เราใช้ได้
จาก 26 = 2 x 13 ดังนั้นเลขที่ใช้ได้จะไม่มี 2 กับ 13 ประกอบอยู่เมื่อเราแยกตัวประกอบ
ดังนั้น a สำหรับ Z26 คือ 1, 3, 5, 7, 9, 11, 15, 17, 19, 21 และ 25 (ถ้าเปลี่ยน Z26 เป็นอย่างอื่นก็ต้องหากันใหม่)
เห็นได้ว่าวิธีนี้มี a ที่ใช้ได้อยู่ 12 แบบ ส่วน b ยังเหมือนเดิม 26 แบบ ดังนั้น key space มีขนาด 12 x 26 = 312 วิธี (ไม่ปลอดภัย)

สำหรับจำนวนของกุญแจที่เป็นไปได้นี้ ก็มีทฤษฎีบทมารองรับเช่นกัน
ก่อนอื่นเราจะกล่าวว่าเมื่อ a ? 1 และ m ? 2 เป็นจำนวนเต็ม ถ้า gcd(a, m) = 1 เราจะเรียกว่า a และ m เป็นจำนวนเฉพาะสัมพัทธ์
และจำนวนของสมาชิกใน Zm ที่เป็นจำนวนเฉพาะสัมพัทธ์กับ m (ก็คือ a นั่นเอง) จะเรียกว่า ?(m)
ซึ่ง ?(m) จะเท่ากับผลคูณของ (piei - piei-1) ตั้งแต่ i = 1 ถึง n (ไม่พิสูจน์อีกตามเคย ยากส์ส์)

ลองใช้ดีกว่า จากข้างต้น 26 = 21 x 131
ดังนั้น ?(26) = (21 - 20)(131 - 130) = (2-1)(13-1) = 12 ครับ

แต่ปัญหาก็ยังไม่หมดเท่านี้ เพราะแม้เราจะมี a ทั้ง 12 แบบอยู่ในมือแล้ว แต่กลับไปดูด้านบนสุดจะเห็นว่าเราต้องการ a-1
ถ้านี่เป็นการพิจรณาเลขในชีวิตประจำวัน มันก็ไม่น่ามีปัญหา 3-1 ก็คือ 1/3 ไม่เห็นยาก
แต่อย่าลืมว่าตอนนี้เรากำลังพิจรณาเลขใน Z26 ซึ่งเรานิยามแค่การบวกและคูณ ไม่ได้นิยามการหาร
เราจึงต้องใช้สมบัติพื้นฐานที่ว่า aa-1 = a-1a = 1 (mod m)
งานนี้ถึกก่อนได้เปรียบ ลองหาดูเลยว่า a แต่ละตัวที่ได้มานั้น นำไปคูณอะไรแล้ว mod 26 เหลือ 1 (ผลออกมาดังข้างล่างครับ)

1-1 = 1
3-1 = 9
5-1 = 21
7-1 = 15
11-1 = 19
17-1 = 23
25-1 = 25

และในที่สุด เราก็ทราบเงื่อนไขทั้งหมดเพื่อใช้การเข้ารหัสแบบสัมพรรคอย่างถูกวิธีแล้ว
ต่อไปลองมาวิเคราะห์อัลกอริทึมกันครับ

อย่างที่บอกไปแล้วว่า วิธีนี้ดัดแปลงเพิ่มจากการเข้ารหัสลับแบบเลื่อนเพียงนิดส์เดียว
ดังนั้นเราจะเริ่มด้วยการก๊อปปี้โค้ดเก่ามาเปลี่ยนรายละเอียดครับ (ข้อดีของการเขียนโค้ดให้แก้ง่าย)

ที่บรรทัด 1 เปลี่ยนชื่อ และเพิ่มเงื่อนไขของการใช้กุญแจเป็น 2 องค์ประกอบ
ที่บรรทัด 5 เปลี่ยน logic ของการคำนวนให้เข้ากับสมการคณิตศาสตร์ที่พึ่งเรียนไป

def affine(pain_text, a, b):
cipher_text = ""
for i in range(len(pain_text)):
char_num = lower_to_number(pain_text[i])
char_num = a*char_num + b
char_num %= 26
cipher_text += number_to_upper(char_num)
print(cipher_text)


เราก็จะได้โค้ดของการเข้ารหัสลับแบบสัมพรรคมาใช้อย่างถูไถละครับ

ก่อนที่เราจะเขียนโค้ดส่วนนี้ต่อ สังเกตุว่าห.ร.ม.ของ a กับ 26 หรือ gcd(a, 26) = 1
ดังนั้น เราจึงต้องเขียนป้องกันไม่ให้ a ที่รับมามี gcd(a, 26) != 1 ด้วย
วิธีที่จะเขียนตรวจสอบ gcd(a, 26) นั้นก็มีหลายวิธีครับ ตั้งแต่ไล่หาค่าเองด้วยมือตามด้านบนที่ทำมาแล้ว ไปจนถึงการใช้คณิตศาสตร์มาช่วยเลย
สำหรับวิธีที่จะนำเสนอนี้ เป็นการใช้ขั้นตอนวิธีของยูคลิด โดยอยู่ในรูป Recursion ครับ

def gcd(a, b):
if a%b == 0:
return(b)
else:
return(gcd(b, a%b))


เรียบร้อยแล้วก็กลับมาปรับปรุงโค้ดของเราครับ

def affine(pain_text, a, b):
if gcd(26, a) != 1:
return("gcd(26, %(a)i) must be 1") % locals()
else:
cipher_text = ""
for i in range(len(pain_text)):
char_num = lower_to_number(pain_text[i])
char_num = a*char_num + b
char_num %= 26
cipher_text += number_to_upper(char_num)
return(cipher_text)


สองตอนที่แล้วปล่อยให้คิดวิธีเขียน decode เอง แต่คราวนี้ค่อนข้างยากเพราะมีเรื่องของ a-1 ด้วย
ซึ่งเราจะใช้ตัวแปรดิกชันนารีเพื่อจับคู่ a กับ a-1 ก็ได้ แต่มันง่ายไปแถมถ้าเราเปลี่ยนจาก Z26 เป็นอย่างอื่นแล้วก็ต้องหาใหม่
ถ้าอย่างนั้นแล้วเรามาดูฟังก์ชันที่มันสนุกๆ กันดีกว่าครับ

แต่ก่อนอื่น เพื่อให้เรื่องต่างๆ เป็นระเบียบและจัดการง่าย เราจะสร้างไฟล์ใหม่ที่ชื่อว่า cryptologic.py ครับ
และจากตอนที่ผ่านๆ มา จะเห็นว่ามีฟังก์ชันสั้นๆ ที่ไม่ใช่ฟังก์ชันที่เราจะเรียกใช้โดยตรง จะใช้แค่ประกอบในฟังก์ชันหลัก
เช่นพวก lower_to_number(text), ged(a,b) เราย้ายมันมาไว้ที่นี่ครับ
แล้วจึงเพิ่มโค้ดอันแสนสนุกสนานนี้เข้าไปร่วมกับเพื่อนๆ ครับ

def multiple_inv(a, b, s = 0, t = 1):
if a%b == 0:
if b != 1:
return(None) # case of no inverse
else:
return(t)
else:
return(multiple_inv(b, a%b, t, (s-t*int(a/b))%26))


จะเห็นว่า ฟังก์ชันนี้เป็น Recursion อีกแล้ว และที่บรรทัดแรกนั้นมีตัวแปร 4 ตัว คือ a, b, s, t
แต่เวลาจะใช้งานนั้น s เริ่มที่ 0 และ t เริ่มที่ 1 หลังจากนั้นจึงค่อยส่งค่าที่คำนวนกลับเข้าไป
เราจึงสามารถกำหนด s = 0 และ t = 1 ได้ตั้งแต่เริ่มเลย
และยิ่งไปกว่านั้น เวลาเราเรียกใช้ฟังก์ชันครั้งแรก เราสามารถใส่ค่าเพียง a กับ b ก็พอ

อย่าลืมเขียนโค้ด import ที่ไฟล์ encrypt.py เพื่อเรียกใช้งานฟังก์ชันที่อยู่ต่างไฟล์ออกไปนะครับ

from cryptologic import * 


ส่วนการโค้ดรับรหัสลับเพื่อนำมาถอดเป็นข้อความก็จะเป็นดังนี้ครับ (ไฟล์ใหม่ decrypt.py ครับ)

def affine(cipher_text, a, b):
a_inv = multiple_inv(26, a)
if a_inv == None:
return("%(a)i has no inverse") % locals()
else:
pain_text = ""
for i in range(len(cipher_text)):
char_num = upper_to_number(cipher_text[i])
char_num = a_inv*(char_num - b)
char_num %= 26
pain_text += number_to_lower(char_num)
return(pain_text)


เดี๋ยวตอนหน้าจะมันส์กว่านี้อีกครับ ยังไงก็ติดตามกันด้วยนะครับ ^__^

Nov 20, 2010

Cryptography ตอนที่ 3 การเข้ารหัสลับแบบจับคู่

การเข้ารหัสลับด้วยวิธีต่อมานั้นก็คือ Substitution Cipher หรือแบบจับคู่
วิธีการก็ไม่รู้ว่าจะอธิบายให้ยุ่งยากทำไมเนาะ - -"
แต่ก็เอาถอะ ไหนๆ ก็พูดในเชิงคณิตศาสตร์ละ งั้นก็ลงอธิบายแบบคณิตศาสตร์เลยละกัน

ให้ P = C = Z26, ส่วน K คือวิธีเรียงสับเปลี่ยนของเลข 0 ถึง 25 ทั่งหมดที่เป็นไปได้ ให้ ? เป็นสมาชิกของ K จะกล่าวว่า
e?(x) = ?(x) และ d?(x) = ?-1(x) เมื่อ ?-1 คืออินเวอร์สของ ?

จะเห็นว่า วิธีนี้ให้ key space ที่ใหญ่มากถึง 26! หรือประมาณ 4.03 x 1026 เลยทีเดียว (แต่ก็ยังไม่ปลอดภัยอยู่ดี!)

จุดที่อาจเสียเวลาหน่อยคือตอนสร้าง key ขึ้นมา เพราะต้องเรียงสับเปลี่ยนตัวเลขถึง 26 ตัว
งั้นก็ต้องใช้เครื่องทุ่นแรงกันหน่อยหละ ก่อนอื่นก็สร้างลิสต์ของเลข 26 ตัวขึ้นมาก่อน

>>> list = []
>>> for i in range(26):
... list.append(i)
...


ต่อมาเราจะสับเปลี่ยนเลขพวกนี้แล้ว วิธีที่ง่ายที่สุดคือไล่สลับตำแหน่งที่สนใจกับตำแหน่งสุ่มไปเรื่อยๆ จนครบ
ถึงแม้ว่าการใช้วิธีนี้จะครอบคลุมการเรียงสับเปลี่ยนทุกรูปแบบก็ตาม แต่ข้อเสียคือความน่าจะเป็นจะไม่เท่าการเรียงสับเปลี่ยนจริงๆ นะครับ

>>> import random
>>> for i in range(26):
... temp = random.randint(0, 25)
... list[i], list[temp] = list[temp], list[i]
...


จัดการเปลี่ยนมันให้เป็นตัวอักษร และเซฟเป็นไฟล์ *.txt ซะ (เพราะต้องได้ใช้ในอนาคตแน่นอน!)

>>> mapping = ""
>>> for i in range(26):
... mapping += chr(list[i] + ord('A'))
...
>>> f = open("map_key.txt", 'w')
>>> f.write(mapping)
>>> f.close


ตอนนี้ เราจะได้ไฟล์ map_key.txt ออกมา ซึ่งบรรจุการจับคู่ของตัวอักษรแล้วครับ
สำหรับการจับคู่ของผมในครั้งนี้ (ไล่จาก a ไป z) คือ XLNYKIHFJWTRBMVPGSAUZQECOD
ต่อมา เช่นเดียวกับที่เราได้เขียนฟังก์ชันไว้ใช้ในตอนที่แล้ว คราวนี้เราจะเปิดไฟล์เดิมมาเขียนเพิ่ม ดังนี้ครับ

def substitution(pain_text, key_file):
cipher_text = ""
mapping = []
for i in range(26):
mapping.append(0)
f = open(key_file)
for i in range(26):
mapping[i] = upper_to_number(f.read(1))
f.close()
for i in range(len(pain_text)):
char_num = lower_to_number(pain_text[i])
char_num = mapping[char_num]
cipher_text += number_to_upper(char_num)
print(cipher_text)

def upper_to_number(text):
return(ord(text) - start_upper)


เสร็จเรียบร้อย ลองเรียกใช้ฟังก์ชันโดยการ import encrypt เข้ามาก่อน
และเรียกที่อยู่ฟังก์ชัน encrypt.substitution("canyoureadme", "map_key.txt ")
ก็ได้ผลลัพท์เป็น NXMOVZSKXYBK ครับ

AKKOVZMKCUUJBK

Nov 17, 2010

Cryptography ตอนที่ 2 การเข้ารหัสลับแบบเลื่อน

การเข้ารหัสลับแบบแรกที่ง่ายที่สุดนั้น คือการเข้ารหัสแบบ Shift Cipher หรือการเข้ารหัสแบบเลื่อน
วิธีการก็เป็นไปตามชื่อเลย คือทำการเลื่อนตัวอักษรออกไปตามความยาวที่ต้องการ เท่านั้นเองครับ
ชื่อเฉพาะที่น่าสนใจของวิธีนี้คือ Caesar Cipher อันเนื่องมาจากนี่เป็นวิธีที่จูเลียส ซีซาร์ใช้ในการส่งข้อความลับโดยการเลื่อนอักษรออกไป 3 ตำแหน่งนั่นเอง

เราสามารถเขียนการเข้ารหัสแบบเลื่อนเป็นภาษาคณิตศาสตร์ที่รัดกุมได้ ดังนี้

ให้ P = C = K = Z26, สำหรับ 0 ≤ K ≤ 25 จะกล่าวว่า
eK(x) = (x + K) mod 26 และ dK(y) = (y - K) mod 26 สำหรับ x, y ที่เป็นสมาชิกของ Z26

สำหรับบรรทัดแรก จะกล่าวถึงขนาดของ space ข้อมูลที่เราสนใจ ซึ่งในที่นี้ก็คืออักษรภาษาอังกฤษ 26 ตัวตามที่ตกลงกันแต่แรก
ส่วนต่อมาคือการกำหนด key space ที่ถูกนำไปใช้ในบรรทัดต่อไปว่ามีค่าอยู่ในช่วงระหว่าง 0 ถึง 25 นั่นเอง ซึ่งก็คือ 26 แบบนั่นเอง (ไม่ปลอดภัยอย่างแรง!!!)
ตรงนี้ที่ต้องเขียนบอกให้ชัดเจนเพราะเราอาจเขียนมันในกรณีอื่นอีกก็ได้ เช่นสำหรับ K ที่เป็นเลขคู่ให้เลื่อนไปด้านหน้า ส่วน K ที่เป็นเลขคี่ให้เลื่อนไปด้านหลัง เป็นต้นครับ
บรรทัด 2 คือการบอกว่าสำหรับ k ต่างๆ ที่อยู่ใน K นั้นใช้อย่างไร ในที่นี้ก็คือเลื่อนไปด้านหน้าตามขนาดของ K นั่นเองครับ
สังเกตว่าเราใช้ K ตัวใหญ่ใน eKและ dK นั่นก็เพราะว่าเราเขียนระบุในเรื่องของเซตครับ ซึ่งหมายรวมว่าเราสามารถจับ k ใน K ใดๆ ก็ได้มาแทนตรงนั้น

ต่อมาเราจะมาวิเคราะห์อัลกอริทึมกัน โดยทดลงใน Python Shell ตรงๆ
ในเบื้องต้นนั้น เราต้องรับค่าของข้อความที่ต้องการในรูปแบบของ String และกำหนด key ที่เราต้องการให้เลื่อนอักษรไป

>>> pain_text = "testshiftcipher"
>>> k = 3


ต่อมา ให้สร้างตัวแปร String สำหรับเก็บรหัส และใช้ loop วนเข้าไปเพื่อแปลงค่าของตัวอักษรแต่ละตัวๆ ออกมา
เนื่องจากรหัสอักษรในคอมพิวเตอร์นั้นเป็นรหัส ASCII ซึ่งเรียงกันไปตั้งแต่ a = 97 ถึง z = 122 อยู่แล้ว
ในขั้นต้นเพื่อความง่าย เราจะบวกค่าเหล่านี้เข้าไปทันทีด้วยค่า k แล้วแปลงกลับเป็นตัวอักษรเหมือนเดิม

>>> cipher_text = ""
>>> for i in range(len(pain_text)):
... cipher_text += chr(ord(pain_text[i]) + k)
...


เราสามารถเรียก cipher_text ออกมาดูได้ จะเห็นว่าคำที่เราแปลงนั้นกลายเป็น whvwvkliwflskhu (เกือบ) เป็นที่เรียบร้อย
แต่ว่าโค๊ดตรงนี้ยังมีปัญหาอยู่ เพราะว่าถ้าเราใส่อักษรท้ายๆ เข้าไปนั้น เมื่อแปลงเป็นรหัสแล้วก็มีสิทธิ์หลุดออกจากเซตของตัวอักษรอังกฤษไปเป็นอักษรแปลกๆ ได้
เช่นข้อความว่า howareyoutoday เมื่อใช้อัลกอริทึมเก่าจะได้ข้อความ KRZDUH|RXWRGD| จะเห็นว่ามี | ซึ่งไม่ใช่อักษรอังกฤษโผล่เข้ามา
ดังนั้นเราจึงต้องใช้ if เพื่อเช็คว่าค่าที่ได้นั้นเกิน z หรือยัง ถ้าเกินแล้วให้ลบค่าออกด้วย 26
นอกจากนี้ เนื่องจากเราต้องการให้อักษรที่เข้ารหัสแล้วเป็นตัวพิมพ์ใหญ่ด้วย
จาก A = 65 ดังนั้น a - A = 32 เราจึงต้องลบค่าอักษรแต่ละตัวออกไปอีกตัวละ 32 ดังนี้

>>> pain_text = "howareyoutoday"
>>> k = 3
>>> cipher_text = ""
>>> for i in range(len(pain_text)):
... temp = ord(pain_text[i]) + k
... if temp > 122:
... temp -= 26
... temp -= 32
... cipher_text += chr(temp)
...


คราวนี้เมื่อเราใส่ข้อความ howareyoutoday เข้าไป ก็จะได้ผลลัพท์เป็น KRZDUHBRXWRGDB เรียบร้อยแล้วครับ
ต่อไป เราจะสร้างไฟล์ *.py ขึ้นมาเพื่อเก็บฟังก์ชันที่เขียนให้ง่ายต่อการเรียกใช้ในครั้งถัดๆ ไป
โดยคราวนี้เราจะไม่เขียนลวกๆ แล้ว เพราะการเขียนที่เป็นระเบียบจะทำให้ดูแลและพัฒนา code ต่อภายหลังได้ง่ายขึ้น

start_lower = ord('a')
start_upper = ord('A')

def shift(pain_text, key):
cipher_text = ""
for i in range(len(pain_text)):
char_num = lower_to_number(pain_text[i])
char_num += key
char_num %= 26
cipher_text += number_to_upper(char_num)
print(cipher_text)

def lower_to_number(text):
return(ord(text) - start_lower)

def number_to_upper(num):
return(chr(num + start_upper))


จัดการบันทึกไฟล์ที่เขียนนี้ (ในที่นี้ใช้ชื่อ encrypt.py) แล้ว import ไฟล์ผ่าน python shell
เวลาจะเข้ารหัสก็เรียงฟังก์ชันนี้โดยพิมพ์ encrypt.shift("abcdefg", key) เข้าไปเลย
(abcdefg คือคำที่ต้องการให้เข้ารหัส, key คือตัวเลขที่ต้องการให้เลื่อน) แค่นี้ก็เรียบร้อยแล้วครับ ^__^

อ๋อ สำหรับวิธี decrypt นั้น ฝากเป็นการบ้านให้ไปคิดต่อละกันเน้อออ
JRRGOXFN

Nov 16, 2010

Cryptography ตอนที่ 1 ธรรมชาติของการเข้ารหัส (อย่างง่าย)

เมื่อเราลองวิเคราะห์ระบบรหัสลับนั้น เราจะกล่าวได้ว่ามันเป็น (P, C, K, E, D) 5-tuple
เริ่มมาก็งงเลยใช่ปะละ (คนแปลก็งงเหมือนกัน) งั้นเราค่อยๆ ดูกันไปทีละส่วนละกันครับ

tuple คำนี้อาจไม่คุ้นเคยและดูยุ่งยาก แต่ที่จริงแล้วมันเป็นเพียงวิธีการเขียนเรียงลำดับสมาชิกเท่านั้นเอง (ต่างจากเซตที่สมาชิกแต่ละตัวไม่มีความสำคัญในเรื่องลำดับ)
โดยสมาชิกของ tuple นั้นจะต้องมีจำนวนจำกัด n ตัวเสมอ n-tuple ที่เราคุ้นเคยกันดีก็คือ 2-tuple ที่อยู่ในรูป (x, y) หรือเรียกติดปากกันว่าคู่อันดับนั่นเอง
ดังนั้นการที่กล่าวได้ว่าระบบรหัสลับเป็น 5-tuple ก็หมายความว่าระบบนี้มีสิ่งที่สำคัญประกอบอยู่ 5 อย่างนั่นเอง ซึ่งมีความสัมพันธ์กันดังนี้

1. P (Plaintext) คือเซตจำกัดของข้อความอ่านออกที่เป็นไปได้
2. C (Ciphertext) คือเซตจำกัดของข้อความเข้ารหัสที่เป็นไปได้
3. K (Key) คือเซตจำกัดของกุญแจการเข้ารหัสที่เป็นไปได้
4. สำหรับแต่ละ k ที่เป็นสมาชิกของ K (ในทางคณิตศาสตร์ ตัวพิมพ์ใหญ่คือเซต ตัวพิมพ์เล็กคือสมาชิกของเซตนั้นๆ) จะมีวิธีการใช้กุญแจเข้ารหัส (Encryption) eK ที่เป็นสมาชิกของ E และมีวิธีใช้กุญแจถอดรหัส (Decryption) dK ที่เป็นสมาชิกของ D โดยที่ eK : P -> C (eK เป็นฟังก์ชันจาก P ไปยัง C หรือกล่าวง่ายๆ ว่าฟังก์ชัน eK นี้มี P เป็น input ส่วน C เป็น output นั่นเอง) และ dK : C -> P โดยที่ p = dK(eK(p))

จากข้อ 4 นี้ จะหมายความว่า dK เป็นอินเวอร์สของ eK เสมอ และเขียนได้ว่า dK = eK-1
นอกจากนี้ eK และ dK ยังต้องเป็นฟังก์ชันแบบ 1-1 อีกด้วย (จับคู่กันและกันแค่คู่ต่อคู่เท่านั้น) เพราะถ้าไม่เป็นฟังก์ชัน 1-1 แล้ว เมื่อเราต้องการถอดรหัสกลับเป็นข้อความธรรมดา เราอาจไม่รู้เลยว่าคำที่ถูกต้องคืออะไรกันแน่ เพราะ 1 คำอาจถอดรหัสกลับได้หลายแบบนั่นเอง

จากที่เกริ่นมานี้หมายความว่า ถ้าเราสามารถล่วงรู้ eK ได้ เราก็จะหา dK เพื่อถอดรหัสลับได้เช่นกัน
หรือว่าถ้าเราสามารถดักจับข้อความลับ c ได้ และล่วงรู้ข้อความถูกต้อง p บางส่วน เราอาจทดลองหา k ที่ทำให้ c = ek(p) จนสำเร็จ และหา dk ได้ด้วย

Nov 14, 2010

เก็บตกงานโกะวันสุดท้าย

ไดอารีเค้ามีแต่เขียนกันในวันนั้นๆ ไอ่นี่เป็นไงไม่รู้อยากเขียนไดเก่าเมื่อสอง-สามสัปดาห์ที่แล้วซะได้
เหตุก็เพราะมันเป็นเหตุการณ์ที่ยากจะลืม และจะยากยิ่งกว่าถ้าจะพยายามทำใจให้ลืมมันลงให้ได้
อาจเรียกได้ว่าเป็น turn point ในชีวิตครั้งสำคัญอีกครั้งหนึ่งในชีวิตเลยก็ว่าได้

เรื่องมันมีอยู่ว่า เราได้รับหน้าที่เป็นกรรมก(า)รในงานแข่ง U-Go ครั้งที่ 15
งานที่ได้รับมอบหมายคือ จัดโต๊ะ ยกของ ไม่ใช้สมอง ใช้แต่แรง อะม่ายช่ายยย
หน้าที่จริงๆ คือ การเป็นผู้ช่วยกรรมการคอยอำนวยความสะดวกแก่การแข่งขัน
ซึ่งได้แก่การปักธงจับคู่ นับหมากเบียวโยมิ และส่งผลคะแนนการแข่งขัน
ส่วนพวกงานใช้แรงนั้น เพราะคนไม่พอเลยต้องลงมือช่วยอย่างเต็มใจ 555+

Nov 13, 2010

Cryptography ตอนที่ 0 เกริ่นนำ

เกริ่นนำ
Cryptography เป็นวิชาที่ว่าด้วยเรื่องของรหัสลับ โดยชื่อนี้มีที่มาจากรากศัพท์จากภาษากรีกว่า kryptos "ลับ" สมาสกับ graph "เขียน" แปลว่าวิธีเขียนความลับนั่นเอง
อีกคำนึงที่มักปรากฎบ่อยๆ ในศาสตร์แห่งการซ่อนเร้นความลับก็คือคำว่า cipher "วิธีเข้ารหัสลับ" ซึ่งเอาไว้บ่งบอกว่าใช้วิธีใดเข้ารหัสลับครับ

ทั้งนี้ทั้งนั้น อย่าสับสนกับ Steganography หรือการอำพรางข้อมูล เพราะแม้ว่าทั้งการเข้ารหัสและการอำพรางข้อมูลนั้นมีจุดมุ่งหมายสูงสุดเดียวกัน (ป้องกันผู้อื่นรับรู้ข้อมูลที่ต้องการปกปิด)
แต่การเข้ารหัสนั้นจะมุ่งเน้นไปที่การปกป้องข้อมูลจากการถูกแกะอ่านได้โดยผู้อื่น ส่วนการอำพรางข้อมูลนั้นมุ่งไปที่การทำให้ผู้อื่นสำคัญผิดว่าไม่มีข้อมูลใดๆ ซ่อนอยู่ในข้อความที่ถ่ายทอดมานั้น


เกี่ยวกับผู้เรียบเรียง
เนื่องจากผมเรียนเอกคณิตศาสตร์ บทเรียนชุดนี้จึงอิงความรู้คณิตศาสตร์บริสุทธิ์ค่อนข้างมาก
บวกกับความชื่นชอบในคอมพิวเตอร์ ก็จะพยายามวิเคราะห์อัลกอริทึมและเขียนโปรแกรมควบคู่กับบทเรียนไปด้วย เพื่อให้สามารถเห็นตัวอย่างได้ชัดเจนยิ่งขึ้น
ส่วนผู้ที่ไม่รู้ทั้งคณิตฯ และคอมฯ ก็ไม่ต้องกังวลไป เพราะผมจะพยายามเขียนให้เข้าใจทั้งคณิตฯ และคอมฯ นั่นแหละ 555+


ข้อตกลง
เพื่อความง่ายในการทำความเข้าใจ รหัสลับทั้งหมดที่ใช้ในบทเรียนจะประกอบด้วยตัวอักษรภาษาอังกฤษเพียง 26 ตัวเท่านั้น ไม่ใช้ตัวเลขหรือเครื่องหมายพิเศษอื่นใดทั้งสิ้น
โดยข้อความที่ถูกต้องนั้นจะเขียนอยู่ในรูปของตัวพิมพ์เล็กทั้งหมด ส่วนข้อความที่ถูกเข้ารหัสแล้วจะเขียนด้วยตัวพิมพ์ให้ญ่ทั้งหมด ดังตัวอย่าง

OHWVVWXGBFUBSWRJUDSKB

คือรหัสลับของคำว่า

letsstudycryptography

และเนื่องจากเราต้องการศึกษาในเชิงคณิตศาสตร์และคอมพิวเตอร์เป็นหลัก การแทนตัวอักษรด้วยตัวเลขจะทำให้ง่ายต่อการนำไปคำนวณในขั้นตอนที่สูงกว่านี้
เราจะให้เลข 0 แทนตัวอักษร a, A เรื่อยไปจนถึงให้ 25 แทน z, Z และเรียกระบบนี้ว่า Z26
ซึ่งหมายถึงเซตของเลขจำนวนเต็มจาก 0 ถึง 25 สำหรับสมาชิกใน Z26 ที่นำมาดำเนินการกันแล้วมีค่าเกิน 25 ก็จะนำไป mod 26 เพื่อให้ผลลัพท์อยู่ใน Z26 เหมือนเดิมครับ

สำหรับการวิเคราะห์อัลกอริทึมและเขียนโปรแกรมนั้น จะใช้ภาษา Python ทั้งหมด เพราะผู้เขียนชอบภาษานี้ครับ ...เอ้ย ไม่ใช่ละ
ที่เลือก Python ก็เนื่องด้วยความง่ายของตัวภาษา สามารถลงมือเขียนได้ทันที ไม่ต้องรู้เชิงลึกเกี่ยวกับคอมพิวเตอร์ก็ได้
หรือถ้าใครเรียนคอมพิวเตอร์มาโดยตรง พอเห็นแล้วจะร้องอ๋อเลย เพราะมีความคล้ายกับ pseudo code เป็นอย่างมาก อ่านแล้วเขียนเป็นภาษาที่ตนเองถนัดได้ทันที
อยากให้ทุกคนที่ต่มอ่านลองเขียนโปรแกรมเล่นกันดูนะครับ ^__^

ความรู้ที่ควรมีประกอบ
Modular arithmetic
Discrete mathematics
Linear algebra
Boolean algebra
Python (programing language)


อ้างอิง
Stinson, D.R., Cryptography: Theory and Practice, Third Edition, 2006
(ในห้องสมุดมีหนังสือให้ยืมมาอ้างอิงแค่เล่มเดียวอยู่ ถ้าหาเพิ่มจะได้ทยอยอัพเดทครับ)