/** * Creates the subkeys $_mkey (the masking key) and * $_rkey (the rotate key) which are 16 bytes each. These are * created from the original key. The original key is null * padded up to 16 bytes and expanded to 32 bytes. It is then * split in half to create $_mkey and $_rkey * * @return void */ private function createSubKeys() { $x = $this->key(); $z = ""; // init to 16 bytes $skey = array(); // the max length of the key is 16 bytes, however if it is // less, pad it with null to get ito to 16 bytes if ($this->keySize() < self::BYTES_KEY_MAX) { $x = str_pad($x, self::BYTES_KEY_MAX, "", STR_PAD_RIGHT); } /* * NOW FOR THE UGLY PART, THIS IS TAKEN FROM PAGE 3-4 OF * http://tools.ietf.org/html/rfc2144 */ // two loops, each loop does 16 bytes for a total of 32 bytes for ($i = 0; $i < 2; ++$i) { // z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8] $tmp = substr($x, 0x0, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0xd])] ^ self::$_s6[ord($x[0xf])] ^ self::$_s7[ord($x[0xc])] ^ self::$_s8[ord($x[0xe])] ^ self::$_s7[ord($x[0x8])]), 4); $z = substr_replace($z, $tmp, 0x0, 4); //print "Z0: ".parent::str2Hex($z)." (".strlen($z).")\n"; // z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA] $tmp = substr($x, 0x8, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0x0])] ^ self::$_s6[ord($z[0x2])] ^ self::$_s7[ord($z[0x1])] ^ self::$_s8[ord($z[0x3])] ^ self::$_s8[ord($x[0xa])]), 4); $z = substr_replace($z, $tmp, 0x4, 4); // z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9] $tmp = substr($x, 0xc, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0x7])] ^ self::$_s6[ord($z[0x6])] ^ self::$_s7[ord($z[0x5])] ^ self::$_s8[ord($z[0x4])] ^ self::$_s5[ord($x[0x9])]), 4); $z = substr_replace($z, $tmp, 0x8, 4); // zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB] $tmp = substr($x, 0x4, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0xa])] ^ self::$_s6[ord($z[0x9])] ^ self::$_s7[ord($z[0xb])] ^ self::$_s8[ord($z[0x8])] ^ self::$_s6[ord($x[0xb])]), 4); $z = substr_replace($z, $tmp, 0xc, 4); //print "Z: ".parent::str2Hex($z)." (".strlen($z).")\n"; // K1 = S5[z8] ^ S6[z9] ^ S7[z7] ^ S8[z6] ^ S5[z2] $skey[] = parent::uInt32(self::$_s5[ord($z[0x8])] ^ self::$_s6[ord($z[0x9])] ^ self::$_s7[ord($z[0x7])] ^ self::$_s8[ord($z[0x6])] ^ self::$_s5[ord($z[0x2])]); // K2 = S5[zA] ^ S6[zB] ^ S7[z5] ^ S8[z4] ^ S6[z6] $skey[] = parent::uInt32(self::$_s5[ord($z[0xa])] ^ self::$_s6[ord($z[0xb])] ^ self::$_s7[ord($z[0x5])] ^ self::$_s8[ord($z[0x4])] ^ self::$_s6[ord($z[0x6])]); // K3 = S5[zC] ^ S6[zD] ^ S7[z3] ^ S8[z2] ^ S7[z9] $skey[] = parent::uInt32(self::$_s5[ord($z[0xc])] ^ self::$_s6[ord($z[0xd])] ^ self::$_s7[ord($z[0x3])] ^ self::$_s8[ord($z[0x2])] ^ self::$_s7[ord($z[0x9])]); // K4 = S5[zE] ^ S6[zF] ^ S7[z1] ^ S8[z0] ^ S8[zC] $skey[] = parent::uInt32(self::$_s5[ord($z[0xe])] ^ self::$_s6[ord($z[0xf])] ^ self::$_s7[ord($z[0x1])] ^ self::$_s8[ord($z[0x0])] ^ self::$_s8[ord($z[0xc])]); // x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0] $tmp = substr($z, 0x8, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0x5])] ^ self::$_s6[ord($z[0x7])] ^ self::$_s7[ord($z[0x4])] ^ self::$_s8[ord($z[0x6])] ^ self::$_s7[ord($z[0x0])]), 4); $x = substr_replace($x, $tmp, 0x0, 4); // x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2] $tmp = substr($z, 0x0, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0x0])] ^ self::$_s6[ord($x[0x2])] ^ self::$_s7[ord($x[0x1])] ^ self::$_s8[ord($x[0x3])] ^ self::$_s8[ord($z[0x2])]), 4); $x = substr_replace($x, $tmp, 0x4, 4); // x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1] $tmp = substr($z, 0x4, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0x7])] ^ self::$_s6[ord($x[0x6])] ^ self::$_s7[ord($x[0x5])] ^ self::$_s8[ord($x[0x4])] ^ self::$_s5[ord($z[0x1])]), 4); $x = substr_replace($x, $tmp, 0x8, 4); // xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3] $tmp = substr($z, 0xc, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0xa])] ^ self::$_s6[ord($x[0x9])] ^ self::$_s7[ord($x[0xb])] ^ self::$_s8[ord($x[0x8])] ^ self::$_s6[ord($z[0x3])]), 4); $x = substr_replace($x, $tmp, 0xc, 4); // K5 = S5[x3] ^ S6[x2] ^ S7[xC] ^ S8[xD] ^ S5[x8] $skey[] = parent::uInt32(self::$_s5[ord($x[0x3])] ^ self::$_s6[ord($x[0x2])] ^ self::$_s7[ord($x[0xc])] ^ self::$_s8[ord($x[0xd])] ^ self::$_s5[ord($x[0x8])]); // K6 = S5[x1] ^ S6[x0] ^ S7[xE] ^ S8[xF] ^ S6[xD] $skey[] = parent::uInt32(self::$_s5[ord($x[0x1])] ^ self::$_s6[ord($x[0x0])] ^ self::$_s7[ord($x[0xe])] ^ self::$_s8[ord($x[0xf])] ^ self::$_s6[ord($x[0xd])]); // K7 = S5[x7] ^ S6[x6] ^ S7[x8] ^ S8[x9] ^ S7[x3] $skey[] = parent::uInt32(self::$_s5[ord($x[0x7])] ^ self::$_s6[ord($x[0x6])] ^ self::$_s7[ord($x[0x8])] ^ self::$_s8[ord($x[0x9])] ^ self::$_s7[ord($x[0x3])]); // K8 = S5[x5] ^ S6[x4] ^ S7[xA] ^ S8[xB] ^ S8[x7] $skey[] = parent::uInt32(self::$_s5[ord($x[0x5])] ^ self::$_s6[ord($x[0x4])] ^ self::$_s7[ord($x[0xa])] ^ self::$_s8[ord($x[0xb])] ^ self::$_s8[ord($x[0x7])]); // z0z1z2z3 = x0x1x2x3 ^ S5[xD] ^ S6[xF] ^ S7[xC] ^ S8[xE] ^ S7[x8] $tmp = substr($x, 0x0, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0xd])] ^ self::$_s6[ord($x[0xf])] ^ self::$_s7[ord($x[0xc])] ^ self::$_s8[ord($x[0xe])] ^ self::$_s7[ord($x[0x8])]), 4); $z = substr_replace($z, $tmp, 0x0, 4); // z4z5z6z7 = x8x9xAxB ^ S5[z0] ^ S6[z2] ^ S7[z1] ^ S8[z3] ^ S8[xA] $tmp = substr($x, 0x8, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0x0])] ^ self::$_s6[ord($z[0x2])] ^ self::$_s7[ord($z[0x1])] ^ self::$_s8[ord($z[0x3])] ^ self::$_s8[ord($x[0xa])]), 4); $z = substr_replace($z, $tmp, 0x4, 4); // z8z9zAzB = xCxDxExF ^ S5[z7] ^ S6[z6] ^ S7[z5] ^ S8[z4] ^ S5[x9] $tmp = substr($x, 0xc, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0x7])] ^ self::$_s6[ord($z[0x6])] ^ self::$_s7[ord($z[0x5])] ^ self::$_s8[ord($z[0x4])] ^ self::$_s5[ord($x[0x9])]), 4); $z = substr_replace($z, $tmp, 0x8, 4); // zCzDzEzF = x4x5x6x7 ^ S5[zA] ^ S6[z9] ^ S7[zB] ^ S8[z8] ^ S6[xB] $tmp = substr($x, 0x4, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0xa])] ^ self::$_s6[ord($z[0x9])] ^ self::$_s7[ord($z[0xb])] ^ self::$_s8[ord($z[0x8])] ^ self::$_s6[ord($x[0xb])]), 4); $z = substr_replace($z, $tmp, 0xc, 4); // K9 = S5[z3] ^ S6[z2] ^ S7[zC] ^ S8[zD] ^ S5[z9] $skey[] = parent::uInt32(self::$_s5[ord($z[0x3])] ^ self::$_s6[ord($z[0x2])] ^ self::$_s7[ord($z[0xc])] ^ self::$_s8[ord($z[0xd])] ^ self::$_s5[ord($z[0x9])]); // K10 = S5[z1] ^ S6[z0] ^ S7[zE] ^ S8[zF] ^ S6[zC] $skey[] = parent::uInt32(self::$_s5[ord($z[0x1])] ^ self::$_s6[ord($z[0x0])] ^ self::$_s7[ord($z[0xe])] ^ self::$_s8[ord($z[0xf])] ^ self::$_s6[ord($z[0xc])]); // K11 = S5[z7] ^ S6[z6] ^ S7[z8] ^ S8[z9] ^ S7[z2] $skey[] = parent::uInt32(self::$_s5[ord($z[0x7])] ^ self::$_s6[ord($z[0x6])] ^ self::$_s7[ord($z[0x8])] ^ self::$_s8[ord($z[0x9])] ^ self::$_s7[ord($z[0x2])]); // K12 = S5[z5] ^ S6[z4] ^ S7[zA] ^ S8[zB] ^ S8[z6] $skey[] = parent::uInt32(self::$_s5[ord($z[0x5])] ^ self::$_s6[ord($z[0x4])] ^ self::$_s7[ord($z[0xa])] ^ self::$_s8[ord($z[0xb])] ^ self::$_s8[ord($z[0x6])]); // x0x1x2x3 = z8z9zAzB ^ S5[z5] ^ S6[z7] ^ S7[z4] ^ S8[z6] ^ S7[z0] $tmp = substr($z, 0x8, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($z[0x5])] ^ self::$_s6[ord($z[0x7])] ^ self::$_s7[ord($z[0x4])] ^ self::$_s8[ord($z[0x6])] ^ self::$_s7[ord($z[0x0])]), 4); $x = substr_replace($x, $tmp, 0x0, 4); // x4x5x6x7 = z0z1z2z3 ^ S5[x0] ^ S6[x2] ^ S7[x1] ^ S8[x3] ^ S8[z2] $tmp = substr($z, 0x0, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0x0])] ^ self::$_s6[ord($x[0x2])] ^ self::$_s7[ord($x[0x1])] ^ self::$_s8[ord($x[0x3])] ^ self::$_s8[ord($z[0x2])]), 4); $x = substr_replace($x, $tmp, 0x4, 4); // x8x9xAxB = z4z5z6z7 ^ S5[x7] ^ S6[x6] ^ S7[x5] ^ S8[x4] ^ S5[z1] $tmp = substr($z, 0x4, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0x7])] ^ self::$_s6[ord($x[0x6])] ^ self::$_s7[ord($x[0x5])] ^ self::$_s8[ord($x[0x4])] ^ self::$_s5[ord($z[0x1])]), 4); $x = substr_replace($x, $tmp, 0x8, 4); // xCxDxExF = zCzDzEzF ^ S5[xA] ^ S6[x9] ^ S7[xB] ^ S8[x8] ^ S6[z3] $tmp = substr($z, 0xc, 4); $tmp = parent::dec2Str(parent::uInt32(parent::str2Dec($tmp) ^ self::$_s5[ord($x[0xa])] ^ self::$_s6[ord($x[0x9])] ^ self::$_s7[ord($x[0xb])] ^ self::$_s8[ord($x[0x8])] ^ self::$_s6[ord($z[0x3])]), 4); $x = substr_replace($x, $tmp, 0xc, 4); // K13 = S5[x8] ^ S6[x9] ^ S7[x7] ^ S8[x6] ^ S5[x3] $skey[] = parent::uInt32(self::$_s5[ord($x[0x8])] ^ self::$_s6[ord($x[0x9])] ^ self::$_s7[ord($x[0x7])] ^ self::$_s8[ord($x[0x6])] ^ self::$_s5[ord($x[0x3])]); // K14 = S5[xA] ^ S6[xB] ^ S7[x5] ^ S8[x4] ^ S6[x7] $skey[] = parent::uInt32(self::$_s5[ord($x[0xa])] ^ self::$_s6[ord($x[0xb])] ^ self::$_s7[ord($x[0x5])] ^ self::$_s8[ord($x[0x4])] ^ self::$_s6[ord($x[0x7])]); // K15 = S5[xC] ^ S6[xD] ^ S7[x3] ^ S8[x2] ^ S7[x8] $skey[] = parent::uInt32(self::$_s5[ord($x[0xc])] ^ self::$_s6[ord($x[0xd])] ^ self::$_s7[ord($x[0x3])] ^ self::$_s8[ord($x[0x2])] ^ self::$_s7[ord($x[0x8])]); // K16 = S5[xE] ^ S6[xF] ^ S7[x1] ^ S8[x0] ^ S8[xD] $skey[] = parent::uInt32(self::$_s5[ord($x[0xe])] ^ self::$_s6[ord($x[0xf])] ^ self::$_s7[ord($x[0x1])] ^ self::$_s8[ord($x[0x0])] ^ self::$_s8[ord($x[0xd])]); } // create the 16 byte masking and rotate subkeys $this->_mkey = array_slice($skey, 0, 16); $this->_rkey = array_slice($skey, 16, 16); // $_rkey only uses the least significant 5 bits $this->_rkey = array_map(function ($v) { return $v &= 31; }, $this->_rkey); // there is 4kb in the s5 - s8 sboxes, which are not needed after we // create the subkeys, so free up the memory. unset() doesn't work here for ($i = 5; $i <= 8; ++$i) { self::${"_s{$i}"} = null; } }
/** * Generates the subkeys used in Blowfish * * @return void */ private function subKeys() { // now xor each element of $_p with 32 bits from the key for ($i = 0; $i < 18; ++$i) { $c = $this->keyChunk(4); self::$_p[$i] ^= parent::str2Dec($c); } // start with an 8 byte null string $zero = ""; // now we loop, each loop replacing elements of $_p, or an $_sbox with the // repeatedly encrypted zero string for ($i = 0; $i < 1042; $i += 2) { // encrypt the 64 bit null string $this->encrypt($zero); // split the encrypted null string into two 32 bit parts $z0 = parent::str2Dec(substr($zero, 0, 4)); $z1 = parent::str2Dec(substr($zero, 4, 4)); // now fill the $_p, $_sbox1, $_sbox2, $_sbox3, $_sbox4 // with 4 bytes from the repeatedly encrypted 8 byte null string if ($i < 18) { self::$_p[$i] = $z0; self::$_p[$i + 1] = $z1; } else { if ($i >= 18 && $i < 274) { self::$_sbox1[$i - 18] = $z0; self::$_sbox1[$i - 18 + 1] = $z1; } else { if ($i >= 274 && $i < 530) { self::$_sbox2[$i - 274] = $z0; self::$_sbox2[$i - 274 + 1] = $z1; } else { if ($i >= 530 && $i < 786) { self::$_sbox3[$i - 530] = $z0; self::$_sbox3[$i - 530 + 1] = $z1; } else { if ($i >= 786 && $i < 1042) { self::$_sbox4[$i - 786] = $z0; self::$_sbox4[$i - 786 + 1] = $z1; } } } } } } }