เมื่อวานนี้ธนาคารแห่งประเทศไทยเปิดตัว PromptPay QR แต่การใช้งานก็ยังจำกัดบางพื้นที่โดยต้องใช้แอปพลิเคชั่นของธนาคารในการสร้างตัว QR อย่างไรก็ดี PromptPay QR นี้เป็นมาตรฐานเปิดของ EMVco ที่เปิดให้อ่านฟรีโดยไม่ต้องเป็นหน่วยงานที่เกี่ยวข้องแต่อย่างใด เอกสารฉบับนี้คือ "EMVCo QR Code Specification for Payment Systems: Merchant-Presented Mode" หรือสเปคสำหรับการสร้าง QR จากฝั่งผู้ขายเพื่อขอรับเงินจากผู้รับ ตอนนี้เราจะมาดูกันว่าข้อมูลใน QR นี้มีข้อมูลอะไรบ้าง อย่างไรก็ดีบทความนี้ข้ามข้อมูลที่ยังไม่สามารถหาได้ จากการดู QR ที่เปิดเผยออกมา หากเราสแกน QR ที่ใช้จ่ายเงินตอนนี้ด้วยแอปพลิเคชั่นสแกน QR โดยเฉพาะ ไม่ใช่แอปของธนาคาร จะเห็นตัวเลขและข้อความยาวๆ เป็นชุดเดียว เช่นตัวอย่าง "00020101021129370016A000000677010111011300660000000005802TH530376463048956" (ตัวอย่างนี้ใช้ข้อมูลหลอก ด้วยหมายเลขโทรศัพท์ 000-000-0000) แนวทางการอ่านข้อมูลของมาตรฐาน EMVco คือ หมายเลขประจำฟิลด์ข้อมูล (เป็น 00-99), ความยาวของข้อมูลในฟิลด์นั้น (เป็น 01-99), และตัวข้อมูลจริงๆ การอ่านข้อมูลตัวอย่างจะทำเป็นขั้นได้ดังนี้ หมายเลขเวอร์ชั่น ฟิลด์ 00 ความยาว 02 ข้อมูลตอนนี้คือ 01 เสมอ ดังนั้นข้อมูลชุดแรกคือ "000201" ประเภทของ QR ฟิลด์ 01 ความยาว 02 ข้อมูล "11" แปลว่า QR นี้มีเพื่อให้ผู้ซื้อสแกนจ่ายเงิน ถ้าเป็นผู้ขายสแกนผู้ซื้อจะมีค่าเป็น 12 ส่วนค่าอื่นๆ ห้ามใช้งาน ข้อมูลผู้ขาย (merchant account information) ฟิลด์ 29 ความยาว 37 ข้อมูล "0016A00000067701011101130066000000000" โดยข้อมูลนี้แบ่งออกเป็นสองฟิลด์ย่อย หมายเลขแอปพลิเคชั่น (application ID - AID) เป็นหมายเลขที่ปกติแล้วใช้อ้างอิงประเภทบัตรสมาร์ตการ์ดแบบต่างๆ ตั้งแต่บัตรประชาชนไปจนถึงบัตรเครดิตทั้งหลาย ในกรณีนี้มีการนำหมายเลขนี้มาใช้ใน QR เพื่อระบุว่า QR นี้เป็น PromptPay หมายเลขฟิลด์ย่อย 00 ความยาว 16 ข้อมูล "A000000677010111" หมายเลขบัญชี เป็นหมายเลข PromptPay โดยตรง ตอนนี้มีหมายเลขฟิลด์ เช่น 01 หมายเลขโทรศัพท์ ความยาว 13 นำหน้าด้วย 00 แล้วตามด้วยรหัสประเทศ 66 แล้วจึงเป็นหมายเลขโทรศัพท์ตัดศูนย์นำหน้าออก 00-000-0000 02 หมายเลขบัตรประชาชน ความยาว 15 นำหน้าด้วย 00 เช่นกัน และไม่มีขีดคั่น ประเทศ ฟิลด์ 58 ความยาว 02 ข้อมูล "TH" หมายถึงประเทศไทย สกุลเงินที่ใช้งาน ฟิลด์ 53 ความยาว 03 ข้อมูล "764" โดยหมายเลข 764 เป็นหมายเลขประจำค่าเงินบาทตาม ISO 4217 ค่า check sum ฟิลด์ 63 ความยาว 04 ข้อมูล "8956" ข้อมูลนี้ต้องอยู่ท้ายสุดเสมอ โดยค่า check sum เป็นการคำนวณจากข้อมูลทั้งหมด รวมถึงหมายเลขฟิลด์ของ check sum และความยาวของฟิลด์ check sum เอง กระบวนการหาค่า check sum ใช้ CRC-16 และ ค่าคงที่ polynomial 0x1021 (XMODEM) พร้อมกับค่าเริ่มต้น 0xFFFF (อันนี้ต้องระวังเพราะไลบรารีส่วนมากมักใส่ค่าเริ่มต้นเป็น 0x0000) ตัวไลบรารีสามารถใช้ pycrc16 ได้โดยตรง ตัวอย่างการหาค่า check sum ด้วย crc16pure.py เช่น In [7]: hex(crc16pure.crc16xmodem("00020101021129370016A000000677010111011300660000000005802TH53037646304",0xffff)) Out[7]: '0x8956' สังเกตว่าหมายเลขฟิลด์กระโดดจาก 01 ซึ่งเป็นฟิลด์บังคับ ไปยัง 29 ทันที เพราะหมายเลข 02-25 นั้นสงวนไว้สำหรับผู้ให้บริการบัตรเครดิตโดยเฉพาะ เช่น 02-03 สำหรับ VISA, 04-05 สำหรับ Mastercard, 06-08, 11-12 สำหรับ Amex, 13-14 สำหรับ JCB, และ 15-16 สำหรับ UnionPay ที่เหลือทาง EMVco ก็ให้เว้นไว้สำหรับการใช้งานในอนาคต เราได้ข้อมูลหลายอย่างจากการดูว่ามีข้อมูลอยู่ใน QR เช่น ตัว QR ยังคงแสดงข้อมูลหมายเลข PromptPay เช่นเดิม ซึ่งอาจจะหมายถึงหมายเลขโทรศัพท์หรือหมายเลขบัตรประชาชน หากใครมีความไม่สะดวกใจที่จะให้หมายเลขทั้งสองกับผู้ซื้อก็อาจจะต้องระวัง QR เหล่านี้ไม่มีกระบวนการยืนยันว่าสร้างโดยใคร ที่จริงแล้วตอนนี้ทาง Digio ก็เปิดเว็บสร้าง QR PromptPay แล้ว เท่าที่ทดสอบสามารถใช้ได้กับ PromptPay ทุกธนาคาร ความเสี่ยงมีอยู่บ้างคือธนาคารเองก็ไม่สามารถตรวจสอบได้ว่ามีการสร้าง QR ไปแปะทับเพื่อขโมยเงินกันหรือไม่ ดังนั้นการจ่ายเงินควรตรวจสอบชื่อบัญชีของผู้รับเสมอว่าตรงกับคนที่เราต้องการจ่ายไป มีความเป็นไปได้ที่จะสร้าง QR เหล่านี้โดยอัตโนมัติ ในเร็วๆ นี้เราคงได้เห็นไลบรารีโอเพนซอร์ส หรือบริการต่างๆ เพื่อสร้าง QR ทั้งระบุและไม่ระบุจำนวนเงิน ความเป็นไปได้อื่นๆ ของบริการนี้คงมีอีกมาก เช่นร้านค้าออนไลน์อาจจะเริ่มรับเงินผ่าน PromptPay กันมากขึ้นเพราะสามารถส่ง QR ระบุจำนวนเงินไปในแชตหรือเว็บอีคอมเมิร์ชได้โดยตรง ข้อมูลเปิดเผย: Digio เป็นผู้ลงประกาศหางานบน Blognone แบบเด่นพิเศษ แต่บทความนี้เขียนโดยไม่ได้มีการติดต่อกันมาก่อน (ผมพบโพสประกาศหลังเริ่มเขียนบทความไปแล้ว) อย่างไรก็ดี QR ตัวอย่างสร้างโดยเว็บของ Digio เพื่อปิดบัง QR จริงที่ผมใช้แกะข้อมูล Topics: PromptPayMobile Payment