לאחריה מעבירים בתמורה ההפוכה: formula_110. חוזרים שוב על formula_108 ושוב מעבירים בתמורה האמורה. מחסרים מהתוצאה את המפתח formula_112, החיסור מתבצע באופן הבא, את הבתים 1,4,5,8,9,12,13,16 מחסרים פשוט על ידי XOR ואת הבתים 2,3,6,7,10,11,14,15 מחסרים מודולו 256. את התוצאה מחליפים לפי תיבות ההחלפה אך בסדר הפוך. כלומר הבתים 1,4,5,8,9,12,13,16 מוחלפים בלוגריתם בבסיס 45 של הערך שלהם מודולו 257 ואילו הבתים 2,3,6,7,10,11,14,15 מוחלפים על ידי העלאה של 45 בחזקת הערך שלהם מודולו 257. יש לזכור שבמקרה שהתוצאה היא 256 מחזירים אפס (הערך 256 לא נכנס בבית אחד) וזה קורה כאשר הקלט הוא 128 לכן formula_113 וכן formula_114. מחסרים את המפתח formula_115 לפי כלל דומה למפתח הקודם. הבתים 1,4,5,8,9,12,13,16 מחוסרים ב-XOR ואילו היתר בחיסור מודולו 256.
הכנת מפתחות.
תהליך הכנת תת-המפתחות של SAFER++ מפיק מהמפתח המסופק על ידי המשתמש formula_25 מפתחות באורך 16 בתים כל אחד, כל זוג מתאים לסבב אחד של הפונקציה הפנימית של הצופן. בגלל שמספר הסבבים שונה בהתאם לאורך המפתח של המשתמש ובגלל שבגרסאות הישנות גודל המפתח היה רק 64 סיביות, את המפתחות מפיקים באופן כזה שכל תת-המפתחות הם למעשה קינון של המפתחות בהתאם לסוג הצופן, כלומר המפתחות הראשונים מתאימים לגרסת 64 סיביות, אחריהם המפתחות של גרסת מפתח 128 סיביות ואחריהם המפתחות לגרסת 256. כך שאפשר להשתמש באותו תהליך הכנה לכל הוריאציות של הצופן. את המפתחות מכינים בדרך מאוד פשוטה תחילה מוסיפים בית זוגיות שהוא XOR של כל בתי המפתח שנבחר על ידי המשתמש. ואז מפיקים את כל תת-המפתחות על ידי שילוב של הזזה מעגלית ברמה של סיביות בתוך כל בית, הזזה מעגלית ברמה של בתים של כל מפתח וחיבור עם קבועים הנקראים בתי "הטיה" שמספרם תלוי באורך המפתח. את בתי ההטייה מחשבים על ידי:
כאשר formula_4 מתייחס לאינדקס המפתח ו-formula_5 מתייחס למספר הבית בתוך המפתח. עבור מפתח 256 סיביות מחשבים את 48 הבתים האחרונים כך:
בסך הכול קיימים לכל היותר formula_121 בתי הטיה.
סיכום סדר הפעולות להכנת המפתחות
חוזרים על הפעולות הללו עד שמקבלים את כל המפתחות הדרושים. עבור מפתח באורך 256 סיביות דרושים בסך הכול 21 תת-מפתחות.
formula_121 בתי ההטייה מופיעים בטבלה הבאה:
קוד לדוגמה.
להלן קוד C++ שלם של אלגוריתם SAFER+ כפי שאומץ בתקן בלוטות'. הקוד אינו אופטימלי ונותר כך למען הפשטות והבהירות. קובץ הכותר SAFER.h מכיל את השורות הבאות:
typedef unsigned char BYTE; /* an 8 bit unsigned character type */
typedef unsigned int UINT; /* a 32 bit unsigned integer type */
void set_key(const UINT in_key[], const UINT key_len);
void encrypt(const UINT in_blk[4], UINT out_blk[4]);
void decrypt(const UINT in_blk[4], UINT out_blk[4]);
((UINT*)(x))[0] = in_blk[0]; \
((UINT*)(x))[1] = in_blk[1]; \
((UINT*)(x))[2] = in_blk[2]; \
((UINT*)(x))[3] = in_blk[3]
out_blk[0] = ((UINT*)(x))[0]; \
out_blk[1] = ((UINT*)(x))[1]; \
out_blk[2] = ((UINT*)(x))[2]; \
out_blk[3] = ((UINT*)(x))[3]
((UINT*)(x))[4] = ((UINT*)(x))[5] = \
((UINT*)(x))[6] = ((UINT*)(x))[7] = 0; \
switch((((len) + 63) / 64)) { \
case 4: \
((UINT*)(x))[6] = in_key[6]; \
((UINT*)(x))[7] = in_key[7]; \
case 3: \
((UINT*)(x))[4] = in_key[4]; \
((UINT*)(x))[5] = in_key[5]; \
case 2: \
((UINT*)(x))[0] = in_key[0]; \
((UINT*)(x))[1] = in_key[1]; \
((UINT*)(x))[2] = in_key[2]; \
((UINT*)(x))[3] = in_key[3]; \
הקוד בקובץ SAFER.cpp הוא:
BYTE expf[256] = {
1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63,
8, 103, 9, 148, 235, 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247,
64, 53, 72, 156, 81, 47, 59, 85, 227, 192, 159, 216, 211, 243, 141, 177,
255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, 146, 145, 100, 131,
241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, 20,
129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160,
4, 180, 133, 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252,
32, 155, 36, 78, 169, 152, 158, 171, 242, 96, 208, 108, 234, 250, 199, 217,
0, 212, 31, 110, 67, 188, 236, 83, 137, 254, 122, 93, 73, 201, 50, 194,
249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, 143, 10,
193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80,
2, 90, 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126,
16, 206, 18, 39, 213, 76, 79, 214, 121, 48, 104, 54, 117, 125, 228, 237,
128, 106, 144, 55, 162, 94, 118, 170, 197, 127, 61, 175, 165, 229, 25, 97,
253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, 200, 5,
225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40
BYTE logf[512] = {
128, 0, 176, 9, 96, 239, 185, 253, 16, 18, 159, 228, 105, 186, 173, 248,
192, 56, 194, 101, 79, 6, 148, 252, 25, 222, 106, 27, 93, 78, 168, 130,
112, 237, 232, 236, 114, 179, 21, 195, 255, 171, 182, 71, 68, 1, 172, 37,
201, 250, 142, 65, 26, 33, 203, 211, 13, 110, 254, 38, 88, 218, 50, 15,
32, 169, 157, 132, 152, 5, 156, 187, 34, 140, 99, 231, 197, 225, 115, 198,
175, 36, 91, 135, 102, 39, 247, 87, 244, 150, 177, 183, 92, 139, 213, 84,
121, 223, 170, 246, 62, 163, 241, 17, 202, 245, 209, 23, 123, 147, 131, 188,
189, 82, 30, 235, 174, 204, 214, 53, 8, 200, 138, 180, 226, 205, 191, 217,
208, 80, 89, 63, 77, 98, 52, 10, 72, 136, 181, 86, 76, 46, 107, 158,
210, 61, 60, 3, 19, 251, 151, 81, 117, 74, 145, 113, 35, 190, 118, 42,
95, 249, 212, 85, 11, 220, 55, 49, 22, 116, 215, 119, 167, 230, 7, 219,
164, 47, 70, 243, 97, 69, 103, 227, 12, 162, 59, 28, 133, 24, 4, 29,
41, 160, 143, 178, 90, 216, 166, 126, 238, 141, 83, 75, 161, 154, 193, 14,
122, 73, 165, 44, 129, 196, 199, 54, 43, 127, 67, 149, 51, 242, 108, 104,
109, 240, 2, 40, 206, 221, 155, 234, 94, 153, 124, 20, 134, 207, 229, 66,
184, 64, 120, 45, 58, 233, 100, 31, 146, 144, 125, 57, 111, 224, 137, 48,
128, 0, 176, 9, 96, 239, 185, 253, 16, 18, 159, 228, 105, 186, 173, 248,
192, 56, 194, 101, 79, 6, 148, 252, 25, 222, 106, 27, 93, 78, 168, 130,
112, 237, 232, 236, 114, 179, 21, 195, 255, 171, 182, 71, 68, 1, 172, 37,
201, 250, 142, 65, 26, 33, 203, 211, 13, 110, 254, 38, 88, 218, 50, 15,
32, 169, 157, 132, 152, 5, 156, 187, 34, 140, 99, 231, 197, 225, 115, 198,
175, 36, 91, 135, 102, 39, 247, 87, 244, 150, 177, 183, 92, 139, 213, 84,
121, 223, 170, 246, 62, 163, 241, 17, 202, 245, 209, 23, 123, 147, 131, 188,
189, 82, 30, 235, 174, 204, 214, 53, 8, 200, 138, 180, 226, 205, 191, 217,
208, 80, 89, 63, 77, 98, 52, 10, 72, 136, 181, 86, 76, 46, 107, 158,
210, 61, 60, 3, 19, 251, 151, 81, 117, 74, 145, 113, 35, 190, 118, 42,
95, 249, 212, 85, 11, 220, 55, 49, 22, 116, 215, 119, 167, 230, 7, 219,
164, 47, 70, 243, 97, 69, 103, 227, 12, 162, 59, 28, 133, 24, 4, 29,
41, 160, 143, 178, 90, 216, 166, 126, 238, 141, 83, 75, 161, 154, 193, 14,
122, 73, 165, 44, 129, 196, 199, 54, 43, 127, 67, 149, 51, 242, 108, 104,
109, 240, 2, 40, 206, 221, 155, 234, 94, 153, 124, 20, 134, 207, 229, 66,
184, 64, 120, 45, 58, 233, 100, 31, 146, 144, 125, 57, 111, 224, 137, 48
BYTE l_key[33 * 16];
UINT k_bytes;
void set_key(const UINT in_key[], const UINT key_len)
BYTE by, lk[33];
UINT i, j, k, l, m;
get_key(lk, key_len);
k_bytes = key_len / 8; lk[k_bytes] = 0;
for (i = 0; i &lt; k_bytes; ++i){
lk[k_bytes] ^= lk[i]; l_key[i] = lk[i];
for (i = 0; i &lt; k_bytes; ++i){
for (j = 0; j &lt;= k_bytes; ++j){
by = lk[j]; lk[j] = by « 3 | by » 5;
k = 17 * i + 35; l = 16 * i + 16; m = i + 1;
if (i &lt; 16){
for (j = 0; j &lt; 16; ++j){
l_key[l + j] = lk[m] + expf[expf[(k + j) &amp; 255]];
m = (m == k_bytes ? 0 : m + 1);
} else {
for (j = 0; j &lt; 16; ++j){
l_key[l + j] = lk[m] + expf[(k + j) &amp; 255];
m = (m == k_bytes ? 0 : m + 1);
void do_forward_round(BYTE x[16], BYTE *kp)
BYTE t;
x[0] = expf[x[0] ^ kp[0]] + kp[16];
x[1] = logf[x[1] + kp[1]] ^ kp[17];
x[2] = logf[x[2] + kp[2]] ^ kp[18];
x[3] = expf[x[3] ^ kp[3]] + kp[19];
x[4] = expf[x[4] ^ kp[4]] + kp[20];
x[5] = logf[x[5] + kp[5]] ^ kp[21];
x[6] = logf[x[6] + kp[6]] ^ kp[22];
x[7] = expf[x[7] ^ kp[7]] + kp[23];
x[8] = expf[x[8] ^ kp[8]] + kp[24];
x[9] = logf[x[9] + kp[9]] ^ kp[25];
x[10] = logf[x[10] + kp[10]] ^ kp[26];
x[11] = expf[x[11] ^ kp[11]] + kp[27];
x[12] = expf[x[12] ^ kp[12]] + kp[28];
x[13] = logf[x[13] + kp[13]] ^ kp[29];
x[14] = logf[x[14] + kp[14]] ^ kp[30];
x[15] = expf[x[15] ^ kp[15]] + kp[31];
x[1] += x[0]; x[0] += x[1];
x[3] += x[2]; x[2] += x[3];
x[5] += x[4]; x[4] += x[5];