מפתחות

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

מערכי מפתחות הם הדרך העיקרית שבה משתמשים יכולים לגשת למפתחות (דרך המחלקה KeysetHandle), כך שלכל משתמש יהיה קוד לטיפול בכמה מפתחות בבת אחת. עבור רוב משתמשי הקריפטוגרפיה, הטיפול במספר מפתחות הוא צורך: צריכה להיות אפשרות לשנות מפתחות (למשל, יכול להיות הדלפה של מפתחות ישנים), וכמעט אף פעם אין לחצן 'מעבר למפתח הבא' עם אפקט אטומי שאפשר להחיל על המכונות שהקוד מריץ ועל כל המידע המוצפן, באופן גלובלי ומיידי. לכן המשתמש צריך לכתוב קוד שפועל כשמתבצע שינוי ממפתח אחד למפתחות אחרים.

דוגמה: AEAD

נשתמש בערכת מפתחות AEAD שמכילה כמה מפתחות לפרימיטיב של AEAD. כמו שהסברנו, כל מפתח מציין שתי פונקציות באופן ייחודי: \(\mathrm{Enc}\) ו- \(\mathrm{Dec}\). ערכת המפתחות מציינת עכשיו גם שתי פונקציות חדשות: \(\mathrm{Enc}\) ו- \(\mathrm{Dec}\) - \(\mathrm{Enc}\) שווה לפונקציה \(\mathrm{Enc}\) של המפתח הראשי של קבוצת המפתחות, בעוד שהפונקציה \(\mathrm{Dec}\) מנסה לפענח אותם באמצעות כל המפתחות, כשהיא עוברת עליהם בסדר מסוים (בהמשך אפשר לראות איך Tink משפרת את הביצועים).

מעניין לציין ש-Keyets הם מפתחות מלאים: הם תיאור מלא של הפונקציות \(\mathrm{Enc}\) וה\(\mathrm{Dec}\) שימושיות. כלומר, המשתמשים יכולים לכתוב מחלקה שמשתמשת בקלט KeysetHandle, ולבטא את הרעיון שהמחלקה זקוקה לתיאור מלא של אובייקטים \(\mathrm{Enc}\) ו \(\mathrm{Dec}\) כדי לתפקד כראוי. כך המשתמשים יכולים לכתוב ממשקי API שמציינים כי: כדי להשתמש במחלקה הזו צריך לספק תיאור של פרימיטיב קריפטוגרפי.

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

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

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

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

מזהים של מפתחות במידע מוצפן

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

לכן, מערכת Tink מאפשרת להוסיף תחילית של מידע מוצפן (ciphertext) למחרוזת של 5 בייטים שנגזרת מהמזהה. בהתאם לפילוסופיה של 'מפתחות מלאים' שלמעלה, קידומת זו היא חלק מהמפתח, וכל המידע המוצפן שנוצר אי פעם עם המפתח הזה צריך לכלול אותה. כשמשתמשים יוצרים מפתחות, הם יכולים לבחור אם להשתמש במפתח כזה בקידומת כזו, או אם להשתמש בפורמט של מידע מוצפן (ciphertext) בלעדיו.

כשמפתח נמצא בקבוצת מפתחות, Tink מחשבת את התג הזה מהמזהה שיש למפתח במערך המפתחות. העובדה שהמזהים הם ייחודיים2 בתוך קבוצת מפתחות מצביעה על כך שהתגים ייחודיים. לכן, אם משתמשים רק במפתחות מתויגים, אין אובדן ביצועים בהשוואה לפענוח באמצעות מפתח יחיד: Tink צריך לנסות רק את אחד מהמפתחות במהלך הפענוח.

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


  1. חלקים מסוימים של Tink עדיין מתייחסים ל-Keyets כקבוצה. עם זאת, צריך לשנות זאת. הסיבה לכך היא שהסדר חשוב באופן כללי: לדוגמה, חשוב להביא בחשבון את מחזור החיים האופייני של רוטציית מפתחות עם Aead. תחילה, מתווסף מפתח חדש לערכת מפתחות. המפתח הזה עדיין לא הפך לראשי, אבל פעיל. קבוצת המפתחות החדשה הזו הושקה לכל הקבצים הבינאריים. אחרי שכל הקבצים הבינאריים יכירו את המפתח החדש, המפתח יהיה ראשי (רק בשלב הזה, השימוש במפתח הזה בטוח). בשלב השני, רוטציית המפתחות צריכה לזהות את המפתח האחרון שנוסף.

  2. כדי לוודא תאימות לספרייה פנימית של Google, ב-Tink מאפשר להשתמש במערכי מפתחות שבהם מזהים חוזרים. התמיכה הזו תוסר בעתיד.