/** * 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; } }
/** * The same alorigthm is used for both Encryption, and Decryption * * @param string $data A 96 bit block of data * @return boolean Returns true */ private function threeway(&$data) { // first split $data into three 32 bit parts $data = str_split($data, 4); $data = array_map("parent::str2Dec", $data); // split the key into three 32 bit parts $key = str_split($this->key(), 4); $key = array_map("parent::str2Dec", $key); // determine which round constant to use if ($this->operation() == parent::ENCRYPT) { $rcon = self::$_rcon_enc; } else { $rcon = self::$_rcon_dec; } if ($this->operation() == parent::DECRYPT) { $this->theta($key); $this->invertBits($key); $this->invertBits($data); } // 3Way uses 11 rounds for ($i = 0; $i < self::ROUNDS; ++$i) { $data[0] = parent::uInt32($data[0] ^ $key[0] ^ $rcon[$i] << 16); $data[1] = parent::uInt32($data[1] ^ $key[1]); $data[2] = parent::uInt32($data[2] ^ $key[2] ^ $rcon[$i]); $this->rho($data); } $data[0] = parent::uInt32($data[0] ^ $key[0] ^ $rcon[self::ROUNDS] << 16); $data[1] = parent::uInt32($data[1] ^ $key[1]); $data[2] = parent::uInt32($data[2] ^ $key[2] ^ $rcon[self::ROUNDS]); $this->theta($data); if ($this->operation() == parent::DECRYPT) { $this->invertBits($data); } // assemble the three 32 bit parts back to a 96 bit string $data = parent::dec2Str($data[0], 4) . parent::dec2Str($data[1], 4) . parent::dec2Str($data[2], 4); return true; }
/** * CAST-256 F3 function * * @param $d integer The the data input * @param $m integer The 32 bit masking key * @param $r integer The round number * @return integer The value after the F3 calculation */ private function f3($d, $m, $r) { $n = parent::uInt32($m - $d); $n = parent::uInt32(parent::rotBitsLeft32($n, $r)); $n = parent::dec2Str($n, 4); return parent::uInt32((self::$_s1[ord($n[0])] + self::$_s2[ord($n[1])] ^ self::$_s3[ord($n[2])]) - self::$_s4[ord($n[3])]); }
/** * The same alorigthm is used for both Encryption, and Decryption * * @param string $data A 64 bit block of data * @return boolean Returns true */ private function blowfish(&$data) { // divide the data into into two 32 bit halves $xl = parent::str2Dec(substr($data, 0, 4)); $xr = parent::str2Dec(substr($data, 4, 4)); for ($i = 0; $i < 16; ++$i) { if ($this->operation() == parent::ENCRYPT) { $xl ^= self::$_p[$i]; } else { $xl ^= self::$_p[17 - $i]; } // perform F() on the left half, and XOR with the right half $xr = $this->F($xl) ^ $xr; // swap $xl and $xr $tmp = $xr; $xr = $xl; $xl = $tmp; } // swap $xl and $xr after the 16th round to undo the last swap $tmp = $xl; $xl = $xr; $xr = $tmp; // XOR the final two elements of $_p if ($this->operation() == parent::ENCRYPT) { $xr ^= self::$_p[16]; $xl = $xl ^ self::$_p[17]; } else { $xr ^= self::$_p[1]; $xl ^= self::$_p[0]; } // recombine the two halves, force them to be 4 bytes each $data = parent::dec2Str($xl, 4) . parent::dec2Str($xr, 4); return true; }