การเข้ารหัสลับ (Encryption) เบื้องต้น สำหรับนักพัฒนา

การเข้ารหัสลับ (Encryption) เบื้องต้น สำหรับนักพัฒนา

27 พฤษภาคม 2565

บทความ “การเข้ารหัสลับ (Encryption) เบื้องต้น สำหรับนักพัฒนา” นี้ใช้แหล่งข้อมูลส่วนใหญ่จาก e-book ชื่อ Practical Cryptography for Developers

อวจ: ที่อยู่ในบทความนั้นย่อมาจาก เอาไว้จำ จุดประสงค์ของผู้เขียนมีไว้เพื่อสรุปความสำหรับผู้อ่านที่มีความเข้าใจอยู่บ้างแล้ว หรืออ่านหัวข้อนั้นแล้วให้สามารถจำนิยามของหัวข้อนั้นได้

สาร ในบทความนี้ไม่ใช่ สารเคมี แต่เป็นข้อความ (message)

ในปัจจุบันอินเทอร์เน็ตเข้ามาเป็นส่วนหนึ่งของชีวิตทุกคน แต่กระนั้นความสะดวกสบายที่มาพร้อมกับอินเทอร์เน็ต ก็ไม่ได้นำมาเฉพาะข้อดีเพียงอย่างเดียว หากมองในด้านความปลอดภัยด้วยนั้น อินเทอร์เน็ตจึงเป็นเหมือนดาบสองคม เนื่องจากว่าหากนักพัฒนา หรือผู้ใช้งานขาดความเข้าใจ ก็จะทำให้เกิดช่องโหว่ให้ผู้ไม่ประสงค์ดีโจมตีระบบ หรือเกิดการโจรกรรมทางไซเบอร์ได้ และหนึ่งในหัวใจสำคัญของการสื่อสารระหว่างผู้ใช้งาน (Client) กับแม่ข่าย (Server) นั่นก็คือ การเข้ารหัสลับ (Encryption) โดยบทความนี้จะค่อย ๆ ปูนิยามของศัพท์ต่าง ๆ ที่เกี่ยวข้อง เช่น การเข้ารหัส (Encoding), ฟังก์ชันแฮช (Hashing function) เป็นต้น จนนำไปสู่เรื่องการเข้ารหัสลับ (Encryption) ทีละหัวเรื่อง ดังต่อไปนี้

การเข้ารหัส (Encoding)

อวจ: ด <-> d ; เสียง “ด” ในภาษาไทย คือเสียง “d” ในภาษาอังกฤษ

ผู้เขียนใช้ภาษาไทยว่า การเข้ารหัส เพื่อแปลคำว่า Encoding และ การเข้ารหัสลับ เพื่อแปลคำว่า Encryption เนื่องจากทั้งสองสิ่งนี้แตกต่างกันอย่างมาก การเข้ารหัสนั้นไม่ได้ทำเพื่อรักษาความลับของสาร แต่ทำเพื่อความสะดวกในการรับส่งสาร หรืออ่านสารได้ง่ายขึ้น ตัวอย่างเช่น การแปลงเลขฐานสองเป็นฐานสิบ หรือการแปลงเลขฐานสิบเป็นสายอักขระ (byte array) หรือการแปลงสายอักขระเป็นสาร base64 เป็นต้น

ตัวอย่างการเข้ารหัส
รูปที่ 1 ตัวอย่างการเข้ารหัส, แหล่งอ้างอิง

การเข้ารหัสนั้น สามารถย้อนกลับได้ง่ายด้วย การถอดรหัส (Decoding) ถ้าหากเรารู้ว่าสารที่เรารับมาถูกเข้ารหัสมาแบบใด เราก็จะสามารถถอดรหัสสารนั้นเป็นสิ่งที่เราต้องการได้ เช่น การแปลงสาร base64 เป็นสายอักขระ

ตัวอย่าง การเข้ารหัสจากสายอักขระเป็นสาร base64 และถอดรหัสจากสาร base64 เป็นสายอักขระ ในภาษา python

import base64
m = b"testing"
b64_m = base64.b64encode(m)
print(b64_m)
# b'dGVzdGluZw=='
_m = base64.b64decode(b64_m)
print(_m)
# b'testing'
assert (m == _m)

