פורמט חוט Tink

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

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

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

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

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

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

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

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

הפרימיטיב Prehash משתמש בבייט הגרסה 0xff, ראו ערכי Prehash חיצוניים של Mu ML-DSA.

חשוב לזכור שהקידומות האלה לא מאומתות ואי אפשר להסתמך עליהן למטרות אבטחה. ‫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 בביטים, שמיוצג כמספר שלם לא חתום מסוג big-endian‏ (64 ביט). סכמת ה-HMAC הזו מבוססת על טיוטה של AES-CBC-HMAC מאת מקגרו.

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 Set אף פעם לא מוסיפים קידומת פלט של Tink. כך מוודאים שהפלט הוא באמת פונקציית פסאודו-אקראיות.

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

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

prefix || encapsulated_key || encrypted_data

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

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

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

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

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

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

במקרה של X25519 DHKEM, הערך 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 חלופי לא תקפות).

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

ערכי גיבוב מראש של External Mu ML-DSA

הפרימיטיב 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 השני הוא האורך של מחרוזת ההקשר (הריקה). מכיוון ש-tr נגזר מהמפתח הציבורי, mu הוא קשור למפתח הזה באופן קריפטוגרפי – אבל כדי לבדוק את הקשר הזה צריך את ההודעה המקורית.
  • הקידומת באורך 5 בייט היא מסגור של Tink, ולא חלק מ-mu. היא משייכת את ערך הגיבוב המוקדם למפתח ספציפי אחד, כדי שהפונקציה SignPrehash תדע באיזה מפתח לחתום ותוכל לדחות ערך גיבוב מוקדם שאין לה מפתח בשבילו. הקידומת היא מטא-נתונים רגילים, ולא קושרת שום דבר באופן קריפטוגרפי: כל אחד יכול לשכתב אותה.

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