OCB
OCB3

בגרסאות הקודמות בוצעו  m+2 קריאות לצופן הבלוקים כדי להצפין  m בלוקים עם אימות, קריאה ראשונה לייצר את האופסט הראשון מוקטור האתחול, לאחר מכן הצפנת  m הבלוקים ולבסוף קריאה אחרונה להצפנת התג. אפשר להיפטר מהקריאה הראשונה לצופן הבלוקים על ידי החלפה בפונקציית גיבוב XOR אוניברסלית מהירה  \Delta =H_{K}(N)=({\text{Stretch}}\ll {\text{Bottom}}[1..128] כאשר  {\text{Bottom}} הוא 6 הסיביות הפחות משמעותיות של  N והמחרוזת  {\text{Stretch}} נוצרת על ידי הצפנה של  N עם שש הסיביות הפחות משמעותיות מאופסות (הפונקציה מפורטת בהמשך). מבנה זה הוכח כפונקציית גיבוב אוניברסלית. בדרך זו מתבצעות  m+1.016 קריאות בממוצע לצופן הבלוקים בנוסף לביצוע פונקציית הגיבוב המהירה. ב-OCB3 התג אינו תלוי בטקסט המוצפן מה שמאפשר האצה נוספת בביצועים ביישום מקבילי לעומת הגרסאות הקודמות. כמו כן מסתבר שפעולת כפל בשדה  GF(2^{128}) סובלת מביצועים גרועים ברוב הפלטפורמות לכן הוחלט על גשה אחרת לקידום המונה מאשר בגרסאות הקודמות. כעת כל הבלוקים מטופלים באותה דרך, גם הבלוק האחרון והם נפרדים זה מזה. שיפור נוסף הוא החלפת צופן הבלוקים בצופן בלוקים בר-התאמה, בדרך זו האלגוריתם פשוט יותר וקל להוכחה.
להלן תיאור האלגוריתם בגרסת  \Theta {\text{OCB3}}[{\tilde {E}},\tau ] מעל צופן בלוקים בר התאמה:
| --- | --- |
  \mathbf {OCB3.Encrypt} _{N,K}(M,A)  {\text{let }}M=M_{1}...M_{m}M_{*};\ |M_{i}|=n,\ |M_{*}|<n  {\text{Checksum}}=0^{n},\ C_{*}={\text{empty}}  {\text{For }}i=1{\text{ to }}m{\text{ do}}  C_{i}={\tilde {E}}_{K}^{N\ i}(M_{i})  {\text{Checksum}}={\text{Checksum}}\oplus M_{i}  {\text{If }}M_{*}={\text{empty then:}}  {\text{Final}}={\tilde {E}}_{K}^{N\ m\ \$}({\text{Checksum}})  {\text{else Pad}}={\tilde {E}}_{K}^{N\ m\ *}(0^{n})  C_{*}=M_{*}\oplus {\text{Pad}}[1..|M_{*}|]  {\text{Checksum}}={\text{Checksum}}\oplus M_{*}10^{*}  {\text{Final}}={\tilde {E}}_{K}^{m\ *\ \$}({\text{Checksum}})  {\text{Auth}}={\text{Hash}}_{K}(A)  {\text{Tag}}={\text{Final}}\oplus {\text{Auth}}  T={\text{Tag}}[1..\tau ]  {\text{Return }}C_{1}...C_{m}C_{*}\ \|\ T ‎  \mathbf {Hash} _{K}(A)  {\text{Sum}}=0^{n}  {\text{let }}A=A_{1}...A_{m}A_{*};\ |A_{i}|=n,\ |A_{*}|<n  {\text{For }}i=1{\text{ to }}m{\text{ do}}  {\text{Sum}}={\text{Sum}}\oplus {\tilde {E}}_{K}^{i}(A_{i})  {\text{If }}A_{*}\neq {\text{empty then:}}  {\text{Sum}}={\text{Sum}}\oplus {\tilde {E}}_{K}^{m\ *}(A_{*}10^{*})  {\text{Return Sum}}:   \mathbf {OCB3.Decrypt} _{K,N}(C\ \|\ T,A)  {\text{let }}C=C_{1}...C_{m}C_{*};\ |C_{i}|=n,|C_{*}|<n  {\text{Checksum}}=0^{n},M_{*}={\text{empty}}  {\text{For }}i=1{\text{ do }}m{\text{ do}}  M_{i}={\tilde {D}}_{K}^{N\ i}(C_{i})  {\text{Checksum}}={\text{Checksum}}\oplus M_{i}  {\text{If }}C_{*}={\text{empty then:}}  {\text{Final}}={\tilde {E}}_{K}^{N\ m\ \$}({\text{Checksum}})  {\text{else Pad}}={\tilde {E}}_{K}^{N\ m\ *}(0^{n})  M_{*}=C_{*}\oplus {\text{Pad}}[1..|C_{*}|]  {\text{Checksum}}={\text{Checksum}}\oplus M_{*}10^{*}  {\text{Final}}={\tilde {E}}_{K}^{N\ m\ *\ \$}({\text{Checksum}})  {\text{Auth}}={\text{Hash}}_{K}(A)  {\text{Tag}}={\text{Final}}\oplus {\text{Auth}}  T'={\text{Tag}}[1..\tau ]  {\text{If }}T=T'{\text{ then return }}M_{1}...M_{m}M_{*}  {\text{else return INVALID}} ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎
הסבר: צופן הבלוקים בר התאמה מסומן על ידי  {\tilde {E}} כשגודל הבלוק נקבע ל-128. הוא מקבל מפתח הצפנה, tweak וטקסט קריא ומחזיר טקסט מוצפן (להלן תיאור מפורט כיצד להפוך צופן בלוקים רגיל לצופן בלוקים בר התאמה). הסימן  \tau  מייצג את אורך תג האימות בסיביות. בנוסף האלגוריתם מקבל את הטקסט הנלווה A. הסימנים * ו-$ מייצגים ערכי tweak שונים בהתאם להיסטים (מבוארים בהרחבה להלן). הביטוי  0^{n} פירושו מחרוזת של  n אפסים. בניסוי שערכו המפתחים פיליפ רוגווי וטד קרובץ לטענתם האלגוריתם מהיר הרבה יותר מ-CCM או GCM בניגוד לטענת המפתחים של האלגוריתמים הללו. ביישום ממוטב האלגוריתם יכול הגיע למהירות הצפנה של 1.5 CPB.
הטכניקה להפיכת צופן הבלוקים לצופן בלוקים בר התאמה נעשית כך:
| ביטוי | ביטוי | ביטוי | ביטוי | תיאור |
| --- | --- | --- | --- | --- |
|  L=E_{K}(0^{128}) |  L=E_{K}(0^{128}) |  L=E_{K}(0^{128}) |  L=E_{K}(0^{128}) | הצפנת מחרוזת של 128 אפסים |
|  \lambda _{i}=4a(i)\  |  \lambda _{i}^{*}=4a(i)+1\  |  \lambda _{i}^{\$}=4a(i)+2\  |  \lambda _{i}^{*\$}=4a(i)+3\  | ארבעה היסטים לפי אינדקס (עם הסימנים *, $ או *$) |
|  {\tilde {E}}_{K}^{N\ i}(M)=E_{K}(M\oplus \Delta )\oplus \Delta  |  {\tilde {E}}_{K}^{N\ i}(M)=E_{K}(M\oplus \Delta )\oplus \Delta  |  {\tilde {E}}_{K}^{N\ i}(M)=E_{K}(M\oplus \Delta )\oplus \Delta  |  \Delta ={\text{Initial}}\oplus \lambda _{i}L;\ \ i\geq 1 | tweak "N i" |
|  {\tilde {E}}_{K}^{N\ i\ *}(M)=E_{K}(X\oplus \Delta ) |  {\tilde {E}}_{K}^{N\ i\ *}(M)=E_{K}(X\oplus \Delta ) |  {\tilde {E}}_{K}^{N\ i\ *}(M)=E_{K}(X\oplus \Delta ) |  \Delta ={\text{Initial}}\oplus \lambda _{i}^{*}L;\ \ i\geq 0 | tweak "N i *" |
|  {\tilde {E}}_{K}^{N\ i\ \$}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{N\ i\ \$}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{N\ i\ \$}(M)=E_{K}(M\oplus \Delta ) |  \Delta ={\text{Initial}}\oplus \lambda _{i}^{\$}L;\ \ i\geq 0 | tweak "N i $" |
|  {\tilde {E}}_{K}^{N\ i\ *\ \$}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{N\ i\ *\ \$}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{N\ i\ *\ \$}(M)=E_{K}(M\oplus \Delta ) |  \Delta ={\text{Initial}}\oplus \lambda _{i}^{*\$}L;\ \ i\geq 1 | tweak "N i * $" |
|  {\tilde {E}}_{K}^{i}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{i}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{i}(M)=E_{K}(M\oplus \Delta ) |  \Delta =\lambda _{i}L;\ \ i\geq 1 | tweak "i" |
|  {\tilde {E}}_{K}^{i\ *}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{i\ *}(M)=E_{K}(M\oplus \Delta ) |  {\tilde {E}}_{K}^{i\ *}(M)=E_{K}(M\oplus \Delta ) |  \Delta =\lambda _{i}^{*}L;\ \ i\geq 0 | tweak "i *" |
הסבר: תחילה מצפינים מחרוזת אפסים באמצעות צופן הבלוקים עם מפתח ההצפנה המסופק על ידי המשתמש, לאחר מכן כל בלוק מסר מחובר עם tweak שונה ב-XOR לפני שהוא מוצפן. כדי לייצר את ה-tweak המתאים לכל בלוק, תחילה מייצרים אופסט  \lambda  מתאים, אותו מכפילים ב- L ומחברים ב-XOR עם תוצאת פונקציית הגיבוב האוניברסלית של המפתח (להלן). את האופסט מכינים על ידי וריאציה של קוד גריי רקורסיבי כשהביטוי  a(i-1)\oplus 2^{{\text{ntz}}(i)} פירושו שכדי לקבל את הקוד ה- i ברצף מחברים ב-XOR את האלמנט הקודם בחזקה של מספר האפסים המסיימים (הפחות משמעותיים) באינדקס  i, לדוגמה  {\text{ntz}}(8)=3 וכן  {\text{ntz}}(7)=0. את פונקציית הגיבוב האוניברסלית מכינים כך:
הסבר: ה-Nonce הוא ערך ייחודי וחד פעמי הנוצר פשוט על ידי וקטור האתחול  N המסופק על ידי המשתמש, כשהוא מרופד בסיבית 1 ואפסים במספר הנדרש כדי להשלימו לבלוק שלם באורך 128 סיביות. ואז מחלקים את הבלוק לשני חלקים העליון באורך 122 סיביות והתחתון באורך 6 סיביות (הסימן  \land  מייצג AND המתפקד כאן כמסכת סיביות), מצפינים את העליון באמצעות צופן הבלוקים עם המפתח  K. לאחר הזזה (shift), הצמדה ( \|) והצפנה כמתואר התוצאה היא הערך Initial.