เกร็ด: ภาษาคาราโอเกะ ภาษาลู หรือคำผวน ก็เป็นการเข้ารหัสเช่นกัน 🙂

ฟังก์ชันแฮช (Hashing function)

อวจ: คิดถึง -> 345e28e423062ecb7dad358f1b47e4abb836a0cd77cf9f47cf6e6478f8d43403 ; ให้แฮชของความคิดถึง แทนความซาบซึ้งในใจ (เพราะจำไม่ได้ 555)

การแฮชนั้นคล้ายกับการเข้ารหัสตรงที่ ถ้าเรามีสาร และฟังก์ชันการแฮช เราก็สามารถ ผลิต เลขแฮชได้ แต่กลับกัน หากเราได้เลขแฮชมา เราจะไม่สามารถรู้ได้ว่า สารก่อนเข้าฟังก์ชันแฮชเขียนไว้ว่าอย่างไร ซึ่งจะนำไปสู่คุณสมบัติของฟังก์ชันแฮช คุณสมบัติของฟังก์ชันแฮชนั้นมีสองประการ คือ

  1. ไม่สามารถย้อนกลับได้
  2. แทบจะไม่มีสิทธิ์ชนกัน

คำว่า แทบจะไม่มีสิทธิ์ชนกัน นั้น แน่นอนว่าอาจจะเกิดการชนกันได้ แต่เกิดขึ้นยาก อภิมหาโคตรยาก เรียกว่า การพยายามจะหาสารสองอันที่จะให้ผลลัพธ์เลขแฮชเดียวกัน ก็เหมือนกับการควานหาฝุ่นในจักรวาลก็ปานนั้น แต่ในอนาคตก็ไม่แน่ว่า Quantum Computer อาจจะทำให้ SHA-2 ที่ได้รับความนิยมอยู่ในปัจจุบันถูกโค่นลงได้สักวัน อันนี้ก็เป็นเรื่องของอนาคตที่เราต้องติดตามกันต่อไป

ตัวอย่าง ฟังก์ชันแฮชในภาษา python ในที่นี้ ผู้เขียนขอใช้ตัวอย่างฟังก์ชัน sha256 หรือ SHA-2 มาเป็นตัวอย่าง

import hashlib
m = "คิดถึง"
hash_m = hashlib.sha256(m.encode("utf-8")).digest().hex()
print(hash_m)
# 345e28e423062ecb7dad358f1b47e4abb836a0cd77cf9f47cf6e6478f8d43403

เกร็ด: ยังมีกลุ่มฟังก์ชันที่มีแนวคิดคล้ายกับฟังก์ชันแฮชอีกสองอย่าง คือ check digit และ checksum แต่ต่างกันตรงความยากในการชนกัน เช่น

def calc_thai_citizen_id_check_digit(cid12: str) -> int:
  return (11 - sum([(13 - idx) * int(cid) for idx, cid in enumerate(cid12)]) % 11) % 10
assert (
  calc_thai_citizen_id_check_digit("000000000070") ==  # check digit ของ 000000000070 คือ 1
  calc_thai_citizen_id_check_digit("000000000005")     # check digit ของ 000000000005 ก็ได้ 1 ด้วยเหมือนกัน
)

หมายเหตุ: วิธีการคำนวน check digit นำมาจาก ที่นี่

จะสังเกตว่า การคำนวน check digit นั้นสามารถเกิดผลลัพธ์ที่ชนกัน (หรือเหมือนกันจากในตัวอย่างคือเลข หนึ่ง) ได้ค่อนข้างง่าย ส่วน checksum นั้นจะเกิดผลลัพธ์ที่ชนกันค่อนข้างยาก ตัวอย่างคือ SHA-1 ในอดีตฟังก์ชันนี้ถูกใช้เพื่อเป็นฟังก์ชันแฮชด้วย แต่ปัจจุบันมีผู้ที่สามารถหาผลลัพธ์ที่ทำให้เกิดผลลัพธ์ที่เหมือนกันได้แล้ว ดังนั้น SHA-1 จึงไม่ดีพอที่จะใช้เป็นฟังก์ชันแฮชเพื่อความปลอดภัยอีกต่อไป อย่างไรก็ดี SHA-1 นั้นยังมีการใช้เพื่อทำ checksum เพื่อตรวจสอบความถูกต้องของไฟล์อยู่

