OCB

בקריפטוגרפיה, Offset CodeBook היא משפחה של מצבי הפעלה מקביליים עבור צופן בלוקים המספקים הצפנה מאומתת של מסרים ארוכים. OCB1 פותח ב-2003 על ידי פיליפ רוגווי, מיהיר בלייר אוניברסיטת קליפורניה בסן דייגו וג'ון בלאק מאוניברסיטת קולורדו. OCB הם מצבי הפעלה אלגנטיים, יעילים ובטוחים לפי פרדיגמה של "הצפנה ואחריה אימות" והם שיפור של מצב ההפעלה IAPM שהוצע על ידי Charanjit Jutla. בהתבסס על צופן בלוקים בטוח כמו AES ווקטור אתחול, האלגוריתם מצפין מסר שהוא מחרוזת בינארית ארוכה <math>M</math>, תוך הפעלה של צופן הבלוקים <math>\left \lceil |M|/n\right \rceil+2</math> פעמים, כאשר <math>n</math> הוא גודל הבלוק שהצופן מקבל (128 סיביות במקרה של AES) תוך חישובי היסט (offset) ותהליך הכנת מפתח מהירים מאוד. ומפיק טקסט מוצפן בליווי תג אימות באורך משתנה לפי הצורך כדי לאמת ולהבטיח את שלמות הטקסט המוצפן. תג האימות מבטיח מעצם ההגדרה שלא ניתן יהיה לזייף טקסט מוצפן עם תג אימות מתאים ללא ידיעת מפתח ההצפנה המשותף לשולח והמקבל, כך שהמקבל לא יבחין בכך. OCB1 הוכח כבטוח כנגד התקפות על שלב הסודיות או האימות בהנחה שצופן הבלוקים מוגדר פרמוטציה פסאודו אקראית (PRP). אולם התגלו בעיות בעמידות בפני התנגשויות, שמגבילות את כמות המידע הניתן להצפנה עם מפתח יחיד. ביישום אופטימלי OCB1 מהיר מאוד ויכול להגיע למהירות של 1.48 CPB על מעבד אינטל 64 ביט (עם AES-NI).

OCB מוגן בפטנט בארצות הברית, השימוש בו כרוך ברישיון מבוסס הרישיון הציבורי הכללי של גנו לשימוש פרטי, בתנאי שאינו משמש לצורך מסחרי או ממשלתי. ב-2013 המפתחים נתנו הסכמתם לרישיון חופשי בקוד פתוח המאושר על ידי OSI. האלגוריתם נכלל ברשימת האלגוריתמים המובילים שמנהל NIST לצורך תקן הצפנה מאומתת. כמו כן מומלץ על ידי IETF.

תרשים לדוגמה של הצפנה מאומתת בשיטת OCB

==הצפנה מאומתת==

הצפנה מאומתת היא סכמת הצפנה המבוססת על צופן סימטרי שמטרתה לספק סודיות והבטחת שלמות המידע. כאשר פונקציית ההצפנה מקבלת טקסט מקור, מפתח סודי המשותף לשולח והמקבל ווקטור אתחול ומחזירה טקסט מוצפן, בעוד שפונקציית הפענוח מקבלת טקסט מוצפן ווקטור אתחול ומפתח סודי ומפיקה טקסט קריא או סמל מיוחד "INVALID" אם אחד הערכים שונה כתוצאה משגיאה במהלך המשלוח או בזדון. בהקשר זה וקטור האתחול מכונה גם Nonce כלומר ערך ייחודי וחד פעמי אך אינו בהכרח סודי או אקראי כמו למשל מספר רץ. למעשה אפשר להשיג הצפנה מאומתת על ידי שילוב נכון של צופן בלוקים עם קוד אימות מסרים כמו שקורה בפועל ובתקני הצפנה. בעבר השתמשו בטכניקה של ריפוד על ידי הוספת יתירות אולם דרך זו הוכחה כלא בטוחה. שיטות רבות שבשימוש אינן יעילות וחלקן לא בטוחות. המטרה היא השגת אימות במחיר הנמוך ביותר אפשרי מהיבט של יעילות ביישום מעשי בתוכנה או בחומרה, כמעט כמו הצפנה ללא אימות, תוך שמירה על ביטחון גבוה. בנוסף רצוי שתהיה תמיכה במקביליות להשגת תפוקה גבוהה. OCB מכיל את התכונות הבאות:
*אורך מינימלי של טקסט מוצפן בהתחשב באורך הטקסט המקורי. כמו כן אורך המסר לא חייב להיות כפולה של גודל הבלוק שהצופן מקבל.
*הצורך בוקטור אתחול גמיש. צריך להיות שונה בכל פעם שמצפינים מסר חדש עם אותו מפתח אך אינו חייב להיות סודי או אקראי.
*מספר הקריאות לצופן הבלוקים (כאשר המסר ארוך) הוא מינימלי, כמעט אופטימלי.
*יש צורך במפתח הצפנה סודי יחיד כאשר מפתח האימות נגזר ממנו.
*יעילות רבה בחישובי האופסט או הרצף. ההצפנה והפענוח יכולים להתבצע ללא עיכוב גם אם המסר לא הגיע בשלמותו. וכן היכולת לטפל בבלוקים קצרים ביעילות והיכולת לבצע חישוב מקבילי או לחדש תג אימות ביעילות כאשר בוצע שינוי בחלק מהמסר. זאת ללא חישובים אריתמטיים מסובכים. 
*תפוקה גבוהה. בניסוי שעשו המפתחים על פנטיום 3 הוכח ש-OCB איטי רק ב-6.5% לעומת הצפנה ישירה ללא אימות. ומהיר פי 54% ממצב הצפנה CBC עם MAC כמו CCM.
*יישום מקבילי בחומרה ייעודית יכול להניב תפוקה של 10 Gbps.
*ביטחון סמנטי מוכח לפי מודל של מיקלי וגולדווסר שנקרא indistinguishability כנגד התקפת גלוי-נבחר יחד עם אימות מוכח לפי מודל של בלייר כץ ויונג. מה שמספק הגנה כנגד ההתקפה החזקה ביותר התקפת מוצפן-נבחר בקיצור CCA שמקביל גם למודל ביטחון מחמיר שנקרא אי-חשילות של דולב ואחרים. מודלים של ביטחון אילו אינם מתקיימים במצבי הפעלה סטנדרטיים כמו PCBC שייושם בפרוטוקול קרברוס.

