HotXLS כותב בלוק dataIntegrity תואם לתוך חבילות XLSX מוצפנות ב-Agile ומאמת אותו בפתיחה. ה-HMAC-SHA-512 מכסה את זרם ה-EncryptedPackage המלא, כולל קידומת ה-StreamSize בת שמונת הבייטים שלו, ונבדק מעל הצופן לפני שכל מקטע מפוענח, כך שסיסמה שגויה או חבילה שהשתנתה מתגלות במקום להתפענח לג'יבריש
הצפנה ללא שלמות היא תשובה חצייה, וקבצי Office הופכים את הפער הזה לקל להתעלמות מפני שההצפנה נראית כה יסודית מבחוץ. הבנת מה שכל שכבה מבטיחה היא מה ששומר על סקירת אבטחה קצרה
מה חוברת עבודה מוצפנת באמת מבטיחה?
הצפנת Agile, המוגדרת ב-[MS-OFFCRYPTO], נותנת סודיות דרך AES במצב CBC עם מפתח שנגזר מגיבוב SHA-512 איטרטיבי של הסיסמה. סודיות היא כל ההבטחה של הבנייה הזו. CBC אינו מצב מאומת: הוא לא אומר דבר על השאלה אם הצופן שמפענחים הוא הצופן שנכתב
ההשלכה המעשית ספציפית. הפוך ביטים בחבילה מוצפנת ו-CBC יפענח אותם בשמחה לתוכן גלוי שונה. בדרך כלל תקבלו שגיאת ניתוח ZIP אי-שם בהמשך, מפני שזרם deflate פגום נדיר ששורד, אבל "בדרך כלל" עושה הרבה עבודה במשפט הזה, ושגיאת מנתח בהמשך היא מקום נורא ללמוד בו שקובץ שונה. האלמנט dataIntegrity קיים כדי לענות על השאלה ישירות, לפני הפענוח, עם MAC מעל הבייטים המדויקים
איך הבדיקה רצה, ובאיזה סדר
הסדר הוא החלק המעניין. HotXLS גוזר את המפתח הביניים מהסיסמה, מפענח את מפתח ה-HMAC המוצפן ואת ערך ה-HMAC מתכונות ה-dataIntegrity באמצעות IV שנגזרים ממפתח בלוק, מחשב HMAC-SHA-512 מעל חבילת ההצפנה כפי שהיא מאוחסנת, ומשווה. רק אז מתחיל פענוח המקטעים
בדיקת ה-MAC מעל צופן ולא מעל תוכן גלוי היא המשמעת הסטנדרטית של הצפנה-ואז-MAC, וזה מה שהופך את הבדיקה למשמעותית: חבילה מזויפת נדחית מבלי שבייט אחד בשליטת תוקף עבר דרך נתיב הפענוח והניפוח. שתי ההשוואות בנתיב הפתיחה, גיבוב מאמת הסיסמה וערך ה-HMAC, צוברות הבדלים עם XOR ו-OR על פני כל הדיגסט במקום לחזור מוקדם על ההתאמה השגויה הראשונה, כך שאף אחת מהן לא מדליפה מיקום בייט דרך תזמון
var
Book: TXLSXWorkbook;
begin
Book := TXLSXWorkbook.Create;
try
// עובד עבור קבצים רגילים, מוצפני-Standard ומוצפני-Agile
if Book.OpenEncrypted('incoming.xlsx', PasswordFromVault) = 1 then
ProcessWorkbook(Book)
else
// סיסמה שגויה, או חבילה שה-HMAC של ה-dataIntegrity שלה לא התאים
Quarantine('incoming.xlsx');
except
on E: Exception do
Quarantine('incoming.xlsx: ' + E.Message);
end;
Book.Free;
end;
בצד הכתיבה שום דבר לא משתנה בקוד שלכם. SaveAsEncrypted מטמיע את הבלוק אוטומטית, והמלחים, קלט המאמת ומפתח ה-HMAC מגיעים מ-CryptGenRandom. אם הקריאה הזו נכשלת, HotXLS מעלה חריגה במקום ליפול בחזרה למקור אקראיות חלש יותר. CSPRNG שנכשל-סגור אינה פרנויה; הורדת דרגה שקטה למקור אקראיות צפוי מפיקה קבצים שנראים מוצפנים, עוברים כל בדיקה פונקציונלית, וחסרי ערך
מדוע קבצים ללא הבלוק עדיין נפתחים?
מפני שהרבה מאוד חוברות עבודה מוצפנות-Agile במחזור נכתבו על ידי מחוללים שמשמיטים את dataIntegrity לגמרי, ודחייתן הייתה שוברת הרבה יותר עבודה לגיטימית ממה שהייתה מגנה. HotXLS מתייחס לשלמות כקיימת רק כששתי התכונות, מפתח ה-HMAC המוצפן וערך ה-HMAC המוצפן, נמצאות ומעוצבות היטב. אחרת האימות מדולג והקובץ נפתח כפי שהיה קודם
זו החלטת תאימות עם השלכת אבטחה שכדאי לנקוב בה במפורש במודל האיום שלכם: היעדר הבלוק לא ניתן להבחנה מתוקף שהסיר אותו, מפני שהתכונות מחוץ ל-MAC שהיו נושאות. אם שולטים בשני קצוות של צינור, התייחסו לבלוק חסר ככשל מדיניות ברמת היישום. אם מקבלים קבצים מהעולם, התייחסו לבדיקה למה שהיא, אות בעל ערך כשהיא נוכחת ואין אות כלל כשהיא נעדרת
סיסמה לשינוי היא מוסכמה, לא גבול
חוברות עבודה קלאסיות מסוג XLS תומכות במנגנון נפרד שנבלבל שגרתית עם הצפנה: שריון הכתיבה, ה"סיסמה לשינוי" של Excel. HotXLS חושף אותו דרך SetModifyPassword, שמקבל את הסיסמה, דגל מומלץ-קריאה-בלבד, ואת שם המשתמש שמשריין. הוא מדווח מצב דרך IsWriteReserved. העברת סיסמה ריקה מנקה את השריון
מה שנכתב הוא זוג רשומות WRITEPROT ו-FILESHARING שנושאות את דגל מומלץ-קריאה-בלבד, גיבוב סיסמה ישן בן 16 סיביות ואת שם המשתמש כמחרוזת Unicode מסוג BIFF8. הגיבוב בן 16 הסיביות הוא checksum, לא דיגסט קריפטוגרפי, ותוכן המסמך כלל לא מוצפן. כל מי שפותח את הקובץ בכלי אחר כלשהו קורא הכל. התפקיד האמיתי של התכונה הוא תיאום: היא אומרת לאדם הבא שמישהו רואה בקובץ הזה שלו לערוך, באותה קטגוריה כמו הבקרות ברמת הגיליון המכוסות בהגנת גיליון XLSX ואפשרויות היתר
var
Book: IXLSWorkbook; // ספור-ממשק: אל תשחררו עם Free
begin
Book := TXLSWorkbook.Create;
if Book.Open('shared-model.xls') = 1 then
begin
// מומלץ קריאה-בלבד, משוריין על ידי שירות הדיווח
Book.SetModifyPassword('edit-me', True, 'Reporting Service');
if Book.IsWriteReserved then
Book.SaveAs('shared-model.xls', xlExcel97);
end;
end;
השתמשו בשתי השכבות למה שכל אחת טובה בו. סודיות אמיתית מגיעה מ-SaveAsEncrypted עם סיסמה שאף אחד מחוץ לקהל היעד לא מחזיק, שמפיקה את פלט ה-AES-256 המתואר בפלט XLSX מוגן-AES. שריון הכתיבה מתווסף כשחוברת העבודה היא ארטיפקט עריכה משותפת ורוצים ש-Excel ישאל לפני שמישהו שומר מעל
מה לבדוק בנתיב קליטה לא מהימן
אימות השלמות מגן על המטען המוצפן, לא על המכל שסביבו. קובץ XLSX הוא ארכיון ZIP, ומבנה הארכיון מנותח לפני שכל לוגיקת הצפנה רצה, כך שאימות ברמת המכל שייך ראשון בשרשרת; אופני הכשל הספציפיים מכוסים באימות ZIP end-of-central-directory ל-XLSX לא מהימן. אחרי זה, התייחסו לכשל שלמות ולסיסמה שגויה כאותו אירוע תפעולי, מפני שמנקודת המבט שלכם הם בלתי ניתנים להבחנה בעיצוב, ושניהם אומרים שאי אפשר לסמוך על הקובץ שיהיה מה שהשולח חושב
רשמו ביומן אילו קבצים נשאו בלוק dataIntegrity בכלל. על פני כמה אלפי מסמכים הסטטיסטיקה הזו אומרת לכם משהו שימושי על כלי השולחים שלכם, והופכת בדיקה לפי-קובץ לתצפית ברמת הצי שאפשר לפעול לפיה
HotXLS קורא וכותב XLS, XLSX ו-ODS מ-Delphi ומ-C++Builder ללא התקנת Excel, ומממש את נתיבי ההצפנה Standard ו-Agile של [MS-OFFCRYPTO] ב-Pascal. ה-API של ההצפנה, ההגנה וחוברת העבודה מתועד בדף רכיב HotXLS ל-Delphi