ฟังก์ชัน MAC

อวจ: mac_func(สาร, รู้กันแค่เรา) -> ตัวเทียบว่าสารถูกต้อง ; นายเอส่งจดหมายรัก(สาร)หาน้องบีโดยใช้กระดาษสองแผ่นเสมอ(รู้กันแค่เรา) แต่วันหนึ่งไปรษณีย์ทำปลิวหายไปแผ่นหนึ่ง น้องบีจึงรู้ว่าจดหมายนั้นไม่ครบถ้วน(ไม่ถูกต้อง)เพราะไม่ครบสองแผ่น

MAC ในที่นี้ย่อมาจาก Message Authenticaion Code ไม่ได้เกี่ยวข้องกับ MAC Address หรือ Media Access Control Address แต่อย่างใด MAC มีไว้เพื่อทำหน้าที่พิสูจน์ว่าสารที่เราได้รับมาถูกต้องสมบูรณ์หรือไม่

การทำงานของ MAC
รูปที่ 2 การทำงานของ MAC

เนื่องจากการคำนวน MAC โดยวิธีใช้ hash_func(key + msg) นั้นไม่ปลอดภัยจากการโจมตีแบบ Length Extension Attack ดังนั้นฟังก์ชัน MAC ที่ปลอดภัยและได้รับความนิยมคือ HMAC (Hash-based MAC) โดยมีหน้าตาคือ mac = HMAC(key, msg, hash_func)

ตัวอย่างฟังก์ชัน HMAC ในภาษา python

import hashlib, hmac
def hmac_sha256(key, msg):
  return hmac.new(key, msg, hashlib.sha256).digest().hex()
key = "รู้กันแค่เรา"
msg = "คำบอกรักที่ฝากถึงเธอหนา สุดเกินกว่าพรรณาด้วยคำไหน ผ่านโลกหล้าผ่านเวลาสิ่งใดใด โปรดรู้ไว้คำว่ารักจักเหมือนเดิม"
mac = hmac_sha256(key.encode("utf-8"), msg.encode("utf-8"))
print(mac)
# 241e6bdd7b1b06ca8bdff88f19515e89e4b32d984cfb22174ce9cccb3680b830

ฟังก์ชัน KDF

อวจ: kdf_func(เกลือ, รหัสผ่าน, อย่างอื่นถ้ามี) -> รหัสผ่านที่แปลงแล้ว

KDF ย่อมาจาก Key Derivation Functions ฟังจากชื่อแล้วแอบน่ากลัวว่าจะเกี่ยวกับ Derivative ในคณิตศาสตร์ใช่ไหม แต่ไม่ใช่เช่นนั้น ฟังก์ชันนี้ไม่ได้เกี่ยวกับการคำนวน Derivative ผู้อ่านจึงไม่ต้องกังวล โดยในหัวข้อนี้จะพาผู้อ่านสู่ความเข้าใจ KDF ผ่านการจัดการรหัสผ่านระดับต่าง ๆ  ในการจัดการรหัสผ่าน (password) นั้นแน่นอนว่าเราไม่สามารถหลีกหนีเรื่องความปลอดภัยไปได้ และการเก็บรหัสผ่านของผู้ใช้ที่สามารถนำไปใช้งานกับระบบได้ทันทีก็เปรียบเสมือนการเก็บระเบิดเวลาไว้ในระบบ ผู้เขียนขอกล่าวถึง การจัดการรหัสผ่านโดยเริ่มตั้งแต่ระดับ อย่าหาทำ ไปจนถึงระดับ ควรทำ

ระดับ อย่าหาทำ หรือเกรียนสุด