===סימנים מוסכמים===
צופן בלוקים המהווה מרכיב פרימיטיבי באלגוריתם הוא פונקציה מהצורה <math>E : \mathcal{K} \times \{0,1\}^n\rightarrow \{0,1\}^n</math> המסומנת בקיצור <math>E_K(M)</math> כאשר <math>K</math> הוא מפתח ההצפנה ו-<math>M</math> הוא המסר. גודל בלוק שהצופן מסוגל להצפין בריצה אחת הוא <math>n</math> שמומלץ שיהיה לפחות 128 סיביות. ואורך התג מיוצג על ידי <math>\tau</math> ומומלץ שיהיה לפחות 32 סיביות. בפרוטוקול IPSec התקן הוא 96 סיביות.

כל הערכים הם מחרוזות בינאריות והסימן <math>A \ \| \ B</math> מייצג שרשור של <math>A</math> ו-<math>B</math> למחרוזת אחת. המרה של מחרוזת בינארית למספר שלם וההפך היא לפי סדר בתים קטן. הפונקציה <math>\text{ntz}(i)</math> מייצגת את מספר האפסים המסיימים בייצוג הבינארי של המספר <math>i</math> (בספרות הפחות משמעותיות של המספר) למשל <math>\text{ntz}(7)=0</math> וכן <math>\text{ntz}(8)=3</math>. הריפוד של <math>A</math> באפסים מיוצג על ידי <math>A \ 0^*</math>, למשל המספר 5 בייצוג בינארי הוא <math>0^*101</math> הכוכבית מתייחסת למספר האפסים הדרוש כדי להשלימו לגודל בלוק <math>n</math>, כלומר אם <math>n=128</math> סיביות המספר 5 בייצוג בינארי מרופד ב-125 אפסים בסיביות המשמעותיות כדי להשלימו לגודל בלוק). הפעולה <math>A \oplus B</math> נקראת XOR. הסימן <math>A\ll 1</math> נקרא הזזה לשמאל (shift left) של סיביות המחרוזת <math>A</math> צעד אחד, הסיבית המשמעותית ביותר נפלטת ואילו הסיבית הראשונה מתאפסת. וכן לגבי <math>A\gg 1</math> בסדר הפוך. כאשר מחלקים את המסר <math>M</math> לבלוקים בגודל <math>n</math> צריך לזכור שמספר הבלוקים צריך להיות לפחות אחד, כך שהמחרוזת הריקה גודלה 1.

====פעולות אריתמטיות בשדה <math>GF(2^n)</math>====
כדי לחשב את האופסט להלן, רואים במחרוזות באורך <math>n</math> הסיביות כפולינומים מעל השדה <math>\text{GF}(2^n)</math>, כך שהמקדמים של האלמנט <math>a(x)=a_{n-1}x^{n-1}+\cdots +a_1x+a_0</math> הן הסיביות של המספר <math>a</math>. למשל בשדה <math>GF(2^{128})</math> אפשר לראות במספר 5 כמחרוזת בינארית <math>0^{125}101</math> או הפולינום <math>x^2+1</math>. פעולת החיבור של שני אלמנטים בשדה היא חיבור המקדמים בנפרד מודולו 2 שהיא מקבילה לפעולת XOR. כדי לבצע פעולת כפל בשדה <math>c(x)=a(x)\cdot b(x)</math>, יש לבחור תחילה פולינום פרימיטיבי אי-פריק <math>p(x)</math> ממעלה <math>n</math> (שרצוי שיהיה עם מספר מקדמים מינימלי, דהיינו משקל בינארי נמוך) שישמש כמייצג של השדה, כך שכל פעולות הכפל בין שני אלמנטים בשדה צריכות להתבצע מודולו <math>p(x)</math> כדי שהתוצאה תהיה אלמנט בשדה. למשל עבור השדה <math>\text{GF}(2^{128})</math> הפולינום <math>x^{128}+x^7+x^2+x+1</math> מתאים. 

