Rijndael S-box
The Rijndael S-box is a matrix (square array of numbers) used in the Rijndael cipher, which the Advanced Encryption Standard (AES) cryptographic algorithm was based on.[1] The S-box (substitution box) serves as a lookup table.
Forward S-box
The S-box is generated by determining the multiplicative inverse for a given number in GF(28) = GF(2)[x]/(x8 + x4 + x3 + x + 1), Rijndael's finite field. Zero, which has no inverse, is mapped to zero. The multiplicative inverse is then transformed using the following affine transformation:
where [x7, ..., x0] (little-endian format) is the multiplicative inverse as a vector.
This affine transformation is the sum of multiple rotations of the byte as a vector, where addition is the XOR operation.
The matrix multiplication can be calculated by the following algorithm:
- Store the multiplicative inverse of the input number in two 8-bit unsigned temporary variables: s and x.
- Rotate the value s one bit to the left; if the value of s had a high bit (eighth bit from the right) of one, make the low bit of s one; otherwise the low bit of s is zero.
- XOR the value of x with the value of s, storing the value in x
- For three more iterations, repeat steps two and three; steps two and three are done a total of four times.
- The value of x will now have the result of the multiplication.
After the matrix multiplication is done, XOR the value by the decimal number 99 (the hexadecimal number 0x63, the binary number 0b01100011, the bit string 11000110 representing the number in LSb first notation).
This will generate the following S-box, which is represented here with hexadecimal notation:
| 0 1 2 3 4 5 6 7 8 9 a b c d e f ---|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--| 00 |63 7c 77 7b f2 6b 6f c5 30 01 67 2b fe d7 ab 76 10 |ca 82 c9 7d fa 59 47 f0 ad d4 a2 af 9c a4 72 c0 20 |b7 fd 93 26 36 3f f7 cc 34 a5 e5 f1 71 d8 31 15 30 |04 c7 23 c3 18 96 05 9a 07 12 80 e2 eb 27 b2 75 40 |09 83 2c 1a 1b 6e 5a a0 52 3b d6 b3 29 e3 2f 84 50 |53 d1 00 ed 20 fc b1 5b 6a cb be 39 4a 4c 58 cf 60 |d0 ef aa fb 43 4d 33 85 45 f9 02 7f 50 3c 9f a8 70 |51 a3 40 8f 92 9d 38 f5 bc b6 da 21 10 ff f3 d2 80 |cd 0c 13 ec 5f 97 44 17 c4 a7 7e 3d 64 5d 19 73 90 |60 81 4f dc 22 2a 90 88 46 ee b8 14 de 5e 0b db a0 |e0 32 3a 0a 49 06 24 5c c2 d3 ac 62 91 95 e4 79 b0 |e7 c8 37 6d 8d d5 4e a9 6c 56 f4 ea 65 7a ae 08 c0 |ba 78 25 2e 1c a6 b4 c6 e8 dd 74 1f 4b bd 8b 8a d0 |70 3e b5 66 48 03 f6 0e 61 35 57 b9 86 c1 1d 9e e0 |e1 f8 98 11 69 d9 8e 94 9b 1e 87 e9 ce 55 28 df f0 |8c a1 89 0d bf e6 42 68 41 99 2d 0f b0 54 bb 16
Here the column is determined by the least significant nibble, and the row is determined by the most significant nibble. For example, the value 0x9a is converted into 0xb8 by Rijndael's S-box. Note that the multiplicative inverse of 0x00 is defined as itself.
For C, C++ here is the initialization of the table:
unsigned char s[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
};
Inverse S-box
The inverse S-box is simply the S-box run in reverse. For example, the inverse S-box of 0xb8 is 0x9a. It is calculated by first calculating the inverse affine transformation of the input value, followed by the multiplicative inverse. The inverse affine transformation is as follows:
The following table represents Rijndael's inverse S-box:
| 0 1 2 3 4 5 6 7 8 9 a b c d e f ---|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--|--| 00 |52 09 6a d5 30 36 a5 38 bf 40 a3 9e 81 f3 d7 fb 10 |7c e3 39 82 9b 2f ff 87 34 8e 43 44 c4 de e9 cb 20 |54 7b 94 32 a6 c2 23 3d ee 4c 95 0b 42 fa c3 4e 30 |08 2e a1 66 28 d9 24 b2 76 5b a2 49 6d 8b d1 25 40 |72 f8 f6 64 86 68 98 16 d4 a4 5c cc 5d 65 b6 92 50 |6c 70 48 50 fd ed b9 da 5e 15 46 57 a7 8d 9d 84 60 |90 d8 ab 00 8c bc d3 0a f7 e4 58 05 b8 b3 45 06 70 |d0 2c 1e 8f ca 3f 0f 02 c1 af bd 03 01 13 8a 6b 80 |3a 91 11 41 4f 67 dc ea 97 f2 cf ce f0 b4 e6 73 90 |96 ac 74 22 e7 ad 35 85 e2 f9 37 e8 1c 75 df 6e a0 |47 f1 1a 71 1d 29 c5 89 6f b7 62 0e aa 18 be 1b b0 |fc 56 3e 4b c6 d2 79 20 9a db c0 fe 78 cd 5a f4 c0 |1f dd a8 33 88 07 c7 31 b1 12 10 59 27 80 ec 5f d0 |60 51 7f a9 19 b5 4a 0d 2d e5 7a 9f 93 c9 9c ef e0 |a0 e0 3b 4d ae 2a f5 b0 c8 eb bb 3c 83 53 99 61 f0 |17 2b 04 7e ba 77 d6 26 e1 69 14 63 55 21 0c 7d
For C, C++ implementation, here is the initialization of the table:
unsigned char inv_s[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
};
Design criteria
The Rijndael S-Box was specifically designed to be resistant to linear and differential cryptanalysis. This was done by minimizing the correlation between linear transformations of input/output bits, and at the same time minimizing the difference propagation probability.
The Rijndael S-Box can be edited, which defeats the suspicion of a backdoor built into the cipher that exploits a static S-box. The authors claim that the Rijndael cipher structure should provide enough resistance against differential and linear cryptanalysis if an S-Box with "average" correlation / difference propagation properties is used.
Alternate equation for the affine transformation
An equivalent equation for the affine transformation is
where b' b and c are 8 bit arrays and c is 01100011.[2]
Implementations
The following C code calculates the S-box:
#define ROTL8(x,shift) ((uint8_t) ((x) << (shift)) | ((x) >> (8 - (shift))))
void initialize_aes_sbox(uint8_t sbox[256]) {
/* loop invariant: p * q == 1 in the Galois field */
uint8_t p = 1, q = 1;
do {
/* multiply p by x+1 */
p = p ^ (p << 1) ^ (p & 0x80 ? 0x1B : 0);
/* divide q by x+1 */
q ^= q << 1;
q ^= q << 2;
q ^= q << 4;
q ^= q & 0x80 ? 0x09 : 0;
/* compute the affine transformation */
sbox[p] = 0x63 ^ q ^ ROTL8(q, 1) ^ ROTL8(q, 2) ^ ROTL8(q, 3) ^ ROTL8(q, 4);
} while (p != 1);
/* 0 is a special case since it has no inverse */
sbox[0] = 0x63;
}
References
- ↑ "The Rijndael Block Cipher" (PDF). Retrieved 2013-11-11.
- ↑ "FIPS PUB 197: the official AES standard" (PDF). Federal Information Processing Standard. 2001-11-26. Retrieved 2010-04-29.
|section=
ignored (help) - ↑ Jörg J. Buchholz (2001-12-19). "Matlab implementation of the Advanced Encryption Standard" (PDF).
- ↑ Jie Cui; Liusheng Huang; Hong Zhong; Chinchen Chang; Wei Yang (May 2011). "AN IMPROVED AES S-BOX AND ITS PERFORMANCE ANALYSIS" (PDF).