Salsa20 הוא צופן זרם שפותח ב-2005 על ידי דניאל ברנשטיין באוניברסיטת אילינוי בשיקגו והוצע עבור פרויקט eSTREAM האירופאי. ב-2008 נבחר על ידי eSTREAM בסיבוב השלישי (Phase 3), כאחד מארבעת האלגוריתמים המובילים במסגרת פרופיל 1 בקטגוריית צופן זרם בתוכנה. הגרעין של Salsa20 הוא פונקציה פסאודו-אקראית הפועלת על קלט ופלט בגודל 64 בתים ומיושמת כצופן זרם במצב מונה. הפונקציה מקבלת מפתח הצפנה סודי באורך 128 או 256 סיביות, ערך ייחודי חד-פעמי באורך 64 סיביות הנקרא Nonce ומשמש כוקטור אתחול, מונה המייצג את מספר הבלוק באורך 64 סיביות וקבועים נוספים. על ידי גיבוב הערכים הללו כשהם משולבים יחד, מייצרת פלט פסאודו-אקראי באורך 64 בתים, אותו מחברים בחיבור בינארי עם בלוק טקסט קריא לקבלת טקסט מוצפן. אפשר להצפין עם מפתח אחד עד {\displaystyle 2^{70}} בתים של מידע. המבנה הזה מעניק לצופן יתרון ביכולת לשחזר כל בלוק ספציפי מהטקסט המוצפן בזמן קבוע. מימוש ממוטב של צופן Salsa יכול להגיע ליעילות בסדר גודל של כמעט 14 מחזורי שעון לבית או כ-643 מגה לשנייה (לעומת RC4 שמגיע לסדר גודל של 200 מגה לשנייה בקירוב). נכון לשנת 2014 נחשב Salsa לצופן בטוח ולא ידוע על התקפה יעילה נגדו.

תיאור האלגוריתם
---------------

Salsa20 הוא צופן זרם סינכרוני (שבו המפתח מופק ללא תלות בטקסט הקריא או המוצפן), הפועל על יחידת מידע בגודל 64 בתים. השלד העיקרי מורכב מפונקציית גיבוב הכוללת שילוב של שלוש פעולות אריתמטיות פשוטות; חיבור מודולו 2^{32} המבוצע במילים בגודל 32 סיביות, חיבור מודולו 2 (המסומן XOR) והזזה מעגלית (rotation) על מילים (הזזה של כל סיביות המילה שמאלה או ימינה במספר פוזיציות לפי פרמטר, כאשר הסיביות הקיצוניות שנפלטות מצד אחד מוחזרות מהצד השני). ומפיקה פלט בגודל 64 בתים פסאודו-אקראיים שמרכיבים את 'המצב הפנימי' של הצופן. פונקציית הגיבוב הופכת לפונקציית הצפנה בשיטת ורנם, שבה תוצאת הגיבוב הופכת למפתח הצפנה מורחב בגודל 16 מילים. בלוק הטקסט הקריא בגודל 16 מילים מוצפן מילה אחר מילה, בדרך זו: {\displaystyle c\_{i}=m\_{i}\oplus k\_{i}}. הפענוח זהה, כיוון ש-XOR הופכי של עצמו. סדר הפעולות בתוך הליבה של Salsa20 הוא "או-מוציא של חיבור לאחר הזזה מעגלית" בקיצור ARX (ראשי תיבות של שלוש הפעולות לפי הסדר האמור). שילוב זה הוכח כבטוח כנגד התקפה דיפרנציאלית (ראה להלן) וכן מבטיח עמידות כנגד התקפת תזמון (timing attack). 

### המצב הפנימי

את המצב ההתחלתי (initial state) של פונקציית הגיבוב של Salsa מאתחלים בערכים הבאים:

1. **8 מילות מפתח**. מפתח ההצפנה המסופק על ידי המשתמש בסך הכול 256 סיביות, מחולק לשמונה מילים של 32 סיביות. במקרה של מפתח 128 סיביות מכפילים פעמיים לקבלת 8 מילים.
2. **2 מילות מונה**. קידוד של מספר שלם בגודל 64 סיביות המזהה את מספר הבלוק הנוכחי, מתחיל באפס ומקודם באחד לאחר כל הצפנה של בלוק, כך שבכל הצפנה מתקבל מפתח אחר. המונה מאפשר לשחזר את זרם המפתח ששימש להצפנת בלוק נתון ובכך לפענחו ללא תלות בבלוקים האחרים.
3. **2 מילות Nonce**. ערך ייחודי בגודל 64 סיביות המשמש פעם אחת בלבד עבור מסר נתון (המכיל בלוק אחד או יותר) ואינו בהכרח סודי. בדרך כלל בוחרים מספר פסאודו-אקראי או מספר רץ. בתקן eSTREAM הוא מכונה וקטור אתחול (iv). ערך זה מבטיח שלא יהיו שני מסרים שונים שיוצפנו באותו מפתח. ייחודיותו של ערך זה באחריות המשתמש.
4. **4 מילים קבועות**. שהם (16 בתים) של קידוד המחרוזת **"expand 32-byte k"** (כולל רווחים) במקרה של מפתח 256 סיביות, או המחרוזת **"expand 16-byte k"** במקרה של מפתח 128 סיביות.