אפשר לראות שקל לבצע כפל של כל פולינום <math>a(x)</math> בפולינום <math>x</math> כיוון שהתוצאה
:<math>a(x)\cdot x =a_{n-1}x^n+a_{n-2}x^{n-1}+\cdots +a_1x^2+a_0x</math> 
שקולה בעצם להזזת המקדמים שמאלה פוזיציה אחת. כעת אם הסיבית הגבוהה ביותר היא אפס התקבל פולינום ממעלה נמוכה מ-128 והתוצאה נותרת בעצם <math>a\ll 1</math>. אך אם הסיבית המשמעותית היא 1 מתקבל פולינום ממעלה גבוהה או שווה ל-128, מה שמחייב לצמצם את הפולינום <math>a</math> מודולו <math>p(x)</math>. דהיינו צריך למצוא פולינומים <math>q</math> ו-<math>r</math> המקיימים <math>a^{128}+a=q\cdot p+r</math> ואז לקחת את השארית <math>r</math>. קל לפתור את המשוואה האחרונה כאשר <math>q=1</math> כי אחרי העברת אגפים מתקבל <math>r=a^{128}+a-p</math>. במילים אחרות צריך לחסר את <math>p</math> מהתוצאה ואפשר להסתפק במקדמים הנמוכים של <math>p</math> כי הסיבית הגבוהה מתבטלת. חיסור אלמנט בשדה זה מתבצע על ידי XOR כי הוא הופכי של עצמו לכן חיבור וחיסור הן פעולות זהות. לסיכום:
<div class="mw-content-ltr">
:<math>a\cdot x=\begin{cases} a\ll 1, & \text{if the first bit of a }=0 \\ a\ll 1\oplus 0^{120}10000111, & \text{if the first bit of a }=1 \end{cases}</math>
</div>באופן דומה אפשר לבצע חילוק עם ההופכי הכפלי של <math>x</math>.
 
<div class="mw-content-ltr">
:<math>a\cdot x^{-1}=\begin{cases} a\gg 1, & \text{if the last bit of a }=0 \\ a\gg 1\oplus 10^{120}1000011, & \text{if the last bit of a }=1 \end{cases}</math>
</div>
כעת אם <math>L\in \{0,1\}^n</math> הוא מחרוזת בינארית (או פולינום) הביטוי <math>L(i)</math> עבור <math>i\ge -1</math> הוא סימון מקוצר של הפעולה <math>L\cdot x^i</math>. כלומר כפל הפולינום <math>L</math> בחזקות של הפולינום <math>x</math>. בעזרת נוסחאות הכפל והחילוק לעיל קל לחשב מתוך <math>L</math> את <math>L(i-1), L(0),L(1),...,L(\mu)</math>. עבור <math>\mu</math> קטן. את <math>L(-1)</math> מחשבים על ידי <math>L\cdot x^{-1}</math>.

לצורך האופסט בהשאלה מקוד גריי מגדירים את <math>\gamma^l=(\gamma_0^l \ \gamma_1^l\cdots \ \gamma_{2^l-1}^l)</math> של מחרוזות באורך <math>l</math> סיביות הנבדלות זו מזו רק בסיבית אחת. כאן נעשה שימוש בקוד גריי קנוני שאותו בונים על ידי חישוב <math>\gamma^1=(0 \ 1)</math> ועבור כל <math>l</math> הגדול מ-0:
:<math>\gamma^{l+1}=(0\gamma_0^l \ 0\gamma_1^l\cdots \ 0\gamma_{2^l-1}^l 1\gamma_{2^l-1}^l \ 1\gamma_{2^l-2}^l\cdots \ 1\gamma_1^l \ 1\gamma_0^l) </math>
הסיבה לבחירה זו היא שלמעשה <math>\gamma_i=\gamma_{i-1}\oplus (0^{n-1}1\ll\text{ntz}(i))</math>. שזה XOR עם חזקה של 2 כאשר החזקה היא מספר האפסים המסיימים באינדקס <math>i</math>. מה שהופך את המשימה לחישוב נקודות האופסט לקלה במיוחד כי כל שנדרש הוא הזזות ו-XOR בלבד. נקודות <math>\gamma_i</math> האמורות שונות זו מזו בסיבית אחת לפחות ושונות מאפס וכן <math>\gamma_i<2i</math>. תוך שימוש בקוד גריי, במחרוזת <math>L</math> ובמחרוזת <math>R</math> (שיבוארו להלן) מחשבים באופן רקורסיבי את הערכים הבאים:
:<math>\gamma_1\cdot L=L\oplus R,\ \ \gamma_i\cdot L=(\gamma_{i-1}\cdot L)\oplus L(\text{ntz}(i))\oplus R, \ i\ge 2</math>. 

כל נקודה מחושבת על ידי XOR של הנקודה הקודמת עם <math>L(\text{ntz}(i))</math>. כדי לשלב את וקטור האתחול בתהליך ההכנה תחילה מצפינים אותו עם <math>L</math> ומחברים את התוצאה <math>R</math> עם כל ההיסטים <math>\gamma_i</math>, כאשר האופסט הראשון הוא <math>L\oplus R</math>. כך מבטיחים ייחודיות בכל הצפנה.

===תיאור האלגוריתם===
באלגוריתם הבא, מתייחסים לטקסט המיועד להצפנה כאל מחרוזת סיביות המחולקת ל-<math>m</math> בלוקים. כאשר המסר צריך להיות לפחות <math>m-1</math> בלוקים שלמים בגודל 128 סיביות ובלוק האחרון שיכול להיות בלוק חלקי המרופד באפסים במידת הצורך או שהוא יכול להיות ריק לגמרי. על כל פנים צריך שיהיה לפחות בלוק אחד כך שיתקיים <math>128m \le |M|</math>.

====הצפנה ואימות====
<div class="mw-content-ltr">
<math>\boldsymbol{\mathbf{OCB1}.\mathbf{E}_\mathbf{K}(N,M)}</math>
#<math>L=E_K(0^n)</math>
#<math>R=E_K(N\oplus L)</math>
#<math>\text{For }i=1\text{ to }m\text{ do: }\ Z[i]=\gamma_i\cdot L\oplus R</math>
#<math>\text{For }i=1\text{ to }m-1\text{ do: }\ C[i]=E_K(M[i]\oplus Z[i])</math>
#<math>X[m]=\text{len}(M[m])\oplus L\cdot x^{-1}\oplus Z[m])</math>
#<math>Y[m]=E_K(X[m])</math>
#<math>C[m]=Y[m]\oplus M[m]</math>
#<math>C=C[1],...,C[m]</math>
#<math>\text{Checksum}=M[1]\oplus\cdots\oplus M[m-1]\oplus C[m]0^*\oplus Y[m]</math>
#<math>T=E_K(\text{Checksum}\oplus Z[m])[\text{first }\tau\text{ bits}]</math>
#<math>\text{Return }C \ \| \ T</math>
</div>