วิธีการที่ง่ายสุด (และเกรียนที่สุดด้วย) นั่นคือการเก็บรหัสผ่านแบบ โต้ง ๆ ได้มาอย่างไรก็เก็บไปอย่างนั้นซะเลย ตัวอย่างเช่น ผู้ใช้งานกรอกรหัสผ่านตอนลงทะเบียนมาเป็น “hello123” ก็นำรหัสผ่านนี้เขียนลงในฐานข้อมูลตารางผู้ใช้เป็น “hello123” นั่นเอง แม้ว่าการจัดการรหัสผ่านของผู้ใช้โดยวิธีนี้จะไม่มีความซับซ้อน และไม่ต้องใช้ library อื่นจากภายนอกเลย แต่ผู้เขียนกล่าวได้เลยว่าการทำแบบนี้ กรณีดีที่สุด คือ การรอให้คนอื่นมาด่าเราว่า ทำไมทำอะไรหละหลวมแบบนี้เปลี่ยนแปลงซะ หรือกรณีร้ายที่สุดคือระบบถูกเล่นงาน ผู้โจมตีระบบได้ครอบครองรหัสผ่านผู้ใช้งานระบบโดยสมบูรณ์ ถือเป็นความวิบัติใหญ่หลวงอย่างมาก ดังนั้นผู้เขียนกราบวิงวอนผู้อ่านทุกท่านว่า อย่าหาทำ วิธีนี้เลย

ระดับดีขึ้นมานิด (แต่ยังไม่พอ)

ระดับที่ดีขึ้นมาอีกขึ้นหนึ่ง คือ การใช้ฟังก์ชันแฮชมาครอบตัวรหัสผ่านของผู้ใช้ตอนลงทะเบียน และตอนลงชื่อเข้าใช้งาน ตัวอย่างเช่น หากผู้ใช้งานกรอกรหัสผ่านตอนลงทะเบียนมาเป็น “good_to_guess” ก็จะถูกนำไปผ่านฟังก์ชันแฮชก่อนนำไปเก็บลงฐานข้อมูล ตัวอย่าง ในภาษา python

input_password = b"good_to_guess"
hashed_password = hashlib.sha256(input_password).digest().hex()
# '91d9c2367ddc6dab3a36a060c232ac9c14a742b4b2c78b6a64a5c786265135a0'

การทำเช่นนี้ถือว่าดีกว่าการเก็บแบบโต้ง ๆ อย่างแน่นอน แต่ตัวอย่างด้านบนก็ยังไม่ควรทำอยู่ดี เพราะหากผู้โจมตีระบบสามารถลงทะเบียนสมัครสมาชิกได้ และสามารถเข้าถึงฐานข้อมูลตารางผู้ใช้งานได้อีก ผู้โจมตี อาจ คาดเดารหัสผ่านของผู้ใช้คนอื่นได้ ตัวอย่างเช่น บังเอิญผู้โจมตีใส่รหัสผ่านเป็น “good_to_guess” เหมือนกับผู้ใช้ด้านบน จะส่งผลให้ hashed_password นั้น เหมือนกัน นั่นก็แปลว่าผู้โจมตีรู้รหัสผ่านของผู้ใช้คนนั้นโดยปริยาย

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

input_password = b"good_to_guess"
salt = "".join(random.choices(string.ascii_letters + string.digits, k = 8))
hashed_password = hashlib.sha256(input_password + salt).digest().hex()

อย่างไรก็ดีวิธีการนี้ก็ยังไม่ปลอดภัยจากการโจมตีแบบ Length Extension Attack อยู่ดี ดังนั้นเราก็ควรเลี่ยงวิธีนี้เช่นกัน

ระดับพอได้ (แต่ยังดีได้อีก)

วิธีการคือใช้ HMAC เป็น KDF เลย ซึ่งเรียกว่า HKDF (HMAC-based KDF) หรือ hmac_func(salt, password, hash_func) ตัวอย่างเช่น เราสามารถใช้ตัวอย่างรหัสต้น HMAC มาเป็นแปลงเป็นตัวอย่างได้ เช่น

import hashlib, hmac
import string
import random
def hmac_sha256(key, msg):
  return hmac.new(key, msg, hashlib.sha256).digest().hex()
hkdf = hmac_sha256
salt = "".join(random.choices(string.ascii_letters + string.digits, k = 8)).encode()
input_password = b"0z0x9cbv917"
hashed_password = hkdf(salt, input_password)

อย่างไรก็ดี วิธีนี้ก็ยังปลอดภัยน้อยกว่าแนวทางสุดท้ายนั่นก็คือ

ควรทำ ทำเถอะไม่ยากเลย