את הערכים המתוארים פורסים לתוך מצב הראשוני ב-64 בתים לפי הסדר הבא. אם המפתח הוא בגודל 256 סיביות (לפי ההמלצה של המַפַתֵּח דניאל ברנשטיין), תחילה ממירים את מחרוזות הטקסט הקבועות לארבע מילים לפי סדר בתים קטן, סך הכול ארבע אותיות במילה. למשל קוד האסקי של "e" הוא {\displaystyle 101} ובייצוג הקסדצימלי {\displaystyle {\mbox{0x65}}}, של "x" הוא {\displaystyle {\mbox{0x78}}} ושל "p" {\displaystyle {\mbox{0x70}}} וכן הלאה. אחרי המרה של המחרוזת למילים בייצוג הקסדצימלי מתקבל: 

{\displaystyle \sigma \_{0}=({\text{65,78,70,61}}),\sigma \_{1}=({\text{6E,64,20,33}}),\sigma \_{2}=({\text{32,2D,62,79}}),\sigma \_{3}=({\text{74,65,20,6B}})}
וקטור האתחול מיוצג על ידי v ומונה הבלוקים מיוצג על ידי i. אם המפתח בגודל 256 סיביות מחלקים אותו לשני מקטעים בני 16 בתים כל אחד {\displaystyle k\_{0},k\_{1}} ומשרשרים את כל החלקים יחד במבנה הבא:

|  | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| בתים | 1-4 | 5-20 | 21-24 | 25-32 | 33-40 | 41-44 | 45-60 | 61-64 |
| ערך | {\displaystyle \sigma \_{0}} | {\displaystyle k\_{0}} | {\displaystyle \sigma \_{1}} | v | i | {\displaystyle \sigma \_{2}} | {\displaystyle k\_{1}} | {\displaystyle \sigma \_{3}} |

עבור מפתח 128 סיביות קיים רק מפתח k אחד בגודל 16 בתים וערכי המחרוזת "expand 16-byte k" בחלוקה למילים הם: 

{\displaystyle \tau \_{0}=({\text{65,78,70,61}}),\tau \_{1}=({\text{6E,64,20,31}}),\tau \_{2}=({\text{36,2D,62,79}}),\tau \_{3}=({\text{74,65,20,6B}})}
והמבנה המתקבל הוא:

|  | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| בתים | 1-4 | 5-20 | 21-24 | 25-32 | 33-40 | 41-44 | 45-60 | 61-64 |
| ערך | {\displaystyle \tau \_{0}} | k | {\displaystyle \tau \_{1}} | v | i | {\displaystyle \tau \_{2}} | k | {\displaystyle \tau \_{3}} |

  

תיאור הפונקציה הפנימית QuarterRound של צופן Salsa
### פונקציית QuarterRound

הפונקציה השוכנת בליבו של צופן סלסה {\displaystyle z\_{0},...z\_{3}={\mbox{QuarterRound}}(y\_{0},...y\_{3})} (ראו תרשים), היא פונקציה הפיכה המקבלת 4 מילים ומפיקה פלט של 4 מילים כדלהלן:

{\displaystyle z\_{1}=y\_{1}\oplus ((y\_{0}\boxplus y\_{3})\lll 7)}
{\displaystyle z\_{2}=y\_{2}\oplus ((z\_{1}\boxplus y\_{0})\lll 9)}
{\displaystyle z\_{3}=y\_{3}\oplus ((z\_{2}\boxplus z\_{1})\lll {13})}
{\displaystyle z\_{0}=y\_{0}\oplus ((z\_{3}\boxplus z\_{2})\lll {18})}
הסימן {\displaystyle \boxplus } מייצג חיבור מודולו 2^{32}, הסימן {\displaystyle \lll } מייצג הזזה מעגלית של משתנה באורך 32 סיביות שמאלה במספר פוזיציות לפי הערך שלימינו והסימן \oplus מייצג XOR. לדוגמה בייצוג הקסדצימלי בחישוב {\displaystyle {\mbox{QuarterRound}}(1,0,0,0)} מתקבל: 
{\displaystyle (z\_{0}={\text{0x8008145}},z\_{1}={\mbox{0x80}},z\_{2}={\text{0x10200}},z\_{3}={\text{0x20500000}})}

### פונקציית RowRound

הפונקציה RowRound מפעילה את הפונקציה QuarterRound על 16 מילים {\displaystyle y\_{0},...y\_{15}} באופן הבא:

{\displaystyle (z\_{0},z\_{1},z\_{2},z\_{3})={\mbox{QuarterRound}}(y\_{0},y\_{1},y\_{2},y\_{3})}
{\displaystyle (z\_{5},z\_{6},z\_{7},z\_{4})={\mbox{QuarterRound}}(y\_{5},y\_{6},y\_{7},y\_{4})}
{\displaystyle (z\_{10},z\_{11},z\_{8},z\_{9})={\mbox{QuarterRound}}(y\_{10},y\_{11},y\_{8};y\_{9})}
{\displaystyle (z\_{15},z\_{12},z\_{13},z\_{14})={\mbox{QuarterRound}}(y\_{15},y\_{12},y\_{13},y\_{14})}
### פונקציית ColumnRound

