ในยุคที่การรักษาความเป็นส่วนตัวของข้อมูลเป็นเรื่องสำคัญ ระบบก็เลยต้องพัฒนาให้รองรับด้วยการเข้ารหัสระดับคอลัมน์ข้อมูลด้วย เช่นการเข้ารหัสชื่อนามสกุล ที่อยู่ เบอร์โทรศัพท์ เพื่อป้องกันไม่ให้ระบบอื่นๆ เช่น ระบบ log ผู้ดูแลระบบ ผู้ให้บริการคลาวด์ เป็นต้น เอาข้อมูลส่วนตัวไปใช้โดยไม่ได้รับอนุญาต ในส่วนข้อมูลอื่นก็เอาไปประมวลผลในระบบอื่นๆ ได้ ปัญหาก็คือถ้าต้องการประมวลผลข้อมูลที่เข้ารหัสไว้กับข้อมูลขนาดมหึมาหรือที่เรียกกันว่า Big Data นั้นจะทำงานได้ลำบากมากๆ เพราะจะต้องเอาข้อมูลที่มีนั้นย้ายลงมาถอดรหัสด้วยโปรแกรมที่ถอดรหัสมันได้ ซึ่งข้อมูลในระหว่างที่ย้ายข้อมูลและถอดรหัสนี้ข้อมูลที่เป็นความลับก็อาจจะหลุดได้ อีกทั้งการย้ายข้อมูลมาประมวลผลด้วยโปรแกรมธรรมดาจะทำได้ช้ากว่าเพราะไม่ได้มีโครงสร้างพื้นฐานและสถาปัตยกรรมรองรับข้อมูลขนาดใหญ่ การถอดรหัสแล้วนำกลับขึ้นไปโปรเซสที่ Big Query อีกที ก็เสียทั้งเวลาเคลื่อนย้ายข้อมูลและพื้นที่จัดเก็บ ทางเลือกที่เหมาะสมก็คือการถอดรหัสและประมวลผลบน BigQuery ที่รองรับข้อมูลขนาดใหญ่เลยนี่แหละ
แต่จะ Query ถอดรหัส AES ยังไงนั้นมันก็ไม่ใช่เรื่องที่ง่ายเท่าไหร่นัก โดยปกติ MySQL จะมีฟังก์ชั่น AES_DECRYPT ให้ใช้กันอยู่แล้ว และใน Big Query ก็มีฟังก์ชั่นคล้ายๆ กันเรียกว่า AEAD.DECRYPT_STRING แต่ด้วยความที่มันเรียกใช้งานไม่เหมือนกันและไม่เหมือนใครด้วย ตัวอย่างแทบไม่มี ทำให้หลายๆ คนไม่ประสบความสำเร็จในการถอดรหัสด้วย AEAD.DECRYPT_STRING ผมเองและทีมได้ลองผิดลองถูกจนใช้งานมันได้ในที่สุด
ใช้ข้อมูลตัวอย่างดังต่อไปนี้
Plain Message = HELLO_WORLD
KEY= KEYFp0a1qYNQ43KEKo65dpEF9dBr0KEY
IV= IVS934fvEpf9d8IV
AES CBC
โหมดที่ได้รับความนิยมมากๆ ในการเข้ารหัส AES ก็คือ AES CBC
ตัวอย่าง Query ที่ใช้ถอดรหัส
Ciphertext Base64 = EwIEGb4Th6x+nTOuMDcIyw==
SELECT
AEAD.DECRYPT_STRING(KEYS.ADD_KEY_FROM_RAW_BYTES(b'', 'AES_CBC_PKCS', b'KEYFp0a1qYNQ43KEKo65dpEF9dBr0KEY'), CONCAT(b'IVS934fvEpf9d8IV', FROM_BASE64('EwIEGb4Th6x+nTOuMDcIyw==')), '')
จะสังเกตได้ว่า IV จะเป็น 16 Bytes แรก ต่อด้วยข้อมูลที่จะนำมาถอดรหัส มีการใช้ฟังชั่น AEAD.ADD_KEY_FROM_RAW_BYTES เพื่อกำหนด KEY ที่จะใช้ถอดรหัสพร้อมประเภทอัลกอริทึม AES_CBC_PKCS
AES GCM
เนื่องจากว่า AES CBC มีข่าวว่าไม่ค่อยปลอดภัยเท่าไหร่ จึงมีมาตรฐานใหม่เกิดขึ้นมาคือ AES GCM และ BigQuery ก็รองรับด้วย แต่การเข้ารหัสและถอดรหัสตามโค้ดภาษา GO ตามนี้ https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes/ ก็จะมีการใช้งาน BigQuery ตามตัวอย่างต่อไปนี้
ไม่มี IV จะใช้เป็น 0 ความยาว 12 Bytes ตามขนาด nonce ในโค้ด Go
IV HEX = 000000000000000000000000
Ciphertext Base64 (GCM) = F58M3PGVhHoueWyQyMtlLwOJfJ54wpdDzBPe
ตัวอย่าง Query
SELECT
AEAD.DECRYPT_STRING(KEYS.ADD_KEY_FROM_RAW_BYTES(b'', 'AES_GCM', b'KEYFp0a1qYNQ43KEKo65dpEF9dBr0KEY'),
CONCAT(FROM_HEX('000000000000000000000000'), FROM_BASE64('F58M3PGVhHoueWyQyMtlLwOJfJ54wpdDzBPe')), '')
Custom Crypto Function
แล้วมันก็มีคำถามว่าแล้วถ้าใช้อัลกอริทึมแปลกๆ Padding ประหลาดๆ ในการเข้ารหัส AES ล่ะ BigQuery มันซัพพอร์ตแค่ไม่กี่แบบเท่านั้นนิ จะทำอย่างไร วิธีการก็คือการสร้างฟังก์ชั่นเองด้วยภาษา JavaScript (Standard SQL user-defined functions) แต่จะให้เขียน AES หมดเองก็คงไม่ไหว เรียกใช้ไลบรารีที่เขาทำเอาไว้แล้วจะดีกว่า โดยชี้ไปยัง storage ที่เก็บไฟล์ไลบรารี crypto-js
ตัวอย่าง Query ที่ใช้ถอดรหัส
Ciphertext Base64 (ECB) = Yfros43L31hQF4bq1pWaqw==
CREATE TEMPORARY FUNCTION decrypt(_text STRING) RETURNS STRING LANGUAGE js AS
"""
let key = CryptoJS.enc.Utf8.parse("KEYFp0a1qYNQ43KEKo65dpEF9dBr0KEY");
let options = { mode: CryptoJS.mode.ECB };
let _decrypt = CryptoJS.AES.decrypt(_text, key, options).toString(CryptoJS.enc.Utf8);
return _decrypt;
""" OPTIONS (library="gs://crypto-lib/crypto-js.min.js");SELECT decrypt('Yfros43L31hQF4bq1pWaqw==');
เพียงเท่านี้ก็จะใช้งาน AES โหมดอื่นๆ ได้ ทำงานได้ยืดหยุ่นมากขึ้น จะเปลี่ยนไปใช้ RSA โดยเปลี่ยนไลบรารีใหม่ไปเลยก็ยังได้ อีกทั้งได้ใช้งานกับภาษา JavaScrpt และไลบรารีที่นักพัฒนาคุ้นเคยลดความยากในการเรียนรู้ BigQuery SQL ไปได้
จากตัวอย่างถ้าจะ Query จากตารางจริงๆ ก็เปลี่ยนจากข้อความ Base64 เป็นชื่อคอลัมน์ได้เลย เท่านี้ก็จะเอาไปเทียบกับข้อมูลที่เป็น Plain Text ได้แล้ว
การใช้ถอดรหัส AES บน Big Query นั้นง่ายกว่าที่คิด แต่กว่าจะเข้าใจการเรียกใช้มันก็ลองผิดลองถูกเยอะพอสมควร แต่ประโยชน์ของมันนั้นช่วยให้ทำงานกับข้อมูลได้ง่ายขึ้น ตัวอย่างในการใช้ Big Query ถอดรหัสแล้วประมวลผลเลยที่เห็นได้ชัดๆ เลยก็ได้แก่ ถ้าเกิดว่าไทยชนะเก็บเบอร์โทรศัพท์ผู้ใช้และเข้ารหัสเอาไว้ ถ้าเจอผู้ติดเชื้อใช้งานเบอร์อะไร ก็เอาเบอร์นั้นไป WHERE หาเทียบกับเบอร์ที่เข้ารหัสเอาไว้ได้เลย และยัง Query ถอดรหัสเอาเฉพาะเบอร์ที่ไปสถานที่เสี่ยงมาส่ง SMS แจ้งเตือนผู้ใช้เลยก็ยังได้ การทำงานได้รวดเร็วกับข้อมูลมหาศาลบน Big Query ทำให้ตอบสนองความต้องการของข้อมูลได้อย่างทันท่วงที อีกทั้งลดความเสี่ยงที่จะเอาข้อมูลจะหลุดไปเพราะไปถอดรหัสข้อมูลทั้งหมดให้นักวิเคราะห์ข้อมูลได้เห็นด้วย อีกตัวอย่างคือ ถ้ามีสอง dataset มีการเข้ารหัสข้อมูลเบอร์โทรศัพท์ทั้งคู่ แต่เข้ารหัสด้วยคนละคีย์หรือคนละอัลกอริทึม ถ้าต้องเอาข้อมูลจากสองแหลงมาเทียบกันมันก็หลีกเลี่ยงไม่ได้ที่จะต้องถอดรหัสทั้งคู่เพื่อให้ได้เบอร์จริงๆ มาเทียบเคียงกันถึงจะ join ตารางกันได้ เป็นต้น
ที่มา
https://cloud.google.com/bigquery/docs/reference/standard-sql/aead_encryption_functions
https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions
https://stackoverflow.com/questions/53274323/field-level-encryption-in-big-query
https://stackoverflow.com/questions/57723775/how-can-i-decrypt-columns-in-bigquery
https://www.melvinvivas.com/how-to-encrypt-and-decrypt-data-using-aes/
https://www.devglan.com/online-tools/aes-encryption-decryption
http://myujth.blogspot.com/2019/01/field-level-encryption-in-big-query.html