สิ่งที่ควรทำที่สุดก็คือ การใช้ library เพื่อใช้เป็น KDF ตัวอย่างเช่น Bcrypt, Scrypt หรือ Argon2 โดยหลักแล้ว สิ่งที่เราจะต้องเก็บเพิ่มนอกเหนือจาก hashed_password และ salt คือ setting ของอัลกอริทึมที่เราเลือกใช้ ซึ่งโดยส่วนใหญ่ library ใหม่ ๆ จะเก็บสามสิ่งมัดรวมไว้เป็นสายอักขระเดียว เพื่อให้เราสามารถเก็บไว้ในฐานข้อมูลได้ง่าย จากที่จะต้องเก็บข้อมูลในหลายคอลัมน์เป็นคอลัมน์เดียว ในที่นี้ขอตัวอย่าง ใน python ของ Argon2

# pip install argon2_cffi
import argon2
argon2Hasher = argon2.PasswordHasher(
    time_cost=16, memory_cost=2**15, parallelism=2, hash_len=32, salt_len=16)
hash = argon2Hasher.hash("password") # keep this thing into database
print("Argon2 hash (random salt):", hash)
verifyValid = argon2Hasher.verify(hash, "password")
print("Argon2 verify (correct password):", verifyValid)
try:
    argon2Hasher.verify(hash, "wrong123")
except:
    print("Argon2 verify (incorrect password):", False)

การเข้ารหัสลับ (Encryption)

การเข้ารหัสลับ (Encryption) นั้น ทำเพื่อรักษาความลับของสาร ดังนั้นจะมีเรื่องกุญแจ (Key) เข้ามาเกี่ยวข้อง เนื่องจากการเข้ารหัสลับจะใช้กุญแจทั้งในกระบวนการเข้ารหัสลับ และกระบวนการถอดรหัสลับ เราสามารถแบ่งประเภทการเข้ารหัสลับตามลักษณะของกุญแจที่ใช้ ออกเป็นสองลักษณะใหญ่ดังนี้

  1. การเข้ารหัสลับแบบกุญแจสมมาตร (Symmetric Key Encryption)
  2. การเข้ารหัสลับแบบกุญแจอสมมาตร (Asymmetric Key Encryption)

ในบทความนี้ จะกล่าวถึงเฉพาะกุญแจสมมาตรก่อน ส่วนกุญแจอสมมาตรจะอยู่ในบทความถัด ๆ ไป

การเข้ารหัสลับแบบกุญแจสมมาตร (Symmetric Key Encryption )

อวจ: encrypt(สาร, กุญแจ, อย่างอื่นถ้ามี) -> สารที่แปลงแล้ว ; decrypt(สารที่แปลงแล้ว, กุญแจ, อย่างอื่นถ้ามี) -> สาร

การเข้ารหัสลับ และการถอดรหัสลับโดยใช้กุญแจสมมาตรนั้น เราจะใช้กุญแจ ดอกเดียวกัน ทั้งการเข้ารหัสลับ และการถอดรหัสลับ ดังรูป

การเข้ารหัสลับแบบกุญแจสมมาตร
รูปที่ 3 การเข้ารหัสลับแบบกุญแจสมมาตร

โดยปกติแล้ว การเข้ารหัสลับแบบกุญแจสมมาตรจะไม่ได้ใช้อัลกอริทึมเข้ารหัสลับอย่างเดียว แต่จะมีการตัดสารออกเป็นก้อน (Block) ภายในกล่อง “กระบวนการเข้ารหัสลับแบบกุญแจสมมาตร” ด้านล่าง คือ P0 จนถึง Pn โดยแต่ละก้อนมีขนาดเท่า ๆ กัน แล้วจึงนำก้อนแต่ละก้อนไป ผสมผสานกับฟังก์ชันอื่น (มีรายละเอียดใน รูปที่ 5) กระบวนการของการเข้ารหัสแบบกุญแจสมมาตรโดยทั่วไปจะประกอบด้วย

  • KDF
  • กระบวนการเข้ารหัสลับแบบกุญแจสมมาตร
    • Block Cipher Mode
    • Block Cipher Algorithm
  • MAC