{\displaystyle {\begin{pmatrix}x\_{0}&x\_{1}&x\_{2}&x\_{3}\\x\_{4}&x\_{5}&x\_{6}&x\_{7}\\x\_{8}&x\_{9}&x\_{10}&x\_{11}\\x\_{12}&x\_{13}&x\_{14}&x\_{15}\end{pmatrix}}}

אם מדמיינים את 16 הבתים לעיל, כמטריצה ריבועית 4x4 מילים (ראו תרשים), הפונקציה ColumnRound דומה לקודמת מלבד זאת שהיא מפעילה את QurterRound על עמודות המטריצה במקום שורות, כדלהלן:

{\displaystyle (y\_{0},y\_{4},y\_{8},y\_{12})={\mbox{QuarterRound}}(x\_{0},x\_{4},x\_{8},x\_{12})}
{\displaystyle (y\_{5},y\_{9},y\_{13},y\_{1})={\mbox{QuarterRound}}(x\_{5},x\_{9},x\_{13},x\_{1})}
{\displaystyle (y\_{10},y\_{14},y\_{2},y\_{6})={\mbox{QuarterRound}}(x\_{10},x\_{14},x\_{2},x\_{6})}
{\displaystyle (y\_{15},y\_{3},y\_{7},y\_{11})={\mbox{QuarterRound}}(x\_{15},x\_{3},x\_{7},x\_{11})}
### פונקציית DoubleRound

שתי הפונקציות המתוארות כשהן משולבות יחד נקראות DoubleRound דהיינו כל מילה מעובדת פעמיים, פעם אחת כחלק משורות במטריצה ופעם אחת כעמודות, בניסוח פורמלי: {\displaystyle {\mbox{DoubleRound}}(x\_{0},...x\_{15})={\mbox{RowRound}}({\mbox{ColumnRound}}(x\_{0},...x\_{15}))}. 

כמו כן, לצורך הפעולות האריתמטיות, המעבר ממערך של ארבעה בתים למילה אחת הוא לפי סדר בתים קטן שאומר שהבית הראשון מייצג את הספרות הפחות משמעותיות של המילה, לכן במחשב עם סדר בתים גדול, יש צורך בפונקציית המרה כדי להמיר מבתים למילים ובחזרה לפי הנוסחה: {\displaystyle b\_{0}+2^{8}b\_{1}+2^{16}b\_{2}+2^{24}b\_{3}}. לדוגמה אם נתון מערך הבתים: {\displaystyle \{b\_{0}=86,b\_{1}=75,b\_{2}=30,b\_{3}=9\}} בהמרה למילה בת 32 סיביות לפי סדר בתים קטן, יתקבל הערך {\displaystyle 152,980,310} (לפי סדר בתים גדול מתקבל {\displaystyle 1,447,763,456}).

אם מסכמים את כל הפעולות יחד, מימוש הפונקציה DoubleRound ייראה כך:



| ColumnRound | RowRound |
| --- | --- |
| {\displaystyle x\_{4}=x\_{4}\oplus {\mbox{ROTL}}\_{7}(x\_{0}\boxplus x\_{12})}
{\displaystyle x\_{8}=x\_{8}\oplus {\mbox{ROTL}}\_{9}(x\_{4}\boxplus x\_{0})}
{\displaystyle x\_{12}=x\_{12}\oplus {\mbox{ROTL}}\_{13}(x\_{8}\boxplus x\_{4})}
{\displaystyle x\_{0}=x\_{0}\oplus {\mbox{ROTL}}\_{18}(x\_{12}\boxplus x\_{8})}
{\displaystyle x\_{9}=x\_{9}\oplus {\mbox{ROTL}}\_{7}(x\_{5}\boxplus x\_{1})}
{\displaystyle x\_{13}=x\_{13}\oplus {\mbox{ROTL}}\_{9}(x\_{9}\boxplus x\_{5})}
{\displaystyle x\_{1}=x\_{1}\oplus {\mbox{ROTL}}\_{13}(x\_{13}\boxplus x\_{9})}
{\displaystyle x\_{5}=x\_{5}\oplus {\mbox{ROTL}}\_{18}(x\_{1}\boxplus x\_{13})}
{\displaystyle x\_{14}=x\_{14}\oplus {\mbox{ROTL}}\_{7}(x\_{10}\boxplus x\_{6})}
{\displaystyle x\_{2}=x\_{2}\oplus {\mbox{ROTL}}\_{9}(x\_{14}\boxplus x\_{10})}
{\displaystyle x\_{6}=x\_{6}\oplus {\mbox{ROTL}}\_{13}(x\_{2}\boxplus x\_{14})}
{\displaystyle x\_{10}=x\_{10}\oplus {\mbox{ROTL}}\_{18}(x\_{6}\boxplus x\_{2})}
{\displaystyle x\_{3}=x\_{3}\oplus {\mbox{ROTL}}\_{7}(x\_{15}\boxplus x\_{11})}
{\displaystyle x\_{7}=x\_{7}\oplus {\mbox{ROTL}}\_{9}(x\_{3}\boxplus x\_{15})}
{\displaystyle x\_{11}=x\_{11}\oplus {\mbox{ROTL}}\_{13}(x\_{7}\boxplus x\_{3})}
{\displaystyle x\_{15}=x\_{15}\oplus {\mbox{ROTL}}\_{18}(x\_{11}\boxplus x\_{7})} | {\displaystyle x\_{1}=x\_{1}\oplus {\mbox{ROTL}}\_{7}(x\_{0}\boxplus x\_{3})}
{\displaystyle x\_{2}=x\_{2}\oplus {\mbox{ROTL}}\_{9}(x\_{1}\boxplus x\_{0})}
{\displaystyle x\_{3}=x\_{3}\oplus {\mbox{ROTL}}\_{13}(x\_{2}\boxplus x\_{1})}
{\displaystyle x\_{0}=x\_{0}\oplus {\mbox{ROTL}}\_{18}(x\_{3}\boxplus x\_{2})}
{\displaystyle x\_{6}=x\_{6}\oplus {\mbox{ROTL}}\_{7}(x\_{5}\boxplus x\_{4})}
{\displaystyle x\_{7}=x\_{7}\oplus {\mbox{ROTL}}\_{9}(x\_{6}\boxplus x\_{5})}
{\displaystyle x\_{4}=x\_{4}\oplus {\mbox{ROTL}}\_{13}(x\_{7}\boxplus x\_{6})}
{\displaystyle x\_{5}=x\_{5}\oplus {\mbox{ROTL}}\_{18}(x\_{4}\boxplus x\_{7})}
{\displaystyle x\_{11}=x\_{11}\oplus {\mbox{ROTL}}\_{7}(x\_{10}\boxplus x\_{9})}
{\displaystyle x\_{8}=x\_{8}\oplus {\mbox{ROTL}}\_{9}(x\_{11}\boxplus x\_{10})}
{\displaystyle x\_{9}=x\_{9}\oplus {\mbox{ROTL}}\_{13}(x\_{8}\boxplus x\_{11})}
{\displaystyle x\_{10}=x\_{10}\oplus {\mbox{ROTL}}\_{18}(x\_{9}\boxplus x\_{8})}
{\displaystyle x\_{12}=x\_{12}\oplus {\mbox{ROTL}}\_{7}(x\_{15}\boxplus x\_{14})}
{\displaystyle x\_{13}=x\_{13}\oplus {\mbox{ROTL}}\_{9}(x\_{12}\boxplus x\_{15})}
{\displaystyle x\_{14}=x\_{14}\oplus {\mbox{ROTL}}\_{13}(x\_{13}\boxplus x\_{12})}
{\displaystyle x\_{15}=x\_{15}\oplus {\mbox{ROTL}}\_{18}(x\_{14}\boxplus x\_{13})} |