====פענוח ואימות====
<div class="mw-content-ltr">
<math>\boldsymbol{\mathbf{OCB1}.\mathbf{D}_\mathbf{K}(N,C \ \| \ T)}</math>
#<math>L=E_K(0^n)</math>
#<math>R=E_K(N\oplus L)</math>
#<math>\text{For }i=1\text{ to }m\text{ do: }\ Z[i]=\gamma_i\cdot L\oplus R</math>
#<math>\text{For }i=1\text{ to }m-1\text{ do: }\ M[i]=E_K^{-1}(C[i]\oplus Z[i]) \oplus Z[i]</math>
#<math>X[m]=len(C[m])\oplus L\cdot x^{-1}\oplus Z[m]</math>
#<math>Y[m]=E_K(X[m])</math>
#<math>M[m]=Y[m]\oplus C[m]</math>
#<math>M=M[1],...,M[m]</math>
#<math>\text{Checksum}=M[1]\oplus\cdots\oplus M[m-1]\oplus C[m]0^*\oplus Y[m]</math>
#<math>T'=E_K(\text{Checksum} \oplus Z[m])[\text{first }\tau\text{ bits}]</math>
#<math>\text{If }T=T' \text{ Then return }M\text{ else return INVALID}</math>
</div>

====תיאור במילים====
הקלט הוא מפתח סודי <math>K</math>, וקטור האתחול <math>N</math> והמסר <math>M</math> אותו מחלקים ל-<math>m</math> לבלוקים בגודל <math>n</math> סיביות, מרפדים באפסים את הבלוק האחרון אם נדרש. לצורך הכנה, תחילה מחשבים את <math>L</math> על ידי הצפנה של מחרוזת אפסים עם צופן הבלוקים <math>E</math> והמפתח <math>K</math> ואז מחשבים ומאחסנים את הסדרה <math>L(-1),L,L(1),L(2),...,L(\mu)</math> כאשר <math>\mu=\left\lceil \text{log}_2m\right \rceil</math>. אם אורך המסר אינו ידוע מראש אפשר לחשב ולאחסן מראש את הסדרה המתוארת עד לגבול העליון של מספר הבלוקים האפשריים עבור מפתח נתון. את הסדרה מחשבים בשיטה המתוארת לעיל, רקורסיה של כפל ב-<math>x</math> (הזזה ו-XOR מותנה). מחשבים את האופסט הראשון על ידי הצפנה של <math>L</math> עם וקטור האתחול <math>E_K(N\oplus L)</math> ולאחר מכן באופן רקורסיבי מחשבים את כל האופסטים באמצעות הנוסחה <math>\text{Offset}=\text{Offset} \oplus L(\text{ntz}(i))</math> עבור <math>i=1,...,m-1</math>. באמצעות צופן בלוקים מצפינים כל בלוק כשהוא מחובר עם האופסט המתאים ב-XOR פעמיים, לפני ואחרי ההצפנה כדי לקבל את הטקסט המוצפן <math>C</math>. מחשבים את הבלוק האחרון שהוא הצפנה של אורך המסר עם האופסט המתאים, מחשבים את סכום הביקורת אותו מצפינים באמצעות צופן הבלוקים עם האופסט המתאים. מוסיפים הצפנה של הבלוק האחרון עם קידוד של אורך המסר וכן האופסט האחרון. את תג האימות מחשבים על ידי XOR של כל הבלוקים יחד עם הבלוק המוצפן האחרון והצפנתם. <math>\tau</math> הסיביות הראשונות של תוצאת ההצפנה האחרונה הן תג האימות <math>T</math> שמצורף ל-<math>C</math>. תיאור הפענוח דומה. תחילה מבצעים את אותם פעולות הכנה כמו בתהליך ההצפנה. מפענחים את כל הבלוקים המוצפנים כשהם מחוברים ב-XOR עם האופסט המתאים ומחשבים את הבלוק האחרון ותג האימות <math>T'</math> אותו משווים עם <math>T</math> שהתקבל מהשולח. אם כל הערכים נכונים האלגוריתם מחזיר את <math>M</math>, אם אחד מהערכים שגוי האלגוריתם מחזיר <math>\text{INVALID}</math>.

