ARIA (צופן)

בקריפטוגרפיה, ARIA הוא צופן בלוקים סימטרי שפותח ב-2004 על ידי קבוצת חוקרים ב-NSRI עבור המשרד לתקנים וטכנולוגיה של דרום קוריאה (KATS), החבר בגופי התקינה הבינלאומיים ISO ו-IEC. האלגוריתם בנוי מרשת החלפה-תמורה אינוולוציונית ולמעשה המפרט והממשק שלו דומים במידה רבה ל-AES. הוא מקבל בלוק טקסט קריא באורך 128 סיביות ומפתח הצפנה בשלושה אורכים אפשריים: 128, 192 או 256 סיביות ומפיק מהטקסט הקריא בלוק מוצפן באורך 128 סיביות. הוא עושה שימוש בתיבות החלפה (Sbox) בגודל 8 × 8 {\displaystyle 8\times 8} סיביות המבוססות על תיבות ההחלפה של ריינדל והוא פועל ב-12, 14, או 16 סבבים בהתאם לאורך המפתח. תהליך הכנת מפתח ההצפנה מרחיב את המפתח המסופק על ידי המשתמש באמצעות רשת פייסטל משולשת בתוספת קבועים שהם הייצוג הבינארי של π − 1 {\displaystyle \pi ^{-1}} (זאת במטרה להוכיח שאינו מכיל דלתות סתר). האלגוריתם הפך לתקן רשמי של KATS וכן IETF, הוצע בטיוטה RFC 5794 וכן הוצע כתוסף לפרוטוקול SSL/TLS בטיוטה RFC 6209. ביטחונו נחקר היטב על ידי מומחי הצפנה, ביניהם ניתן למנות כמה מחקרים שמראים שהצופן בטוח לשימוש בגרסה העדכנית שלו ולא נמצאו בו פגמים רציניים. ARIA 0.8 הוצע לראשונה ב-2003 בוועידה השנתית לאבטחת מידע של דרום קוריאה. בתחילה הצופן הכיל רק 10, 12, או 14 סבבים בהתאם לאורך המפתח 128/192/256 והכיל רק שתי תיבות החלפה בהן נעשה שימוש לסירוגין. בגרסה 0.9 שהוצעה ב-ICIS 2003 נוספו שתי תיבות החלפה. גרסה 1.0 הנוכחית הוכרזה והופצה על ידי NSRI ב-2004. מספר הסבבים עלה ל-12/14/16 בהתאמה וכן בוצעו שינויים בתהליך הרחבת המפתח. בדצמבר 2004 הכניס מכון התקנים של דרום קוריאה את הצופן לתקן KS X 1213. ARIA מתאים ליישום בחומרת 8 ביט וכן ב-32 ביט הן בתוכנה והן בחומרה. רוב הפעולות בצופן הן פעולות החלפה פשוטות אותן אפשר לבצע ביעילות עם טבלאות חיפוש (lookup table). אם הזיכרון זמין ניתן להמיר את שכבת הפיזור להכפלה בארבע מטריצות וכן אפשר לשלב את שכבת ההחלפה יחד עם שכבת הפיזור באופן יעיל ולהשיג בכך שיפור משמעותי בתפוקת הצופן. באופן כללי תפוקת ARIA דומה לזו של AES וטובה מקמליה. הצופן בנוי מרשת החלפה תמורה המבצעת סדרה של פעולות הפיכות על בלוק קלט באורך 128 סיביות הנקרא "מצב" (state) באופן אחיד. הפעולות הן ברמה של בתים והמצב הפנימי מיוצג כמערך המכיל 16 בתים. הצופן מבצע את פעולות המצב באופן חוזר ונשנה 12, 14 או 16 פעמים בהתאם לאורך המפתח. עבור מפתח 128 סיביות מבוצעים בסך הכול 12 סבבים, עבור מפתח באורך 192 סיביות מבוצעים בסך הכול 14 סבבים ואילו עבור מפתח באורך 256 סיביות מבוצעים 16 סבבים. המצב הפנימי מאותחל בתחילה עם סיביות הקלט, בכל סבב הצופן מעדכן את המצב והפלט הסופי הוא המצב האחרון לאחר כל הסבבים. פעולות הצופן מחולקות לשלושה מרכיבים: הוספת מפתח הסבב. בשלב זה קטע מהמפתח המורחב המתאים לסבב הנוכחי מחובר ב-XOR עם המצב הפנימי והתוצאה נשמרת כמצב החדש. שכבת החלפה. בשכבת ההחלפה המצב הפנימי מוחלף בית אחר בית לפי טבלאות החלפה קבועות. ישנן ארבע תיבות החלפה שבהן משתמשים לסירוגין לפי סדר המתואר בהמשך. שכבת פיזור. בשכבת הפיזור המצב הפנימי מוכפל במטריצה בינארית הפיכה קבועה מסדר 16x16 סיביות. כמו כן פעולת הרחבת המפתח מקבלת את המפתח הסודי המסופק על ידי המשתמש ומרחיבה אותו בסך הכול ל-13, 15 או 17 מקטעים באורך 16 בתים כל אחד, בהתאם לאורך המפתח. כלומר 13 מקטעים עבור מפתח באורך 128 סיביות, 15 מקטעים עבור מפתח באורך 192 סיביות ו-17 מקטעים עבור מפתח באורך 256. הסיבה היא משום שבסבב האחרון במקום שכבת הפיזור מבוצעת שכבת הוספת המפתח פעם נוספת, ראו תרשים. הפעולות הבאות מבוצעות על כל בתי המצב באופן אחיד. בשכבת ההחלפה (substitution layer) משתמש ARIA בשתי תיבות החלפה S 1 {\displaystyle S_{1}} ו- S 2 {\displaystyle S_{2}} וכן התיבות ההופכיות שלהן S 1 − 1 {\displaystyle S_{1}^{-1}} ו- S 2 − 1 {\displaystyle S_{2}^{-1}} . תיבות ההחלפה נתונות בארבע הטבלאות להלן. הטבלאות בנויות מ-16 שורות ו-16 עמודות, בסך הכול 256 כניסות, כל כניסה מכילה מספר באורך 8 סיביות בטווח בין 0 ל-256 (או שתי ספרות הקסדצימליות בין 0x00 {\displaystyle {\text{0x00}}} ל- 0xff {\displaystyle {\text{0xff}}} ). הקלט לפונקציית ההחלפה הוא בית אחד המשמש כאינדקס לשורה והעמודה בטבלה, הניבל הראשון (ספרה הקסדצימלית ראשונה בטווח בין 0 ל-15) מציין עמודה ואילו הניבל השני מציין שורה. למשל אם הקלט הוא 0x00 {\displaystyle {\text{0x00}}} הטבלה S 1 {\displaystyle S_{1}} תחזיר 0x63 {\displaystyle {\text{0x63}}} (בבסיס הקסדצימלי) ואילו הטבלה S 2 {\displaystyle S_{2}} תחזיר 0xe2 {\displaystyle {\text{0xe2}}} וכן S 1 − 1 ( 0x95 ) = 0xad {\displaystyle S_{1}^{-1}({\text{0x95}})={\text{0xad}}} או S 2 − 1 ( 0x48 ) = 0x67 {\displaystyle S_{2}^{-1}({\text{0x48}})={\text{0x67}}} : הצופן עושה שימוש בתיבות ההחלפה בשני אופנים (כמתואר בתרשים לעיל). באופן הראשון הנקרא type 1 הבית הראשון מוחלף לפי התיבה הראשונה S 1 {\displaystyle S_{1}} הבית השני לפי התיבה S 2 {\displaystyle S_{2}} , השלישי והרביעי לפי ההופכיות שלהן S 1 − 1 {\displaystyle S_{1}^{-1}} ו- S 2 − 1 {\displaystyle S_{2}^{-1}} בהתאמה, החמישי והשישי שוב בתיבה הראשונה והשנייה וחוזר חלילה עד שמחליפים את כל בתי המצב. באופן השני הנקרא type 2 מבצעים את ההחלפה בסדר הפוך תחילה בתיבות ההופכיות S 1 − 1 {\displaystyle S_{1}^{-1}} ו- S 2 − 1 {\displaystyle S_{2}^{-1}} ולאחר מכן S 1 {\displaystyle S_{1}} ו- S 2 {\displaystyle S_{2}} לסירוגין, כמתואר בתרשים להלן. הפסאודו קוד הבא מתאר את פונקציות ההחלפה S L 1 {\displaystyle SL_{1}} ו- S L 2 {\displaystyle SL_{2}} לפי type 1 ו-type 2 בהתאמה, הקלט הוא המצב הנוכחי X = x 0 , . . . , x 15 {\displaystyle X=x_{0},...,x_{15}} והפלט הוא המצב החדש Y = y 0 , . . . , y 15 {\displaystyle Y=y_{0},...,y_{15}} : שכבת הפיזור היא פונקציה המסומנת באות A הממפה קלט באורך 16 בתים ( x 0 , x 1 , . . . , x 15 ) {\displaystyle (x_{0},x_{1},...,x_{15})} לפלט באורך דומה ( y 0 , y 1 , . . . , y 15 ) {\displaystyle (y_{0},y_{1},...,y_{15})} והיא מוגדרת כדלהלן: שכבת הפיזור של ARIA תוכננה כך שהיא תהיה אינוולוציה כלומר עבור כל וקטור x {\displaystyle x} מתקיים A ( A ( x ) ) = x {\displaystyle A(A(x))=x} . דרך אחרת להציג את המיפוי של A {\displaystyle A} היא על ידי כפל מטריצות הבא: בכל סבב של צופן ARIA מופעלת אחת משתי הפונקציות F e {\displaystyle F_{e}} ו- F o {\displaystyle F_{o}} שהן פונקציות סבב זוגית ואי זוגית בהתאמה המבצעות את שלוש הפעולות המתוארות לפי הסדר: הוספת מפתח, החלפה ופיזור, או בניסוח רשמי: F o ( P i , e k i ) = A ( S L 1 ( P i ⊕ e k i ) ) {\displaystyle F_{o}(P_{i},ek_{i})=A(SL_{1}(P_{i}\oplus ek_{i}))} F e ( P i , e k i ) = A ( S L 2 ( P i ⊕ e k i ) ) {\displaystyle F_{e}(P_{i},ek_{i})=A(SL_{2}(P_{i}\oplus ek_{i}))} כאשר P i {\displaystyle P_{i}} הוא הבלוק הקלט של סבב i {\displaystyle i} ו- A {\displaystyle A} היא פונקציית הפיזור, S L i {\displaystyle SL_{i}} מתייחס לשכבת ההחלפה והערכים e k i {\displaystyle ek_{i}} הם מפתחות הסבב אותם מכינים לפי תיאור תהליך הכנת המפתחות להלן. ההבדל בין שתי הפונקציות הוא סדר ההחלפה, ב- F o {\displaystyle F_{o}} ההחלפה מבוצעת לפי type 1 ואילו F e {\displaystyle F_{e}} היא לפי type 2. תהליך ההכנה של מפתחות ההצפנה עבור כל הסבבים כולל שני שלבים: בשלב הראשון מכינים ארבעה ערכים באורך 128 סיביות כל אחד המסומנים W 0 , W 1 , W 2 , W 3 {\displaystyle W_{0},W_{1},W_{2},W_{3}} בהם מציבים את המפתח הסודי M K {\displaystyle MK} (מפתח מאסטר) שהוא המפתח הסודי שסופק על ידי המשתמש, תוך שימוש ברשת פייסטל בשלושה סבבים לפי השיטה הבאה. תחילה מחלקים את המפתח הסודי לשני חצאים ימין ושמאל, כלומר מציבים את 128 הסיביות הראשונות של M K {\displaystyle MK} במשתנה זמני K L {\displaystyle KL} ומה שנותר מהמפתח מציבים במשתנה זמני נוסף K R {\displaystyle KR} . יתר סיביות המשתנה הזמני K R {\displaystyle KR} מאופסות. כך שמתקבל: K L   ‖   K R = M K   ‖   0...0 {\displaystyle KL\ \|\ KR=MK\ \|\ 0...0} הסימן ‖ {\displaystyle \|} מייצג שרשור. בשלב השני מיישמים את רשת פייסטל בשלושה סבבים כך: הפונקציות F e {\displaystyle F_{e}} ו- F o {\displaystyle F_{o}} הן פונקציות הסבב המתוארות לעיל כאשר הקבועים C K i {\displaystyle CK_{i}} משמשים כמפתחות הצפנה. כדי להכין את הקבועים C K i {\displaystyle CK_{i}} תחילה מחשבים את 128 × 3 {\displaystyle 128\times 3} הסיביות הראשונות של חלק השבר של π − 1 {\displaystyle \pi ^{-1}} כשהן מחולקות לשלושה המשתנים. הערכים הם: C 1 = 0x517cc1b727220a94fe12abe8fa9a6ee0 {\displaystyle C_{1}={\text{0x517cc1b727220a94fe12abe8fa9a6ee0}}} C 2 = 0x6db14acc9e21c820ff28b1d5ef5de2b0 {\displaystyle C_{2}={\text{0x6db14acc9e21c820ff28b1d5ef5de2b0}}} C 3 = 0xdb92371d2126e9700324977504e8c90e {\displaystyle C_{3}={\text{0xdb92371d2126e9700324977504e8c90e}}} ואז הקבועים C K i {\displaystyle CK_{i}} מוגדרים בהתאם לאורך המפתח, לדוגמה עבור מפתח 128 סיביות משתמשים בקבועים לפי הסדר הזה ואילו עבור מפתחות אחרים משנים את סדר הקבועים לפי הטבלה הבאה: את מפתחות כל הסבבים מכינים על ידי שילוב של ערכי W i {\displaystyle W_{i}} ומהם מייצרים את 17 מפתחות ההצפנה והפענוח עבור כל הסבבים: הביטוי ⋘ n {\displaystyle \lll ^{n}} פירושו הזזה מעגלית ברמה של סיביות n {\displaystyle n} צעדים לשמאל בגבולות משתנה באורך 32 סיביות. יש לשים לב שקיים מפתח סבב נוסף מעבר למספר הסבבים. מפתח זה נועד לשימוש בסבב האחרון שבו הטרנספורמציה A מוחלפת בשכבת הוספת מפתח נוספת. בסיכומו של דבר מספר המפתחות הדרוש הוא 13, 15 או 17 בהתאם לאורך המפתח. מפתחות הפענוח נגזרים ממפתחות ההצפנה כדלהלן: d k 1 = e k n − 1 , d k 2 = A ( e k n ) , d k 3 = A ( e k n − 1 ) , . . . , d k n = A ( e k 2 ) , d k n + 1 = e k 1 {\displaystyle dk_{1}=ek_{n-1},dk_{2}=A(ek_{n}),dk_{3}=A(ek_{n-1}),...,dk_{n}=A(ek_{2}),dk_{n+1}=ek_{1}} . להצפנת בלוק טקסט קריא P {\displaystyle P} באורך 16 בתים עם מפתח באורך 128 סיביות, משתמשים ב-13 מפתחות הסבבים e k 1 , e k 2 , . . . , e k 13 {\displaystyle ek_{1},ek_{2},...,ek_{13}} מתהליך הכנת המפתחות לעיל ומבצעים: C {\displaystyle C} הוא הטקסט המוצפן. הפונקציות F e {\displaystyle F_{e}} ו- F o {\displaystyle F_{o}} הן פונקציות הסבב המתוארות לעיל. בסבב האחרון הושמטה פונקציית הפיזור A ובמקומה מבוצע חיבור עם המפתח ה-13. במקרה של מפתחות אחרים המבנה נותר זהה ורק מספר הסבבים משתנה. פונקציית הפענוח של ARIA זהה לחלוטין לפונקציית ההצפנה למעט מפתחות הסבבים המוחלפים ב- d k 1 , d k 2 , . . . , d k 13 {\displaystyle dk_{1},dk_{2},...,dk_{13}} אותם מכינים ממפתחות ההצפנה כמתואר לעיל. להלן וקטור בדיקה של הצפנה עם מפתח באורך 256 סיביות: typedef unsigned int uint; typedef unsigned char byte; #define ARIA_BLOCK_SIZE 16 #define MODE_ENC 0 #define MODE_DEC 1 #define SWAPINT32(x) ( \ (((x) & 0x000000FFUL) << 24) | (((x) & 0x0000FF00UL) << 8) | \ (((x) & 0x00FF0000UL) >> 8) | (((x) & 0xFF000000UL) >> 24)) typedef struct { uint nr; uint k[16]; uint ek[68]; uint dk[68]; bool mode = false; } AriaContext; //Move operation #define MOV128(b, a) \ { \ (b)[0] = (a)[0]; (b)[1] = (a)[1]; \ (b)[2] = (a)[2]; (b)[3] = (a)[3]; \ } //XOR operation #define XOR128(b, a) \ { \ (b)[0] ^= (a)[0]; (b)[1] ^= (a)[1]; \ (b)[2] ^= (a)[2]; (b)[3] ^= (a)[3]; \ } //Rotate left operation #define ROL128(b, a, n) \ { \ (b)[0] = ((a)[((n) / 32 + 0) % 4] << ((n) % 32)) | ((a)[((n) / 32 + 1) % 4] >> (32 - ((n) % 32))); \ (b)[1] = ((a)[((n) / 32 + 1) % 4] << ((n) % 32)) | ((a)[((n) / 32 + 2) % 4] >> (32 - ((n) % 32))); \ (b)[2] = ((a)[((n) / 32 + 2) % 4] << ((n) % 32)) | ((a)[((n) / 32 + 3) % 4] >> (32 - ((n) % 32))); \ (b)[3] = ((a)[((n) / 32 + 3) % 4] << ((n) % 32)) | ((a)[((n) / 32 + 0) % 4] >> (32 - ((n) % 32))); \ } //Substitution layer SL1 #define SL1(b, a) \ { \ byte *x = (byte *) (a); \ byte *y = (byte *) (b); \ y[0] = sb1[x[0]]; y[1] = sb2[x[1]]; \ y[2] = sb3[x[2]]; y[3] = sb4[x[3]]; \ y[4] = sb1[x[4]]; y[5] = sb2[x[5]]; \ y[6] = sb3[x[6]]; y[7] = sb4[x[7]]; \ y[8] = sb1[x[8]]; y[9] = sb2[x[9]]; \ y[10] = sb3[x[10]]; y[11] = sb4[x[11]]; \ y[12] = sb1[x[12]]; y[13] = sb2[x[13]]; \ y[14] = sb3[x[14]]; y[15] = sb4[x[15]]; \ } //Substitution layer SL2 #define SL2(b, a) \ { \ byte *x = (byte *) (a); \ byte *y = (byte *) (b); \ y[0] = sb3[x[0]]; y[1] = sb4[x[1]]; \ y[2] = sb1[x[2]]; y[3] = sb2[x[3]]; \ y[4] = sb3[x[4]]; y[5] = sb4[x[5]]; \ y[6] = sb1[x[6]]; y[7] = sb2[x[7]]; \ y[8] = sb3[x[8]]; y[9] = sb4[x[9]]; \ y[10] = sb1[x[10]]; y[11] = sb2[x[11]]; \ y[12] = sb3[x[12]]; y[13] = sb4[x[13]]; \ y[14] = sb1[x[14]]; y[15] = sb2[x[15]]; \ } //Diffusion layer #define A(b, a) \ { \ byte *x = (byte *) (a); \ byte *y = (byte *) (b); \ y[0] = x[3] ^ x[4] ^ x[6] ^ x[8] ^ x[9] ^ x[13] ^ x[14]; \ y[1] = x[2] ^ x[5] ^ x[7] ^ x[8] ^ x[9] ^ x[12] ^ x[15]; \ y[2] = x[1] ^ x[4] ^ x[6] ^ x[10] ^ x[11] ^ x[12] ^ x[15]; \ y[3] = x[0] ^ x[5] ^ x[7] ^ x[10] ^ x[11] ^ x[13] ^ x[14]; \ y[4] = x[0] ^ x[2] ^ x[5] ^ x[8] ^ x[11] ^ x[14] ^ x[15]; \ y[5] = x[1] ^ x[3] ^ x[4] ^ x[9] ^ x[10] ^ x[14] ^ x[15]; \ y[6] = x[0] ^ x[2] ^ x[7] ^ x[9] ^ x[10] ^ x[12] ^ x[13]; \ y[7] = x[1] ^ x[3] ^ x[6] ^ x[8] ^ x[11] ^ x[12] ^ x[13]; \ y[8] = x[0] ^ x[1] ^ x[4] ^ x[7] ^ x[10] ^ x[13] ^ x[15]; \ y[9] = x[0] ^ x[1] ^ x[5] ^ x[6] ^ x[11] ^ x[12] ^ x[14]; \ y[10] = x[2] ^ x[3] ^ x[5] ^ x[6] ^ x[8] ^ x[13] ^ x[15]; \ y[11] = x[2] ^ x[3] ^ x[4] ^ x[7] ^ x[9] ^ x[12] ^ x[14]; \ y[12] = x[1] ^ x[2] ^ x[6] ^ x[7] ^ x[9] ^ x[11] ^ x[12]; \ y[13] = x[0] ^ x[3] ^ x[6] ^ x[7] ^ x[8] ^ x[10] ^ x[13]; \ y[14] = x[0] ^ x[3] ^ x[4] ^ x[5] ^ x[9] ^ x[11] ^ x[14]; \ y[15] = x[1] ^ x[2] ^ x[4] ^ x[5] ^ x[8] ^ x[10] ^ x[15]; \ } //S-box 1 static const byte sb1[256] = { 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 }; //S-box 2 static const byte sb2[256] = { 0xE2, 0x4E, 0x54, 0xFC, 0x94, 0xC2, 0x4A, 0xCC, 0x62, 0x0D, 0x6A, 0x46, 0x3C, 0x4D, 0x8B, 0xD1, 0x5E, 0xFA, 0x64, 0xCB, 0xB4, 0x97, 0xBE, 0x2B, 0xBC, 0x77, 0x2E, 0x03, 0xD3, 0x19, 0x59, 0xC1, 0x1D, 0x06, 0x41, 0x6B, 0x55, 0xF0, 0x99, 0x69, 0xEA, 0x9C, 0x18, 0xAE, 0x63, 0xDF, 0xE7, 0xBB, 0x00, 0x73, 0x66, 0xFB, 0x96, 0x4C, 0x85, 0xE4, 0x3A, 0x09, 0x45, 0xAA, 0x0F, 0xEE, 0x10, 0xEB, 0x2D, 0x7F, 0xF4, 0x29, 0xAC, 0xCF, 0xAD, 0x91, 0x8D, 0x78, 0xC8, 0x95, 0xF9, 0x2F, 0xCE, 0xCD, 0x08, 0x7A, 0x88, 0x38, 0x5C, 0x83, 0x2A, 0x28, 0x47, 0xDB, 0xB8, 0xC7, 0x93, 0xA4, 0x12, 0x53, 0xFF, 0x87, 0x0E, 0x31, 0x36, 0x21, 0x58, 0x48, 0x01, 0x8E, 0x37, 0x74, 0x32, 0xCA, 0xE9, 0xB1, 0xB7, 0xAB, 0x0C, 0xD7, 0xC4, 0x56, 0x42, 0x26, 0x07, 0x98, 0x60, 0xD9, 0xB6, 0xB9, 0x11, 0x40, 0xEC, 0x20, 0x8C, 0xBD, 0xA0, 0xC9, 0x84, 0x04, 0x49, 0x23, 0xF1, 0x4F, 0x50, 0x1F, 0x13, 0xDC, 0xD8, 0xC0, 0x9E, 0x57, 0xE3, 0xC3, 0x7B, 0x65, 0x3B, 0x02, 0x8F, 0x3E, 0xE8, 0x25, 0x92, 0xE5, 0x15, 0xDD, 0xFD, 0x17, 0xA9, 0xBF, 0xD4, 0x9A, 0x7E, 0xC5, 0x39, 0x67, 0xFE, 0x76, 0x9D, 0x43, 0xA7, 0xE1, 0xD0, 0xF5, 0x68, 0xF2, 0x1B, 0x34, 0x70, 0x05, 0xA3, 0x8A, 0xD5, 0x79, 0x86, 0xA8, 0x30, 0xC6, 0x51, 0x4B, 0x1E, 0xA6, 0x27, 0xF6, 0x35, 0xD2, 0x6E, 0x24, 0x16, 0x82, 0x5F, 0xDA, 0xE6, 0x75, 0xA2, 0xEF, 0x2C, 0xB2, 0x1C, 0x9F, 0x5D, 0x6F, 0x80, 0x0A, 0x72, 0x44, 0x9B, 0x6C, 0x90, 0x0B, 0x5B, 0x33, 0x7D, 0x5A, 0x52, 0xF3, 0x61, 0xA1, 0xF7, 0xB0, 0xD6, 0x3F, 0x7C, 0x6D, 0xED, 0x14, 0xE0, 0xA5, 0x3D, 0x22, 0xB3, 0xF8, 0x89, 0xDE, 0x71, 0x1A, 0xAF, 0xBA, 0xB5, 0x81 }; //S-box 3 static const byte sb3[256] = { 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D }; //S-box 4 static const byte sb4[256] = { 0x30, 0x68, 0x99, 0x1B, 0x87, 0xB9, 0x21, 0x78, 0x50, 0x39, 0xDB, 0xE1, 0x72, 0x09, 0x62, 0x3C, 0x3E, 0x7E, 0x5E, 0x8E, 0xF1, 0xA0, 0xCC, 0xA3, 0x2A, 0x1D, 0xFB, 0xB6, 0xD6, 0x20, 0xC4, 0x8D, 0x81, 0x65, 0xF5, 0x89, 0xCB, 0x9D, 0x77, 0xC6, 0x57, 0x43, 0x56, 0x17, 0xD4, 0x40, 0x1A, 0x4D, 0xC0, 0x63, 0x6C, 0xE3, 0xB7, 0xC8, 0x64, 0x6A, 0x53, 0xAA, 0x38, 0x98, 0x0C, 0xF4, 0x9B, 0xED, 0x7F, 0x22, 0x76, 0xAF, 0xDD, 0x3A, 0x0B, 0x58, 0x67, 0x88, 0x06, 0xC3, 0x35, 0x0D, 0x01, 0x8B, 0x8C, 0xC2, 0xE6, 0x5F, 0x02, 0x24, 0x75, 0x93, 0x66, 0x1E, 0xE5, 0xE2, 0x54, 0xD8, 0x10, 0xCE, 0x7A, 0xE8, 0x08, 0x2C, 0x12, 0x97, 0x32, 0xAB, 0xB4, 0x27, 0x0A, 0x23, 0xDF, 0xEF, 0xCA, 0xD9, 0xB8, 0xFA, 0xDC, 0x31, 0x6B, 0xD1, 0xAD, 0x19, 0x49, 0xBD, 0x51, 0x96, 0xEE, 0xE4, 0xA8, 0x41, 0xDA, 0xFF, 0xCD, 0x55, 0x86, 0x36, 0xBE, 0x61, 0x52, 0xF8, 0xBB, 0x0E, 0x82, 0x48, 0x69, 0x9A, 0xE0, 0x47, 0x9E, 0x5C, 0x04, 0x4B, 0x34, 0x15, 0x79, 0x26, 0xA7, 0xDE, 0x29, 0xAE, 0x92, 0xD7, 0x84, 0xE9, 0xD2, 0xBA, 0x5D, 0xF3, 0xC5, 0xB0, 0xBF, 0xA4, 0x3B, 0x71, 0x44, 0x46, 0x2B, 0xFC, 0xEB, 0x6F, 0xD5, 0xF6, 0x14, 0xFE, 0x7C, 0x70, 0x5A, 0x7D, 0xFD, 0x2F, 0x18, 0x83, 0x16, 0xA5, 0x91, 0x1F, 0x05, 0x95, 0x74, 0xA9, 0xC1, 0x5B, 0x4A, 0x85, 0x6D, 0x13, 0x07, 0x4F, 0x4E, 0x45, 0xB2, 0x0F, 0xC9, 0x1C, 0xA6, 0xBC, 0xEC, 0x73, 0x90, 0x7B, 0xCF, 0x59, 0x8F, 0xA1, 0xF9, 0x2D, 0xF2, 0xB1, 0x00, 0x94, 0x37, 0x9F, 0xD0, 0x2E, 0x9C, 0x6E, 0x28, 0x3F, 0x80, 0xF0, 0x3D, 0xD3, 0x25, 0x8A, 0xB5, 0xE7, 0x42, 0xB3, 0xC7, 0xEA, 0xF7, 0x4C, 0x11, 0x33, 0x03, 0xA2, 0xAC, 0x60 }; //Key scheduling constants static const uint c[12] = { SWAPINT32(0x517CC1B7), SWAPINT32(0x27220A94), SWAPINT32(0xFE13ABE8), SWAPINT32(0xFA9A6EE0), SWAPINT32(0x6DB14ACC), SWAPINT32(0x9E21C820), SWAPINT32(0xFF28B1D5), SWAPINT32(0xEF5DE2B0), SWAPINT32(0xDB92371D), SWAPINT32(0x2126E970), SWAPINT32(0x03249775), SWAPINT32(0x04E8C90E) }; static void OF(uint *d, const uint *rk) { uint t[4]; XOR128(d, rk); //XOR D with RK SL1(t, d); //Substitution layer SL1 A(d, t); //Diffusion layer } static void EF(uint *d, const uint *rk) { uint t[4]; XOR128(d, rk); //XOR D with RK SL2(t, d); //Substitution layer SL2 A(d, t); //Diffusion layer } int ariaInit(AriaContext *context, const byte *key, size_t keyLength) { uint i; uint *ek, *dk; const uint *ck1, *ck2, *ck3; uint w[16]; //128-bit master key? if (keyLength == 16) { ck1 = c + 0; //Select the relevant constants ck2 = c + 4; ck3 = c + 8; //The number of rounds depends on the size of the master key context->nr = 12; } else if (keyLength == 24) { //192-bit master key? ck1 = c + 4; //Select the relevant constants ck2 = c + 8; ck3 = c + 0; //The number of rounds depends on the size of the master key context->nr = 14; } else if (keyLength == 32) { //256-bit master key? ck1 = c + 8; //Select the relevant constants ck2 = c + 0; ck3 = c + 4; //The number of rounds depends on the size of the master key context->nr = 16; } else return -1; //Compute 128-bit values KL and KR memset(w, 0, sizeof(w)); memcpy(w, key, keyLength); //Save KR... MOV128(w + 8, w + 4); //Compute intermediate values W0, W1, W2, and W3 MOV128(w + 4, w + 0); OF(w + 4, ck1); XOR128(w + 4, w + 8); MOV128(w + 8, w + 4); EF(w + 8, ck2); XOR128(w + 8, w + 0); MOV128(w + 12, w + 8); OF(w + 12, ck3); XOR128(w + 12, w + 4); //Convert from big-endian byte order to host byte order for (i = 0; i < 16; i++) w[i] = SWAPINT32(w[i]); //Point to the encryption round keys ek = context->ek; //Compute ek1, ..., ek17 as follow ROL128(ek + 0, w + 4, 109); XOR128(ek + 0, w + 0); ROL128(ek + 4, w + 8, 109); XOR128(ek + 4, w + 4); ROL128(ek + 8, w + 12, 109); XOR128(ek + 8, w + 8); ROL128(ek + 12, w + 0, 109); XOR128(ek + 12, w + 12); ROL128(ek + 16, w + 4, 97); XOR128(ek + 16, w + 0); ROL128(ek + 20, w + 8, 97); XOR128(ek + 20, w + 4); ROL128(ek + 24, w + 12, 97); XOR128(ek + 24, w + 8); ROL128(ek + 28, w + 0, 97); XOR128(ek + 28, w + 12); ROL128(ek + 32, w + 4, 61); XOR128(ek + 32, w + 0); ROL128(ek + 36, w + 8, 61); XOR128(ek + 36, w + 4); ROL128(ek + 40, w + 12, 61); XOR128(ek + 40, w + 8); ROL128(ek + 44, w + 0, 61); XOR128(ek + 44, w + 12); ROL128(ek + 48, w + 4, 31); XOR128(ek + 48, w + 0); ROL128(ek + 52, w + 8, 31); XOR128(ek + 52, w + 4); ROL128(ek + 56, w + 12, 31); XOR128(ek + 56, w + 8); ROL128(ek + 60, w + 0, 31); XOR128(ek + 60, w + 12); ROL128(ek + 64, w + 4, 19); XOR128(ek + 64, w + 0); //Convert from host byte order to big-endian byte order for (i = 0; i < 68; i++) ek[i] = SWAPINT32(ek[i]); //Decryption round keys are derived from the encryption round keys dk = context->dk; //Compute dk1 MOV128(dk + 0, ek + context->nr * 4); //Compute dk2, ..., dk(n) for (i = 1; i < context->nr; i++) A(dk + i * 4, ek + (context->nr - i) * 4); //Compute dk(n + 1) MOV128(dk + i * 4, ek + 0); //No error to report return 0; } void ariaEncryptBlock(AriaContext *context, const byte *input, byte *output, bool mode) { uint *ek; uint p[4], q[4]; //Copy the plaintext to the buffer memcpy(p, input, ARIA_BLOCK_SIZE); //Point to the encryption/decryption round keys if(mode == MODE_DEC) ek = context->dk; else ek = context->ek; //Apply 11 rounds OF(p, ek + 0); EF(p, ek + 4); OF(p, ek + 8); EF(p, ek + 12); OF(p, ek + 16); EF(p, ek + 20); OF(p, ek + 24); EF(p, ek + 28); OF(p, ek + 32); EF(p, ek + 36); OF(p, ek + 40); //128-bit master keys require a total of 12 rounds if (context->nr == 12) { XOR128(p, ek + 44); SL2(q, p); XOR128(q, ek + 48); } else if (context->nr == 14) { //192-bit master keys require a total of 14 rounds EF(p, ek + 44); OF(p, ek + 48); XOR128(p, ek + 52); SL2(q, p); XOR128(q, ek + 56); } else { //256-bit master keys require a total of 16 rounds EF(p, ek + 44); OF(p, ek + 48); EF(p, ek + 52); OF(p, ek + 56); XOR128(p, ek + 60); SL2(q, p); XOR128(q, ek + 64); } //Copy the resulting ciphertext from the buffer memcpy(output, q, ARIA_BLOCK_SIZE); } צופן בלוקים AES SSL New Block Cipher: ARIA A. Biryukov; C. De Canni're; J. Lano; B. Preneel; S. B. Ors (January 7, 2004). "Security and Performance Analysis of ARIA"(PostScript). Version 1.2-Final Report. Katholieke Universiteit Leuven. Retrieved March 2, 2007. Wenling Wu; Wentao Zhang; Dengguo Feng (2006). Impossible Differential Cryptanalysis of ARIA and Camellia (PDF). Retrieved January 19, 2007. Xuehai Tang; Bing Sun; Ruilin Li; Chao Li (March 30, 2010). "A Meet-in-the-Middle Attack on ARIA" (PDF). Retrieved April 24, 2010. Linear Cryptanalysis of ARIA Block Cipher Security Analysis of the Keyschedule of ARIA-128