זרימת AESD של AES-CTR HMAC

המסמך הזה מגדיר באופן רשמי את הפונקציה המתמטית שמיוצגת על ידי מפתחות סטרימינג מסוג AES-CTR HMAC Streaming (מקודדים בפורמט 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 עם הדרכה מפורטת מלאה להשגת מידע מוצפן (ciphertext).

מפתחות ופרמטרים

המפתחות מתוארים בחלקים הבאים (כל הגדלים במסמך הזה הם בבייטים):

  • \(\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 עם פונקציית גיבוב (hash) \(\mathrm{HkdfHashType}\)כדי לחשב חומר חשוב באורך של המילים\(\mathrm{DerivedKeySize} + 32\) בהודעה הזו:\(k := \mathrm{HKDF}(\mathrm{InitialKeyMaterial}, \mathrm{Salt}, \mathrm{AssociatedData})\). ערכי הקלט המתאימים משמשים לקלט המתאים של: \(\mathrm{HKDF}\): \(\mathrm{InitialKeyMaterial}\) שווה \(\mathrm{ikm}\), \(\mathrm{Salt}\) הוא ה-salt ו-\(\mathrm{AssociatedData}\) משמש כ \(\mathrm{info}\).

לאחר מכן המחרוזת \(k\) מפוצלת לשני חלקים \(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 בייטים באמצעות קידוד Bigendian. אנחנו מגדירים את הבייט $b$ לערך 0x00 אם $i < n-1$ ואם לא מגדירים 0x01.

לאחר מכן, אנחנו מצפינים \(M_i\) באמצעות מפתח שיעור קליקים של AES \(k_1\)וקטור האתחול\(\mathrm{IV}_i\). במילים אחרות, הקלט להפעלות של AES הוא\(\mathrm{IV}_i, \mathrm{IV}_i + 1, \mathrm{IV}_i + 2, \ldots\) וכאשר \(\mathrm{IV}_i\) מפוענח כמספר שלם ב-Big-endian. התוצאה היא \(C'_i\).

אנחנו מחשבים את התג באמצעות HMAC באמצעות פונקציית הגיבוב שמוגדרת על ידי \(\mathrm{HmacHashType}\) ועם מפתח \(k_2\) מעל השרשור \(\mathrm{IV}_i \| C'_i\).

לאחר מכן אנחנו משרשרים את המידע מוצפן (ciphertext) ואחריו את התג כדי לקבל את \(C_i\).

משרשרים את הפלחים

בסוף כל הקטעים משורשרים כ-\(\mathrm{Header} \| C_0 \| \cdots \| C_{n-1}\), שהוא המידע המוצפן האחרון.

פונקציית פענוח

הפענוח פשוט הופך את ההצפנה. אנחנו משתמשים בכותרת כדי לקבל את הצופן החד-פעמי (nonce) ולפענח כל קטע של מידע מוצפן בנפרד.

ממשקי API עשויים (ובדרך כלל מאפשרים) לאפשר גישה אקראית או גישה להתחלת קובץ בלי לבדוק את סוף הקובץ. הפעולה הזו בוצעה בכוונה, כי ניתן לפענח את \(M_i\) החל מ- \(C_i\)בלי לפענח את כל הבלוקים הקודמים של המידע מוצפן (ciphertext) ושאר הבלוקים שלה.

עם זאת, חשוב להקפיד שממשקי API לא יאפשרו למשתמשים להתבלבל בין שגיאות של סוף קובץ ושגיאות פענוח: בשני המקרים, סביר להניח שה-API יצטרך להחזיר שגיאה, והתעלמות מההבדל עלולה לגרום ליריב לקצץ קבצים.

עריכה טורית וניתוח של מפתחות

כדי ליצור רצף של מפתח בפורמט "Tink Proto", תחילה אנחנו ממפים את הפרמטרים באופן הברור לפרוטו שמופיע ב-aes_ctr_hmac_streaming.proto. השדה version צריך להיות מוגדר ל-0. לאחר מכן, אנחנו עורכים את הקוד בסדרה רגילה של פרוטו, ומטמיעים את המחרוזת שמתקבלת בערך השדה של פרוטו 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] הואנג, רייאניטבר, רוגאווי, Vizar. הצפנה מאומתת אונליין ועמידות לשימוש לרעה לשימוש חד-פעמי. CRYPTO 2015. https://eprint.iacr.org/2015/189 

  2. [HS20] אבטחה של הצפנת סטרימינג ב-Tink של Google. Hoang, Shen, 2020. https://eprint.iacr.org/2020/1019 

  3. [HKDF] פונקציית חילוץ והרחבה של מפתח שמבוססת על HMAC (HKDF), RFC 5869. https://www.rfc-editor.org/rfc/rfc5869