===ביטחון===
OCB נחשב בטוח לפי הגדרות שנהגו לראשונה ב-1984 על ידי מיקלי וגולדווסר בשם ביטחון סמנטי וכן על ידי בלייר ורוגווי ב-1997 ובשנת 2000. תאורטית זיוף תג אימות באופן כללי יכול להצליח בסיבוכיות של <math>1/2^\tau</math>. מעבר לזה, ככל שמוצפנים בלוקים נוספים כמות המידע שעומדת לרשות התוקף גדלה באופן יחסי עד <math>1.5\sigma^2/2^n</math>. כאשר <math>\sigma</math> מייצג את מספר הבלוקים. כך שאם <math>\sigma</math> קטן OCB יהיה בטוח בהנחה שצופן הבלוקים בטוח. במילים אחרות מצב ההפעלה אינו גורע מביטחון הצופן אלא בשיעור נמוך שצפוי לפחות מכל מצב הפעלה אחר. איבוד הביטחון הנובע מהגדרה זו מביא למסקנה שצופן הבלוקים צריך להיות לפחות 128 סיביות כדי להגיע לרמת ביטחון ראויה לצורך מעשי. לצורך המחשה, אם תג האימות הוא 64 סיביות ולתוקף גישה ל-<math>2^{40}</math> בתים מוצפנים שהוא בחר ושהוצפנו עם אותו מפתח. הסיכויים שלו להצליח לייצר מסר מזויף עם תג אימות תקף ללא ידיעת המפתח כאשר גודל הבלוק הוא 128, הם בערך <math>1.5(2^{40-4})^2/2^{128}+2^{-64}<2^{-55}</math>. בניסוח פורמלי בהינתן יריב בעל עוצמת חישוב מוגבלת וכן שיש לו גישה לאורקל והוא מסוגל להגיש <math>q</math> שאילתות שבסך הכול מסתכמות ב-<math>\sigma</math> בלוקים ואז מנסה לזייף מסר מסוים תוך <math>c</math> ניסיונות, יהי <math>\bar \sigma=\sigma+2q+5c+11</math>, ביטחון שלב האימות של האלגוריתם יהיה 
:<math>\text{Adv}_{\text{OCB}[\text{Perm}(n),\tau]}^{\text{auth}} \ (\text{A})\le 1.5\bar\sigma^2/2^n + 1/2^\tau</math>
ביטחון שלב הסודיות באלגוריתם מוגדר על ידי 
:<math>\text{Adv}_{\text{OCB}[\text{Perm}(n),\tau]}^{\text{priv}} \ (\text{A})\le 1.5\bar\sigma^2/2^n</math>

<math>\text{Adv}</math> הוא היתרון של היריב המנסה לתקוף את המערכת. <math>\text{Perm}</math> מייצג פרמוטציה (PRP). והסימן <math>\text{auth}</math> מייצג את חלק האימות ואילו <math>\text{priv}</math> הוא הסודיות.

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

ב-2002 פרסם ניילס פרגוסון התקפת התנגשויות כנגד OCB המכוונת נגד שלב האימות. ההתקפה מאלצת להגביל את כמות המידע שניתן לאימות עם מפתח יחיד לרמה של 64GB. והוא ממליץ שלא להשתמש במצב הפעלה זה.

==פסאודו-קוד==
<div class="mw-content-ltr">
{| align="center"
|-
| 
<math>\boldsymbol{\textbf{OCB1-ENCRYPT}(K, N, A, P)}</math>
:<math>R = E_K(0^{128})</math>
:<math>L = R \cdot x</math>
:<math>L_0 = L \cdot x</math>
:<math>\text{For }i = 1\text{ to }m\text{ do: }L_i = L_{i-1} \cdot x</math>
: 
:<math>\color{blue}\mathit{m \ is\ the\ largest\ integer\ so\ that\ 128m \le |P|}</math>
:<math>P = P_1 \ \| \ P_2 \ \| \ ... \ \| \ P_m \ \| \ P_*</math>
:<math>\color{blue}\mathit{(Note:\ P_*\ may\ possibly\ be\ empty)}</math>
: 
:<math>\text{Nonce} = \text{num2str}(\text{TAGLEN mod }128, 7) \ \| \ 0^{120-|N|} \ \| \ 1 \ \| \ N</math>
:<math>\text{bottom} = \text{str2num}(\text{Nonce}_{123 \ \text{to} \ 128})</math>
:<math>\text{Ktop} = E_K(\text{Nonce}_{1 \ .. \ 122} || 0^6)</math>
:<math>\text{Stretch} = \text{Ktop} \ \| \ (\text{Ktop}_{1..64} \oplus \text{Ktop}_{9..72})</math>
:<math>\text{offset} = \text{Stretch}_{1+\text{bottom} \ \text{to} \ 128+\text{bottom}}</math>
:<math>\text{checksum} = 0</math>
: 
:<math>\text{For }i = 1\text{ to }m\text{ do:}</math>
::<math>\text{offset} = \text{offset} \oplus L_{\text{ntz}(i)}</math>
::<math>C_i = \text{offset} \oplus E_K(P_i \oplus \text{offset})</math>
::<math>\text{checksum} = \text{checksum} \oplus P_i</math>
: 
:<math>\color{blue}\mathit{Process\ any\ final\ partial\ block\ and\ compute\ raw\ tag}</math>
:<math>\text{offset} = \text{offset} \oplus R</math>
:<math>\text{Pad} = E_K(\text{offset})</math>
:<math>C_* = P_* \oplus \text{Pad}_{1 \ \text{to} \ |P_*|}</math>
:<math>\text{checksum} = \text{checksum} \oplus (P_* \ \| \ 1 \ \| \ 0^{127-|P_*|})</math>
:<math>\text{Tag} = E_K(\text{checksum} \oplus \text{offset} \oplus L) \oplus \text{HASH}(K,A)</math>
:
:<math>\text{Return: }C_1 \ \| \ C_2 \ \| \ ... \ \| \ C_m \ \| \ C_* \ \| \ \text{Tag}_{1 \ \text{to} \ \text{TAGLEN}}</math>
||
<math>\boldsymbol{\textbf{hash}(A,K)}</math>
:<math>\text{sum} = 0</math>
:<math>\text{offset} = 0</math>
:<math>R = E_K(0^{128})</math>
:<math>L = R \cdot x</math> 
:<math>L_0 = L \cdot x</math>
:<math>\text{For }i = 1\text{ to }m\text{ do: }L_i = L_{i-1} \cdot x</math>
:<math>\color{blue}\mathit{m\ is\ the\ largest\ integer\ so\ that\ 128m \le |A|}</math>
:<math>A = A_1 \ \| \ A_2 \ \| \ ... \ \| \ A_m \ \| \ A_*</math>
:<math>\color{blue}\mathit{(Note:\ A_*\ may\ possibly\ be\ empty)}</math>
:<math>\text{For }i=1\text{ to }m\text{ do: }</math>
::<math>\text{offset} = \text{offset} \oplus L_{\text{ntz}(i)}</math>
::<math>\text{sum} = \text{sum} \oplus E_K(A_i \oplus \text{offset})</math>
:<math>\color{blue}\mathit{(process\ final\ partial\ block)}</math>
:<math>\text{offset} = \text{offset} \oplus R</math>
:<math>\text{sum} = \text{sum} \oplus E_K(A_*)</math>
:<math>\text{Return }sum</math>
:
:
:
<math>\textbf{OCB1-DECRYPT}(K, N, A, C)</math>
:<math>\color{blue}\mathit{(process\ OCB-ENCRYPT\ and\ then:)}</math>
:<math>\text{If Tag}_{(1 \ \text{to} \ \text{TAGLEN})} = T \ \text{then return }P</math>
:<math>\text{else return }\textbf{INVALID}</math>
 
|}
</div>