เรารู้จักกับ KDF และ MAC ไปแล้ว ส่วน Block Cipher Algorithm นั้น เป็นอัลกอริทึมการเข้ารหัสลับแบบกุญแจสมมาตรจริง ๆ เช่น AES และ ChaCha20 ซึ่งจะฝังอยู่ใน Block Cipher Mode ส่วน Block Cipher Mode คือ วิธีจัดการกับข้อมูลที่ตัดเป็นก้อนแล้ว ซึ่งมีหลายวิธี อาทิเช่น CBC, CTR และ GCM ใน Block Cipher Mode แต่ละตัวนั้นก็จะมีคุณสมบัติแตกต่างกันไป แต่ผู้เขียนจะไม่ลงลึกไปกว่านี้ เพราะจะทำให้บทความนี้ยาวเกินไป แต่จะขอยกบางคุณสมบัติคร่าว ๆ อาทิเช่น

  • CBC ต้องมีการทำ Padding ข้อมูลก้อนสุดท้ายด้วยอักขระพิเศษที่กำหนดเนื่องจาก CBC ใช้วิธีการตัดข้อมูลจริง ๆ ไม่ได้ใช้ XOR Operation เหมือนกับวิธีอื่น
  • GCM มีการทำ MAC ให้อยู่ภายในตัวแล้ว แบบ encrypt-then-MAC

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

กระบวนการเข้ารหัสจนถึงถอดรหัสลับแบบกุญแจสมมาตร
รูปที่ 4 กระบวนการเข้ารหัสจนถึงถอดรหัสลับแบบกุญแจสมมาตร

ซึ่งภายในกล่อง “กระบวนการเข้ารหัสลับแบบกุญแจสมมาตร” จะมีกลไกโดยภาพรวม ดังภาพด้านล่าง

แสดงกลไกภายในกล่อง  “กระบวนการเข้ารหัสลับแบบกุญแจสมมาตร” ใน รูปที่ 4
รูปที่ 5 แสดงกลไกภายในกล่อง “กระบวนการเข้ารหัสลับแบบกุญแจสมมาตร” ใน รูปที่ 4

ผลลัพธ์ที่ได้จากกล่อง “กระบวนการเข้ารหัสลับแบบกุญแจสมมาตร” คือ ก้อนสารที่เข้ารหัสแล้วคือ C0 จนถึง Cn ซึ่งถูกนำมารวมกันเป็นก้อนเดียวอีกครั้ง เป็นสารที่ถูกเข้ารหัสลับ (Ciphertext)

การเรียกชื่อของการเข้ารหัสลับแบบกุญแจสมมาตรจะใช้รูปแบบ [ชื่อ Block Cipher Algorithm ที่ใช้]-[ความยาวของกุญแจเป็น bit ที่กับ Block Cipher Algorithm]-[ชื่อ Block Cipher Mode] อาจจะจำย่อๆ เป็น [Block Cipher Algorithm]-[Key Length]-[Block Cipher Mode] ตัวอย่างเช่น ชื่อการเข้ารหัสลับ AES-256-GCM

ตัวอย่าง การใช้ library ใน python

# pip install scrypt pycryptodome
from Crypto.Cipher import AES
import scrypt, os
def encrypt_aes_gcm(message, password):
    """
    เข้ารหัสลับด้วย Block Cipher Algorithm AES และ GCM Block Cipher Mode
    """
   
    # ทำ KDF
    kdf_salt = os.urandom(16)
    secret_key = scrypt.hash(password, kdf_salt, N=16384, r=8, p=1, buflen=32)
    # ระบุ Block Cipher Mode
    aes_cipher = AES.new(secret_key, AES.MODE_GCM)
    # สร้าง Additional Authenticated Data - AAD
    aad = os.urandom(32)
    # จาก https://stackoverflow.com/questions/64381895/is-the-aes-gcm-in-python-crypto-cipher-library-can-take-care-the-aad-portion
    aes_cipher.update(aad)
    # ในที่นี้ Block Cipher Mode GCM ทำ MAC ให้ในตัวได้ผลลัพธ์เป็น auth_tag
    ciphertext, auth_tag = aes_cipher.encrypt_and_digest(message)
    # Initial Vector - IV มีชื่อเรียกอีกอย่างหนึ่งว่า nonce
    return (kdf_salt, ciphertext, aes_cipher.nonce, aad, auth_tag)
def decrypt_aes_gcm(encrypted_message, password):
    """
    ถอดรหัสลับด้วย Block Cipher Algorithm AES และ GCM Block Cipher Mode
    """
    # แกะ parameter ออกจาก encrypted_message
    (kdf_salt, ciphertext, nonce, aad, auth_tag) = encrypted_message
    # ทำ KDF
    secret_key = scrypt.hash(password, kdf_salt, N=16384, r=8, p=1, buflen=32)
    # ระบุ Block Cipher Mode
    aes_cipher = AES.new(secret_key, AES.MODE_GCM, nonce)
    aes_cipher.update(aad)
    # ถอดรหัส และทวนสอบความถูกต้องของ authTag หรือ MAC
    plaintext = aes_cipher.decrypt_and_verify(ciphertext, auth_tag)
    return plaintext