הפונקציה {\displaystyle {\mbox{ROTL}}} היא פונקציית הזזה מעגלית לשמאל והמספר התחתי מציין את מספר הפוזיציות שיש להזיז. הזזה מעגלית ניתנת ליישום בתוכנה בקריאה לפונקציית ספרייה או באמצעות הזזות Shift ו-OR המובנות ברוב שפות התיכנות, למשל בשפת C הביטוי: **(value << count) | (value >> (32 - count))** מבצע הזזה מעגלית של **value** במספר פוזיציות לפי **count**.

### פונקציית הגיבוב

פונקציית הגיבוב של Salsa משלבת את הפונקציות האמורות על קלט בגודל 64 בתים, כדי להפיק פלט של 64 בתים פסאודו-אקראיים. בניסוח פורמלי אם נתון המצב הראשוני x המתואר לעיל, הנוסחה היא:

{\displaystyle {\mbox{Salsa20}}(x\_{0},...x\_{15})=(x\_{0},...x\_{15})+{\mbox{DoubleRound}}^{10}(x\_{0},...x\_{15})}.
כלומר מחלקים את הקלט x ל-16 מילים x\_0 עד {\displaystyle x\_{15}}, אותם מחשבים באמצעות פונקציית DoubleRound עשר פעמים. ופלט הפונקציה הוא תוצאת החיבור מודולו 2^{32} עם מילות המצב הראשוני x\_0 עד {\displaystyle x\_{15}}. המציין מעל הפונקציה DoubleRound מייצג את מספר החזרות. כיוון שהפונקציה הפנימית מבוצעת פעמיים (בשורות ובעמודות) מסומן הצופן בקיצור Salsa20, כלומר ביצוע {\displaystyle {\mbox{DoubleRound}}^{10}}, נחשב כ-20 סבבים. כאשר מעוניינים בפונקציית הצפנה מהירה יותר על חשבון ביטחון אפשר להפחית במספר הסבבים. האופציות המומלצות הן 8 או 12 סבבים.

### הצפנה ופענוח

עם פלט פונקציית הגיבוב Slasa20 המתוארת, אפשר להצפין מסר m באורך מקסימלי של {\displaystyle 2^{70}} בתים כשהוא מחולק לבלוקים בגודל 64 בתים, עם וקטור האתחול v, המונה i כאשר {\displaystyle 0\leq i\leq 2^{64}-1} והמפתח k באופן הבא:

{\displaystyle c\_{i}={\mbox{Salsa20}}\_{k}(v,i)\oplus m\_{i}}.
לאחר הצפנת {\displaystyle 2^{70}} בתים יש לאתחל את הצופן עם וקטור אתחול חדש ולהתחיל את המונה מאפס או להחליף מפתח. כאמור v לא חייב להיות סודי אך חייב להיות ייחודי. מעשית יכול להיות מונה כלשהו. לפענוח פועלים באופן זהה לחלוטין:

{\displaystyle m\_{i}={\mbox{Salsa20}}\_{k}(v,i)\oplus c\_{i}}.
למעשה הנוסחה המתוארת מתאימה רק למסר המתחלק ב-64 בתים. אם המסר קטן יותר, או שהבלוק האחרון אינו בגודל 64 בתים, חותכים את תוצאת פונקציית הגיבוב כאורך המסר ומתעלמים מהיתר.

ביטחון ויעילות
--------------

ב-2005 דווח על סוג של ההתקפה דיפרנציאלית נגד גרסה מצומצמת של סלסה בחמשה סבבים, מסומן בקיצור Salsa20/5 בסיבוכיות זמן של {\displaystyle 2^{165}} בקירוב. מפתח ההתקפה זכה באלף דולר מאת דניאל ברנשטיין שהבטיח את הפרס לכל מי שיצליח להציג "קריפטואנליזה הכי מעניינת של סלסה". ב-2006 הצליחו מספר חוקרים לפתח התקפה כנגד Salsa20/6 בסיבוכיות זמן של {\displaystyle 2^{177}} וכן התקפת Related key על Salsa20/7 בזמן של {\displaystyle 2^{217}}. ב-2007 פותחה התקפה על Salsa20/8 בזמן של {\displaystyle 2^{255}} עם {\displaystyle 2^{11.37}} מפתחות. ב-2008 פותחה התקפה נגד Salsa20/7 בזמן של {\displaystyle 2^{153}} וכן התקפה על Salsa20/8 בזמן של {\displaystyle 2^{251}}. ב-2012 התקפה של אמסון ושי כנגד Salsa20/8 הצליחה לשבור את הצופן בזמן של {\displaystyle 2^{109}} או בזמן של {\displaystyle 2^{250}} במקרה של מפתח 256 סיביות עם 8 סבבים. ב-2013 פורסמה הוכחה שצופן סלסה מעל 15 סבבים בטוח כנגד התקפה דיפרנציאלית, כלומר לא נמצאו מאפיינים דיפרנציאליים בהסתברות גבוהה מ-{\displaystyle 2^{-130}} כך שהיא אינה יעילה מכוח גס.

Salsa20 מהיר יותר מ-AES ובמבחני ביצועים של eSTREAM נמצא שבעשרים סבבים הצופן מסוגל להצפין בקצב של 3.93 מחזורי שעון לבית על Xeon בעל ליבה כפולה 3 גיגה-הרץ. כמו כן קיימות שתי גרסאות של הצופן פחותות סבבים הנקראות Salsa20/8 ו-Salsa20/12 עם שמונה סבבים או 12 סבבים בהתאמה, המיועדים למשתמשים הרואים צורך בצופן יעיל ומוכנים להקריב מעט בביטחונו.

ChaCha
------

ב-2008 הציע דניאל ברנשטיין את משפחת ChaCha שהיא גרסה משופרת של צפני זרם החולקת אותם עקרונות תכנון עם Salsa20 אך בשינויים קלים שנועדו בעיקר להגברת רמת הפיזור (diffusion) של הצופן. הפיזור הנוסף אינו בא על חשבון ביצועים, כמו ב-Salsa20 בכל סבב מתבצעים 16 פעולות חיבור, XOR והזזה מעגלית בהיסטים קבועים וכן נשמרת אותה רמת מקביליות ואף יותר. ההערכה היא שגרסאות ChaCha מספקות עמידות גבוהה יותר נגד קריפטואנליזה ומשפרות במעט את הביצועים אם כי רק על פלטפורמות מסוימות. בגלל אחידות כמות העבודה בכל סבב, למספר הסבבים השפעה ישירה על ביצועי הצופן. מסיבה זו הוצעו גרסאות מופחתות סבבים לשיפור ביצועים על חשבון ביטחון. ChaCha8 מבוסס על Salsa20 עם שמונה סבבים, ChaCha12 על Salsa20 עם 12 סבבים בהתאמה. ההבדלים בין צופן Salsa וצופן ChaCha הם כדלהלן:

### פונקציית QuarterRound

פונקציית הסבב הפנימית של ChaCha גם היא מבצעת 4 פעולות חיבור, 4 פעולות XOR ו-4 פעולות הזזה מעגלית על ארבעה משתני המצב הפנימי אך בסדר שונה. ב-Salsa20 כל משתנה מעודכן בפעולה אחת למשל {\displaystyle b=b\oplus ((a\boxplus d)\lll 7)}. לעומתו ב-ChaCha כל מילה מעודכנת פעמיים בנפרד, כך שכל מילת קלט משפיעה על מילות קלט אחרות בשני הכיוונים. אפשר לראות על ידי מעקב אחרי כל סיבית כי ב-ChaCha לפחות 12.5 סיביות בממוצע משתנות בכל סבב לעומת רק 8 ב-Salsa20.



|  |
| --- |
| {\displaystyle a=a+b,\ \ d=d\oplus a,\ \ d=d\lll 16}
{\displaystyle c=c+d,\ \ b=b\oplus c,\ \ \ b=b\lll 12}
{\displaystyle a=a+b,\ \ d=d\oplus a,\ \ d=d\lll 8}
{\displaystyle c=c+d,\ \ b=b\oplus c,\ \ \ b=b\lll 7} |

