פורמט חוט Tink

בדף הזה מתואר פורמט הנתונים של Tink למפתחות ולפלט של פרימיטיבים. המסמכים מיועדים למומחים בהצפנה שרוצים להוסיף שפות נוספות ל-Tink, ולמנהלים של ספריות הצפנה אחרות ברמה גבוהה שרוצים מצב תואם ל-wire. התוכן לא מיועד לקהל הרחב.

סריאליזציה של קבוצת מפתחות

‫Tink משתמשת ב-Google protobuf כדי לבצע סריאליזציה של קבוצות המפתחות שלה.

  • קבוצת מפתחות בינארית שעברה סריאליזציה היא פרוטוקול Keyset שעבר סריאליזציה ומוגדר ב-tink.proto. מאפיין הערך KeyData של מפתח הוא פרוטו מסוג serialized של סוג המפתח המתאים.
  • קבוצת מפתחות שעברה סריאליזציה ב-JSON היא פרוטוקול Keyset שעבר סריאליזציה בפורמט JSON. שימו לב שהערך KeyData הוא עדיין פרוטו מסוג binary שעבר סריאליזציה.
  • קבוצת מפתחות מוצפנת היא פרוטוקול EncryptedKeyset סדרתי שמוגדר ב-tink.proto. הוא מכיל קבוצת מפתחות מוצפנת בינארית שעברה סריאליזציה ובאופן אופציונלי גם מטא-נתונים לא מוצפנים של KeysetInfo.

קידומת הפלט של Tink

רוב הפרימיטיבים של Tink תומכים בקידומת פלט של 5 בייט שכוללת:

  • גרסה של בייט אחד: 0x01
  • רמז למפתח באורך 4 בייט: זהו מזהה המפתח שבו נעשה שימוש.

יכול להיות שחלק מהמפתחות מדור קודם תומכים גם בבייט הגרסה 0x00.

חשוב לזכור שהקידומת הזו לא מאומתת ואי אפשר להסתמך עליה למטרות אבטחה. ‫Tink משתמש בו כרמז כדי לזרז את הפענוח או האימות.

AEAD

באופן כללי, Tink מעצב טקסטים מוצפנים של AEAD כך:

prefix || IV || ciphertext || tag

אלא אם צוין אחרת ב-RFC המתאים. ‫prefix הוא ריק או שהוא קידומת פלט של Tink באורך 5 בייט.

AES-CTR-HMAC

ב-AES-CTR-HMAC, ‏ Tink מחשב את ה-MAC עם נתונים משויכים (AD) באופן הבא:

AD || IV || ciphertext || bitlen(AD)

כאשר bitlen(AD) הוא אורך ה-AD בביטים, שמיוצג כמספר שלם לא מסומן ב-64 ביטים בשיטת big-endian. סכמת ה-HMAC הזו מבוססת על הטיוטה של AES-CBC-HMAC מאת Mcgrew.

Deterministic AEAD

‫Tink מטמיע את RFC 5297 עבור AES-SIV, ומציב את וקטור האתחול הסינתטי (SIV) בתחילת הטקסט המוצפן. יכול להיות שהפרימיטיב יוסיף קידומת של 5 בייט לפלט של Tink.

למרות שתקן RFC 5297 תומך ברשימה של נתונים משויכים, Tink תומך רק בנתון משויך אחד בדיוק, שמתאים לרשימה עם רכיב אחד בתקן RFC 5297. נתונים משויכים ריקים הם רשימה עם אלמנט ריק אחד, ולא רשימה ריקה.

סטרימינג AEAD

מידע נוסף זמין במאמרים בנושא AES-CTR HMAC ו-AES-GCM-HKDF.

הצפנת מעטפות