==OCB2==
החסרונות העיקריים ב-OCB הם המחיר של הצפנה נוספת בתהליך ההכנה וכן חישובי האופסטים שדורשים זמן ביצוע לא קבוע. בגרסת OCB2 מ-2004 מוצע פתרון אחר המבוסס על צופן בלוקים בר התאמה להלן תיאור האלגוריתם:

<div class="mw-content-ltr" align="center">
{| class="wikitable" align="center"
|-
| 
<math>\mathbf{OCB2.Encrypt}\boldsymbol{_K^N(M,\tau)}</math>
:<math>\text{Let }M = M[1],M[2],...,M[m]</math>
:<math>\text{For }i\in [1..m-1]\text{ do }C[i]\leftarrow \boldsymbol{\pi}_i^N(M[i])</math>
:<math>\text{Pad}\leftarrow \pi_m^N(\text{len}(M[m]))</math>
:<math>C[m]\leftarrow M[m]\oplus \text{Pad}</math>
:<math>C\leftarrow C[1],C[2],...,C[m]</math>
:<math>\Sigma\leftarrow M[1]\oplus\cdots\oplus M[m-1]\oplus C[m]0^*\oplus\text{Pad}</math>
:<math>\text{Tag}\leftarrow \bar\pi_m^N(\Sigma)</math>
:<math>T\leftarrow\text{Tag}[\text{first }\tau\text{ bits}]</math>
:<math>\text{return }\mathcal{C}=C \ \| \ T</math>
|| 
<math>\mathbf{OCB2.Decrypt}\boldsymbol{_K^N}(\boldsymbol{\mathcal{C}},\tau)</math>
:<math>\text{Let }\mathcal{C} = C[1],C[2],...,C[m],T</math>
:<math>\text{For }i\in [1..m-1]\text{ do }M[i]\leftarrow (\boldsymbol{\pi}_i^N)^{-1}(C[i])</math>
:<math>\text{Pad}\leftarrow \pi_m^N(\text{len}(M[m]))</math>
:<math>M[m]\leftarrow C[m]\oplus \text{Pad}</math>
:<math>M\leftarrow M[1],M[2],...,M[m]</math>
:<math>\Sigma\leftarrow M[1]\oplus\cdots\oplus M[m-1]\oplus C[m]0^*\oplus\text{Pad}</math>
:<math>\text{Tag}\leftarrow \bar\pi_m^N(\Sigma)</math>
:<math>T'\leftarrow\text{Tag}[\text{first }\tau\text{ bits}]</math>
:<math>\text{if }T=T'\text{ then return }M\text{ else return INVALID}</math>
|}
</div>

<math>\text{OCB2}[\tilde{E},\tau]</math> עם צופן בלוקים בר התאמה <math>\tilde{E}:\mathcal{K}\times\mathcal{T}\times\{0,1\}^n\rightarrow\{0,1\}^n</math> המקבל tweak המסומן <math>\mathcal{T}=\{0,1\}\times\{0,1\}^n\times [1..2^{n/2}]\times\{0,1\}</math> (סיבית תחילית, ערך בטווח הרצוי וסיבית סופית) ומייצר בנוסף תג אימות באורך <math>\tau\in [0..n]</math>. למען הפשטות באלגוריתם המתואר הסימן <math>\boldsymbol{\pi}_i^N</math> (כאשר ה-<math>\pi</math> מודגש) מייצג צופן בלוקים בר התאמה <math>\tilde{E}_K^{1\ N\ i\ 0}</math> שבו ה-tweak מורכב מטווח ערכים המיוצג על ידי <math>N</math> בנוסף ל-'1' מוביל, המונה <math>i</math> ו-'0' מסיים באותו אופן <math>\pi_i^N</math> מתאים ל-<math>\tilde{E}_K^{0\ N\ i\ 0}</math> והאחרון <math>\bar\pi_i^N</math> מתאים ל-<math>\tilde{E}_K^{0\ N\ i\ 1}</math>. ההבדלים בין הגרסאות הם בסיבית הפותחת והמסיימת.