בנוסף קיים הבדל פחות משמעותי בערכי ההיסטים הקבועים של ההזזה המעגלית 16,12,8,7 לעומת 7,9,13,18 ב-Salsa20. ההשפעה של הבדל זה על ביטחון הצופן זניחה. לעומת זאת קיים שיפור במהירות על פלטפורמות מסוימות.

### מטריצת הקלט

בצופן Salsa20 הקלט המורכב מוקטור אתחול ומונה בלוקים וכן שמונה מילות מפתח וארבע מילים קבועות, נטענים לתוך טבלה או מטריצה ראשונית {\displaystyle 4\times 4} במבנה זה:


|  |  |  |  |
| --- | --- | --- | --- |
| קבוע | מפתח | מפתח | מפתח |
| מפתח | קבוע | קלט | קלט |
| קלט | קלט | קבוע | מפתח |
| מפתח | מפתח | מפתח | קבוע |

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


|  |  |  |  |
| --- | --- | --- | --- |
| קבוע | קבוע | קבוע | קבוע |
| מפתח | קלט | מפתח | מפתח |
| קלט | מפתח | מפתח | קלט |
| מפתח | מפתח | קלט | מפתח |

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


|  |  |  |  |
| --- | --- | --- | --- |
| קבוע | קבוע | קבוע | קבוע |
| מפתח | מפתח | מפתח | מפתח |
| מפתח | מפתח | מפתח | מפתח |
| קלט | קלט | קלט | קלט |

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



|  |
| --- |
| {\displaystyle {\text{QuarterRound}}(x\_{0}\ ,x\_{4}\ ,x\_{8}\ ,x\_{12})} |
| {\displaystyle {\text{QuarterRound}}(x\_{1}\ ,x\_{5}\ ,x\_{9}\ ,x\_{13})} |
| {\displaystyle {\text{QuarterRound}}(x\_{2}\ ,x\_{6}\ ,x\_{10},x\_{14})} |
| {\displaystyle {\text{QuarterRound}}(x\_{3}\ ,x\_{7}\ ,x\_{11},x\_{15})} |
| {\displaystyle {\text{QuarterRound}}(x\_{0}\ ,x\_{5}\ ,x\_{10},x\_{15})} |
| {\displaystyle {\text{QuarterRound}}(x\_{1}\ ,x\_{6}\ ,x\_{11},x\_{12})} |
| {\displaystyle {\text{QuarterRound}}(x\_{2}\ ,x\_{7}\ ,x\_{8}\ ,x\_{13})} |
| {\displaystyle {\text{QuarterRound}}(x\_{3}\ ,x\_{4}\ ,x\_{9}\ ,x\_{14})} |

ארבעת הרבעים של כל סבב תמיד מסודרים מלמעלה למטה מה שמוסיף מהיבט של מהירות. פונקציית הגיבוב BLAKE הנמנית עם רשימת הפינלסטים של תחרות הגיבוב של NIST וגרסת ההמשך שלה BLAKE2 מבוססים על ChaCha.

### שימושים

ב-2014 אימצה גוגל את ChaCha יחד עם קוד אימות מסרים Poly1305 כתחליף ל-RC4 ב-OpenSSL. כמו כן המימוש של גוגל עבור TLS משמש להגנה על תעבורת הרשת (HTTPS) בין דפדפן כרום לאנדרואיד לבין אתרי גוגל. באופן דומה האלגוריתם שולב בפרוטוקול OpenSSH. הצופן ChaCha נכלל גם במערכות ההפעלה OpenBSD ו-NetBSD. וכן הוצע לפרוטוקול IPSec בטיוטה RFC 7539 וטיוטה RFC 7634. פונקציית הגיבוב BLAKE מבוססת על ליבת צופן ChaCha בשינויים מינוריים.

קוד לדוגמה
----------

להלן קוד C++‎ שלם של צופן ChaCha20 המלא (20 סבבים). למען הבהירות הקוד אינו ממוטב והוא תואם את ההמלצה המופיעה באתר המפתח. ההנחה שהמהדר תומך בסדר בתים קטן. הפונקציה ‎\_lrotl‎ היא פונקציית הזזה מעגלית לשמאל הכלולה בספרייה הסטנדרטית של VS. אפשר לשנות את מספר הסבבים בפונקציה ChaCha\_encrypt בקריאה לפונקציה Salsa20\_Rounds בהתאם לצורך, למשל לגרסת שמונה סבבים יש לציין 8 בפרמטר האחרון, ערכים מומלצים הם 8,12 או 20.