הצפנת מעטפת מצפינה את הנתונים באמצעות מפתח להצפנת נתונים DEK באמצעות פרימיטיבים של AEAD ב-Tink. ההצפנה פועלת באופן הבא:

  • נוצר DEK חדש באמצעות תבנית מפתח נתונה (או פרמטרים של מפתח).
  • המחרוזת DEK עוברת סריאליזציה למחרוזת בייטים. פורמט הסריאליזציה של מאגר אחסון לפרוטוקולים של מפתח ההצפנה. לדוגמה, זוהי הודעת AesGcmKey מאגר אחסון לפרוטוקולים שעברה סריאליזציה ומוגדרת ב-aes_gcm.proto עבור DEK מסוג מפתח AES GCM. במאמר סריאליזציה של מאגר אחסון לפרוטוקולים מוסבר איך לבצע סריאליזציה של מאגר אחסון לפרוטוקולים.
  • המחרוזת DEK עוברת הצפנה על ידי ספק חיצוני (לדוגמה, GCP) והופכת למחרוזת encrypted DEK.
  • המפתח DEK משמש להצפנת הטקסט ללא הצפנה עם הנתונים המשויכים ל-ciphertext. לכן, ciphertext הוא בדיוק באותו פורמט כמו הפרימיטיב AEAD שמתאים ל-DEK.

פורמט הפלט של הצפנת מעטפה הוא כזה:

encrypted DEK length || encrypted DEK || ciphertext

הערך encrypted DEK length הוא 4 בייטים, שבהם מאוחסן האורך של encrypted DEK כמספר שלם מסוג big-endian של 32 ביט.

MAC

‫Tink פועל בהתאם לתקני ה-RFC המתאימים. יכול להיות שפרימיטיבים יוסיפו לתג קידומת של 5 בייט של פלט Tink.

קבוצת PRF

‫Tink פועל בהתאם לתקני ה-RFC המתאימים. שימו לב: עבור PRF, סוג המפתח שונה מסוג מפתח ה-MAC של אותו אלגוריתם, כי הוא לא כולל את אורך הפלט. מפתחות PRF אף פעם לא מוסיפים קידומת פלט של Tink. כך מוודאים שהפלט הוא אכן PRF.

הצפנה היברידית

פורמט החיבור הכללי להצפנה היברידית ב-Tink הוא:

prefix || encapsulated_key || encrypted_data

prefix ריק או שהוא תחילית פלט של Tink באורך 5 בייט. כל סוג מפתח מכיל את המידע על מספר הבייטים לניתוח, ועל אופן הניתוח של הבייטים האלה מ-encapsulated_key.

HPKE (הצפנה היברידית של מפתח ציבורי)

‫Tink פועל לפי תקן ה-HPKE שמוגדר ב-RFC 9180. חבילת הצפנה של HPKE כוללת את שלושת הפרימיטיבים הבאים.

  • מנגנון אנקפסולציה של מפתח (KEM)
  • פונקציית נגזרת מפתח (KDF)
  • הצפנה מאומתת עם נתונים משויכים (AEAD)

תקן HPKE לא מגדיר פורמט כללי של נתונים ב-RFC 9180, סעיף 10. ההטמעה של HPKE ב-Tink משתמשת בערכים הבאים של encapsulated_key ו-encrypted_data.

  • encapsulated_key
    • המפתח הציבורי הסדרתי של השולח
    • מוגדר כ-enc ב-RFC 9180, סעיף 4.1
    • הפורמט נקבע לפי ה-KEM הספציפי של HPKE שבו נעשה שימוש
  • encrypted_data
    • טקסט מוצפן ותג (כלומר, ‫ciphertext || tag ללא וקטור האתחול)
    • מוגדר כ-ct בRFC 9180, סעיף 4
    • הפורמט נקבע לפי ה-AEAD הספציפי של HPKE שבו נעשה שימוש
X25519 Diffie-Hellman-based KEM

ב-X25519 DHKEMs, הערך enc הוא המפתח הציבורי של שולח Diffie-Hellman בגודל 32 בייט.

ECIES-AEAD-HKDF

ביישום של Tink ל-ECIES-AEAD-HKDF, ‏ encapsulated_key הוא הפלט של מנגנון האנקפסולציה של המפתח (KEM) ו-encrypted_data הוא הפלט של מנגנון האנקפסולציה של הנתונים (DEM).

KEM

