สตรีมมิง AEAD สำหรับ HMAC ของ AES-CTR

เอกสารนี้กำหนดฟังก์ชันทางคณิตศาสตร์ที่แสดงด้วยคีย์สตรีมมิง HMAC ของ AES-CTR (เข้ารหัสในรูปแบบ Proto เป็น type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey)

การเข้ารหัสนี้อิงตาม [HRRV15]1 แบบหลวมๆ เราอ้างอิง [HS20]2 เพื่อวิเคราะห์ความปลอดภัย โปรดทราบว่าการทดสอบข้ามภาษา Tink มีการทดสอบ aes_ctr_hmac_streaming_key_test.py ซึ่งมี test_manually_created_test_vector พร้อมคำแนะนำแบบทีละขั้นฉบับสมบูรณ์เกี่ยวกับวิธีรับข้อความเข้ารหัส

คีย์และพารามิเตอร์

คีย์จะอธิบายตามส่วนต่างๆ ต่อไปนี้ (ขนาดทั้งหมดในเอกสารนี้มีรูปแบบเป็นไบต์)

  • \(\mathrm{InitialKeyMaterial}\)สตริงไบต์: เนื้อหาคีย์เริ่มต้น
  • \(\mathrm{CiphertextSegmentSize} \in \{1, 2, \ldots, 2^{31}-1\}\).
  • \(\mathrm{DerivedKeySize} \in \{16, 32\}\).
  • \(\mathrm{HkdfHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).
  • \(\mathrm{HmacHashType} \in \{\mathrm{SHA1}, \mathrm{SHA256}, \mathrm{SHA512}\}\).
  • \(\mathrm{HmacTagSize} \in \mathbb{N}\).

คีย์ที่ถูกต้องยังตรงตามพร็อพเพอร์ตี้ต่อไปนี้ด้วย

  • \(\mathrm{len}(\mathrm{InitialKeyMaterial}) \geq \mathrm{DerivedKeySize}\).
  • หาก \(\mathrm{HmacHashType} = \mathrm{SHA1}\) แล้ว \(\mathrm{HmacTagSize} \in \{10, \ldots, 20\}\)
  • หาก \(\mathrm{HmacHashType} = \mathrm{SHA256}\) แล้ว \(\mathrm{HmacTagSize} \in \{10, \ldots, 32\}\)
  • หาก \(\mathrm{HmacHashType} = \mathrm{SHA512}\) แล้ว \(\mathrm{HmacTagSize} \in \{10, \ldots, 64\}\)
  • \(\mathrm{CiphertextSegmentSize} > \mathrm{DerivedKeySize} + \mathrm{HmacTagSize} + 8\) (เท่ากับ\(\mathrm{len}(\mathrm{Header}) + \mathrm{HmacTagSize}\) ตามที่อธิบายไว้ภายหลัง)

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

ฟังก์ชันการเข้ารหัส

ในการเข้ารหัสข้อความ \(\mathrm{Msg}\) ด้วยข้อมูลที่เกี่ยวข้อง\(\mathrm{AssociatedData}\)เราจะสร้างส่วนหัว แบ่งข้อความออกเป็นกลุ่มต่างๆ เข้ารหัสแต่ละกลุ่ม และเชื่อมกลุ่มเข้าด้วยกัน เราอธิบายขั้นตอนเหล่านี้ดังต่อไปนี้

การสร้างส่วนหัว

ในการสร้างส่วนหัว ก่อนอื่นเราจะเลือกสตริงที่มีความยาวเหมือนกัน \(\mathrm{Salt}\)\(\mathrm{DerivedKeySize}\)ต่อไปเราจะเลือกสตริงแบบสุ่มแบบเดียวกัน \(\mathrm{NoncePrefix}\) ที่มีความยาว 7.

จากนั้นตั้งค่า\(\mathrm{Header} := \mathrm{len}(\mathrm{Header}) \| \mathrm{Salt} \| \mathrm{NoncePrefix}\)ซึ่งความยาวของส่วนหัวมีการเข้ารหัสเป็นไบต์เดี่ยว เราทราบมาว่า \(\mathrm{len}(\mathrm{Header}) \in \{24, 40\}\)

ต่อไป เราใช้ HKDF3 กับฟังก์ชันแฮช \(\mathrm{HkdfHashType}\) เพื่อคำนวณเนื้อหาสำคัญของความยาว \(\mathrm{DerivedKeySize} + 32\) สำหรับข้อความนี้ \(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\) โดยอินพุตจะยึดตามอินพุตที่สอดคล้องกันของ \(\mathrm{HKDF}\): \(\mathrm{InitialKeyMaterial}\) คือ \(\mathrm{ikm}\), \(\mathrm{Salt}\) คือเกลือ และ \(\mathrm{AssociatedData}\) ใช้เป็น \(\mathrm{info}\)

จากนั้นสตริง \(k\) จะแบ่งออกเป็น 2 ส่วน \(k_1 \| k_2 := k\) เช่น\(\mathrm{len}(k_1) = \mathrm{DerivedKeySize}\) และ \(\mathrm{len}(k_2) = 32\)

แยกข้อความ

ข้อความ \(M\) จะแบ่งออกเป็นส่วนต่างๆ ดังนี้ \(M = M_0 \| M_1 \| \cdots \| M_{n-1}\)

ความยาวของวิดีโอที่เลือกนั้นตรงกับความต้องการของผู้ชมดังต่อไปนี้

  • \(\mathrm{len}(M_0) \in \{0,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{len}(\mathrm{Header}) - \mathrm{HmacTagSize}\}\).
  • หากเป็น \(n > 1\)ให้ \(\mathrm{len}(M_1), \ldots, \mathrm{len}(M_{n-1}) \in \{1,\ldots, \mathrm{CiphertextSegmentSize} - \mathrm{HmacTagSize}\}\)
  • หาก \(n > 1\)\(M_{0}, \ldots, M_{n-2}\) ต้องมีความยาวสูงสุดตามข้อจำกัดข้างต้น

ในการแยกนี้ \(n\) ไม่เกิน \(2^{32}\)ไม่เช่นนั้นจะเข้ารหัสไม่สำเร็จ

การเข้ารหัสบล็อก

ในการเข้ารหัสเซกเมนต์ \(M_i\)ก่อนอื่นเราจะประมวลผล \(\mathrm{IV}_i := \mathrm{NoncePrefix} \| \mathrm{i} \| b \| 0x00000000\) ซึ่งเราเข้ารหัส \(\mathrm{i}\) ขนาด 4 ไบต์โดยใช้การเข้ารหัสแบบ Big-endian และตั้งค่าไบต์ $b$ เป็น 0x00 หาก $i < n-1$ และ 0x01 เป็นอย่างอื่น

จากนั้นเราเข้ารหัส \(M_i\) โดยใช้คีย์ AES CTR \(k_1\)และเวกเตอร์การเริ่มต้น \(\mathrm{IV}_i\)กล่าวคือ อินพุตไปยังคำขอของ AES คือ \(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\) โดย \(\mathrm{IV}_i\) ระบบจะตีความว่าเป็นจำนวนเต็มขนาดใหญ่ ซึ่งทำให้เกิด \(C'_i\)

เราคํานวณแท็กโดยใช้ HMAC กับฟังก์ชันแฮชที่ระบุโดย \(\mathrm{HmacHashType}\) และคีย์ \(k_2\) เหนือการต่อกัน \(\mathrm{IV}_i \| C'_i\)

จากนั้นเราเชื่อมต่อข้อความเข้ารหัสตามด้วยแท็กเพื่อรับ \(C_i\)

เชื่อมเซกเมนต์

สุดท้าย ทุกกลุ่มจะต่อกันเป็น\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\)ซึ่งเป็นข้อความเข้ารหัสสุดท้าย

ฟังก์ชันการถอดรหัส

โดยการถอดรหัสจะกลับการเข้ารหัสเท่านั้น เราใช้ส่วนหัวเพื่อรับค่า Nonce และถอดรหัสข้อความเข้ารหัสแต่ละส่วนแยกกัน

API อาจ (และมักจะทำเช่นนั้น) อนุญาตการเข้าถึงแบบสุ่ม หรือเข้าถึงจุดเริ่มต้นของไฟล์โดยไม่ต้องตรวจสอบจุดสิ้นสุดไฟล์ การดำเนินการเช่นนี้เป็นไปโดยตั้งใจ เนื่องจากคุณถอดรหัส \(M_i\) จาก \(C_i\)ได้โดยไม่ต้องถอดรหัสบล็อกข้อความเข้ารหัสก่อนหน้าและที่เหลือทั้งหมด

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

การทำให้เป็นอนุกรมและการแยกวิเคราะห์ของคีย์

ในการเรียงอันดับคีย์ในรูปแบบ "Tink Proto" ขั้นแรก เราจะจับคู่พารามิเตอร์ด้วยวิธีที่ชัดเจนลงใน Proto ที่ให้ไว้ที่ aes_ctr_hmac_streaming.proto ต้องกำหนดค่าฟิลด์ version เป็น 0 จากนั้นเราจะทำให้เป็นอนุกรมโดยใช้การทำให้เป็นอนุกรมของ Pro ปกติ และฝังสตริงที่ได้ลงในค่าของช่องของ Proto KeyData เราตั้งค่าช่อง type_url เป็น type.googleapis.com/google.crypto.tink.AesCtrHmacStreamingKey จากนั้นเราจึงตั้งค่า key_material_type เป็น SYMMETRIC และฝังรายการนี้ลงในชุดคีย์ เรามักจะตั้งค่า output_prefix_type เป็น RAW แต่มีข้อยกเว้นคือ หากมีการแยกวิเคราะห์คีย์ด้วยค่าที่ต่างกันสำหรับ output_prefix_type Tink อาจเขียน RAW หรือค่าก่อนหน้า

ในการแยกวิเคราะห์คีย์ เราจะกลับขั้นตอนด้านบน (ตามปกติเมื่อแยกวิเคราะห์โปรโตคอล) ระบบจะไม่สนใจช่อง key_material_type โดยจะไม่สนใจค่าของ output_prefix_type หรือจะปฏิเสธคีย์ที่มี output_prefix_type ต่างจาก RAW ก็ได้ คีย์ที่มี version ต่างจาก 0 จะถูกปฏิเสธ

รายการอ้างอิง


  1. [HRRV15] Hoang, Reyhanitabar, Rogaway, Vizar การเข้ารหัสที่ตรวจสอบสิทธิ์แล้วทางออนไลน์และการต่อต้านการใช้ในทางที่ผิดแบบไม่ต้องใช้ซ้ำ คริปโตเคอเรนซี 2015 https://eprint.iacr.org/2015/189 

  2. [HS20] การรักษาความปลอดภัยของการเข้ารหัสสตรีมมิงใน Tink Library ของ Google Hoang, Shen, 2020 https://eprint.iacr.org/2020/1019 

  3. [HKDF] ฟังก์ชันการแตกและขยายคีย์ (HKDF), ที่ใช้ HMAC, RFC 5869 https://www.rfc-editor.org/rfc/rfc5869