# กระบวนการทำงาน
# ผู้ส่งสารเตรียมสาร และรหัสผ่าน
message = b'Message for AES-256-GCM + Scrypt encryption'
password = b's3kr3tp4ssw0rd'
# ผู้ส่งสารเรียกฟังก์ชันการเข้ารหัสลับ และได้ผลลัพธ์
encrypted_msg = encrypt_aes_gcm(message, password)
encrypted_msg_json = {
    'kdfSalt': encrypted_msg[0].hex(),
    'ciphertext': encrypted_msg[1].hex(),
    'aesIV': encrypted_msg[2].hex(),
    'aad': encrypted_msg[3].hex(),
    'authTag': encrypted_msg[4].hex()
}
print("encryptedMsg", encrypted_msg_json)
# ผู้ส่งสารส่งสารที่เข้ารหัสให้กับผู้รับสารผ่าน Internet โดยทั่วไปคือ Restful API (HTTP)
# ผู้รับสารรับสารมาแปลงเป็น byte array
encrypted_msg = (
    bytes.fromhex(encrypted_msg_json['kdfSalt']),
    bytes.fromhex(encrypted_msg_json['ciphertext']),
    bytes.fromhex(encrypted_msg_json['aesIV']),
    bytes.fromhex(encrypted_msg_json['aad']),
    bytes.fromhex(encrypted_msg_json['authTag']),
)
# ผู้ส่งสารเรียกฟังก์ชันการเข้ารหัสลับ และได้สารจากผู้ส่งสาร
decryptedMsg = decrypt_aes_gcm(encrypted_msg, password)
print("decryptedMsg", decryptedMsg)

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

อีกสักนิดก่อนจากกัน ผู้เขียนขอแนะนำบทความด้านล่างนี้ สำหรับผู้ที่สนใจเกี่ยวกับความลับของข้อมูล และการเข้ารหัสเพิ่มเติม
การจัดทำข้อมูลนิรนาม (Data Anonymization)
Searchable Encryption กลไกการปกป้องข้อมูลบน Cloud ที่คุณไว้วางใจได้

เนื้อหาโดย ประณิธาน ธรรมเจริญพร
ตรวจทานและปรับปรุงโดย เมธิยาภาวิ์ ศรีมนตรินนท์

แบ่งปันบทความ

กลุ่มเนื้อหา

แท็กยอดนิยม

แจ้งเรื่องที่อยากอ่าน

คุณสามารถแจ้งเรื่องที่อยากอ่านให้เราทราบได้ !
และเราจะนำไปพัฒนาบทความให้มีเนื้อหาที่น่าสนใจมากขึ้น

ไอคอน PDPA

เราใช้คุกกี้เพื่อพัฒนาประสิทธิภาพ และประสบการณ์ที่ดีในการใช้เว็บไซต์ของคุณ คุณสามารถศึกษารายละเอียดได้ที่ “นโยบายคุ้กกี้” และสามารถจัดการความเป็นส่วนตัวเองได้ของคุณได้เองโดยคลิกที่ “ตั้งค่า”

ตั้งค่าความเป็นส่วนตัว

คุณสามารถเลือกการตั้งค่าคุกกี้โดยเปิด/ปิด คุกกี้ในแต่ละประเภทได้ตามความต้องการ ยกเว้น คุกกี้ที่จำเป็น

ยอมรับทั้งหมด
จัดการความเป็นส่วนตัว
  • คุกกี้ที่มีความจำเป็น (Strictly Necessary Cookies)
    เปิดใช้งานตลอด

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

  • คุกกี้เพื่อการวิเคราะห์และประเมินผลการใช้งาน (Performance Cookies)

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

  • คุกกี้เพื่อการใช้งานเว็บไซต์ (Functional Cookies)

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

  • คุกกี้เพื่อการโฆษณาไปยังกลุ่มเป้าหมาย (Targeting Cookies)

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

บันทึกการตั้งค่า