בהתאם לסוג המפתח, Tink משתמשת בנקודות של עקומות אליפטיות דחוסות ולא דחוסות, בהתאם לתקני הקידוד RFC 8422/ANSI.X9-62.2005. בנקודות לא דחוסות, אחרי הבייט 0x04 מופיעים הקואורדינטות x ו-y כמספרים שלמים בגודל קבוע. במקרה של קואורדינטות דחוסות, נעשה שימוש בבייט 0x02 או 0x03 ובקואורדינטה x כמספר שלם בגודל קבוע. ‫X25519, נעשה שימוש בהגדרה של RFC 7748 (קואורדינטה x כמספר שלם בגודל קבוע).

DEM

במקרה של encrypted_data, ‏ Tink משתמש באותו פורמט כמו AEAD. זה כולל ציון של IV.

גזירת מפתח

קודם מחשבים את קואורדינטת ה-x‏ x_ss של הנקודה המשותפת. המפתח של AEAD מוגדר כך:

HKDF(ikm = encapsulated_key || x_ss, salt = salt_of_key, info = context_info, length = dem_key_size)

כאשר encapsulated_key הוא הפלט המלא של KEM בבייטים.

חתימות דיגיטליות

‫Tink פועל בהתאם לתקני ה-RFC המתאימים. יכול להיות שפרימיטיבים יוסיפו לתג שנוצר קידומת של 5 בייט של פלט Tink.

ECDSA

בהתאם לשדה EcdsaSignatureEncoding במפתח, הפורמט של חתימת ECDSA הוא IEEE P1363 או ASN.1 DER.

הפורמט של החתימה IEEE P1363 הוא r || s, כאשר r ו-s מרופדים באפסים ויש להם את אותו גודל בבייטים כמו הסדר של העקומה. לדוגמה, עבור עקומת NIST P-256, הערכים r ו-s מרופדים באפסים עד 32 בייטים.

חתימת ה-DER מקודדת באמצעות ASN.1:

ECDSA-Sig-Value :: = SEQUENCE { r INTEGER, s INTEGER }

באופן ספציפי, הקידוד הוא:

0x30 || totalLength || 0x02 || r's length || r || 0x02 || s's length || s

‫Tink פועל בהתאם לשיטות המומלצות לאימות חתימות, ומקבל רק חתימות ECDSA עם קידוד DER (חתימות עם קידוד BER חלופיות לא תקפות).

כך אפשר למנוע מתקפות של שינוי חתימה, שמשפיעות לעיתים קרובות על מערכות של מטבעות קריפטוגרפיים.

External Mu ML-DSA prehash values

הפרימיטיב Prehash הופך הודעה לערך prehash, שפרימיטיב SignPrehash חותם עליו. ב-ML-DSA במצב External Mu, כפי שמתואר ב-RFC 9881, ערך ה-prehash הוא 69 בייט עם הפריסה הבאה:

0xff || key_id (4 bytes, big-endian) || mu (64 bytes)
  • mu הוא נציג ההודעה של ML-DSA, שמחושב כ-SHAKE256(tr || 0x00 || 0x00 || message, 64), כאשר tr הוא הגיבוב (hash) של המפתח הציבורי באורך 64 בייט, 0x00 הראשון הוא מפריד הדומיין FIPS 204 עבור ML-DSA טהור, ו-0x00 השני הוא האורך של מחרוזת ההקשר (context) (הריקה). מכיוון ש-tr נגזר מהמפתח הציבורי, הוא קשור למפתח הזה באופן קריפטוגרפי – אבל כדי לבדוק את הקשר הזה צריך את ההודעה המקורית.mu
  • הקידומת בת 5 הבייטים היא מסגור של Tink, ולא חלק מ-mu. היא משייכת את ערך הגיבוב המוקדם למפתח ספציפי אחד, כדי שהפונקציה SignPrehash תדע באיזה מפתח לחתום ותוכל לדחות ערך גיבוב מוקדם שאין לה מפתח בשבילו. הקידומת היא מטא-נתונים רגילים, ולא מתבצעת הצפנה: כל אחד יכול לשנות אותה.

החתימה דוחה כל קלט שלא בדיוק 69 בייט, שלא מתחיל ב-0xff, או שמזהה המפתח שלו לא תואם למפתח מופעל בערכת המפתחות שלו.