```
typedef unsigned char byte;
typedef unsigned int uint;

#define BYTES\_TO\_INT(p) (((uint\*)(p))[0])
#define INT\_TO\_BYTES(p, v) (((uint\*)(p))[0] = (v))
#define ROTATE(v,c) (\_lrotl(v, c))
#define XOR(v,w) ((v) ^ (w))
#define PLUS(v,w) ( (uint)(((v) + (w)) & 0xFFFFFFFF))
#define PLUSONE(v) (PLUS((v),1))

typedef struct
{
 uint input[16];
} ChaCha\_Context;

#define QUARTERROUND(a,b,c,d) \
 x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \
 x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \
 x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \
 x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7);

static const char sigma[] = "expand 32-byte k";
static const char tau[] = "expand 16-byte k";

static void Salsa20\_Rounds(byte output[64], const uint input[16], uint nrounds)
{
 uint x[16];

 for (uint i = 0; i < 16; ++i) 
 x[i] = input[i];

 for (uint i = nrounds; i > 0; i -= 2) {
 QUARTERROUND( 0, 4, 8, 12)
 QUARTERROUND( 1, 5, 9, 13)
 QUARTERROUND( 2, 6, 10, 14)
 QUARTERROUND( 3, 7, 11, 15)
 QUARTERROUND( 0, 5, 10, 15)
 QUARTERROUND( 1, 6, 11, 12)
 QUARTERROUND( 2, 7, 8, 13)
 QUARTERROUND( 3, 4, 9, 14)
 }
 for (uint i = 0; i < 16; ++i) 
 x[i] = PLUS(x[i], input[i]);

 for (uint i = 0; i < 16; ++i) 
 INT\_TO\_BYTES(output + 4 \* i, x[i]);
}

void ChaCha\_keysetup(ChaCha\_Context \*ctx, const byte \*k, uint kbits, uint ivbits)
{
 const char \*constants;

 ctx->input[4] = BYTES\_TO\_INT(k + 0);
 ctx->input[5] = BYTES\_TO\_INT(k + 4);
 ctx->input[6] = BYTES\_TO\_INT(k + 8);
 ctx->input[7] = BYTES\_TO\_INT(k + 12);

 if (kbits == 256) { // recommended
 k += 16;
 constants = sigma;
 }
 else { // kbits == 128
 constants = tau;
 }
 ctx->input[8] = BYTES\_TO\_INT(k + 0);
 ctx->input[9] = BYTES\_TO\_INT(k + 4);
 ctx->input[10] = BYTES\_TO\_INT(k + 8);
 ctx->input[11] = BYTES\_TO\_INT(k + 12);
 ctx->input[0] = BYTES\_TO\_INT(constants + 0);
 ctx->input[1] = BYTES\_TO\_INT(constants + 4);
 ctx->input[2] = BYTES\_TO\_INT(constants + 8);
 ctx->input[3] = BYTES\_TO\_INT(constants + 12);
}

void ChaCha\_ivsetup(ChaCha\_Context \*ctx, const byte \*iv)
{
 ctx->input[12] = 0;
 ctx->input[13] = 0;
 ctx->input[14] = BYTES\_TO\_INT(iv + 0);
 ctx->input[15] = BYTES\_TO\_INT(iv + 4);
}

void ChaCha\_encrypt(ChaCha\_Context \*ctx, const byte \*m, byte \*c, uint bytes)
{
 byte output[64];

 if (!bytes) return;
 for (;;) {
 Salsa20\_Rounds(output, ctx->input, 20);
 ctx->input[12] = PLUSONE(ctx->input[12]);
 if (!ctx->input[12]) {
 ctx->input[13] = PLUSONE(ctx->input[13]);
 // stopping at 2^70 bytes per nonce is user's responsibility
 }
 if (bytes <= 64) {
 for (uint i = 0; i < bytes; ++i) c[i] = m[i] ^ output[i];
 return;
 }
 for (uint i = 0; i < 64; ++i) c[i] = m[i] ^ output[i];
 bytes -= 64;
 c += 64;
 m += 64;
 }
}

```

וקטור בדיקה
-----------

מפתח (32 בתים):

|  |
| --- |
| 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |

וקטור אתחול (8 בתים):

|  |
| --- |
| 00 00 00 00 00 00 00 00 |

מספר סבבים: 20

64 בתים פסאודו אקראיים הראשונים של פלט הצופן בבסיס הקסדצימלי:

|  |
| --- |
| 76 b8 e0 ad a0 f1 3d 90 40 5d 6a e5 53 86 bd 28
bd d2 19 b8 a0 8d ed 1a a8 36 ef cc 8b 77 0d c7
da 41 59 7c 51 57 48 8d 77 24 e0 3f b8 d8 4a 37
6a 43 b8 f4 15 18 a1 1c c3 87 b6 69 b2 ee 65 86 |

ראו גם
------

* צופן זרם
* RC4

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

1. ↑  Snuffle 2005: the Salsa20 encryption function
2. ↑  eSTREAM: the ECRYPT Stream Cipher Project
3. ↑  Truncated differential cryptanalysis of five rounds of Salsa20
4. ↑  Simon Fischer, Willi Meier, Côme Berbain, Jean-Francois Biasse, Matt Robshaw, Non-Randomness in eSTREAM Candidates Salsa20 and TSC-4, Indocrypt 2006
5. ↑  Yukiyasu Tsunoo, Teruo Saito, Hiroyasu Kubo, Tomoyasu Suzaki and Hiroki Nakashima (2007-01-02)
6. ↑  Zhenqing Shi, Bin Zhang, Dengguo Feng, Wenling Wu (2012): „Improved Key Recovery Attacks on Reduced-Round Salsa20 and ChaCha". Information Security and Cryptology – ICISC 2012. Springer Verlag, 2013, pp. 337-351
7. ↑  Nicky Mouha, Bart Preneel (2013)
8. ↑  The Salsa20 family of stream ciphers
9. ↑  The ChaCha family of stream ciphers
10. ↑  ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS) draft-ietf-tls-chacha20-poly1305-04
11. ↑  Google Swaps Out Crypto Ciphers in OpenSSL
12. ↑  Super User's BSD Cross Reference: PROTOCOL.chacha20poly1305
13. ↑  The ChaCha family of stream ciphers

  