==OCB3==
בגרסאות הקודמות בוצעו <math>m+2</math> קריאות לצופן הבלוקים כדי להצפין <math>m</math> בלוקים עם אימות, קריאה ראשונה לייצר את האופסט הראשון מוקטור האתחול, לאחר מכן הצפנת <math>m</math> הבלוקים ולבסוף קריאה אחרונה להצפנת התג. אפשר להיפטר מהקריאה הראשונה לצופן הבלוקים על ידי החלפה בפונקציית גיבוב XOR אוניברסלית מהירה <math>\Delta=H_K(N)=(\text{Stretch}\ll\text{Bottom}[1..128]</math> כאשר <math>\text{Bottom}</math> הוא 6 הסיביות הפחות משמעותיות של <math>N</math> והמחרוזת <math>\text{Stretch}</math> נוצרת על ידי הצפנה של <math>N</math> עם שש הסיביות הפחות משמעותיות מאופסות (הפונקציה מפורטת בהמשך). מבנה זה הוכח כפונקציית גיבוב אוניברסלית. בדרך זו מתבצעות <math>m+1.016</math> קריאות בממוצע לצופן הבלוקים בנוסף לביצוע פונקציית הגיבוב המהירה. ב-OCB3 התג אינו תלוי בטקסט המוצפן מה שמאפשר האצה נוספת בביצועים ביישום מקבילי לעומת הגרסאות הקודמות. כמו כן מסתבר שפעולת כפל בשדה <math>GF(2^{128})</math> סובלת מביצועים גרועים ברוב הפלטפורמות לכן הוחלט על גשה אחרת לקידום המונה מאשר בגרסאות הקודמות. כעת כל הבלוקים מטופלים באותה דרך, גם הבלוק האחרון והם נפרדים זה מזה. שיפור נוסף הוא החלפת צופן הבלוקים בצופן בלוקים בר-התאמה, בדרך זו האלגוריתם פשוט יותר וקל להוכחה.

להלן תיאור האלגוריתם בגרסת <math>\Theta\text{OCB3}[\tilde{E},\tau]</math> מעל צופן בלוקים בר התאמה:
<div class="mw-content-ltr" align="center">
{| class="wikitable" align="center"
|-
| 
<math>\mathbf{OCB3.Encrypt}_{N,K}(M,A)</math>
:<math>\text{let }M=M_1...M_mM_*; \ |M_i|=n, \ |M_*|<n</math>
:<math>\text{Checksum}=0^n, \ C_*=\text{empty}</math>
:<math>\text{For }i=1\text{ to }m\text{ do}</math>
::<math>C_i=\tilde{E}_K^{N \ i}(M_i)</math>
::<math>\text{Checksum}=\text{Checksum}\oplus M_i</math>
:<math>\text{If }M_*=\text{empty then:}</math>
::<math>\text{Final}=\tilde{E}_K^{N \ m \ \$}(\text{Checksum})</math>
:<math>\text{else Pad}=\tilde{E}_K^{N \ m \ *}(0^n)</math>
::::<math>C_*=M_*\oplus\text{Pad}[1..|M_*|]</math>
::::<math>\text{Checksum}=\text{Checksum}\oplus M_*10^*</math>
::::<math>\text{Final}=\tilde{E}_K^{m \ * \ \$}(\text{Checksum})</math>
:<math>\text{Auth}=\text{Hash}_K(A)</math>
:<math>\text{Tag}=\text{Final}\oplus\text{Auth}</math>
:<math>T=\text{Tag}[1..\tau]</math>
:<math>\text{Return }C_1...C_mC_*\ \| \ T</math>
:
<math>\mathbf{Hash}_K(A)</math>
:<math>\text{Sum}=0^n</math>
:<math>\text{let }A=A_1...A_mA_*; \ |A_i|=n, \ |A_*|<n</math>
:<math>\text{For }i=1\text{ to }m\text{ do}</math>
::<math>\text{Sum}=\text{Sum}\oplus\tilde{E}_K^i(A_i)</math>
:<math>\text{If }A_*\ne\text{empty then:}</math>
::<math>\text{Sum}=\text{Sum}\oplus\tilde{E}_K^{m \ *}(A_*10^*)</math>
:<math>\text{Return Sum}</math>
|| 
<math>\mathbf{OCB3.Decrypt}_{K,N}(C \ \| \ T,A)</math>
:<math>\text{let }C=C_1...C_mC_*; \ |C_i|=n,|C_*|<n</math>
:<math>\text{Checksum}=0^n,M_*=\text{empty}</math>
:<math>\text{For }i=1\text{ do }m\text{ do}</math>
::<math>M_i=\tilde{D}_K^{N \ i}(C_i)</math>
::<math>\text{Checksum}=\text{Checksum}\oplus M_i</math>
:<math>\text{If }C_*=\text{empty then:}</math>
::<math>\text{Final}=\tilde{E}_K^{N \ m \ \$}(\text{Checksum})</math>
:<math>\text{else Pad}=\tilde{E}_K^{N \ m \ *}(0^n)</math>
::::<math>M_*=C_*\oplus\text{Pad}[1..|C_*|]</math>
::::<math>\text{Checksum}=\text{Checksum}\oplus M_*10^*</math>
::::<math>\text{Final}=\tilde{E}_K^{N \ m \ * \ \$}(\text{Checksum})</math>
:<math>\text{Auth}=\text{Hash}_K(A)</math>
:<math>\text{Tag}=\text{Final}\oplus\text{Auth}</math>
:<math>T'=\text{Tag}[1..\tau]</math>
:<math>\text{If }T=T'\text{ then return }M_1...M_mM_*</math>
:<math>\text{else return INVALID}</math>
:
:
:
:
:
:
:
:
:
|}
</div>

הסבר: צופן הבלוקים בר התאמה מסומן על ידי <math>\tilde{E}</math> כשגודל הבלוק נקבע ל-128. הוא מקבל מפתח הצפנה, tweak וטקסט קריא ומחזיר טקסט מוצפן (להלן תיאור מפורט כיצד להפוך צופן בלוקים רגיל לצופן בלוקים בר התאמה). הסימן <math>\tau</math> מייצג את אורך תג האימות בסיביות. בנוסף האלגוריתם מקבל את הטקסט הנלווה A. הסימנים * ו-$ מייצגים ערכי tweak שונים בהתאם להיסטים (מבוארים בהרחבה להלן). הביטוי <math>0^n</math> פירושו מחרוזת של <math>n</math> אפסים. בניסוי שערכו המפתחים פיליפ רוגווי וטד קרובץ לטענתם האלגוריתם מהיר הרבה יותר מ-CCM או GCM בניגוד לטענת המפתחים של האלגוריתמים הללו. ביישום ממוטב האלגוריתם יכול הגיע למהירות הצפנה של 1.5 CPB.
הטכניקה להפיכת צופן הבלוקים לצופן בלוקים בר התאמה נעשית כך:
<div class="mw-content-ltr">
{| class="wikitable" align="center"
|-
! colspan="4" | ביטוי !! תיאור
|-
| colspan="4"| <math>L=E_K(0^{128})</math> || הצפנת מחרוזת של 128 אפסים
|-
| <math>\lambda_i=4a(i) \ </math> || <math>\lambda_i^*=4a(i)+1 \ </math> || <math>\lambda_i^\$=4a(i)+2 \ </math> || <math>\lambda_i^{*\$}=4a(i)+3 \ </math> || ארבעה היסטים לפי אינדקס (עם הסימנים *, $ או *$)
|-
| colspan="3" | <math>\tilde{E}_K^{N \ i}(M)=E_K(M\oplus\Delta)\oplus\Delta</math> || <math>\Delta=\text{Initial}\oplus\lambda_iL; \ \ i\ge 1</math> || tweak "N i"
|-
| colspan="3" | <math>\tilde{E}_K^{N \ i \ *}(M)=E_K(X\oplus\Delta)</math> || <math>\Delta=\text{Initial}\oplus\lambda_i^*L; \ \ i\ge 0</math> || tweak "N i *"
|-
| colspan="3" | <math>\tilde{E}_K^{N \ i \ \$}(M)=E_K(M\oplus\Delta)</math> || <math>\Delta=\text{Initial}\oplus\lambda_i^\$L; \ \ i\ge 0</math> || tweak "N i $"
|-
| colspan="3" | <math>\tilde{E}_K^{N \ i \ * \ \$}(M)=E_K(M\oplus\Delta)</math> || <math>\Delta=\text{Initial}\oplus\lambda_i^{*\$}L; \ \ i\ge 1</math> || tweak "N i * $"
|-
| colspan="3" | <math>\tilde{E}_K^{i}(M)=E_K(M\oplus\Delta)</math> || <math>\Delta=\lambda_iL; \ \ i\ge 1</math> || tweak "i"
|-
| colspan="3" | <math>\tilde{E}_K^{i \ *}(M)=E_K(M\oplus\Delta)</math> || <math>\Delta=\lambda_i^*L; \ \ i\ge 0</math> || tweak "i *" 
|}</div>

הסבר: תחילה מצפינים מחרוזת אפסים באמצעות צופן הבלוקים עם מפתח ההצפנה המסופק על ידי המשתמש, לאחר מכן כל בלוק מסר מחובר עם tweak שונה ב-XOR לפני שהוא מוצפן. כדי לייצר את ה-tweak המתאים לכל בלוק, תחילה מייצרים אופסט <math>\lambda</math> מתאים, אותו מכפילים ב-<math>L</math> ומחברים ב-XOR עם תוצאת פונקציית הגיבוב האוניברסלית של המפתח (להלן). את האופסט מכינים על ידי וריאציה של קוד גריי רקורסיבי כשהביטוי <math>a(i-1)\oplus 2^{\text{ntz}(i)}</math> פירושו שכדי לקבל את הקוד ה-<math>i</math> ברצף מחברים ב-XOR את האלמנט הקודם בחזקה של מספר האפסים המסיימים (הפחות משמעותיים) באינדקס <math>i</math>, לדוגמה <math>\text{ntz}(8)=3</math> וכן <math>\text{ntz}(7)=0</math>. את פונקציית הגיבוב האוניברסלית מכינים כך:

<div class="mw-content-ltr">
:::::<math>\text{Nonce}=0^{127-|N|}1N</math>
:::::<math>\text{Top}=\text{Nonce}\land 1^{122}0^6</math>
:::::<math>\text{Bottom}=\text{Nonce}\land 0^{122}1^6</math>
:::::<math>\text{Stretch}=E_K(Top)\ \| \ (E_K(\text{Top})\oplus(E_K(\text{Top})\ll 8))</math>
:::::<math>\text{Initial}=(\text{Stretch}\ll\text{Bottom})[1..128]</math></div>

הסבר: ה-Nonce הוא ערך ייחודי וחד פעמי הנוצר פשוט על ידי וקטור האתחול <math>N</math> המסופק על ידי המשתמש, כשהוא מרופד בסיבית 1 ואפסים במספר הנדרש כדי להשלימו לבלוק שלם באורך 128 סיביות. ואז מחלקים את הבלוק לשני חלקים העליון באורך 122 סיביות והתחתון באורך 6 סיביות (הסימן <math>\land</math> מייצג AND המתפקד כאן כמסכת סיביות), מצפינים את העליון באמצעות צופן הבלוקים עם המפתח <math>K</math>. לאחר הזזה (shift), הצמדה (<math>\|</math>) והצפנה כמתואר התוצאה היא הערך Initial.

==ראו גם==
* CCM
* GCM
* מצב הפעלה של צופן בלוקים

==קישורים חיצוניים==
* 

==הערות שוליים==

קטגוריה:קריפטוגרפיה