| קריפטוגרפיה |
| --- |
| 

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

 |
| 

| הצפנה קלאסית |
| --- |
| מכונת הצפנה • צופן החלפה • צופן אתב"ש • צופן קיסר • צופן ויז'נר • צופן ורנם • צופן פלייפייר • צופן היל • אולטרה • אניגמה • ציקלומטר • קולוסוס • PURPLE • ג'ייד • מג'יק • צופן שחלוף |

 |
| 

| צופן בלוקים |
| --- |
| לוציפר • AES • 3DES • DES • Threefish • Twofish • Blowfish • FEAL • SEED • CAST • IDEA • RC2 • RC6 • MARS • RC5 • GOST • סרפנט • MISTY • KASUMI • קמליה • ARIA • SAFER • TEA • LEA • CLEFIA • SEA • Hummingbird • PRESENT • KATAN • KeeLoq • Simon & Speck • אנוביס |

 |
| 

| אופני הפעלה |
| --- |
| אופן הפעלה של צופן בלוקים • EAX • OCB • IAPM • CWC mode • GCM • CCM |

 |
| 

| צופן זרם |
| --- |
| RC4 • Salsa20 • SOSEMANUK • גריין • E0 • A5/1 • A5/2 • A5/3 • A5/4 • MICKEY • HC-128 • SNOW • Trivium • Rabbit • ZUC • ChaCha |

 |
| 

| הצפנה אסימטרית |
| --- |
| פרוטוקול דיפי-הלמן • חידות מרקל • חתימת למפורט • הצפנת תרמיל • RSA • הצפנת רבין • חתימה דיגיטלית רבין • צופן אל-גמאל • חתימה דיגיטלית אל-גמאל • DSA • הצפנת בלום-גולדווסר • ECC • הצפנת קריימר-שופ • הצפנת פאיי • הצפנת מקאליס • GGH • NTRU • עקום 25519 • חתימה דיגיטלית של שנור • הצפנת אוקמוטו-אושיאמה |

 |
| 

| פרוטוקולים |
| --- |
| עץ מרקל • פרוטוקול אתגר-מענה • פרוטוקול נידהאם-שרודר • פרוטוקול קרברוס • הוכחה באפס ידע • פרוטוקול פייגה-פיאט-שמיר • העברה עלומה • חלוקת סוד • TLS (SSL) • Secure Shell • MQV • X.509 • פרוטוקול שיתוף מפתח
• מיסור שלא לפרסום • פרוטוקול סיגנל |

 |
| 

| פרימיטיבים תאורטיים |
| --- |
| מחולל פסבדו-אקראי קריפטוגרפי • פונקציה חד-כיוונית • תמורה חד-כיוונית • סיבית קשה • פונקציה פסבדו-אקראית קריפטוגרפית • תמורה פסאודו-אקראית • פונקציית גיבוב קריפטוגרפית • וקטור אתחול • פונקציית ספוג • הצפנה מבוססת סריג |

 |
| 

| קריפטואנליזה |
| --- |
| ניתוח תדירויות • כוח גס • התקפת איזון זמן/זיכרון • תקיפת היפגשות באמצע • קריפטואנליזה ליניארית • קריפטואנליזה דיפרנציאלית • התקפת גלוי-ידוע • התקפת גלוי-נבחר • התקפת מוצפן-נבחר • פירוק לגורמים של מספר שלם • התקפת ערוץ צדדי • התקפת קורלציה • התקפת שיבוש • מודל אורקל אקראי • התקפת התנגשויות |

 |
| 

| בעיות מתמטיות ואלגוריתמים |
| --- |
| בעיית לוגריתם דיסקרטי • תחשיב אינדקסים • נפה ריבועית • אלגוריתם rho של פולרד • נפת שדה מספרים • אלגוריתם רו של פולרד ללוגריתמים • אלגוריתם פוליג-הלמן |

 |
| 

| פונקציות גיבוב קריפטוגרפיות |
| --- |
| SHA • MD5 • MD4 • SHA-1 • SHA-2 • SHA-3 • RIPEMD • Skein • BLAKE • Grøstl • SipHash |

 |
| 

| אימות וזיהוי |
| --- |
| אימות זהות • סיסמה • קוד אימות מסרים • Poly1305 • סיסמה חד-פעמית |

 |
| 

| נושאים נלווים |
| --- |
| מספר אקראי • מספר ראשוני • יתירות • מפתח שיחה • סטגנוגרפיה • הצפנה קוונטית • הצפנה פוסט-קוונטית • עקרון קרקהופס • אבטחת מידע • קריפטוגרפיה ויזואלית • אליס ובוב • מסיבת חתימה על מפתחות ציבוריים • שידור מוצפן • הצפנת דיסקים • הצפנת סף • חתימה דיגיטלית מבוססת פונקציית גיבוב • פונקציה זניחה • רשת פייסטל • רשת החלפה-תמורה • הלבנה • אימות מסרים • חתימה עיוורת • חישוב רב משתתפים בטוח |

 |