├── .gitignore ├── client ├── servicemanager │ ├── servicemanager.exe │ ├── servicemanager_mac │ ├── servicemanager_nix_32 │ ├── servicemanager_nix_64 │ ├── servicemanager_nix.systemd │ ├── servicemanager_mac.launchd │ ├── servicemanager_nix.sysvinit │ └── sdks │ │ └── servicemanager.php ├── support │ ├── phpseclib │ │ ├── license.txt │ │ └── Crypt │ │ │ ├── AES.php │ │ │ └── Rijndael.php │ ├── crc32_stream.php │ ├── wkfs_functions.php │ ├── deflate_stream.php │ ├── random.php │ ├── cli.php │ └── utf_utils.php ├── install.php └── run.php ├── server ├── servicemanager │ ├── servicemanager_nix_32 │ ├── servicemanager_nix_64 │ ├── servicemanager_nix.systemd │ ├── servicemanager_nix.sysvinit │ └── sdks │ │ └── servicemanager.php ├── support │ ├── phpseclib │ │ ├── license.txt │ │ └── Crypt │ │ │ ├── AES.php │ │ │ └── Rijndael.php │ ├── wkfs_functions.php │ ├── ipaddr.php │ └── random.php ├── index.php ├── install.php └── server.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /client/config.* 2 | /server/config.* 3 | -------------------------------------------------------------------------------- /client/servicemanager/servicemanager.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/web-knocker-firewall-service/master/client/servicemanager/servicemanager.exe -------------------------------------------------------------------------------- /client/servicemanager/servicemanager_mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/web-knocker-firewall-service/master/client/servicemanager/servicemanager_mac -------------------------------------------------------------------------------- /client/servicemanager/servicemanager_nix_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/web-knocker-firewall-service/master/client/servicemanager/servicemanager_nix_32 -------------------------------------------------------------------------------- /client/servicemanager/servicemanager_nix_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/web-knocker-firewall-service/master/client/servicemanager/servicemanager_nix_64 -------------------------------------------------------------------------------- /server/servicemanager/servicemanager_nix_32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/web-knocker-firewall-service/master/server/servicemanager/servicemanager_nix_32 -------------------------------------------------------------------------------- /server/servicemanager/servicemanager_nix_64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cubiclesoft/web-knocker-firewall-service/master/server/servicemanager/servicemanager_nix_64 -------------------------------------------------------------------------------- /client/servicemanager/servicemanager_nix.systemd: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=@SERVICENAME@ 3 | After=syslog.target network.target remote-fs.target nss-lookup.target 4 | 5 | [Service] 6 | Type=forking 7 | PIDFile=@SERVICEPIDFILE@ 8 | ExecStart='@SERVICEMANAGER@' start '@SERVICENAME@' 9 | ExecReload='@SERVICEMANAGER@' reload '@SERVICENAME@' 10 | ExecStop='@SERVICEMANAGER@' stop '@SERVICENAME@' 11 | Restart=no 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /server/servicemanager/servicemanager_nix.systemd: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=@SERVICENAME@ 3 | After=syslog.target network.target remote-fs.target nss-lookup.target 4 | 5 | [Service] 6 | Type=forking 7 | PIDFile=@SERVICEPIDFILE@ 8 | ExecStart='@SERVICEMANAGER@' start '@SERVICENAME@' 9 | ExecReload='@SERVICEMANAGER@' reload '@SERVICENAME@' 10 | ExecStop='@SERVICEMANAGER@' stop '@SERVICENAME@' 11 | Restart=no 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /client/servicemanager/servicemanager_mac.launchd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Label 6 | com.servicemanager.@SERVICENAME@ 7 | ProgramArguments 8 | 9 | @SERVICEMANAGER@ 10 | run 11 | @SERVICENAME@ 12 | 13 | KeepAlive 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /client/servicemanager/servicemanager_nix.sysvinit: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: @SERVICENAME@ 4 | # Required-Start: $local_fs $remote_fs $network 5 | # Required-Stop: $local_fs $remote_fs $network 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: starts @SERVICENAME@ 9 | # Description: starts @SERVICENAME@ 10 | ### END INIT INFO 11 | 12 | '@SERVICEMANAGER@' $1 '@SERVICENAME@' 13 | 14 | if [ "$?" != 0 ] ; then 15 | echo 16 | echo "Service Manager returned a failure code." 17 | echo 18 | echo "Usage: $0 {start|stop|restart|reload|status|configfile|custom-action-name|uninstall}" 19 | 20 | exit 1 21 | fi 22 | -------------------------------------------------------------------------------- /server/servicemanager/servicemanager_nix.sysvinit: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | ### BEGIN INIT INFO 3 | # Provides: @SERVICENAME@ 4 | # Required-Start: $local_fs $remote_fs $network 5 | # Required-Stop: $local_fs $remote_fs $network 6 | # Default-Start: 2 3 4 5 7 | # Default-Stop: 0 1 6 8 | # Short-Description: starts @SERVICENAME@ 9 | # Description: starts @SERVICENAME@ 10 | ### END INIT INFO 11 | 12 | '@SERVICEMANAGER@' $1 '@SERVICENAME@' 13 | 14 | if [ "$?" != 0 ] ; then 15 | echo 16 | echo "Service Manager returned a failure code." 17 | echo 18 | echo "Usage: $0 {start|stop|restart|reload|status|configfile|custom-action-name|uninstall}" 19 | 20 | exit 1 21 | fi 22 | -------------------------------------------------------------------------------- /client/support/phpseclib/license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2007-2016 TerraFrost and other contributors 2 | http://phpseclib.sourceforge.net/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/support/phpseclib/license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2007-2016 TerraFrost and other contributors 2 | http://phpseclib.sourceforge.net/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /client/support/phpseclib/Crypt/AES.php: -------------------------------------------------------------------------------- 1 | explicit_key_length) { 44 | $length = strlen($key); 45 | switch (true) { 46 | case $length <= 16: 47 | $this->key_length = 16; 48 | break; 49 | case $length <= 24: 50 | $this->key_length = 24; 51 | break; 52 | default: 53 | $this->key_length = 32; 54 | } 55 | $this->_setEngine(); 56 | } 57 | } 58 | }} -------------------------------------------------------------------------------- /server/support/phpseclib/Crypt/AES.php: -------------------------------------------------------------------------------- 1 | explicit_key_length) { 44 | $length = strlen($key); 45 | switch (true) { 46 | case $length <= 16: 47 | $this->key_length = 16; 48 | break; 49 | case $length <= 24: 50 | $this->key_length = 24; 51 | break; 52 | default: 53 | $this->key_length = 32; 54 | } 55 | $this->_setEngine(); 56 | } 57 | } 58 | }} -------------------------------------------------------------------------------- /client/install.php: -------------------------------------------------------------------------------- 1 | Init($config); 56 | 57 | $result = $wkfshelper->GetServerInfo(); 58 | if (!$result["success"]) WKFS_DisplayError("An error occurred while retrieving information from the remote server. Try again.", $result, false); 59 | } while (!$result["success"]); 60 | 61 | echo "----------\n\n"; 62 | echo "This section is optional. As a system service, the web knocker will regularly attempt to keep all protected ports open for the maximum amount of time. This can be useful if you are protecting an e-mail, database, or other server(s) where TCP/IP connections are created and destroyed on a regular basis behind the scenes.\n\n"; 63 | echo "System service name (leave blank to not install): "; 64 | $config["servicename"] = trim(fgets(STDIN)); 65 | 66 | file_put_contents($rootpath . "/config.dat", json_encode($config, JSON_PRETTY_PRINT)); 67 | 68 | echo "\n"; 69 | echo "**********\n"; 70 | echo "Configuration file is located at '" . $rootpath . "/config.dat'.\n\n"; 71 | echo "Server information:\n\n"; 72 | var_dump($result); 73 | echo "**********\n"; 74 | echo "\n"; 75 | 76 | if ($config["servicename"] !== "") 77 | { 78 | system(escapeshellarg(PHP_BINARY) . " " . escapeshellarg($rootpath . "/run.php") . " install"); 79 | system(escapeshellarg(PHP_BINARY) . " " . escapeshellarg($rootpath . "/run.php") . " start"); 80 | echo "\n"; 81 | } 82 | 83 | echo "Done.\n"; 84 | ?> -------------------------------------------------------------------------------- /server/index.php: -------------------------------------------------------------------------------- 1 | Init($config); 21 | 22 | // Packet decryption failure response. 23 | $data = @base64_decode(str_replace(array("-", "_"), array("+", "/"), $_POST["data"])); 24 | if ($data === false) 25 | { 26 | http_response_code(403); 27 | 28 | exit(); 29 | } 30 | 31 | $data = $wkfshelper->ExtractPacket($data); 32 | if ($data === false) 33 | { 34 | http_response_code(403); 35 | 36 | exit(); 37 | } 38 | 39 | // This packet should not receive a unique response yet. 40 | $data = @json_decode($data, true); 41 | if (!is_array($data) || !isset($data["ver"]) || !isset($data["ts"]) || (int)$data["ts"] > time() + 15 || (int)$data["ts"] < time() - 15 || !isset($data["api"])) 42 | { 43 | http_response_code(403); 44 | 45 | exit(); 46 | } 47 | 48 | // If there is a client/server mismatch, then respond accordingly. 49 | if ((int)$data["ver"] != 1) 50 | { 51 | http_response_code(405); 52 | 53 | echo "The version of your client does not match the version of the server."; 54 | 55 | exit(); 56 | } 57 | 58 | // The client is probably valid past this point. 59 | if ($data["api"] === "getinfo") 60 | { 61 | $result = array( 62 | "success" => true, 63 | "tcp" => array_keys($config["tcpprotected"]), 64 | "udp" => array_keys($config["udpprotected"]), 65 | "maxtime" => $config["maxtime"], 66 | "ip" => $_SERVER["REMOTE_ADDR"] 67 | ); 68 | 69 | header("Content-Type: application/octet-stream"); 70 | 71 | echo $wkfshelper->CreatePacket(json_encode($result)); 72 | } 73 | else if ($data["api"] === "openports") 74 | { 75 | if (!isset($data["ip"]) || $data["ip"] !== $_SERVER["REMOTE_ADDR"] || !isset($data["ports"]) || !isset($data["time"])) 76 | { 77 | http_response_code(403); 78 | 79 | exit(); 80 | } 81 | 82 | $context = @stream_context_create(); 83 | $fp = @stream_socket_client("tcp://" . $config["host"] . ":" . $config["port"], $errornum, $errorstr, 3, STREAM_CLIENT_CONNECT, $context); 84 | if ($fp === false) 85 | { 86 | http_response_code(504); 87 | 88 | exit(); 89 | } 90 | 91 | // Send the request. 92 | $data2 = array( 93 | "secret" => $config["secret"], 94 | "ip" => $data["ip"], 95 | "ports" => $data["ports"], 96 | "time" => $data["time"] 97 | ); 98 | 99 | @fwrite($fp, json_encode($data2)); 100 | 101 | // Get the response. 102 | $result = ""; 103 | do 104 | { 105 | $data2 = @fread($fp, 4096); 106 | if ($data2 === false) $data2 = ""; 107 | $result .= $data2; 108 | 109 | } while ($data2 !== ""); 110 | 111 | @fclose($fp); 112 | 113 | header("Content-Type: application/octet-stream"); 114 | 115 | echo $wkfshelper->CreatePacket($result); 116 | } 117 | else 118 | { 119 | http_response_code(405); 120 | 121 | echo "Unknown 'api' option."; 122 | } 123 | ?> -------------------------------------------------------------------------------- /client/support/crc32_stream.php: -------------------------------------------------------------------------------- 1 | 0x04C11DB7, "start" => 0xFFFFFFFF, "xor" => 0xFFFFFFFF, "refdata" => 1, "refcrc" => 1); 14 | 15 | public function __construct() 16 | { 17 | $this->open = false; 18 | } 19 | 20 | public function Init($options = false) 21 | { 22 | if ($options === false && function_exists("hash_init")) $this->hash = hash_init("crc32b"); 23 | else 24 | { 25 | if ($options === false) $options = self::$default; 26 | 27 | $this->hash = false; 28 | $this->crctable = array(); 29 | $poly = $this->LIM32($options["poly"]); 30 | for ($x = 0; $x < 256; $x++) 31 | { 32 | $c = $this->SHL32($x, 24); 33 | for ($y = 0; $y < 8; $y++) $c = $this->SHL32($c, 1) ^ ($c & 0x80000000 ? $poly : 0); 34 | $this->crctable[$x] = $c; 35 | } 36 | 37 | $this->datareflect = $options["refdata"]; 38 | $this->crcreflect = $options["refcrc"]; 39 | $this->firstcrc = $options["start"]; 40 | $this->currcrc = $options["start"]; 41 | $this->finalxor = $options["xor"]; 42 | } 43 | 44 | $this->open = true; 45 | } 46 | 47 | public function AddData($data) 48 | { 49 | if (!$this->open) return false; 50 | 51 | if ($this->hash !== false) hash_update($this->hash, $data); 52 | else 53 | { 54 | $y = strlen($data); 55 | 56 | for ($x = 0; $x < $y; $x++) 57 | { 58 | if ($this->datareflect) $this->currcrc = $this->SHL32($this->currcrc, 8) ^ $this->crctable[$this->SHR32($this->currcrc, 24) ^ self::$revlookup[ord($data[$x])]]; 59 | else $this->currcrc = $this->SHL32($this->currcrc, 8) ^ $this->crctable[$this->SHR32($this->currcrc, 24) ^ ord($data[$x])]; 60 | } 61 | } 62 | 63 | return true; 64 | } 65 | 66 | public function Finalize() 67 | { 68 | if (!$this->open) return false; 69 | 70 | if ($this->hash !== false) 71 | { 72 | $result = hexdec(hash_final($this->hash)); 73 | 74 | $this->hash = hash_init("crc32b"); 75 | } 76 | else 77 | { 78 | if ($this->crcreflect) 79 | { 80 | $tempcrc = $this->currcrc; 81 | $this->currcrc = self::$revlookup[$this->SHR32($tempcrc, 24)] | $this->SHL32(self::$revlookup[$this->SHR32($tempcrc, 16) & 0xFF], 8) | $this->SHL32(self::$revlookup[$this->SHR32($tempcrc, 8) & 0xFF], 16) | $this->SHL32(self::$revlookup[$this->LIM32($tempcrc & 0xFF)], 24); 82 | } 83 | $result = $this->currcrc ^ $this->finalxor; 84 | 85 | $this->currcrc = $this->firstcrc; 86 | } 87 | 88 | return $result; 89 | } 90 | 91 | // These functions are a hacky, but effective way of enforcing unsigned 32-bit integers onto a generic signed int. 92 | // Allow bitwise operations to work across platforms. Minimum integer size must be 32-bit. 93 | private function SHR32($num, $bits) 94 | { 95 | $num = (int)$num; 96 | if ($bits < 0) $bits = 0; 97 | 98 | if ($num < 0 && $bits) 99 | { 100 | $num = ($num >> 1) & 0x7FFFFFFF; 101 | $bits--; 102 | } 103 | 104 | return $this->LIM32($num >> $bits); 105 | } 106 | 107 | private function SHL32($num, $bits) 108 | { 109 | if ($bits < 0) $bits = 0; 110 | 111 | return $this->LIM32((int)$num << $bits); 112 | } 113 | 114 | private function LIM32($num) 115 | { 116 | return (int)((int)$num & 0xFFFFFFFF); 117 | } 118 | } 119 | ?> -------------------------------------------------------------------------------- /client/servicemanager/sdks/servicemanager.php: -------------------------------------------------------------------------------- 1 | rootpath = str_replace(array("\\", "/"), DIRECTORY_SEPARATOR, $rootpath); 12 | } 13 | 14 | public function Install($servicename, $phpfile, $args, $options = array(), $display = false) 15 | { 16 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 17 | if (!isset($options["dir"])) $options["dir"] = $this->rootpath; 18 | foreach ($options as $key => $val) $cmd .= " " . escapeshellarg("-" . $key . "=" . $val); 19 | $cmd .= " install " . escapeshellarg($servicename); 20 | $cmd .= " " . escapeshellarg($phpfile . ".notify"); 21 | $cmd .= " " . escapeshellarg($this->GetPHPBinary()); 22 | $cmd .= " " . escapeshellarg($phpfile); 23 | foreach ($args as $arg) $cmd .= " " . escapeshellarg($arg); 24 | 25 | return $this->RunCommand($cmd, $display); 26 | } 27 | 28 | public function Uninstall($servicename, $display = false) 29 | { 30 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 31 | $cmd .= " uninstall " . escapeshellarg($servicename); 32 | 33 | return $this->RunCommand($cmd, $display); 34 | } 35 | 36 | public function Start($servicename, $display = false) 37 | { 38 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 39 | $cmd .= " start " . escapeshellarg($servicename); 40 | 41 | return $this->RunCommand($cmd, $display); 42 | } 43 | 44 | public function Stop($servicename, $display = false) 45 | { 46 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 47 | $cmd .= " stop " . escapeshellarg($servicename); 48 | 49 | return $this->RunCommand($cmd, $display); 50 | } 51 | 52 | public function Restart($servicename, $display = false) 53 | { 54 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 55 | $cmd .= " restart " . escapeshellarg($servicename); 56 | 57 | return $this->RunCommand($cmd, $display); 58 | } 59 | 60 | public function Reload($servicename, $display = false) 61 | { 62 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 63 | $cmd .= " reload " . escapeshellarg($servicename); 64 | 65 | return $this->RunCommand($cmd, $display); 66 | } 67 | 68 | public function WaitFor($servicename, $display = false) 69 | { 70 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 71 | $cmd .= " waitfor " . escapeshellarg($servicename); 72 | 73 | return $this->RunCommand($cmd, $display); 74 | } 75 | 76 | public function Status($servicename, $display = false) 77 | { 78 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 79 | $cmd .= " status " . escapeshellarg($servicename); 80 | 81 | return $this->RunCommand($cmd, $display); 82 | } 83 | 84 | public function GetConfig($servicename) 85 | { 86 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 87 | $cmd .= " configfile " . escapeshellarg($servicename); 88 | 89 | $result = $this->RunCommand($cmd); 90 | if (!$result["success"]) return $result; 91 | 92 | $filename = trim($result["output"]); 93 | if (strtolower(substr($filename, 0, 6)) === "error:") return array("success" => false, "error" => self::SMTranslate("Unable to locate the '%s' configuration file.", $servicename), "errorcode" => "missing_config", "info" => $result); 94 | 95 | $fp = fopen($filename, "rb"); 96 | if ($fp === false) return array("success" => false, "error" => self::SMTranslate("Unable to open the configuration file '%s' for reading.", $filename), "errorcode" => "fopen_failed"); 97 | 98 | $result = array( 99 | "success" => true, 100 | "filename" => $filename, 101 | "options" => array() 102 | ); 103 | 104 | while (($line = fgets($fp)) !== false) 105 | { 106 | $line = trim($line); 107 | 108 | $pos = strpos($line, "="); 109 | if ($pos !== false) 110 | { 111 | $key = substr($line, 0, $pos); 112 | $val = (string)substr($line, $pos + 1); 113 | 114 | if (!isset($result["options"][$key])) $result["options"][$key] = $val; 115 | } 116 | 117 | if (feof($fp)) break; 118 | } 119 | 120 | fclose($fp); 121 | 122 | return $result; 123 | } 124 | 125 | public function AddAction($servicename, $actionname, $actiondesc, $phpfile, $args, $display = false) 126 | { 127 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 128 | $cmd .= " addaction " . escapeshellarg($servicename); 129 | $cmd .= " " . escapeshellarg($actionname); 130 | $cmd .= " " . escapeshellarg($actiondesc); 131 | $cmd .= " " . escapeshellarg($this->GetPHPBinary()); 132 | $cmd .= " " . escapeshellarg($phpfile); 133 | foreach ($args as $arg) $cmd .= " " . escapeshellarg($arg); 134 | 135 | return $this->RunCommand($cmd, $display); 136 | } 137 | 138 | public function GetServiceManagerRealpath() 139 | { 140 | $os = php_uname("s"); 141 | 142 | if (strtoupper(substr($os, 0, 3)) == "WIN") $result = $this->rootpath . "\\servicemanager.exe"; 143 | else 144 | { 145 | if (file_exists($this->rootpath . "/servicemanager_nix")) $result = $this->rootpath . "/servicemanager_nix"; 146 | else if (file_exists("/usr/local/bin/servicemanager")) $result = "/usr/local/bin/servicemanager"; 147 | else if (strtoupper(substr($os, 0, 6)) == "DARWIN") $result = $this->rootpath . "/servicemanager_mac"; 148 | else if (PHP_INT_SIZE >= 8) $result = $this->rootpath . "/servicemanager_nix_64"; 149 | else $result = $this->rootpath . "/servicemanager_nix_32"; 150 | 151 | @chmod($result, 0755); 152 | } 153 | 154 | return $result; 155 | } 156 | 157 | public function GetPHPBinary() 158 | { 159 | if (file_exists("/usr/bin/php") && realpath("/usr/bin/php") === PHP_BINARY) $result = "/usr/bin/php"; 160 | else $result = PHP_BINARY; 161 | 162 | return $result; 163 | } 164 | 165 | public function RunCommand($cmd, $display = false) 166 | { 167 | if ($display) echo self::SMTranslate("Running command: %s", $cmd) . "\n\n"; 168 | 169 | $fp = popen($cmd, "rb"); 170 | if ($fp === false) return array("success" => false, "error" => self::SMTranslate("The executable failed to start."), "errorcode" => "start_process", "info" => $cmd); 171 | 172 | $data = ""; 173 | while (($data2 = fread($fp, 65536)) !== false) 174 | { 175 | if ($display) echo $data2; 176 | $data .= $data2; 177 | 178 | if (feof($fp)) break; 179 | } 180 | 181 | pclose($fp); 182 | 183 | if ($display) echo "\n"; 184 | 185 | return array("success" => true, "cmd" => $cmd, "output" => $data); 186 | } 187 | 188 | protected static function SMTranslate() 189 | { 190 | $args = func_get_args(); 191 | if (!count($args)) return ""; 192 | 193 | return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); 194 | } 195 | } 196 | ?> -------------------------------------------------------------------------------- /server/servicemanager/sdks/servicemanager.php: -------------------------------------------------------------------------------- 1 | rootpath = str_replace(array("\\", "/"), DIRECTORY_SEPARATOR, $rootpath); 12 | } 13 | 14 | public function Install($servicename, $phpfile, $args, $options = array(), $display = false) 15 | { 16 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 17 | if (!isset($options["dir"])) $options["dir"] = $this->rootpath; 18 | foreach ($options as $key => $val) $cmd .= " " . escapeshellarg("-" . $key . "=" . $val); 19 | $cmd .= " install " . escapeshellarg($servicename); 20 | $cmd .= " " . escapeshellarg($phpfile . ".notify"); 21 | $cmd .= " " . escapeshellarg($this->GetPHPBinary()); 22 | $cmd .= " " . escapeshellarg($phpfile); 23 | foreach ($args as $arg) $cmd .= " " . escapeshellarg($arg); 24 | 25 | return $this->RunCommand($cmd, $display); 26 | } 27 | 28 | public function Uninstall($servicename, $display = false) 29 | { 30 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 31 | $cmd .= " uninstall " . escapeshellarg($servicename); 32 | 33 | return $this->RunCommand($cmd, $display); 34 | } 35 | 36 | public function Start($servicename, $display = false) 37 | { 38 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 39 | $cmd .= " start " . escapeshellarg($servicename); 40 | 41 | return $this->RunCommand($cmd, $display); 42 | } 43 | 44 | public function Stop($servicename, $display = false) 45 | { 46 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 47 | $cmd .= " stop " . escapeshellarg($servicename); 48 | 49 | return $this->RunCommand($cmd, $display); 50 | } 51 | 52 | public function Restart($servicename, $display = false) 53 | { 54 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 55 | $cmd .= " restart " . escapeshellarg($servicename); 56 | 57 | return $this->RunCommand($cmd, $display); 58 | } 59 | 60 | public function Reload($servicename, $display = false) 61 | { 62 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 63 | $cmd .= " reload " . escapeshellarg($servicename); 64 | 65 | return $this->RunCommand($cmd, $display); 66 | } 67 | 68 | public function WaitFor($servicename, $display = false) 69 | { 70 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 71 | $cmd .= " waitfor " . escapeshellarg($servicename); 72 | 73 | return $this->RunCommand($cmd, $display); 74 | } 75 | 76 | public function Status($servicename, $display = false) 77 | { 78 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 79 | $cmd .= " status " . escapeshellarg($servicename); 80 | 81 | return $this->RunCommand($cmd, $display); 82 | } 83 | 84 | public function GetConfig($servicename) 85 | { 86 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 87 | $cmd .= " configfile " . escapeshellarg($servicename); 88 | 89 | $result = $this->RunCommand($cmd); 90 | if (!$result["success"]) return $result; 91 | 92 | $filename = trim($result["output"]); 93 | if (strtolower(substr($filename, 0, 6)) === "error:") return array("success" => false, "error" => self::SMTranslate("Unable to locate the '%s' configuration file.", $servicename), "errorcode" => "missing_config", "info" => $result); 94 | 95 | $fp = fopen($filename, "rb"); 96 | if ($fp === false) return array("success" => false, "error" => self::SMTranslate("Unable to open the configuration file '%s' for reading.", $filename), "errorcode" => "fopen_failed"); 97 | 98 | $result = array( 99 | "success" => true, 100 | "filename" => $filename, 101 | "options" => array() 102 | ); 103 | 104 | while (($line = fgets($fp)) !== false) 105 | { 106 | $line = trim($line); 107 | 108 | $pos = strpos($line, "="); 109 | if ($pos !== false) 110 | { 111 | $key = substr($line, 0, $pos); 112 | $val = (string)substr($line, $pos + 1); 113 | 114 | if (!isset($result["options"][$key])) $result["options"][$key] = $val; 115 | } 116 | 117 | if (feof($fp)) break; 118 | } 119 | 120 | fclose($fp); 121 | 122 | return $result; 123 | } 124 | 125 | public function AddAction($servicename, $actionname, $actiondesc, $phpfile, $args, $display = false) 126 | { 127 | $cmd = escapeshellarg($this->GetServiceManagerRealpath()); 128 | $cmd .= " addaction " . escapeshellarg($servicename); 129 | $cmd .= " " . escapeshellarg($actionname); 130 | $cmd .= " " . escapeshellarg($actiondesc); 131 | $cmd .= " " . escapeshellarg($this->GetPHPBinary()); 132 | $cmd .= " " . escapeshellarg($phpfile); 133 | foreach ($args as $arg) $cmd .= " " . escapeshellarg($arg); 134 | 135 | return $this->RunCommand($cmd, $display); 136 | } 137 | 138 | public function GetServiceManagerRealpath() 139 | { 140 | $os = php_uname("s"); 141 | 142 | if (strtoupper(substr($os, 0, 3)) == "WIN") $result = $this->rootpath . "\\servicemanager.exe"; 143 | else 144 | { 145 | if (file_exists($this->rootpath . "/servicemanager_nix")) $result = $this->rootpath . "/servicemanager_nix"; 146 | else if (file_exists("/usr/local/bin/servicemanager")) $result = "/usr/local/bin/servicemanager"; 147 | else if (strtoupper(substr($os, 0, 6)) == "DARWIN") $result = $this->rootpath . "/servicemanager_mac"; 148 | else if (PHP_INT_SIZE >= 8) $result = $this->rootpath . "/servicemanager_nix_64"; 149 | else $result = $this->rootpath . "/servicemanager_nix_32"; 150 | 151 | @chmod($result, 0755); 152 | } 153 | 154 | return $result; 155 | } 156 | 157 | public function GetPHPBinary() 158 | { 159 | if (file_exists("/usr/bin/php") && realpath("/usr/bin/php") === PHP_BINARY) $result = "/usr/bin/php"; 160 | else $result = PHP_BINARY; 161 | 162 | return $result; 163 | } 164 | 165 | public function RunCommand($cmd, $display = false) 166 | { 167 | if ($display) echo self::SMTranslate("Running command: %s", $cmd) . "\n\n"; 168 | 169 | $fp = popen($cmd, "rb"); 170 | if ($fp === false) return array("success" => false, "error" => self::SMTranslate("The executable failed to start."), "errorcode" => "start_process", "info" => $cmd); 171 | 172 | $data = ""; 173 | while (($data2 = fread($fp, 65536)) !== false) 174 | { 175 | if ($display) echo $data2; 176 | $data .= $data2; 177 | 178 | if (feof($fp)) break; 179 | } 180 | 181 | pclose($fp); 182 | 183 | if ($display) echo "\n"; 184 | 185 | return array("success" => true, "cmd" => $cmd, "output" => $data); 186 | } 187 | 188 | protected static function SMTranslate() 189 | { 190 | $args = func_get_args(); 191 | if (!count($args)) return ""; 192 | 193 | return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); 194 | } 195 | } 196 | ?> -------------------------------------------------------------------------------- /client/support/wkfs_functions.php: -------------------------------------------------------------------------------- 1 | $size) $key = $algo($key, true); 51 | $key = str_pad($key, $size, "\x00"); 52 | 53 | $y = strlen($key) - 1; 54 | for ($x = 0; $x < $y; $x++) 55 | { 56 | $opad[$x] = $opad[$x] ^ $key[$x]; 57 | $ipad[$x] = $ipad[$x] ^ $key[$x]; 58 | } 59 | 60 | $result = $algo($opad . $algo($ipad . $data, true), $raw_output); 61 | 62 | return $result; 63 | } 64 | } 65 | 66 | class WKFS_Helper 67 | { 68 | private $config, $rng, $cipher1, $cipher2, $sign, $ipaddr; 69 | 70 | public function Init($config) 71 | { 72 | global $rootpath; 73 | 74 | $this->config = $config; 75 | 76 | // Set up encryption. 77 | require_once $rootpath . "/support/random.php"; 78 | require_once $rootpath . "/support/phpseclib/Crypt/AES.php"; 79 | 80 | $encryptkey = array(); 81 | foreach ($this->config["encryption_key"] as $key => $val) $encryptkey[$key] = hex2bin($val); 82 | 83 | $this->rng = new CSPRNG(); 84 | $this->cipher1 = new Crypt_AES(); 85 | $this->cipher1->setKey($encryptkey["key1"]); 86 | $this->cipher1->setIV($encryptkey["iv1"]); 87 | $this->cipher1->disablePadding(); 88 | $this->cipher2 = new Crypt_AES(); 89 | $this->cipher2->setKey($encryptkey["key2"]); 90 | $this->cipher2->setIV($encryptkey["iv2"]); 91 | $this->cipher2->disablePadding(); 92 | $this->sign = $encryptkey["sign"]; 93 | 94 | $this->ipaddr = false; 95 | } 96 | 97 | public function CreatePacket($data) 98 | { 99 | // Generate block. 100 | $block = $this->rng->GetBytes(4); 101 | 102 | $block .= pack("N", strlen($data)); 103 | $block .= $data; 104 | 105 | $block .= hash_hmac("sha1", $data, $this->sign, true); 106 | $block .= $this->rng->GetBytes(4); 107 | if (strlen($block) % 512 != 0) $block .= $this->rng->GetBytes(512 - (strlen($block) % 512)); 108 | 109 | // Encrypt the block. 110 | $block = $this->cipher1->encrypt($block); 111 | 112 | // Alter block. (See: http://cubicspot.blogspot.com/2013/02/extending-block-size-of-any-symmetric.html) 113 | $block = substr($block, -1) . substr($block, 0, -1); 114 | 115 | // Encrypt the block again. 116 | $block = $this->cipher2->encrypt($block); 117 | 118 | return $block; 119 | } 120 | 121 | public function ExtractPacket($block) 122 | { 123 | if ($block === "" || strlen($block) % 512 != 0) return false; 124 | 125 | // Decrypt the block. 126 | $block = $this->cipher2->decrypt($block); 127 | 128 | // Alter block. (See: http://cubicspot.blogspot.com/2013/02/extending-block-size-of-any-symmetric.html) 129 | $block = substr($block, 1) . substr($block, 0, 1); 130 | 131 | // Decrypt the block again. 132 | $block = $this->cipher1->decrypt($block); 133 | 134 | // 32 bytes of overhead (4 byte prefix random, 4 byte data size, 20 byte hash, 4 byte suffix random). 135 | $size = WKFS_UnpackInt(substr($block, 4, 4)); 136 | if ($size > strlen($block) - 32) return false; 137 | 138 | $data = substr($block, 8, $size); 139 | $hash = substr($block, 8 + $size, 20); 140 | $hash2 = hash_hmac("sha1", $data, $this->sign, true); 141 | if ($hash !== $hash2) return false; 142 | 143 | return $data; 144 | } 145 | 146 | // Client API. 147 | public function GetServerInfo() 148 | { 149 | $options = array( 150 | "api" => "getinfo" 151 | ); 152 | 153 | $result = $this->RunAPI($options); 154 | if ($result["success"] && isset($result["ip"])) $this->ipaddr = $result["ip"]; 155 | 156 | return $result; 157 | } 158 | 159 | public function OpenServerPorts($tcp, $udp, $time) 160 | { 161 | $options = array( 162 | "api" => "openports", 163 | "ip" => $this->ipaddr, 164 | "ports" => array(), 165 | "time" => (int)$time 166 | ); 167 | 168 | foreach ($tcp as $num) $options["ports"][] = array("proto" => "TCP", "num" => (int)$num); 169 | foreach ($udp as $num) $options["ports"][] = array("proto" => "UDP", "num" => (int)$num); 170 | 171 | return $this->RunAPI($options); 172 | } 173 | 174 | private static function WKFS_Translate() 175 | { 176 | $args = func_get_args(); 177 | if (!count($args)) return ""; 178 | 179 | return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); 180 | } 181 | 182 | private function RunAPI($data) 183 | { 184 | global $rootpath; 185 | 186 | require_once $rootpath . "/support/web_browser.php"; 187 | 188 | $web = new WebBrowser(); 189 | 190 | $data["ver"] = 1; 191 | $data["ts"] = time(); 192 | if ($this->ipaddr !== false) $data["ip"] = $this->ipaddr; 193 | $data = $this->CreatePacket(json_encode($data)); 194 | 195 | $options = array( 196 | "postvars" => array( 197 | "data" => str_replace(array("+", "/", "="), array("-", "_", ""), base64_encode($data)) 198 | ) 199 | ); 200 | 201 | $result = $web->Process($this->config["url"], $options); 202 | 203 | if (!$result["success"]) return $result; 204 | 205 | if ($result["response"]["code"] != 200) return array("success" => false, "error" => self::WKFS_Translate("Expected a 200 response from the web server. Received '%s'.", $result["response"]["line"]), "errorcode" => "unexpected_server_response", "info" => $result); 206 | 207 | // Attempt to decrypt the packet. 208 | $data = $this->ExtractPacket($result["body"]); 209 | if ($data === false) return array("success" => false, "error" => self::WKFS_Translate("Unable to decrypt response data."), "errorcode" => "bad_decrypt"); 210 | 211 | $data = @json_decode($data, true); 212 | if ($data === NULL || $data === false) return array("success" => false, "error" => self::WKFS_Translate("Unable to decode JSON response."), "errorcode" => "bad_json_decode"); 213 | 214 | return $data; 215 | } 216 | } 217 | ?> -------------------------------------------------------------------------------- /server/support/wkfs_functions.php: -------------------------------------------------------------------------------- 1 | $size) $key = $algo($key, true); 51 | $key = str_pad($key, $size, "\x00"); 52 | 53 | $y = strlen($key) - 1; 54 | for ($x = 0; $x < $y; $x++) 55 | { 56 | $opad[$x] = $opad[$x] ^ $key[$x]; 57 | $ipad[$x] = $ipad[$x] ^ $key[$x]; 58 | } 59 | 60 | $result = $algo($opad . $algo($ipad . $data, true), $raw_output); 61 | 62 | return $result; 63 | } 64 | } 65 | 66 | class WKFS_Helper 67 | { 68 | private $config, $rng, $cipher1, $cipher2, $sign, $ipaddr; 69 | 70 | public function Init($config) 71 | { 72 | global $rootpath; 73 | 74 | $this->config = $config; 75 | 76 | // Set up encryption. 77 | require_once $rootpath . "/support/random.php"; 78 | require_once $rootpath . "/support/phpseclib/Crypt/AES.php"; 79 | 80 | $encryptkey = array(); 81 | foreach ($this->config["encryption_key"] as $key => $val) $encryptkey[$key] = hex2bin($val); 82 | 83 | $this->rng = new CSPRNG(); 84 | $this->cipher1 = new Crypt_AES(); 85 | $this->cipher1->setKey($encryptkey["key1"]); 86 | $this->cipher1->setIV($encryptkey["iv1"]); 87 | $this->cipher1->disablePadding(); 88 | $this->cipher2 = new Crypt_AES(); 89 | $this->cipher2->setKey($encryptkey["key2"]); 90 | $this->cipher2->setIV($encryptkey["iv2"]); 91 | $this->cipher2->disablePadding(); 92 | $this->sign = $encryptkey["sign"]; 93 | 94 | $this->ipaddr = false; 95 | } 96 | 97 | public function CreatePacket($data) 98 | { 99 | // Generate block. 100 | $block = $this->rng->GetBytes(4); 101 | 102 | $block .= pack("N", strlen($data)); 103 | $block .= $data; 104 | 105 | $block .= hash_hmac("sha1", $data, $this->sign, true); 106 | $block .= $this->rng->GetBytes(4); 107 | if (strlen($block) % 512 != 0) $block .= $this->rng->GetBytes(512 - (strlen($block) % 512)); 108 | 109 | // Encrypt the block. 110 | $block = $this->cipher1->encrypt($block); 111 | 112 | // Alter block. (See: http://cubicspot.blogspot.com/2013/02/extending-block-size-of-any-symmetric.html) 113 | $block = substr($block, -1) . substr($block, 0, -1); 114 | 115 | // Encrypt the block again. 116 | $block = $this->cipher2->encrypt($block); 117 | 118 | return $block; 119 | } 120 | 121 | public function ExtractPacket($block) 122 | { 123 | if ($block === "" || strlen($block) % 512 != 0) return false; 124 | 125 | // Decrypt the block. 126 | $block = $this->cipher2->decrypt($block); 127 | 128 | // Alter block. (See: http://cubicspot.blogspot.com/2013/02/extending-block-size-of-any-symmetric.html) 129 | $block = substr($block, 1) . substr($block, 0, 1); 130 | 131 | // Decrypt the block again. 132 | $block = $this->cipher1->decrypt($block); 133 | 134 | // 32 bytes of overhead (4 byte prefix random, 4 byte data size, 20 byte hash, 4 byte suffix random). 135 | $size = WKFS_UnpackInt(substr($block, 4, 4)); 136 | if ($size > strlen($block) - 32) return false; 137 | 138 | $data = substr($block, 8, $size); 139 | $hash = substr($block, 8 + $size, 20); 140 | $hash2 = hash_hmac("sha1", $data, $this->sign, true); 141 | if ($hash !== $hash2) return false; 142 | 143 | return $data; 144 | } 145 | 146 | // Client API. 147 | public function GetServerInfo() 148 | { 149 | $options = array( 150 | "api" => "getinfo" 151 | ); 152 | 153 | $result = $this->RunAPI($options); 154 | if ($result["success"] && isset($result["ip"])) $this->ipaddr = $result["ip"]; 155 | 156 | return $result; 157 | } 158 | 159 | public function OpenServerPorts($tcp, $udp, $time) 160 | { 161 | $options = array( 162 | "api" => "openports", 163 | "ip" => $this->ipaddr, 164 | "ports" => array(), 165 | "time" => (int)$time 166 | ); 167 | 168 | foreach ($tcp as $num) $options["ports"][] = array("proto" => "TCP", "num" => (int)$num); 169 | foreach ($udp as $num) $options["ports"][] = array("proto" => "UDP", "num" => (int)$num); 170 | 171 | return $this->RunAPI($options); 172 | } 173 | 174 | private static function WKFS_Translate() 175 | { 176 | $args = func_get_args(); 177 | if (!count($args)) return ""; 178 | 179 | return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); 180 | } 181 | 182 | private function RunAPI($data) 183 | { 184 | global $rootpath; 185 | 186 | require_once $rootpath . "/support/web_browser.php"; 187 | 188 | $web = new WebBrowser(); 189 | 190 | $data["ver"] = 1; 191 | $data["ts"] = time(); 192 | if ($this->ipaddr !== false) $data["ip"] = $this->ipaddr; 193 | $data = $this->CreatePacket(json_encode($data)); 194 | 195 | $options = array( 196 | "postvars" => array( 197 | "data" => str_replace(array("+", "/", "="), array("-", "_", ""), base64_encode($data)) 198 | ) 199 | ); 200 | 201 | $result = $web->Process($this->config["url"], $options); 202 | 203 | if (!$result["success"]) return $result; 204 | 205 | if ($result["response"]["code"] != 200) return array("success" => false, "error" => self::WKFS_Translate("Expected a 200 response from the web server. Received '%s'.", $result["response"]["line"]), "errorcode" => "unexpected_server_response", "info" => $result); 206 | 207 | // Attempt to decrypt the packet. 208 | $data = $this->ExtractPacket($result["body"]); 209 | if ($data === false) return array("success" => false, "error" => self::WKFS_Translate("Unable to decrypt response data."), "errorcode" => "bad_decrypt"); 210 | 211 | $data = @json_decode($data, true); 212 | if ($data === NULL || $data === false) return array("success" => false, "error" => self::WKFS_Translate("Unable to decode JSON response."), "errorcode" => "bad_json_decode"); 213 | 214 | return $data; 215 | } 216 | } 217 | ?> -------------------------------------------------------------------------------- /client/run.php: -------------------------------------------------------------------------------- 1 | array( 28 | "f" => "frequency", 29 | "m" => "maxtime", 30 | "t" => "tcp", 31 | "u" => "udp", 32 | "?" => "help" 33 | ), 34 | "rules" => array( 35 | "frequency" => array("arg" => true), 36 | "maxtime" => array("arg" => true), 37 | "tcp" => array("arg" => true, "multiple" => true), 38 | "udp" => array("arg" => true, "multiple" => true), 39 | "help" => array("arg" => false) 40 | ) 41 | ); 42 | $args = CLI::ParseCommandLine($options); 43 | 44 | if (isset($args["opts"]["help"])) 45 | { 46 | echo "Web Knocker Firewall Service client\n"; 47 | echo "Purpose: Open preconfigured remote host firewall ports.\n"; 48 | echo "\n"; 49 | echo "Syntax: " . $args["file"] . " [options] [servicecommand]\n"; 50 | echo "Options:\n"; 51 | echo "\t-f The amount of time to wait before sending another port request.\n"; 52 | echo "\t-m The maximum amount of time to open the ports for. Server capped.\n"; 53 | echo "\t-t The TCP port to open. Defaults to all possible options.\n"; 54 | echo "\t-u The UDP port to open. Defaults to all possible options.\n"; 55 | echo "\n"; 56 | echo "Example:\n"; 57 | echo "\tphp " . $args["file"] . " -t=22\n"; 58 | 59 | exit(); 60 | } 61 | 62 | if (count($args["params"])) 63 | { 64 | // Service Manager PHP SDK. 65 | require_once $rootpath . "/servicemanager/sdks/servicemanager.php"; 66 | 67 | $sm = new ServiceManager($rootpath . "/servicemanager"); 68 | 69 | echo "Service manager: " . $sm->GetServiceManagerRealpath() . "\n\n"; 70 | 71 | $servicename = preg_replace('/[^a-z0-9]/', "-", $config["servicename"]); 72 | if ($servicename === "") WKFS_DisplayError("The configuration file 'servicename' field is empty. Update the configuration file and then re-run the command."); 73 | 74 | $argv[1] = $args["params"][0]; 75 | 76 | if ($argv[1] == "install") 77 | { 78 | // Install the service. 79 | $args = array(); 80 | $options = array(); 81 | 82 | $result = $sm->Install($servicename, __FILE__, $args, $options, true); 83 | if (!$result["success"]) WKFS_DisplayError("Unable to install the '" . $servicename . "' service.", $result); 84 | } 85 | else if ($argv[1] == "start") 86 | { 87 | // Start the service. 88 | $result = $sm->Start($servicename, true); 89 | if (!$result["success"]) WKFS_DisplayError("Unable to start the '" . $servicename . "' service.", $result); 90 | } 91 | else if ($argv[1] == "stop") 92 | { 93 | // Stop the service. 94 | $result = $sm->Stop($servicename, true); 95 | if (!$result["success"]) WKFS_DisplayError("Unable to stop the '" . $servicename . "' service.", $result); 96 | } 97 | else if ($argv[1] == "uninstall") 98 | { 99 | // Uninstall the service. 100 | $result = $sm->Uninstall($servicename, true); 101 | if (!$result["success"]) WKFS_DisplayError("Unable to uninstall the '" . $servicename . "' service.", $result); 102 | } 103 | else if ($argv[1] == "dumpconfig") 104 | { 105 | $result = $sm->GetConfig($servicename); 106 | if (!$result["success"]) WKFS_DisplayError("Unable to retrieve the configuration for the '" . $servicename . "' service.", $result); 107 | 108 | echo "Service configuration: " . $result["filename"] . "\n\n"; 109 | 110 | echo "Current service configuration:\n\n"; 111 | foreach ($result["options"] as $key => $val) echo " " . $key . " = " . $val . "\n"; 112 | } 113 | else 114 | { 115 | echo "Command not recognized. Run the service manager directly for anything other than 'install', 'start', 'stop', 'uninstall', and 'dumpconfig'.\n"; 116 | } 117 | } 118 | else 119 | { 120 | // Make sure PHP doesn't introduce weird limitations. 121 | ini_set("memory_limit", "-1"); 122 | set_time_limit(0); 123 | 124 | $wkfshelper = new WKFS_Helper(); 125 | $wkfshelper->Init($config); 126 | 127 | $nextquery = 0; 128 | $serverinfo = false; 129 | 130 | // Main service code. 131 | $stopfilename = __FILE__ . ".notify.stop"; 132 | $reloadfilename = __FILE__ . ".notify.reload"; 133 | $lastservicecheck = time(); 134 | $running = true; 135 | 136 | do 137 | { 138 | if ($nextquery > 0) sleep(1); 139 | 140 | if ($nextquery <= time()) 141 | { 142 | // Get server information. 143 | if ($serverinfo === false) 144 | { 145 | $result = $wkfshelper->GetServerInfo(); 146 | if (!$result["success"]) 147 | { 148 | WKFS_DisplayError("An error occurred while retrieving information from the remote server. Try again.", $result, false); 149 | 150 | $nextquery = time() + 15; 151 | } 152 | else 153 | { 154 | echo "Retrieved server information.\n"; 155 | 156 | if (isset($args["opts"]["tcp"])) 157 | { 158 | $ports = array(); 159 | foreach ($result["tcp"] as $num) 160 | { 161 | if (in_array($num, $args["opts"]["tcp"])) $ports[] = $num; 162 | } 163 | $result["tcp"] = $ports; 164 | } 165 | 166 | if (isset($args["opts"]["udp"])) 167 | { 168 | $ports = array(); 169 | foreach ($result["udp"] as $num) 170 | { 171 | if (in_array($num, $args["opts"]["udp"])) $ports[] = $num; 172 | } 173 | $result["udp"] = $ports; 174 | } 175 | 176 | $serverinfo = $result; 177 | } 178 | } 179 | 180 | if ($serverinfo !== false) 181 | { 182 | $maxtime = (isset($args["opts"]["maxtime"]) ? min((int)$args["opts"]["maxtime"], (int)$serverinfo["maxtime"]) : $serverinfo["maxtime"]); 183 | if ($maxtime <= 0) $maxtime = 10; 184 | $frequency = (int)(isset($args["opts"]["frequency"]) ? min((int)$args["opts"]["frequency"], $maxtime / 3) : $maxtime / 3); 185 | if ($frequency <= 0) $frequency = 1; 186 | 187 | $result = $wkfshelper->OpenServerPorts($serverinfo["tcp"], $serverinfo["udp"], $maxtime); 188 | if (!$result["success"]) 189 | { 190 | WKFS_DisplayError("An error occurred while attempting to open the requested server ports.", $result, false); 191 | 192 | $serverinfo = false; 193 | $nextquery = 0; 194 | } 195 | else 196 | { 197 | echo "Renewed until: " . date("Y-m-d H:i:s", $result["expires"]) . "\n"; 198 | $nextquery = time() + $frequency; 199 | } 200 | } 201 | } 202 | 203 | // Check the status of the two service file options. 204 | if ($lastservicecheck <= time() - 3) 205 | { 206 | if (file_exists($stopfilename) || file_exists($reloadfilename)) $running = false; 207 | 208 | $lastservicecheck = time(); 209 | } 210 | } while ($running); 211 | } 212 | ?> -------------------------------------------------------------------------------- /server/support/ipaddr.php: -------------------------------------------------------------------------------- 1 | $segment) 40 | { 41 | $segment = trim($segment); 42 | if ($segment != "") $ipaddr2[] = $segment; 43 | else if ($foundpos === false && count($ipaddr) > $num + 1 && $ipaddr[$num + 1] != "") 44 | { 45 | $foundpos = count($ipaddr2); 46 | $ipaddr2[] = "0000"; 47 | } 48 | } 49 | // Convert ::ffff:123.123.123.123 format. 50 | if (strpos($ipaddr2[count($ipaddr2) - 1], ".") !== false) 51 | { 52 | $x = count($ipaddr2) - 1; 53 | if ($ipaddr2[count($ipaddr2) - 2] != "ffff") $ipaddr2[$x] = "0"; 54 | else 55 | { 56 | $ipaddr = explode(".", $ipaddr2[$x]); 57 | if (count($ipaddr) != 4) $ipaddr2[$x] = "0"; 58 | else 59 | { 60 | $ipaddr2[$x] = str_pad(strtolower(dechex($ipaddr[0])), 2, "0", STR_PAD_LEFT) . str_pad(strtolower(dechex($ipaddr[1])), 2, "0", STR_PAD_LEFT); 61 | $ipaddr2[] = str_pad(strtolower(dechex($ipaddr[2])), 2, "0", STR_PAD_LEFT) . str_pad(strtolower(dechex($ipaddr[3])), 2, "0", STR_PAD_LEFT); 62 | } 63 | } 64 | } 65 | $ipaddr = array_slice($ipaddr2, 0, 8); 66 | if ($foundpos !== false && count($ipaddr) < 8) array_splice($ipaddr, $foundpos, 0, array_fill(0, 8 - count($ipaddr), "0000")); 67 | foreach ($ipaddr as $num => $segment) 68 | { 69 | $ipaddr[$num] = substr(str_pad(strtolower(dechex(hexdec($segment))), 4, "0", STR_PAD_LEFT), -4); 70 | } 71 | $ipv6addr = implode(":", $ipaddr); 72 | 73 | // Extract IPv4 address. 74 | if (substr($ipv6addr, 0, 30) == "0000:0000:0000:0000:0000:ffff:") $ipv4addr = hexdec(substr($ipv6addr, 30, 2)) . "." . hexdec(substr($ipv6addr, 32, 2)) . "." . hexdec(substr($ipv6addr, 35, 2)) . "." . hexdec(substr($ipv6addr, 37, 2)); 75 | 76 | // Make a short IPv6 address. 77 | $shortipv6 = $ipv6addr; 78 | $pattern = "0000:0000:0000:0000:0000:0000:0000"; 79 | do 80 | { 81 | $shortipv6 = str_replace($pattern, ":", $shortipv6); 82 | $pattern = substr($pattern, 5); 83 | } while (strlen($shortipv6) == 39 && $pattern != ""); 84 | $shortipv6 = explode(":", $shortipv6); 85 | foreach ($shortipv6 as $num => $segment) 86 | { 87 | if ($segment != "") $shortipv6[$num] = strtolower(dechex(hexdec($segment))); 88 | } 89 | $shortipv6 = implode(":", $shortipv6); 90 | 91 | return array("ipv6" => $ipv6addr, "shortipv6" => $shortipv6, "ipv4" => $ipv4addr); 92 | } 93 | 94 | public static function GetRemoteIP($proxies = array()) 95 | { 96 | $ipaddr = self::NormalizeIP(isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : "127.0.0.1"); 97 | 98 | // Check for trusted proxies. Stop at first untrusted IP in the chain. 99 | if (isset($proxies[$ipaddr["ipv6"]]) || ($ipaddr["ipv4"] != "" && isset($proxies[$ipaddr["ipv4"]]))) 100 | { 101 | $xforward = (isset($_SERVER["HTTP_X_FORWARDED_FOR"]) ? explode(",", $_SERVER["HTTP_X_FORWARDED_FOR"]) : array()); 102 | $clientip = (isset($_SERVER["HTTP_CLIENT_IP"]) ? explode(",", $_SERVER["HTTP_CLIENT_IP"]) : array()); 103 | 104 | do 105 | { 106 | $found = false; 107 | 108 | if (isset($proxies[$ipaddr["ipv6"]])) $header = $proxies[$ipaddr["ipv6"]]; 109 | else $header = $proxies[$ipaddr["ipv4"]]; 110 | 111 | $header = strtolower($header); 112 | if ($header == "xforward" && count($xforward) > 0) 113 | { 114 | $ipaddr = self::NormalizeIP(array_pop($xforward)); 115 | $found = true; 116 | } 117 | else if ($header == "clientip" && count($clientip) > 0) 118 | { 119 | $ipaddr = self::NormalizeIP(array_pop($clientip)); 120 | $found = true; 121 | } 122 | } while ($found && (isset($proxies[$ipaddr["ipv6"]]) || ($ipaddr["ipv4"] != "" && isset($proxies[$ipaddr["ipv4"]])))); 123 | } 124 | 125 | return $ipaddr; 126 | } 127 | 128 | public static function IsMatch($pattern, $ipaddr) 129 | { 130 | if (is_string($ipaddr)) $ipaddr = self::NormalizeIP($ipaddr); 131 | 132 | if (strpos($pattern, ":") !== false) 133 | { 134 | // Pattern is IPv6. 135 | $pattern = explode(":", strtolower($pattern)); 136 | $ipaddr = explode(":", $ipaddr["ipv6"]); 137 | if (count($pattern) != 8 || count($ipaddr) != 8) return false; 138 | foreach ($pattern as $num => $segment) 139 | { 140 | $found = false; 141 | $pieces = explode(",", $segment); 142 | foreach ($pieces as $piece) 143 | { 144 | $piece = trim($piece); 145 | $piece = explode(".", $piece); 146 | if (count($piece) == 1) 147 | { 148 | $piece = $piece[0]; 149 | 150 | if ($piece == "*") $found = true; 151 | else if (strpos($piece, "-") !== false) 152 | { 153 | $range = explode("-", $piece); 154 | $range[0] = hexdec($range[0]); 155 | $range[1] = hexdec($range[1]); 156 | $val = hexdec($ipaddr[$num]); 157 | if ($range[0] > $range[1]) $range[0] = $range[1]; 158 | if ($val >= $range[0] && $val <= $range[1]) $found = true; 159 | } 160 | else if ($piece === $ipaddr[$num]) $found = true; 161 | } 162 | else if (count($piece) == 2) 163 | { 164 | // Special IPv4-like notation. 165 | $found2 = false; 166 | $found3 = false; 167 | $val = hexdec(substr($ipaddr[$num], 0, 2)); 168 | $val2 = hexdec(substr($ipaddr[$num], 2, 2)); 169 | 170 | if ($piece[0] == "*") $found2 = true; 171 | else if (strpos($piece[0], "-") !== false) 172 | { 173 | $range = explode("-", $piece[0]); 174 | if ($range[0] > $range[1]) $range[0] = $range[1]; 175 | if ($val >= $range[0] && $val <= $range[1]) $found2 = true; 176 | } 177 | else if ($piece[0] == $val) $found2 = true; 178 | 179 | if ($piece[1] == "*") $found3 = true; 180 | else if (strpos($piece[1], "-") !== false) 181 | { 182 | $range = explode("-", $piece[1]); 183 | if ($range[0] > $range[1]) $range[0] = $range[1]; 184 | if ($val >= $range[0] && $val <= $range[1]) $found3 = true; 185 | } 186 | else if ($piece[1] == $val2) $found3 = true; 187 | 188 | if ($found2 && $found3) $found = true; 189 | } 190 | 191 | if ($found) break; 192 | } 193 | 194 | if (!$found) return false; 195 | } 196 | } 197 | else 198 | { 199 | // Pattern is IPv4. 200 | $pattern = explode(".", strtolower($pattern)); 201 | $ipaddr = explode(".", $ipaddr["ipv4"]); 202 | if (count($pattern) != 4 || count($ipaddr) != 4) return false; 203 | foreach ($pattern as $num => $segment) 204 | { 205 | $found = false; 206 | $pieces = explode(",", $segment); 207 | foreach ($pieces as $piece) 208 | { 209 | $piece = trim($piece); 210 | 211 | if ($piece == "*") $found = true; 212 | else if (strpos($piece, "-") !== false) 213 | { 214 | $range = explode("-", $piece); 215 | if ($range[0] > $range[1]) $range[0] = $range[1]; 216 | if ($ipaddr[$num] >= $range[0] && $ipaddr[$num] <= $range[1]) $found = true; 217 | } 218 | else if ($piece == $ipaddr[$num]) $found = true; 219 | 220 | if ($found) break; 221 | } 222 | 223 | if (!$found) return false; 224 | } 225 | } 226 | 227 | return true; 228 | } 229 | } 230 | ?> -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Web Knocker Firewall Service 2 | ============================ 3 | 4 | A web-based service written in pure PHP for Linux servers that opens protected TCP and UDP ports in response to encrypted requests from a correctly configured client for a limited but renewable time period. 5 | 6 | This software is for Linux system administrators who are serious about network security. Web Knocker Firewall Service (WKFS) takes your [elegant iptables rules](http://cubicspot.blogspot.com/2016/06/elegant-iptables-rules-for-your-linux.html) to a whole different level without introducing weaknesses in the IP stack. WKFS has been running successfully in CubicleSoft production environments since June 2016 without any issues. 7 | 8 | [![Donate](https://cubiclesoft.com/res/donate-shield.png)](https://cubiclesoft.com/donate/) [![Discord](https://img.shields.io/discord/777282089980526602?label=chat&logo=discord)](https://cubiclesoft.com/product-support/github/) 9 | 10 | Features 11 | -------- 12 | 13 | * IPv4 and IPv6 support. 14 | * Dynamic iptables chains and rules. 15 | * Can run multiple instances of the server on a single host. 16 | * Can run multiple instances of the client on a single host. 17 | * Optionally sends notification e-mail(s) whenever a client successfully opens a port on the server. 18 | * Port access is renewable. The PHP client takes advantage of this by attempting to renew twice during the access period. 19 | * Server controlled ports and timeouts limit what a client can do. 20 | * Two-way communication with pre-established encryption keys. Clients don't just send an encrypted data packet and hope that it worked. 21 | * Standard CubicleSoft dual-encryption. 22 | * Clients can be installed as system services via the included [Service Manager](https://github.com/cubiclesoft/service-manager) binaries. Windows, Mac, and Linux support. 23 | * Reasonable defenses against various attacks such as replay attacks. 24 | * Also has a liberal open source license. MIT or LGPL, your choice. 25 | * Designed for relatively painless integration into your environment. 26 | * Sits on GitHub for all of that pull request and issue tracker goodness to easily submit changes and ideas respectively. 27 | 28 | Why You Need WKFS 29 | ----------------- 30 | 31 | * Block rogue connection attempts to critical system services such as SSH, private e-mail servers, and the like. Russia, China, and North Korea run bots that automatically probe the edges of networks looking for weaknesses. 32 | * Allows time-limited traffic to critical system services from authorized dynamic/roaming IPs without setting up a VPN. Or you have a VPN but want another layer of security. 33 | * Relies on standard, battle-hardened web technologies such as Apache, Nginx, and PHP. Classical libpcap-based port knocking or newer single-packet authorization (SPA) solutions inject early into the network stack _before_ iptables, which merely exchanges one security risk for another more serious one. 34 | * Comes with officially supported client software for Windows, Mac, and Linux. 35 | 36 | Getting Started 37 | --------------- 38 | 39 | Download or clone this project. Upload the 'server' subdirectory to a relatively unguessable location on your Linux-based web server. 40 | 41 | Make sure you have the command-line (CLI) version of PHP installed for your Linux distribution (e.g. 'apt install php-cli'). The WKFS installer is written in PHP and therefore requires PHP to be somewhere on the system to function. 42 | 43 | From a command-line/shell session on the server, run: 44 | 45 | `php install.php` 46 | 47 | You will be asked a series of questions that will configure the service and then install and run it. Firewall/iptables rules _will be modified_ when the WKFS service starts. As a result, it is highly recommended to have a working recovery plan just in case access to the server is lost. Two possible options are to have a console/virtual console handy OR switch temporarily from an INPUT DROP policy to an ALLOW policy in case things go horribly wrong. 48 | 49 | Once the server portion is set up, put the 'client' subdirectory somewhere on the client (e.g. your computer) and, from a command-line, run: 50 | 51 | `php install.php` 52 | 53 | During the installation, the client installer will ask for the encryption keys (key1, iv1, key2, iv2) and HMAC signing key (sign) and the server URL where 'index.php' is located. Copy the keys from the server installation screen and calculate the appropriate URL. Once the connectivity test passes, the configuration is saved and the client service is optionally installed and started. It can, of course, be manually run. 54 | 55 | To unblock the ports manually or to debug server issues, run the client from the command-line directly: 56 | 57 | `php run.php` 58 | 59 | On the server side of things, running 'iptables-save' and 'ip6tables-save' will show the current firewall rules including the Web Knocker Firewall Service rules. Once everything looks good, lock down the server if you switched INPUT from DROP to ACCEPT earlier and then gain a little extra peace of mind with fewer ports open to the world. 60 | 61 | How It Works 62 | ------------ 63 | 64 | The client and server share dual encryption keys and a HMAC signing key. Think of it as a permanently established pre-negotiated SSL session. When a client wants to open a port, it first makes an information query to identify what ports for which protocols can be opened, how long they can be opened for, and what the server sees as the client IP address. Stopping a man-in-the-middle (MITM) attack is quite difficult (if not impossible) to begin with but that's not exactly the objective here. The objective is to keep out all of the automated scripts that are just hammering away at the open ports all day long. The client's IP address plus a timestamp prevents replay attacks, which is probably more than sufficient for most purposes. 65 | 66 | When a query is made by the client, it always uses the CubicleSoft dual encryption, packetization method. The block size of the request is 512 bytes and the total request size averages around 1,034 bytes - approximately 50% overhead. If a request is made every 10 minutes, approximately 150KB of data will be sent by the client daily to maintain one or more open ports. Data to be sent is JSON encoded, prefixed with the size, a HMAC is appended using the signing key, the result is wrapped in random bytes using a CSPRNG padded to the nearest 512 bytes, encrypted twice, and then Base64 encoded using the safe encoding mechanism. 67 | 68 | On the server side, the 'index.php' file reverses the procedure to decode, decrypt, and then verify the received data. If any errors occur, a HTTP error code is emitted and additional information may or may not be available - usually nothing beyond the HTTP error code is available. If no errors occur and a valid API action was requested, the server responds with an encrypted data packet of its own. 69 | 70 | When the request in the data packet is to open one or more ports, 'index.php' opens a TCP connection to the running server started by 'server.php' and passes along the packet information. 'index.php' is running under the web server user, which is probably something like 'www-data' and, of course, cannot make firewall changes. 'server.php', on the other hand, is running as a system service as the root user. Incoming localhost TCP connections (default is port 33491) send JSON encoded data to the server that specifies which port(s) to open for a specific IP address and for how long along with a shared secret (via 'config.php') that affords some basic protection. The server responds according to the information received and, upon success, returns when the applied firewall rules will expire. When the server opens a port (renewals don't count), it will also send notification e-mails if it is configured to do so. 71 | 72 | Security Analysis 73 | ----------------- 74 | 75 | In standard SSL notation, the protocol in use is probably: 76 | 77 | `SYSCSPRNG_NA_WITH_AES_2X_4096_CBC_SHA` 78 | 79 | CBC mode is irrelevant here - ECB could have been used - since the packetization method described in the previous section mitigates all known (BEAST, etc). CBC is good for extra mixing, but that's all. The use of the SHA-1 hash for HMAC is more for compatibility than anything else but HMAC-SHA-1 is still considered to be secure. Although, if someone can get past the encryption bits to get to the hash, they probably stole your configuration file which contains the encryption keys AND your HMAC signing key, so it doesn't matter. It's probably much easier to find another way to make a request to 'server.php' via an application vulnerability in the other software running on the web server than to try to break the encryption/signing bits. 80 | 81 | Remember all of this is to simply stop automated attack tools by closing the ports that are open to the world that already have their own security mechanisms built in. Most automated attack tools give up when they don't see an open port and move onto their next target. 82 | 83 | Someone may point out that a web knocker has one serious problem: If the web server is down, it won't work. In my experience, 98% of the time the web server is down, SSH is also inaccessible due to either heavy CPU load or other irregular reasons (e.g. a poorly written script encounters an unexpected network outage and spawns thousands of processes) and only a remote reboot of the system resolves the multitude of issues involved. I've only ever occasionally been able to access such systems or already had an active SSH connection to the box - and, even in those cases, I've found that it is still simpler and more efficient to reboot to correct the immediate performance problem and then resolve the core issue that triggered the performance problem after the system comes back up rather than try to do both simultaneously. 84 | -------------------------------------------------------------------------------- /server/install.php: -------------------------------------------------------------------------------- 1 | 0 && $port < 65536) $config["tcpprotected"][$port] = true; 47 | } 48 | } while ($cmd !== ""); 49 | $config["udpprotected"] = array(); 50 | do 51 | { 52 | echo "UDP port to protect: "; 53 | $cmd = trim(fgets(STDIN)); 54 | if ($cmd !== "") 55 | { 56 | $port = (int)$cmd; 57 | if ($port > 0 && $port < 65536) $config["udpprotected"][$port] = true; 58 | } 59 | } while ($cmd !== ""); 60 | 61 | echo "Maximum length of time to open the specified ports (in seconds): "; 62 | $config["maxtime"] = (int)trim(fgets(STDIN)); 63 | echo "\n\n"; 64 | 65 | echo "----------\n\n"; 66 | echo "The web server 'index.php' file sends allowed IP addresses to 'server.php' over localhost TCP/IP. The following questions configure the server portion so that it functions properly.\n\n"; 67 | echo "IPv6 (Y/N): "; 68 | $ipv6 = (substr(strtoupper(trim(fgets(STDIN))), 0, 1) == "Y"); 69 | $config["host"] = ($ipv6 ? "[::1]" : "127.0.0.1"); 70 | 71 | echo "Port (leave blank for the default - 33491): "; 72 | $port = trim(fgets(STDIN)); 73 | if ($port === "") $port = 33491; 74 | $port = (int)$port; 75 | if ($port < 0 || $port > 65535) $port = 33491; 76 | $config["port"] = $port; 77 | echo "\n\n"; 78 | 79 | echo "----------\n\n"; 80 | echo "This section is optional but highly recommended. When an IP address + port is unlocked, notification e-mails can be sent. Requires PHP mail() to be configured correctly. When done adding recipients, leave blank to move on.\n\n"; 81 | $config["recipients"] = array(); 82 | do 83 | { 84 | echo "Add notification recipient: "; 85 | $cmd = trim(fgets(STDIN)); 86 | if ($cmd !== "") $config["recipients"][] = $cmd; 87 | } while ($cmd !== ""); 88 | echo "\n\n"; 89 | 90 | echo "----------\n\n"; 91 | echo "The next few questions look at the current firewall setup to figure out where to place the rules for Web Knocker Firewall Service.\n\n"; 92 | echo "Below is the current list of chains in iptables (IPv4):\n\n"; 93 | system("iptables -L -n -v | grep Chain | awk '{ print \$2 }'"); 94 | echo "\n\n"; 95 | echo "Parent chain (default is INPUT): "; 96 | $chain = trim(fgets(STDIN)); 97 | if ($chain === "") $chain = "INPUT"; 98 | $config["iptparentchain"] = $chain; 99 | echo "Name for new iptables chain (default is web-knocker-firewall-service): "; 100 | $chain = trim(fgets(STDIN)); 101 | if ($chain === "") $chain = "web-knocker-firewall-service"; 102 | $config["iptchain"] = $chain; 103 | echo "\n\n"; 104 | 105 | echo "Below is the current list of chains in ip6tables (IPv6):\n\n"; 106 | system("ip6tables -L -n -v | grep Chain | awk '{ print \$2 }'"); 107 | echo "\n\n"; 108 | echo "Parent chain (default is INPUT): "; 109 | $chain = trim(fgets(STDIN)); 110 | if ($chain === "") $chain = "INPUT"; 111 | $config["ip6tparentchain"] = $chain; 112 | echo "Name for new ip6tables chain (default is web-knocker-firewall-service): "; 113 | $chain = trim(fgets(STDIN)); 114 | if ($chain === "") $chain = "web-knocker-firewall-service"; 115 | $config["ip6tchain"] = $chain; 116 | echo "\n\n"; 117 | 118 | echo "----------\n\n"; 119 | echo "The next few questions look at the current firewall setup to figure out what rules to remove. If you already use a strong firewall setup (e.g. INPUT DROP), you most likely already have rules in place to allow access to the ports you actually want to protect. Those rules need to be removed to allow Web Knocker Firewall Service to function as expected. The rules will be saved in case you later decide to uninstall Web Knocker Firewall Service.\n\n"; 120 | echo "Current IPv4 firewall rules:\n\n"; 121 | ob_start(); 122 | system("iptables-save | grep -- '-A '"); 123 | $currrules = explode("\n", trim(ob_get_contents())); 124 | ob_end_clean(); 125 | foreach ($currrules as $num => $rule) 126 | { 127 | if (substr($rule, 0, 3) !== "-A ") unset($currrules[$num]); 128 | } 129 | $currrules = array_values($currrules); 130 | foreach ($currrules as $num => $rule) 131 | { 132 | echo $num . ": " . $rule . "\n"; 133 | } 134 | echo "\n\n"; 135 | echo "Use the numbers above to select rules to remove. If you are removing SSH (port 22), save it for last to minimize issues.\n"; 136 | $config["removediptrules"] = array(); 137 | do 138 | { 139 | echo "Remove rule: "; 140 | $cmd = trim(fgets(STDIN)); 141 | if ($cmd !== "") 142 | { 143 | $num = (int)$cmd; 144 | if (isset($currrules[$num])) $config["removediptrules"][] = $currrules[$num]; 145 | } 146 | } while ($cmd !== ""); 147 | echo "\n\n"; 148 | 149 | echo "Current IPv6 firewall rules:\n\n"; 150 | ob_start(); 151 | system("ip6tables-save | grep -- '-A '"); 152 | $currrules = explode("\n", trim(ob_get_contents())); 153 | ob_end_clean(); 154 | foreach ($currrules as $num => $rule) 155 | { 156 | if (substr($rule, 0, 3) !== "-A ") unset($currrules[$num]); 157 | } 158 | $currrules = array_values($currrules); 159 | foreach ($currrules as $num => $rule) 160 | { 161 | echo $num . ": " . $rule . "\n"; 162 | } 163 | echo "\n\n"; 164 | echo "Use the numbers above to select rules to remove. If you are removing SSH (port 22), save it for last to minimize issues.\n"; 165 | $config["removedip6trules"] = array(); 166 | do 167 | { 168 | echo "Remove rule: "; 169 | $cmd = trim(fgets(STDIN)); 170 | if ($cmd !== "") 171 | { 172 | $num = (int)$cmd; 173 | if (isset($currrules[$num])) $config["removedip6trules"][] = $currrules[$num]; 174 | } 175 | } while ($cmd !== ""); 176 | echo "\n\n"; 177 | 178 | require_once "support/random.php"; 179 | 180 | $rng = new CSPRNG(true); 181 | $data = array( 182 | "key1" => bin2hex($rng->GetBytes(32)), 183 | "iv1" => bin2hex($rng->GetBytes(16)), 184 | "key2" => bin2hex($rng->GetBytes(32)), 185 | "iv2" => bin2hex($rng->GetBytes(16)), 186 | "sign" => bin2hex($rng->GetBytes(20)) 187 | ); 188 | 189 | $config["encryption_key"] = $data; 190 | 191 | $config["secret"] = bin2hex($rng->GetBytes(40)); 192 | 193 | $data = "<" . "?php\n"; 194 | $data .= "\t\$config = " . var_export($config, true) . ";\n"; 195 | $data .= "?" . ">"; 196 | file_put_contents($rootpath . "/config.php", $data); 197 | chmod($rootpath . "/config.php", 0444); 198 | 199 | echo "\n"; 200 | echo "**********\n"; 201 | echo "Configuration file is located at '" . $rootpath . "/config.php'.\n\n"; 202 | 203 | echo "Here is information you will need to configure the Web Knocker Firewall Service client:\n\n"; 204 | echo " key1 = " . $config["encryption_key"]["key1"] . "\n"; 205 | echo " iv1 = " . $config["encryption_key"]["iv1"] . "\n"; 206 | echo " key2 = " . $config["encryption_key"]["key2"] . "\n"; 207 | echo " iv2 = " . $config["encryption_key"]["iv2"] . "\n"; 208 | echo " sign = " . $config["encryption_key"]["sign"] . "\n"; 209 | echo "**********\n\n"; 210 | echo "\n\n"; 211 | 212 | echo "----------\n\n"; 213 | echo "Past this point be dragons! The server will be installed and started, which will modify the firewall. Depending on what ports are being protected, your connection to this system may drop and the system may be inaccessible until the client side is set up.\n\n"; 214 | echo "Proceed (Y/N): "; 215 | $proceed = (substr(strtoupper(trim(fgets(STDIN))), 0, 1) == "Y"); 216 | 217 | if (!$proceed) WKFS_DisplayError("Operation cancelled. Installation terminated. Server was not installed nor started and no firewall changes were made."); 218 | 219 | // Install and start 'server.php' as a system service. 220 | echo "Installing system service...\n"; 221 | system("php " . escapeshellarg($rootpath . "/server.php") . " install"); 222 | system("php " . escapeshellarg($rootpath . "/server.php") . " start"); 223 | echo "\n\n"; 224 | 225 | echo "Done.\n"; 226 | ?> -------------------------------------------------------------------------------- /client/support/deflate_stream.php: -------------------------------------------------------------------------------- 1 | open = false; 13 | } 14 | 15 | public function __destruct() 16 | { 17 | $this->Finalize(); 18 | } 19 | 20 | public static function IsSupported() 21 | { 22 | if (!is_bool(self::$supported)) 23 | { 24 | self::$supported = function_exists("stream_filter_append") && function_exists("stream_filter_remove") && function_exists("gzcompress"); 25 | if (self::$supported) 26 | { 27 | $data = self::Compress("test"); 28 | if ($data === false || $data === "") self::$supported = false; 29 | else 30 | { 31 | $data = self::Uncompress($data); 32 | if ($data === false || $data !== "test") self::$supported = false; 33 | } 34 | } 35 | } 36 | 37 | return self::$supported; 38 | } 39 | 40 | public static function Compress($data, $compresslevel = -1, $options = array()) 41 | { 42 | $ds = new DeflateStream; 43 | if (!$ds->Init("wb", $compresslevel, $options)) return false; 44 | if (!$ds->Write($data)) return false; 45 | if (!$ds->Finalize()) return false; 46 | $data = $ds->Read(); 47 | 48 | return $data; 49 | } 50 | 51 | public static function Uncompress($data, $options = array("type" => "auto")) 52 | { 53 | $ds = new DeflateStream; 54 | if (!$ds->Init("rb", -1, $options)) return false; 55 | if (!$ds->Write($data)) return false; 56 | if (!$ds->Finalize()) return false; 57 | $data = $ds->Read(); 58 | 59 | return $data; 60 | } 61 | 62 | public function Init($mode, $compresslevel = -1, $options = array()) 63 | { 64 | if ($mode !== "rb" && $mode !== "wb") return false; 65 | if ($this->open) $this->Finalize(); 66 | 67 | $this->fp = fopen("php://memory", "w+b"); 68 | if ($this->fp === false) return false; 69 | $this->compress = ($mode == "wb"); 70 | if (!isset($options["type"])) $options["type"] = "rfc1951"; 71 | 72 | if ($options["type"] == "rfc1950") $options["type"] = "zlib"; 73 | else if ($options["type"] == "rfc1952") $options["type"] = "gzip"; 74 | 75 | if ($options["type"] != "zlib" && $options["type"] != "gzip" && ($this->compress || $options["type"] != "auto")) $options["type"] = "raw"; 76 | $this->options = $options; 77 | 78 | // Add the deflate filter. 79 | if ($this->compress) $this->filter = stream_filter_append($this->fp, "zlib.deflate", STREAM_FILTER_WRITE, $compresslevel); 80 | else $this->filter = stream_filter_append($this->fp, "zlib.inflate", STREAM_FILTER_READ); 81 | 82 | $this->open = true; 83 | $this->indata = ""; 84 | $this->outdata = ""; 85 | 86 | if ($this->compress) 87 | { 88 | if ($this->options["type"] == "zlib") 89 | { 90 | $this->outdata .= "\x78\x9C"; 91 | $this->options["a"] = 1; 92 | $this->options["b"] = 0; 93 | } 94 | else if ($this->options["type"] == "gzip") 95 | { 96 | if (!class_exists("CRC32Stream", false)) require_once str_replace("\\", "/", dirname(__FILE__)) . "/crc32_stream.php"; 97 | 98 | $this->options["crc32"] = new CRC32Stream(); 99 | $this->options["crc32"]->Init(); 100 | $this->options["bytes"] = 0; 101 | 102 | $this->outdata .= "\x1F\x8B\x08"; 103 | $flags = 0; 104 | if (isset($this->options["filename"])) $flags |= 0x08; 105 | if (isset($this->options["comment"])) $flags |= 0x10; 106 | $this->outdata .= chr($flags); 107 | $this->outdata .= "\x00\x00\x00\x00"; 108 | $this->outdata .= "\x00"; 109 | $this->outdata .= "\x03"; 110 | 111 | if (isset($this->options["filename"])) $this->outdata .= str_replace("\x00", " ", $this->options["filename"]) . "\x00"; 112 | if (isset($this->options["comment"])) $this->outdata .= str_replace("\x00", " ", $this->options["comment"]) . "\x00"; 113 | } 114 | } 115 | else 116 | { 117 | $this->options["header"] = false; 118 | } 119 | 120 | return true; 121 | } 122 | 123 | public function Read() 124 | { 125 | $result = $this->outdata; 126 | $this->outdata = ""; 127 | 128 | return $result; 129 | } 130 | 131 | public function Write($data) 132 | { 133 | if (!$this->open) return false; 134 | 135 | if ($this->compress) 136 | { 137 | if ($this->options["type"] == "zlib") 138 | { 139 | // Adler-32. 140 | $y = strlen($data); 141 | for ($x = 0; $x < $y; $x++) 142 | { 143 | $this->options["a"] = ($this->options["a"] + ord($data[$x])) % 65521; 144 | $this->options["b"] = ($this->options["b"] + $this->options["a"]) % 65521; 145 | } 146 | } 147 | else if ($this->options["type"] == "gzip") 148 | { 149 | $this->options["crc32"]->AddData($data); 150 | $this->options["bytes"] = $this->ADD32($this->options["bytes"], strlen($data)); 151 | } 152 | 153 | $this->indata .= $data; 154 | while (strlen($this->indata) >= 65536) 155 | { 156 | fwrite($this->fp, substr($this->indata, 0, 65536)); 157 | $this->indata = substr($this->indata, 65536); 158 | 159 | $this->ProcessOutput(); 160 | } 161 | } 162 | else 163 | { 164 | $this->indata .= $data; 165 | $this->ProcessInput(); 166 | } 167 | 168 | return true; 169 | } 170 | 171 | // Finalizes the stream. 172 | public function Finalize() 173 | { 174 | if (!$this->open) return false; 175 | 176 | if (!$this->compress) $this->ProcessInput(true); 177 | 178 | if (strlen($this->indata) > 0) 179 | { 180 | fwrite($this->fp, $this->indata); 181 | $this->indata = ""; 182 | } 183 | 184 | // Removing the filter pushes the last buffer into the stream. 185 | stream_filter_remove($this->filter); 186 | $this->filter = false; 187 | 188 | $this->ProcessOutput(); 189 | 190 | fclose($this->fp); 191 | 192 | if ($this->compress) 193 | { 194 | if ($this->options["type"] == "zlib") $this->outdata .= pack("N", $this->SHL32($this->options["b"], 16) | $this->options["a"]); 195 | else if ($this->options["type"] == "gzip") $this->outdata .= pack("V", $this->options["crc32"]->Finalize()) . pack("V", $this->options["bytes"]); 196 | } 197 | 198 | $this->open = false; 199 | 200 | return true; 201 | } 202 | 203 | private function ProcessOutput() 204 | { 205 | rewind($this->fp); 206 | 207 | // Hack! Because ftell() on a stream with a filter is still broken even under the latest PHP a mere 11 years later. 208 | // See: https://bugs.php.net/bug.php?id=49874 209 | ob_start(); 210 | fpassthru($this->fp); 211 | $this->outdata .= ob_get_contents(); 212 | ob_end_clean(); 213 | 214 | rewind($this->fp); 215 | ftruncate($this->fp, 0); 216 | } 217 | 218 | private function ProcessInput($final = false) 219 | { 220 | // Automatically determine the type of data based on the header signature. 221 | if ($this->options["type"] == "auto") 222 | { 223 | if (strlen($this->indata) >= 3) 224 | { 225 | $zlibtest = unpack("n", substr($this->indata, 0, 2)); 226 | 227 | if (substr($this->indata, 0, 3) === "\x1F\x8B\x08") $this->options["type"] = "gzip"; 228 | else if ((ord($this->indata[0]) & 0x0F) == 8 && ((ord($this->indata[0]) & 0xF0) >> 4) < 8 && $zlibtest[1] % 31 == 0) $this->options["type"] = "zlib"; 229 | else $this->options["type"] = "raw"; 230 | } 231 | else if ($final) $this->options["type"] = "raw"; 232 | } 233 | 234 | if ($this->options["type"] == "gzip") 235 | { 236 | if (!$this->options["header"]) 237 | { 238 | if (strlen($this->indata) >= 10) 239 | { 240 | $idcm = substr($this->indata, 0, 3); 241 | $flg = ord($this->indata[3]); 242 | 243 | if ($idcm !== "\x1F\x8B\x08") $this->options["type"] = "ignore"; 244 | else 245 | { 246 | // Calculate the number of bytes to skip. If flags are set, the size can be dynamic. 247 | $size = 10; 248 | $y = strlen($this->indata); 249 | 250 | // FLG.FEXTRA 251 | if ($size && ($flg & 0x04)) 252 | { 253 | if ($size + 2 >= $y) $size = 0; 254 | else 255 | { 256 | $xlen = unpack("v", substr($this->indata, $size, 2)); 257 | $size = ($size + 2 + $xlen <= $y ? $size + 2 + $xlen : 0); 258 | } 259 | } 260 | 261 | // FLG.FNAME 262 | if ($size && ($flg & 0x08)) 263 | { 264 | $pos = strpos($this->indata, "\x00", $size); 265 | $size = ($pos !== false ? $pos + 1 : 0); 266 | } 267 | 268 | // FLG.FCOMMENT 269 | if ($size && ($flg & 0x10)) 270 | { 271 | $pos = strpos($this->indata, "\x00", $size); 272 | $size = ($pos !== false ? $pos + 1 : 0); 273 | } 274 | 275 | // FLG.FHCRC 276 | if ($size && ($flg & 0x02)) $size = ($size + 2 <= $y ? $size + 2 : 0); 277 | 278 | if ($size) 279 | { 280 | $this->indata = substr($this->indata, $size); 281 | $this->options["header"] = true; 282 | } 283 | } 284 | } 285 | } 286 | 287 | if ($this->options["header"] && strlen($this->indata) > 8) 288 | { 289 | fwrite($this->fp, substr($this->indata, 0, -8)); 290 | $this->indata = substr($this->indata, -8); 291 | 292 | $this->ProcessOutput(); 293 | } 294 | 295 | if ($final) $this->indata = ""; 296 | } 297 | else if ($this->options["type"] == "zlib") 298 | { 299 | if (!$this->options["header"]) 300 | { 301 | if (strlen($this->indata) >= 2) 302 | { 303 | $cmf = ord($this->indata[0]); 304 | $flg = ord($this->indata[1]); 305 | $cm = $cmf & 0x0F; 306 | $cinfo = ($cmf & 0xF0) >> 4; 307 | 308 | // Compression method 'deflate' ($cm = 8), window size - 8 ($cinfo < 8), no preset dictionaries ($flg bit 5), checksum validates. 309 | if ($cm != 8 || $cinfo > 7 || ($flg & 0x20) || (($cmf << 8 | $flg) % 31) != 0) $this->options["type"] = "ignore"; 310 | else 311 | { 312 | $this->indata = substr($this->indata, 2); 313 | $this->options["header"] = true; 314 | } 315 | } 316 | } 317 | 318 | if ($this->options["header"] && strlen($this->indata) > 4) 319 | { 320 | fwrite($this->fp, substr($this->indata, 0, -4)); 321 | $this->indata = substr($this->indata, -4); 322 | 323 | $this->ProcessOutput(); 324 | } 325 | 326 | if ($final) $this->indata = ""; 327 | } 328 | 329 | if ($this->options["type"] == "raw") 330 | { 331 | fwrite($this->fp, $this->indata); 332 | $this->indata = ""; 333 | 334 | $this->ProcessOutput(); 335 | } 336 | 337 | // Only set when an unrecoverable header error has occurred for gzip or zlib. 338 | if ($this->options["type"] == "ignore") $this->indata = ""; 339 | } 340 | 341 | private function SHL32($num, $bits) 342 | { 343 | if ($bits < 0) $bits = 0; 344 | 345 | return $this->LIM32((int)$num << $bits); 346 | } 347 | 348 | private function LIM32($num) 349 | { 350 | return (int)((int)$num & 0xFFFFFFFF); 351 | } 352 | 353 | private function ADD32($num, $num2) 354 | { 355 | $num = (int)$num; 356 | $num2 = (int)$num2; 357 | $add = ((($num >> 30) & 0x03) + (($num2 >> 30) & 0x03)); 358 | $num = ((int)($num & 0x3FFFFFFF) + (int)($num2 & 0x3FFFFFFF)); 359 | if ($num & 0x40000000) $add++; 360 | $num = (int)(($num & 0x3FFFFFFF) | (($add & 0x03) << 30)); 361 | 362 | return $num; 363 | } 364 | } 365 | ?> -------------------------------------------------------------------------------- /client/support/random.php: -------------------------------------------------------------------------------- 1 | mode = false; 15 | $this->fp = false; 16 | $this->cryptosafe = $cryptosafe; 17 | 18 | // Native first (PHP 7 and later). 19 | if (function_exists("random_bytes")) $this->mode = "native"; 20 | 21 | // OpenSSL fallback. 22 | if ($this->mode === false && function_exists("openssl_random_pseudo_bytes")) 23 | { 24 | // PHP 5.4.0 introduced native Windows CryptGenRandom() integration via php_win32_get_random_bytes() for performance. 25 | @openssl_random_pseudo_bytes(4, $strong); 26 | if ($strong) $this->mode = "openssl"; 27 | } 28 | 29 | // Locate a (relatively) suitable source of entropy or raise an exception. 30 | if (strtoupper(substr(PHP_OS, 0, 3)) === "WIN") 31 | { 32 | // PHP 5.3.0 introduced native Windows CryptGenRandom() integration via php_win32_get_random_bytes() for functionality. 33 | if ($this->mode === false && PHP_VERSION_ID > 50300 && function_exists("mcrypt_create_iv")) $this->mode = "mcrypt"; 34 | } 35 | else 36 | { 37 | if (!$cryptosafe && $this->mode === false && file_exists("/dev/arandom")) 38 | { 39 | // OpenBSD. mcrypt doesn't attempt to use this despite claims of higher quality entropy with performance. 40 | $this->fp = @fopen("/dev/arandom", "rb"); 41 | if ($this->fp !== false) $this->mode = "file"; 42 | } 43 | 44 | if ($cryptosafe && $this->mode === false && file_exists("/dev/random")) 45 | { 46 | // Everything else. 47 | $this->fp = @fopen("/dev/random", "rb"); 48 | if ($this->fp !== false) $this->mode = "file"; 49 | } 50 | 51 | if (!$cryptosafe && $this->mode === false && file_exists("/dev/urandom")) 52 | { 53 | // Everything else. 54 | $this->fp = @fopen("/dev/urandom", "rb"); 55 | if ($this->fp !== false) $this->mode = "file"; 56 | } 57 | 58 | if ($this->mode === false && function_exists("mcrypt_create_iv")) 59 | { 60 | // mcrypt_create_iv() is last because it opens and closes a file handle every single call. 61 | $this->mode = "mcrypt"; 62 | } 63 | } 64 | 65 | // Throw an exception if unable to find a suitable entropy source. 66 | if ($this->mode === false) 67 | { 68 | throw new Exception(self::RNG_Translate("Unable to locate a suitable entropy source.")); 69 | exit(); 70 | } 71 | } 72 | 73 | public function __destruct() 74 | { 75 | if ($this->mode === "file") fclose($this->fp); 76 | } 77 | 78 | public function GetBytes($length) 79 | { 80 | if ($this->mode === false) return false; 81 | 82 | $length = (int)$length; 83 | if ($length < 1) return false; 84 | 85 | $result = ""; 86 | do 87 | { 88 | switch ($this->mode) 89 | { 90 | case "native": $data = @random_bytes($length); break; 91 | case "openssl": $data = @openssl_random_pseudo_bytes($length, $strong); if (!$strong) $data = false; break; 92 | case "mcrypt": $data = @mcrypt_create_iv($length, ($this->cryptosafe ? MCRYPT_DEV_RANDOM : MCRYPT_DEV_URANDOM)); break; 93 | case "file": $data = @fread($this->fp, $length); break; 94 | default: $data = false; 95 | } 96 | if ($data === false) return false; 97 | 98 | $result .= $data; 99 | } while (strlen($result) < $length); 100 | 101 | return substr($result, 0, $length); 102 | } 103 | 104 | public function GenerateToken($length = 64) 105 | { 106 | $data = $this->GetBytes($length); 107 | if ($data === false) return false; 108 | 109 | return bin2hex($data); 110 | } 111 | 112 | // Get a random number between $min and $max (inclusive). 113 | public function GetInt($min, $max) 114 | { 115 | $min = (int)$min; 116 | $max = (int)$max; 117 | if ($max < $min) return false; 118 | if ($min == $max) return $min; 119 | 120 | $range = $max - $min + 1; 121 | 122 | $bits = 1; 123 | while ((1 << $bits) <= $range) $bits++; 124 | 125 | $numbytes = (int)(($bits + 7) / 8); 126 | $mask = (1 << $bits) - 1; 127 | 128 | do 129 | { 130 | $data = $this->GetBytes($numbytes); 131 | if ($data === false) return false; 132 | 133 | $result = 0; 134 | for ($x = 0; $x < $numbytes; $x++) 135 | { 136 | $result = ($result * 256) + ord($data[$x]); 137 | } 138 | 139 | $result = $result & $mask; 140 | } while ($result >= $range); 141 | 142 | return $result + $min; 143 | } 144 | 145 | // Convenience method to generate a random alphanumeric string. 146 | public function GenerateString($size = 32) 147 | { 148 | $result = ""; 149 | for ($x = 0; $x < $size; $x++) 150 | { 151 | $data = $this->GetInt(0, 61); 152 | if ($data === false) return false; 153 | 154 | $result .= self::$alphanum[$data]; 155 | } 156 | 157 | return $result; 158 | } 159 | 160 | public function GenerateWordLite(&$freqmap, $len) 161 | { 162 | $totalc = 0; 163 | $totalv = 0; 164 | foreach ($freqmap["consonants"] as $chr => $num) $totalc += $num; 165 | foreach ($freqmap["vowels"] as $chr => $num) $totalv += $num; 166 | 167 | if ($totalc <= 0 || $totalv <= 0) return false; 168 | 169 | $result = ""; 170 | for ($x = 0; $x < $len; $x++) 171 | { 172 | if ($x % 2) 173 | { 174 | $data = $this->GetInt(0, $totalv - 1); 175 | if ($data === false) return false; 176 | 177 | foreach ($freqmap["vowels"] as $chr => $num) 178 | { 179 | if ($num > $data) 180 | { 181 | $result .= $chr; 182 | 183 | break; 184 | } 185 | 186 | $data -= $num; 187 | } 188 | } 189 | else 190 | { 191 | $data = $this->GetInt(0, $totalc - 1); 192 | if ($data === false) return false; 193 | 194 | foreach ($freqmap["consonants"] as $chr => $num) 195 | { 196 | if ($num > $data) 197 | { 198 | $result .= $chr; 199 | 200 | break; 201 | } 202 | 203 | $data -= $num; 204 | } 205 | } 206 | } 207 | 208 | return $result; 209 | } 210 | 211 | public function GenerateWord(&$freqmap, $len, $separator = "-") 212 | { 213 | $result = ""; 214 | $queue = array(); 215 | $threshold = $freqmap["threshold"]; 216 | $state = "start"; 217 | while ($len) 218 | { 219 | //echo $state . " - " . $len . ": " . $result . "\n"; 220 | switch ($state) 221 | { 222 | case "start": 223 | { 224 | // The start of the word (or restart). 225 | $path = &$freqmap["start"]; 226 | while (count($queue) < $threshold && $len) 227 | { 228 | if ($len > 1 || !$path["*"]) 229 | { 230 | // Some part of the word. 231 | $found = false; 232 | if ($path[""]) 233 | { 234 | $pos = $this->GetInt(0, $path[""] - 1); 235 | 236 | foreach ($path as $chr => &$info) 237 | { 238 | if (!is_array($info)) continue; 239 | 240 | if ($info["+"] > $pos) 241 | { 242 | $result .= $chr; 243 | $queue[] = $chr; 244 | $path = &$path[$chr]; 245 | $len--; 246 | 247 | $found = true; 248 | 249 | break; 250 | } 251 | 252 | $pos -= $info["+"]; 253 | } 254 | } 255 | 256 | if (!$found) 257 | { 258 | $state = (count($queue) ? "recovery" : "restart"); 259 | 260 | break; 261 | } 262 | } 263 | else 264 | { 265 | // Last letter of the word. 266 | $found = false; 267 | if ($path["*"]) 268 | { 269 | $pos = $this->GetInt(0, $path["*"] - 1); 270 | 271 | foreach ($path as $chr => &$info) 272 | { 273 | if (!is_array($info)) continue; 274 | 275 | if ($info["-"] > $pos) 276 | { 277 | $result .= $chr; 278 | $queue[] = $chr; 279 | $path = &$path[$chr]; 280 | $len--; 281 | 282 | $found = true; 283 | 284 | break; 285 | } 286 | 287 | $pos -= $info["-"]; 288 | } 289 | } 290 | 291 | if (!$found) 292 | { 293 | $state = (count($queue) ? "end" : "restart"); 294 | 295 | break; 296 | } 297 | } 298 | } 299 | 300 | if (count($queue) >= $threshold) $state = ($len >= $threshold ? "middle" : "end"); 301 | 302 | break; 303 | } 304 | case "middle": 305 | { 306 | // The middle of the word. 307 | $str = implode("", $queue); 308 | 309 | if (!isset($freqmap["middle"][$str])) $state = "recovery"; 310 | else 311 | { 312 | $found = false; 313 | 314 | if ($freqmap["middle"][$str][""]) 315 | { 316 | $pos = $this->GetInt(0, $freqmap["middle"][$str][""] - 1); 317 | 318 | foreach ($freqmap["middle"][$str] as $chr => $num) 319 | { 320 | if ($chr === "") continue; 321 | 322 | if ($num > $pos) 323 | { 324 | $result .= $chr; 325 | $queue[] = $chr; 326 | array_shift($queue); 327 | $len--; 328 | 329 | if ($len < $threshold) $state = "end"; 330 | 331 | $found = true; 332 | 333 | break; 334 | } 335 | 336 | $pos -= $num; 337 | } 338 | } 339 | 340 | if (!$found) $state = "recovery"; 341 | } 342 | 343 | break; 344 | } 345 | case "end": 346 | { 347 | if (!isset($freqmap["end"][$len]) || !count($queue) || !isset($freqmap["end"][$len][$queue[count($queue) - 1]])) $state = "restart"; 348 | else 349 | { 350 | $path = &$freqmap["end"][$len][$queue[count($queue) - 1]]; 351 | 352 | $found = false; 353 | 354 | if ($path[""]) 355 | { 356 | $pos = $this->GetInt(0, $path[""] - 1); 357 | 358 | foreach ($path as $str => $num) 359 | { 360 | if ($str === "") continue; 361 | 362 | if ($num > $pos) 363 | { 364 | $result .= $str; 365 | $len = 0; 366 | 367 | $found = true; 368 | 369 | break; 370 | } 371 | 372 | $pos -= $num; 373 | } 374 | } 375 | 376 | if (!$found) $state = "restart"; 377 | } 378 | 379 | break; 380 | } 381 | case "recovery": 382 | { 383 | if (!count($queue) || !isset($freqmap["recovery"][$queue[count($queue) - 1]])) $state = "restart"; 384 | else 385 | { 386 | $path = &$freqmap["recovery"][$queue[count($queue) - 1]]; 387 | 388 | $found = false; 389 | 390 | if ($path[""]) 391 | { 392 | $pos = $this->GetInt(0, $path[""] - 1); 393 | 394 | foreach ($path as $chr => $num) 395 | { 396 | if ($chr === "") continue; 397 | 398 | if ($num > $pos) 399 | { 400 | $result .= $chr; 401 | $queue[] = $chr; 402 | array_shift($queue); 403 | $len--; 404 | 405 | $state = ($len >= $threshold ? "middle" : "end"); 406 | 407 | $found = true; 408 | 409 | break; 410 | } 411 | 412 | $pos -= $num; 413 | } 414 | } 415 | 416 | if (!$found) $state = "restart"; 417 | } 418 | 419 | break; 420 | } 421 | case "restart": 422 | { 423 | $result .= $separator; 424 | $queue = array(); 425 | $len -= strlen($separator); 426 | 427 | $state = "start"; 428 | 429 | break; 430 | } 431 | } 432 | } 433 | 434 | return $result; 435 | } 436 | 437 | public function GetMode() 438 | { 439 | return $this->mode; 440 | } 441 | 442 | protected static function RNG_Translate() 443 | { 444 | $args = func_get_args(); 445 | if (!count($args)) return ""; 446 | 447 | return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); 448 | } 449 | } 450 | ?> -------------------------------------------------------------------------------- /server/support/random.php: -------------------------------------------------------------------------------- 1 | mode = false; 15 | $this->fp = false; 16 | $this->cryptosafe = $cryptosafe; 17 | 18 | // Native first (PHP 7 and later). 19 | if (function_exists("random_bytes")) $this->mode = "native"; 20 | 21 | // OpenSSL fallback. 22 | if ($this->mode === false && function_exists("openssl_random_pseudo_bytes")) 23 | { 24 | // PHP 5.4.0 introduced native Windows CryptGenRandom() integration via php_win32_get_random_bytes() for performance. 25 | @openssl_random_pseudo_bytes(4, $strong); 26 | if ($strong) $this->mode = "openssl"; 27 | } 28 | 29 | // Locate a (relatively) suitable source of entropy or raise an exception. 30 | if (strtoupper(substr(PHP_OS, 0, 3)) === "WIN") 31 | { 32 | // PHP 5.3.0 introduced native Windows CryptGenRandom() integration via php_win32_get_random_bytes() for functionality. 33 | if ($this->mode === false && PHP_VERSION_ID > 50300 && function_exists("mcrypt_create_iv")) $this->mode = "mcrypt"; 34 | } 35 | else 36 | { 37 | if (!$cryptosafe && $this->mode === false && file_exists("/dev/arandom")) 38 | { 39 | // OpenBSD. mcrypt doesn't attempt to use this despite claims of higher quality entropy with performance. 40 | $this->fp = @fopen("/dev/arandom", "rb"); 41 | if ($this->fp !== false) $this->mode = "file"; 42 | } 43 | 44 | if ($cryptosafe && $this->mode === false && file_exists("/dev/random")) 45 | { 46 | // Everything else. 47 | $this->fp = @fopen("/dev/random", "rb"); 48 | if ($this->fp !== false) $this->mode = "file"; 49 | } 50 | 51 | if (!$cryptosafe && $this->mode === false && file_exists("/dev/urandom")) 52 | { 53 | // Everything else. 54 | $this->fp = @fopen("/dev/urandom", "rb"); 55 | if ($this->fp !== false) $this->mode = "file"; 56 | } 57 | 58 | if ($this->mode === false && function_exists("mcrypt_create_iv")) 59 | { 60 | // mcrypt_create_iv() is last because it opens and closes a file handle every single call. 61 | $this->mode = "mcrypt"; 62 | } 63 | } 64 | 65 | // Throw an exception if unable to find a suitable entropy source. 66 | if ($this->mode === false) 67 | { 68 | throw new Exception(self::RNG_Translate("Unable to locate a suitable entropy source.")); 69 | exit(); 70 | } 71 | } 72 | 73 | public function __destruct() 74 | { 75 | if ($this->mode === "file") fclose($this->fp); 76 | } 77 | 78 | public function GetBytes($length) 79 | { 80 | if ($this->mode === false) return false; 81 | 82 | $length = (int)$length; 83 | if ($length < 1) return false; 84 | 85 | $result = ""; 86 | do 87 | { 88 | switch ($this->mode) 89 | { 90 | case "native": $data = @random_bytes($length); break; 91 | case "openssl": $data = @openssl_random_pseudo_bytes($length, $strong); if (!$strong) $data = false; break; 92 | case "mcrypt": $data = @mcrypt_create_iv($length, ($this->cryptosafe ? MCRYPT_DEV_RANDOM : MCRYPT_DEV_URANDOM)); break; 93 | case "file": $data = @fread($this->fp, $length); break; 94 | default: $data = false; 95 | } 96 | if ($data === false) return false; 97 | 98 | $result .= $data; 99 | } while (strlen($result) < $length); 100 | 101 | return substr($result, 0, $length); 102 | } 103 | 104 | public function GenerateToken($length = 64) 105 | { 106 | $data = $this->GetBytes($length); 107 | if ($data === false) return false; 108 | 109 | return bin2hex($data); 110 | } 111 | 112 | // Get a random number between $min and $max (inclusive). 113 | public function GetInt($min, $max) 114 | { 115 | $min = (int)$min; 116 | $max = (int)$max; 117 | if ($max < $min) return false; 118 | if ($min == $max) return $min; 119 | 120 | $range = $max - $min + 1; 121 | 122 | $bits = 1; 123 | while ((1 << $bits) <= $range) $bits++; 124 | 125 | $numbytes = (int)(($bits + 7) / 8); 126 | $mask = (1 << $bits) - 1; 127 | 128 | do 129 | { 130 | $data = $this->GetBytes($numbytes); 131 | if ($data === false) return false; 132 | 133 | $result = 0; 134 | for ($x = 0; $x < $numbytes; $x++) 135 | { 136 | $result = ($result * 256) + ord($data[$x]); 137 | } 138 | 139 | $result = $result & $mask; 140 | } while ($result >= $range); 141 | 142 | return $result + $min; 143 | } 144 | 145 | // Convenience method to generate a random alphanumeric string. 146 | public function GenerateString($size = 32) 147 | { 148 | $result = ""; 149 | for ($x = 0; $x < $size; $x++) 150 | { 151 | $data = $this->GetInt(0, 61); 152 | if ($data === false) return false; 153 | 154 | $result .= self::$alphanum[$data]; 155 | } 156 | 157 | return $result; 158 | } 159 | 160 | public function GenerateWordLite(&$freqmap, $len) 161 | { 162 | $totalc = 0; 163 | $totalv = 0; 164 | foreach ($freqmap["consonants"] as $chr => $num) $totalc += $num; 165 | foreach ($freqmap["vowels"] as $chr => $num) $totalv += $num; 166 | 167 | if ($totalc <= 0 || $totalv <= 0) return false; 168 | 169 | $result = ""; 170 | for ($x = 0; $x < $len; $x++) 171 | { 172 | if ($x % 2) 173 | { 174 | $data = $this->GetInt(0, $totalv - 1); 175 | if ($data === false) return false; 176 | 177 | foreach ($freqmap["vowels"] as $chr => $num) 178 | { 179 | if ($num > $data) 180 | { 181 | $result .= $chr; 182 | 183 | break; 184 | } 185 | 186 | $data -= $num; 187 | } 188 | } 189 | else 190 | { 191 | $data = $this->GetInt(0, $totalc - 1); 192 | if ($data === false) return false; 193 | 194 | foreach ($freqmap["consonants"] as $chr => $num) 195 | { 196 | if ($num > $data) 197 | { 198 | $result .= $chr; 199 | 200 | break; 201 | } 202 | 203 | $data -= $num; 204 | } 205 | } 206 | } 207 | 208 | return $result; 209 | } 210 | 211 | public function GenerateWord(&$freqmap, $len, $separator = "-") 212 | { 213 | $result = ""; 214 | $queue = array(); 215 | $threshold = $freqmap["threshold"]; 216 | $state = "start"; 217 | while ($len) 218 | { 219 | //echo $state . " - " . $len . ": " . $result . "\n"; 220 | switch ($state) 221 | { 222 | case "start": 223 | { 224 | // The start of the word (or restart). 225 | $path = &$freqmap["start"]; 226 | while (count($queue) < $threshold && $len) 227 | { 228 | if ($len > 1 || !$path["*"]) 229 | { 230 | // Some part of the word. 231 | $found = false; 232 | if ($path[""]) 233 | { 234 | $pos = $this->GetInt(0, $path[""] - 1); 235 | 236 | foreach ($path as $chr => &$info) 237 | { 238 | if (!is_array($info)) continue; 239 | 240 | if ($info["+"] > $pos) 241 | { 242 | $result .= $chr; 243 | $queue[] = $chr; 244 | $path = &$path[$chr]; 245 | $len--; 246 | 247 | $found = true; 248 | 249 | break; 250 | } 251 | 252 | $pos -= $info["+"]; 253 | } 254 | } 255 | 256 | if (!$found) 257 | { 258 | $state = (count($queue) ? "recovery" : "restart"); 259 | 260 | break; 261 | } 262 | } 263 | else 264 | { 265 | // Last letter of the word. 266 | $found = false; 267 | if ($path["*"]) 268 | { 269 | $pos = $this->GetInt(0, $path["*"] - 1); 270 | 271 | foreach ($path as $chr => &$info) 272 | { 273 | if (!is_array($info)) continue; 274 | 275 | if ($info["-"] > $pos) 276 | { 277 | $result .= $chr; 278 | $queue[] = $chr; 279 | $path = &$path[$chr]; 280 | $len--; 281 | 282 | $found = true; 283 | 284 | break; 285 | } 286 | 287 | $pos -= $info["-"]; 288 | } 289 | } 290 | 291 | if (!$found) 292 | { 293 | $state = (count($queue) ? "end" : "restart"); 294 | 295 | break; 296 | } 297 | } 298 | } 299 | 300 | if (count($queue) >= $threshold) $state = ($len >= $threshold ? "middle" : "end"); 301 | 302 | break; 303 | } 304 | case "middle": 305 | { 306 | // The middle of the word. 307 | $str = implode("", $queue); 308 | 309 | if (!isset($freqmap["middle"][$str])) $state = "recovery"; 310 | else 311 | { 312 | $found = false; 313 | 314 | if ($freqmap["middle"][$str][""]) 315 | { 316 | $pos = $this->GetInt(0, $freqmap["middle"][$str][""] - 1); 317 | 318 | foreach ($freqmap["middle"][$str] as $chr => $num) 319 | { 320 | if ($chr === "") continue; 321 | 322 | if ($num > $pos) 323 | { 324 | $result .= $chr; 325 | $queue[] = $chr; 326 | array_shift($queue); 327 | $len--; 328 | 329 | if ($len < $threshold) $state = "end"; 330 | 331 | $found = true; 332 | 333 | break; 334 | } 335 | 336 | $pos -= $num; 337 | } 338 | } 339 | 340 | if (!$found) $state = "recovery"; 341 | } 342 | 343 | break; 344 | } 345 | case "end": 346 | { 347 | if (!isset($freqmap["end"][$len]) || !count($queue) || !isset($freqmap["end"][$len][$queue[count($queue) - 1]])) $state = "restart"; 348 | else 349 | { 350 | $path = &$freqmap["end"][$len][$queue[count($queue) - 1]]; 351 | 352 | $found = false; 353 | 354 | if ($path[""]) 355 | { 356 | $pos = $this->GetInt(0, $path[""] - 1); 357 | 358 | foreach ($path as $str => $num) 359 | { 360 | if ($str === "") continue; 361 | 362 | if ($num > $pos) 363 | { 364 | $result .= $str; 365 | $len = 0; 366 | 367 | $found = true; 368 | 369 | break; 370 | } 371 | 372 | $pos -= $num; 373 | } 374 | } 375 | 376 | if (!$found) $state = "restart"; 377 | } 378 | 379 | break; 380 | } 381 | case "recovery": 382 | { 383 | if (!count($queue) || !isset($freqmap["recovery"][$queue[count($queue) - 1]])) $state = "restart"; 384 | else 385 | { 386 | $path = &$freqmap["recovery"][$queue[count($queue) - 1]]; 387 | 388 | $found = false; 389 | 390 | if ($path[""]) 391 | { 392 | $pos = $this->GetInt(0, $path[""] - 1); 393 | 394 | foreach ($path as $chr => $num) 395 | { 396 | if ($chr === "") continue; 397 | 398 | if ($num > $pos) 399 | { 400 | $result .= $chr; 401 | $queue[] = $chr; 402 | array_shift($queue); 403 | $len--; 404 | 405 | $state = ($len >= $threshold ? "middle" : "end"); 406 | 407 | $found = true; 408 | 409 | break; 410 | } 411 | 412 | $pos -= $num; 413 | } 414 | } 415 | 416 | if (!$found) $state = "restart"; 417 | } 418 | 419 | break; 420 | } 421 | case "restart": 422 | { 423 | $result .= $separator; 424 | $queue = array(); 425 | $len -= strlen($separator); 426 | 427 | $state = "start"; 428 | 429 | break; 430 | } 431 | } 432 | } 433 | 434 | return $result; 435 | } 436 | 437 | public function GetMode() 438 | { 439 | return $this->mode; 440 | } 441 | 442 | protected static function RNG_Translate() 443 | { 444 | $args = func_get_args(); 445 | if (!count($args)) return ""; 446 | 447 | return call_user_func_array((defined("CS_TRANSLATE_FUNC") && function_exists(CS_TRANSLATE_FUNC) ? CS_TRANSLATE_FUNC : "sprintf"), $args); 448 | } 449 | } 450 | ?> -------------------------------------------------------------------------------- /client/support/cli.php: -------------------------------------------------------------------------------- 1 | $val) 15 | { 16 | if (!isset($options["rules"][$val])) unset($options["shortmap"][$key]); 17 | } 18 | foreach ($options["rules"] as $key => $val) 19 | { 20 | if (!isset($val["arg"])) $options["rules"][$key]["arg"] = false; 21 | if (!isset($val["multiple"])) $options["rules"][$key]["multiple"] = false; 22 | } 23 | 24 | if ($args === false) $args = $_SERVER["argv"]; 25 | else if (is_string($args)) 26 | { 27 | $args2 = $args; 28 | $args = array(); 29 | $inside = false; 30 | $currarg = ""; 31 | $y = strlen($args2); 32 | for ($x = 0; $x < $y; $x++) 33 | { 34 | $currchr = substr($args2, $x, 1); 35 | 36 | if ($inside === false && $currchr == " " && $currarg != "") 37 | { 38 | $args[] = $currarg; 39 | $currarg = ""; 40 | } 41 | else if ($currchr == "\"" || $currchr == "'") 42 | { 43 | if ($inside === false) $inside = $currchr; 44 | else if ($inside === $currchr) $inside = false; 45 | else $currarg .= $currchr; 46 | } 47 | else if ($currchr == "\\" && $x < $y - 1) 48 | { 49 | $x++; 50 | $currarg .= substr($args2, $x, 1); 51 | } 52 | else if ($inside !== false || $currchr != " ") 53 | { 54 | $currarg .= $currchr; 55 | } 56 | } 57 | 58 | if ($currarg != "") $args[] = $currarg; 59 | } 60 | 61 | $result = array("success" => true, "file" => array_shift($args), "opts" => array(), "params" => array()); 62 | 63 | // Look over shortmap to determine if options exist that are one byte (flags) and don't have arguments. 64 | $chrs = array(); 65 | foreach ($options["shortmap"] as $key => $val) 66 | { 67 | if (isset($options["rules"][$val]) && !$options["rules"][$val]["arg"]) $chrs[$key] = true; 68 | } 69 | 70 | $allowopt = true; 71 | $y = count($args); 72 | for ($x = 0; $x < $y; $x++) 73 | { 74 | $arg = $args[$x]; 75 | 76 | // Attempt to process an option. 77 | $opt = false; 78 | $optval = false; 79 | if ($allowopt && substr($arg, 0, 1) == "-") 80 | { 81 | $pos = strpos($arg, "="); 82 | if ($pos === false) $pos = strlen($arg); 83 | else $optval = substr($arg, $pos + 1); 84 | $arg2 = substr($arg, 1, $pos - 1); 85 | 86 | if (isset($options["rules"][$arg2])) $opt = $arg2; 87 | else if (isset($options["shortmap"][$arg2])) $opt = $options["shortmap"][$arg2]; 88 | else if ($x == 0) 89 | { 90 | // Attempt to process as a set of flags. 91 | $y2 = strlen($arg2); 92 | if ($y2 > 0) 93 | { 94 | for ($x2 = 0; $x2 < $y2; $x2++) 95 | { 96 | $currchr = substr($arg2, $x2, 1); 97 | 98 | if (!isset($chrs[$currchr])) break; 99 | } 100 | 101 | if ($x2 == $y2) 102 | { 103 | for ($x2 = 0; $x2 < $y2; $x2++) 104 | { 105 | $opt = $options["shortmap"][substr($arg2, $x2, 1)]; 106 | 107 | if (!$options["rules"][$opt]["multiple"]) $result["opts"][$opt] = true; 108 | else 109 | { 110 | if (!isset($result["opts"][$opt])) $result["opts"][$opt] = 0; 111 | $result["opts"][$opt]++; 112 | } 113 | } 114 | 115 | continue; 116 | } 117 | } 118 | } 119 | } 120 | 121 | if ($opt === false) 122 | { 123 | // Is a parameter. 124 | if (substr($arg, 0, 1) === "\"" || substr($arg, 0, 1) === "'") $arg = substr($arg, 1); 125 | if (substr($arg, -1) === "\"" || substr($arg, -1) === "'") $arg = substr($arg, 0, -1); 126 | 127 | $result["params"][] = $arg; 128 | 129 | if (!$options["allow_opts_after_param"]) $allowopt = false; 130 | } 131 | else if (!$options["rules"][$opt]["arg"]) 132 | { 133 | // Is a flag by itself. 134 | if (!$options["rules"][$opt]["multiple"]) $result["opts"][$opt] = true; 135 | else 136 | { 137 | if (!isset($result["opts"][$opt])) $result["opts"][$opt] = 0; 138 | $result["opts"][$opt]++; 139 | } 140 | } 141 | else 142 | { 143 | // Is an option. 144 | if ($optval === false) 145 | { 146 | $x++; 147 | if ($x == $y) break; 148 | $optval = $args[$x]; 149 | } 150 | 151 | if (substr($optval, 0, 1) === "\"" || substr($optval, 0, 1) === "'") $optval = substr($optval, 1); 152 | if (substr($optval, -1) === "\"" || substr($optval, -1) === "'") $optval = substr($optval, 0, -1); 153 | 154 | if (!$options["rules"][$opt]["multiple"]) $result["opts"][$opt] = $optval; 155 | else 156 | { 157 | if (!isset($result["opts"][$opt])) $result["opts"][$opt] = array(); 158 | $result["opts"][$opt][] = $optval; 159 | } 160 | } 161 | } 162 | 163 | return $result; 164 | } 165 | 166 | public static function CanGetUserInputWithArgs(&$args, $prefix) 167 | { 168 | return (($prefix !== false && isset($args["opts"][$prefix]) && is_array($args["opts"][$prefix]) && count($args["opts"][$prefix])) || count($args["params"])); 169 | } 170 | 171 | // Gets a line of input from the user. If the user supplies all information via the command-line, this could be entirely automated. 172 | public static function GetUserInputWithArgs(&$args, $prefix, $question, $default, $noparamsoutput = "", $suppressoutput = false, $callback = false, $callbackopts = false) 173 | { 174 | if (!self::CanGetUserInputWithArgs($args, $prefix) && $noparamsoutput != "") 175 | { 176 | echo "\n" . rtrim($noparamsoutput) . "\n\n"; 177 | 178 | $suppressoutput = false; 179 | $noparamsoutput = ""; 180 | } 181 | 182 | do 183 | { 184 | $prompt = ($suppressoutput ? "" : $question . ($default !== false ? " [" . $default . "]" : "") . ": "); 185 | 186 | if ($prefix !== false && isset($args["opts"][$prefix]) && is_array($args["opts"][$prefix]) && count($args["opts"][$prefix])) 187 | { 188 | $line = array_shift($args["opts"][$prefix]); 189 | if ($line === "") $line = $default; 190 | if (!$suppressoutput) echo $prompt . $line . "\n"; 191 | } 192 | else if (count($args["params"])) 193 | { 194 | $line = array_shift($args["params"]); 195 | if ($line === "") $line = $default; 196 | if (!$suppressoutput) echo $prompt . $line . "\n"; 197 | } 198 | else if (strtoupper(substr(php_uname("s"), 0, 3)) != "WIN" && function_exists("readline") && function_exists("readline_add_history")) 199 | { 200 | $line = readline($prompt); 201 | if ($line === false) exit(); 202 | 203 | $line = trim($line); 204 | if ($line === "") $line = $default; 205 | if ($line !== false && $line !== "") readline_add_history($line); 206 | } 207 | else 208 | { 209 | echo $prompt; 210 | fflush(STDOUT); 211 | $line = fgets(STDIN); 212 | if ($line === false || ($line === "" && feof(STDIN))) exit(); 213 | 214 | $line = trim($line); 215 | if ($line === "") $line = $default; 216 | } 217 | 218 | if ($line === false || (is_callable($callback) && !call_user_func_array($callback, array($line, &$callbackopts)))) 219 | { 220 | if ($line !== false) $line = false; 221 | else echo "Please enter a value.\n"; 222 | 223 | if (!self::CanGetUserInputWithArgs($args, $prefix) && $noparamsoutput != "") 224 | { 225 | echo "\n" . $noparamsoutput . "\n"; 226 | 227 | $noparamsoutput = ""; 228 | } 229 | 230 | $suppressoutput = false; 231 | } 232 | } while ($line === false); 233 | 234 | return $line; 235 | } 236 | 237 | // Obtains a valid line of input. 238 | public static function GetLimitedUserInputWithArgs(&$args, $prefix, $question, $default, $allowedoptionsprefix, $allowedoptions, $loop = true, $suppressoutput = false, $multipleuntil = false) 239 | { 240 | $noparamsoutput = $allowedoptionsprefix . "\n\n"; 241 | $size = 0; 242 | foreach ($allowedoptions as $key => $val) 243 | { 244 | if ($size < strlen($key)) $size = strlen($key); 245 | } 246 | 247 | foreach ($allowedoptions as $key => $val) 248 | { 249 | $newtab = str_repeat(" ", 2 + $size + 3); 250 | $noparamsoutput .= " " . $key . ":" . str_repeat(" ", $size - strlen($key)) . " " . str_replace("\n\t", "\n" . $newtab, $val) . "\n"; 251 | } 252 | 253 | $noparamsoutput .= "\n"; 254 | 255 | if ($default === false && count($allowedoptions) == 1) 256 | { 257 | reset($allowedoptions); 258 | $default = key($allowedoptions); 259 | } 260 | 261 | $results = array(); 262 | do 263 | { 264 | $displayed = (!count($args["params"])); 265 | $result = self::GetUserInputWithArgs($args, $prefix, $question, $default, $noparamsoutput, $suppressoutput); 266 | if (is_array($multipleuntil) && $multipleuntil["exit"] === $result) break; 267 | $result2 = false; 268 | if (!count($allowedoptions)) break; 269 | foreach ($allowedoptions as $key => $val) 270 | { 271 | if (!strcasecmp($key, $result) || !strcasecmp($val, $result)) $result2 = $key; 272 | } 273 | if ($loop) 274 | { 275 | if ($result2 === false) 276 | { 277 | echo "Please select an option from the list.\n"; 278 | 279 | $suppressoutput = false; 280 | } 281 | else if (is_array($multipleuntil)) 282 | { 283 | $results[$result2] = $result2; 284 | 285 | $question = $multipleuntil["nextquestion"]; 286 | $default = $multipleuntil["nextdefault"]; 287 | } 288 | } 289 | 290 | if ($displayed) $noparamsoutput = ""; 291 | } while ($loop && ($result2 === false || is_array($multipleuntil))); 292 | 293 | return (is_array($multipleuntil) ? $results : $result2); 294 | } 295 | 296 | // Obtains Yes/No style input. 297 | public static function GetYesNoUserInputWithArgs(&$args, $prefix, $question, $default, $noparamsoutput = "", $suppressoutput = false) 298 | { 299 | $default = (substr(strtoupper(trim($default)), 0, 1) === "Y" ? "Y" : "N"); 300 | 301 | $result = self::GetUserInputWithArgs($args, $prefix, $question, $default, $noparamsoutput, $suppressoutput); 302 | $result = (substr(strtoupper(trim($result)), 0, 1) === "Y"); 303 | 304 | return $result; 305 | } 306 | 307 | public static function GetHexDump($data) 308 | { 309 | $result = ""; 310 | 311 | $x = 0; 312 | $y = strlen($data); 313 | if ($y <= 256) $padwidth = 2; 314 | else if ($y <= 65536) $padwidth = 4; 315 | else if ($y <= 16777216) $padwidth = 6; 316 | else $padwidth = 8; 317 | 318 | $pad = str_repeat(" ", $padwidth); 319 | 320 | $data2 = str_split(strtoupper(bin2hex($data)), 32); 321 | foreach ($data2 as $line) 322 | { 323 | $result .= sprintf("%0" . $padwidth . "X", $x) . " | "; 324 | 325 | $line = str_split($line, 2); 326 | array_splice($line, 8, 0, ""); 327 | $result .= implode(" ", $line) . "\n"; 328 | 329 | $result .= $pad . " |"; 330 | $y2 = $x + 16; 331 | for ($x2 = 0; $x2 < 16 && $x < $y; $x2++) 332 | { 333 | $result .= " "; 334 | if ($x2 === 8) $result .= " "; 335 | 336 | $tempchr = ord($data[$x]); 337 | if ($tempchr === 0x09) $result .= "\\t"; 338 | else if ($tempchr === 0x0D) $result .= "\\r"; 339 | else if ($tempchr === 0x0A) $result .= "\\n"; 340 | else if ($tempchr === 0x00) $result .= "\\0"; 341 | else if ($tempchr < 32 || $tempchr > 126) $result .= " "; 342 | else $result .= " " . $data[$x]; 343 | 344 | $x++; 345 | } 346 | 347 | $result .= "\n"; 348 | } 349 | 350 | return $result; 351 | } 352 | 353 | // Outputs a JSON array (useful for captured output). 354 | public static function DisplayResult($result, $exit = true) 355 | { 356 | if (is_array($result)) echo json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; 357 | else echo $result . "\n"; 358 | 359 | if ($exit) exit(); 360 | } 361 | 362 | // Useful for reparsing remaining parameters as new arguments. 363 | public static function ReinitArgs(&$args, $newargs) 364 | { 365 | // Process the parameters. 366 | $options = array( 367 | "shortmap" => array( 368 | "?" => "help" 369 | ), 370 | "rules" => array( 371 | ) 372 | ); 373 | 374 | foreach ($newargs as $arg) $options["rules"][$arg] = array("arg" => true, "multiple" => true); 375 | $options["rules"]["help"] = array("arg" => false); 376 | 377 | $args = self::ParseCommandLine($options, array_merge(array(""), $args["params"])); 378 | 379 | if (isset($args["opts"]["help"])) self::DisplayResult(array("success" => true, "options" => array_keys($options["rules"]))); 380 | } 381 | 382 | // Tracks messages for a command-line interface app. 383 | private static $messages = array(); 384 | 385 | public static function LogMessage($msg, $data = null) 386 | { 387 | if (isset($data)) $msg .= "\n\t" . trim(str_replace("\n", "\n\t", json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES))); 388 | 389 | self::$messages[] = $msg; 390 | 391 | fwrite(STDERR, $msg . "\n"); 392 | } 393 | 394 | public static function DisplayError($msg, $result = false, $exit = true) 395 | { 396 | self::LogMessage(($exit ? "[Error] " : "") . $msg); 397 | 398 | if ($result !== false && is_array($result) && isset($result["error"]) && isset($result["errorcode"])) self::LogMessage("[Error] " . $result["error"] . " (" . $result["errorcode"] . ")", (isset($result["info"]) ? $result["info"] : null)); 399 | 400 | if ($exit) exit(); 401 | } 402 | 403 | public static function GetLogMessages($filters = array()) 404 | { 405 | if (is_string($filters)) $filters = array($filters); 406 | 407 | $result = array(); 408 | foreach (self::$messages as $message) 409 | { 410 | $found = (!count($filters)); 411 | foreach ($filters as $filter) 412 | { 413 | if (preg_match($filter, $message)) $found = true; 414 | } 415 | 416 | if ($found) $result[] = $message; 417 | } 418 | 419 | return $result; 420 | } 421 | 422 | public static function ResetLogMessages() 423 | { 424 | self::$messages = array(); 425 | } 426 | 427 | 428 | private static $timerinfo = array(); 429 | 430 | public static function StartTimer() 431 | { 432 | $ts = microtime(true); 433 | 434 | self::$timerinfo = array( 435 | "start" => $ts, 436 | "diff" => $ts 437 | ); 438 | } 439 | 440 | public static function UpdateTimer() 441 | { 442 | $ts = microtime(true); 443 | $diff = $ts - self::$timerinfo["diff"]; 444 | self::$timerinfo["diff"] = $ts; 445 | 446 | $result = array( 447 | "success" => true, 448 | "diff" => sprintf("%.2f", $diff), 449 | "total" => sprintf("%.2f", $ts - self::$timerinfo["start"]) 450 | ); 451 | 452 | return $result; 453 | } 454 | } 455 | ?> -------------------------------------------------------------------------------- /server/server.php: -------------------------------------------------------------------------------- 1 | 1) 26 | { 27 | // Service Manager PHP SDK. 28 | require_once $rootpath . "/servicemanager/sdks/servicemanager.php"; 29 | 30 | $sm = new ServiceManager($rootpath . "/servicemanager"); 31 | 32 | echo "Service manager: " . $sm->GetServiceManagerRealpath() . "\n\n"; 33 | 34 | $servicename = preg_replace('/[^a-z0-9]/', "-", $config["iptchain"]); 35 | 36 | if ($argv[1] == "install") 37 | { 38 | // Install the service. 39 | $args = array(); 40 | $options = array(); 41 | 42 | $result = $sm->Install($servicename, __FILE__, $args, $options, true); 43 | if (!$result["success"]) WKFS_DisplayError("Unable to install the '" . $servicename . "' service.", $result); 44 | } 45 | else if ($argv[1] == "start") 46 | { 47 | // Start the service. 48 | $result = $sm->Start($servicename, true); 49 | if (!$result["success"]) WKFS_DisplayError("Unable to start the '" . $servicename . "' service.", $result); 50 | } 51 | else if ($argv[1] == "stop") 52 | { 53 | // Stop the service. 54 | $result = $sm->Stop($servicename, true); 55 | if (!$result["success"]) WKFS_DisplayError("Unable to stop the '" . $servicename . "' service.", $result); 56 | } 57 | else if ($argv[1] == "uninstall") 58 | { 59 | // Uninstall the service. 60 | $result = $sm->Uninstall($servicename, true); 61 | if (!$result["success"]) WKFS_DisplayError("Unable to uninstall the '" . $servicename . "' service.", $result); 62 | 63 | // Since external executables are running here, restoring the path is important. 64 | putenv("PATH=" . $config["path"]); 65 | 66 | // Remove and add iptables rules. 67 | foreach ($config["removediptrules"] as $rule) 68 | { 69 | @system("iptables -D " . substr($rule, 3)); 70 | @system("iptables " . $rule); 71 | } 72 | 73 | foreach ($config["removedip6trules"] as $rule) 74 | { 75 | @system("ip6tables -D " . substr($rule, 3)); 76 | @system("ip6tables " . $rule); 77 | } 78 | 79 | // Remove existing chains. 80 | @system("iptables -D " . escapeshellarg($config["iptparentchain"]) . " -j " . escapeshellarg($config["iptchain"])); 81 | @system("ip6tables -D " . escapeshellarg($config["ip6tparentchain"]) . " -j " . escapeshellarg($config["ip6tchain"])); 82 | @system("iptables -F " . escapeshellarg($config["iptchain"])); 83 | @system("ip6tables -F " . escapeshellarg($config["ip6tchain"])); 84 | @system("iptables -X " . escapeshellarg($config["iptchain"])); 85 | @system("ip6tables -X " . escapeshellarg($config["ip6tchain"])); 86 | } 87 | else if ($argv[1] == "dumpconfig") 88 | { 89 | $result = $sm->GetConfig($servicename); 90 | if (!$result["success"]) WKFS_DisplayError("Unable to retrieve the configuration for the '" . $servicename . "' service.", $result); 91 | 92 | echo "Service configuration: " . $result["filename"] . "\n\n"; 93 | 94 | echo "Current service configuration:\n\n"; 95 | foreach ($result["options"] as $key => $val) echo " " . $key . " = " . $val . "\n"; 96 | } 97 | else 98 | { 99 | echo "Command not recognized. Run the service manager directly for anything other than 'install', 'start', 'stop', 'uninstall', and 'dumpconfig'.\n"; 100 | } 101 | } 102 | else 103 | { 104 | // Make sure PHP doesn't introduce weird limitations. 105 | ini_set("memory_limit", "-1"); 106 | set_time_limit(0); 107 | 108 | // Since external executables are running here, restoring the path is important. 109 | putenv("PATH=" . $config["path"]); 110 | 111 | // Remove existing chains. 112 | @system("iptables -D " . escapeshellarg($config["iptparentchain"]) . " -j " . escapeshellarg($config["iptchain"])); 113 | @system("ip6tables -D " . escapeshellarg($config["ip6tparentchain"]) . " -j " . escapeshellarg($config["ip6tchain"])); 114 | @system("iptables -F " . escapeshellarg($config["iptchain"])); 115 | @system("ip6tables -F " . escapeshellarg($config["ip6tchain"])); 116 | @system("iptables -X " . escapeshellarg($config["iptchain"])); 117 | @system("ip6tables -X " . escapeshellarg($config["ip6tchain"])); 118 | 119 | // Create the iptables chains. 120 | system("iptables -N " . escapeshellarg($config["iptchain"])); 121 | system("iptables -A " . escapeshellarg($config["iptchain"]) . " -j RETURN"); 122 | system("ip6tables -N " . escapeshellarg($config["ip6tchain"])); 123 | system("ip6tables -A " . escapeshellarg($config["ip6tchain"]) . " -j RETURN"); 124 | 125 | // Add the new chain to the target chain at the user-specified location. 126 | system("iptables -A " . escapeshellarg($config["iptparentchain"]) . " -j " . escapeshellarg($config["iptchain"])); 127 | system("ip6tables -A " . escapeshellarg($config["ip6tparentchain"]) . " -j " . escapeshellarg($config["ip6tchain"])); 128 | 129 | // Remove iptables rules. 130 | foreach ($config["removediptrules"] as $rule) 131 | { 132 | @system("iptables -D " . substr($rule, 3)); 133 | } 134 | 135 | foreach ($config["removedip6trules"] as $rule) 136 | { 137 | @system("ip6tables -D " . substr($rule, 3)); 138 | } 139 | 140 | require_once $rootpath . "/support/ipaddr.php"; 141 | 142 | // Start the TCP/IP server. 143 | $context = stream_context_create(); 144 | $serverfp = stream_socket_server("tcp://" . $config["host"] . ":" . $config["port"], $errornum, $errorstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context); 145 | if ($serverfp === false) return array("success" => false, "error" => HTTP::HTTPTranslate("Bind() failed. Reason: %s (%d)", $errorstr, $errornum), "errorcode" => "bind_failed"); 146 | 147 | // Enable non-blocking mode. 148 | stream_set_blocking($serverfp, 0); 149 | 150 | $nextclientid = 1; 151 | $clients = array(); 152 | 153 | $tracker = array(); 154 | 155 | function UpdateStreams(&$readfps, &$writefps) 156 | { 157 | global $serverfp, $clients; 158 | 159 | if ($serverfp !== false) $readfps["wksf_s"] = $serverfp; 160 | 161 | foreach ($clients as $id => $client) 162 | { 163 | if ($client->mode === "request") $readfps["wksf_c_" . $id] = $client->fp; 164 | else if ($client->data !== "") $writefps["wksf_c_" . $id] = $client->fp; 165 | } 166 | } 167 | 168 | // Sometimes keyed arrays don't work properly. 169 | function FixedStreamSelect(&$readfps, &$writefps, &$exceptfps, $timeout) 170 | { 171 | // In order to correctly detect bad outputs, no '0' integer key is allowed. 172 | if (isset($readfps[0]) || isset($writefps[0]) || ($exceptfps !== NULL && isset($exceptfps[0]))) return false; 173 | 174 | $origreadfps = $readfps; 175 | $origwritefps = $writefps; 176 | $origexceptfps = $exceptfps; 177 | 178 | $result2 = @stream_select($readfps, $writefps, $exceptfps, $timeout); 179 | if ($result2 === false) return false; 180 | 181 | if (isset($readfps[0])) 182 | { 183 | $fps = array(); 184 | foreach ($origreadfps as $key => $fp) $fps[(int)$fp] = $key; 185 | 186 | foreach ($readfps as $num => $fp) 187 | { 188 | $readfps[$fps[(int)$fp]] = $fp; 189 | 190 | unset($readfps[$num]); 191 | } 192 | } 193 | 194 | if (isset($writefps[0])) 195 | { 196 | $fps = array(); 197 | foreach ($origwritefps as $key => $fp) $fps[(int)$fp] = $key; 198 | 199 | foreach ($writefps as $num => $fp) 200 | { 201 | $writefps[$fps[(int)$fp]] = $fp; 202 | 203 | unset($writefps[$num]); 204 | } 205 | } 206 | 207 | if ($exceptfps !== NULL && isset($exceptfps[0])) 208 | { 209 | $fps = array(); 210 | foreach ($origexceptfps as $key => $fp) $fps[(int)$fp] = $key; 211 | 212 | foreach ($exceptfps as $num => $fp) 213 | { 214 | $exceptfps[$fps[(int)$fp]] = $fp; 215 | 216 | unset($exceptfps[$num]); 217 | } 218 | } 219 | 220 | return true; 221 | } 222 | 223 | function RemoveClient($id) 224 | { 225 | global $clients; 226 | 227 | if (isset($clients[$id])) 228 | { 229 | @fclose($clients[$id]->fp); 230 | 231 | unset($clients[$id]); 232 | } 233 | } 234 | 235 | // Main service code. 236 | $stopfilename = __FILE__ . ".notify.stop"; 237 | $reloadfilename = __FILE__ . ".notify.reload"; 238 | $lastservicecheck = time(); 239 | $running = true; 240 | 241 | do 242 | { 243 | // Wait for a connection or timeout. 244 | $readfps = array(); 245 | $writefps = array(); 246 | $exceptfps = NULL; 247 | UpdateStreams($readfps, $writefps); 248 | $result = FixedStreamSelect($readfps, $writefps, $exceptfps, 1); 249 | if ($result === false) break; 250 | 251 | // Handle new connections. 252 | if (isset($readfps["wksf_s"])) 253 | { 254 | while (($fp2 = @stream_socket_accept($serverfp, 0)) !== false) 255 | { 256 | // Enable non-blocking mode. 257 | stream_set_blocking($fp2, 0); 258 | 259 | $client = new stdClass(); 260 | $client->id = $nextclientid; 261 | $client->mode = "request"; 262 | $client->data = ""; 263 | $client->fp = $fp2; 264 | $client->lastts = microtime(true); 265 | 266 | $clients[$nextclientid] = $client; 267 | 268 | $nextclientid++; 269 | } 270 | 271 | unset($readfps["wksf_s"]); 272 | } 273 | 274 | // Handle clients in the read queue. 275 | foreach ($readfps as $cid => $fp) 276 | { 277 | if (!is_string($cid) || strlen($cid) < 6 || substr($cid, 0, 7) !== "wksf_c_") continue; 278 | 279 | $id = (int)substr($cid, 7); 280 | 281 | if (!isset($clients[$id])) continue; 282 | 283 | $client = $clients[$id]; 284 | 285 | $client->lastts = microtime(true); 286 | 287 | $data = @fread($client->fp, 4096); 288 | if ($data === false || feof($client->fp)) RemoveClient($id); 289 | else 290 | { 291 | $client->data .= $data; 292 | 293 | $info = @json_decode($client->data, true); 294 | if (is_array($info)) 295 | { 296 | $client->mode = "response"; 297 | 298 | if (!isset($info["secret"]) || !is_string($info["secret"]) || $info["secret"] !== $config["secret"]) $client->data = json_encode(array("success" => false, "error" => "Missing 'secret'.", "missing_secret")); 299 | else if (!isset($info["ip"]) || !is_string($info["ip"])) $client->data = json_encode(array("success" => false, "error" => "Missing 'ip'.", "missing_ip")); 300 | else if (!isset($info["ports"]) || !is_array($info["ports"])) $client->data = json_encode(array("success" => false, "error" => "Missing 'ports'.", "missing_ports")); 301 | else if (!isset($info["time"]) || (int)$info["time"] < 1) $client->data = json_encode(array("success" => false, "error" => "Missing or invalid 'time'.", "missing_time")); 302 | else 303 | { 304 | $ipaddr = IPAddr::NormalizeIP($info["ip"]); 305 | $ipv6 = ($ipaddr["ipv4"] === ""); 306 | $ipaddr = ($ipv6 ? $ipaddr["shortipv6"] : $ipaddr["ipv4"]); 307 | 308 | $time = min((int)$info["time"], $config["maxtime"]); 309 | $ts = time() + $time; 310 | 311 | $added = array(); 312 | foreach ($info["ports"] as $portinfo) 313 | { 314 | if (!isset($portinfo["proto"]) || !isset($portinfo["num"])) continue; 315 | 316 | $proto = strtoupper($portinfo["proto"]); 317 | $num = (int)$portinfo["num"]; 318 | if ($num < 1 || $num > 65535) continue; 319 | $valid = (($proto === "TCP" && isset($config["tcpprotected"][$num])) || ($proto === "UDP" && isset($config["udpprotected"][$num]))); 320 | if (!$valid) continue; 321 | 322 | // Calculate iptables add/remove calls. 323 | $basecmd = " -p " . $proto . " -s " . escapeshellarg($ipaddr) . " --destination-port " . $num . " -j ACCEPT"; 324 | $addcmd = ($ipv6 ? "ip6tables" : "iptables") . " -I " . escapeshellarg($ipv6 ? $config["ip6tchain"] : $config["iptchain"]) . " 1" . $basecmd; 325 | $removecmd = ($ipv6 ? "ip6tables" : "iptables") . " -D " . escapeshellarg($ipv6 ? $config["ip6tchain"] : $config["iptchain"]) . $basecmd; 326 | 327 | // Add the iptables rule (allow access). 328 | if (!isset($tracker[$removecmd])) 329 | { 330 | system($addcmd); 331 | $added[] = $ipaddr . " : " . $num . " (" . $proto . ")"; 332 | } 333 | 334 | // Register the timeout. 335 | if (!isset($tracker[$removecmd]) || $tracker[$removecmd] < $ts) $tracker[$removecmd] = $ts; 336 | } 337 | 338 | if (count($added)) 339 | { 340 | foreach ($config["recipients"] as $recipient) 341 | { 342 | mail($recipient, "[" . gethostname() . "] " . (count($added) == 1 ? "Port" : "Ports") . " opened for " . $ipaddr, implode("\r\n", $added) . "\r\n\r\n" . date("l, F j, Y @ g:i a"), "From: " . $recipient); 343 | } 344 | } 345 | 346 | $client->data = json_encode(array("success" => true, "expires" => $ts)); 347 | } 348 | } 349 | } 350 | } 351 | 352 | // Handle clients in the write queue. 353 | foreach ($writefps as $cid => $fp) 354 | { 355 | if (!is_string($cid) || strlen($cid) < 6 || substr($cid, 0, 7) !== "wksf_c_") continue; 356 | 357 | $id = (int)substr($cid, 7); 358 | 359 | if (!isset($clients[$id])) continue; 360 | 361 | $client = $clients[$id]; 362 | 363 | $client->lastts = microtime(true); 364 | 365 | $result = @fwrite($client->fp, $client->data); 366 | if ($data === false || feof($client->fp)) RemoveClient($id); 367 | else 368 | { 369 | $client->data = (string)substr($client->data, $result); 370 | if ($client->data === "") RemoveClient($id); 371 | } 372 | } 373 | 374 | // Handle client timeouts. 375 | $ts = microtime(true); 376 | foreach ($clients as $id => $client) 377 | { 378 | if ($client->lastts + 30 < $ts) RemoveClient($id); 379 | } 380 | 381 | // Handle firewall timeouts. 382 | $ts = time(); 383 | foreach ($tracker as $removecmd => $ts2) 384 | { 385 | if ($ts2 <= $ts) 386 | { 387 | // Remove the iptables rule (deny access). 388 | system($removecmd); 389 | 390 | unset($tracker[$removecmd]); 391 | } 392 | } 393 | 394 | // Check the status of the two service file options. 395 | if ($lastservicecheck <= time() - 3) 396 | { 397 | if (file_exists($stopfilename) || file_exists($reloadfilename)) $running = false; 398 | 399 | $lastservicecheck = time(); 400 | } 401 | } while ($running); 402 | 403 | // Add removed iptables rules. 404 | foreach ($config["removediptrules"] as $rule) 405 | { 406 | @system("iptables " . $rule); 407 | } 408 | 409 | foreach ($config["removedip6trules"] as $rule) 410 | { 411 | @system("ip6tables " . $rule); 412 | } 413 | 414 | // Remove existing chains. 415 | @system("iptables -D " . escapeshellarg($config["iptparentchain"]) . " -j " . escapeshellarg($config["iptchain"])); 416 | @system("ip6tables -D " . escapeshellarg($config["ip6tparentchain"]) . " -j " . escapeshellarg($config["ip6tchain"])); 417 | @system("iptables -F " . escapeshellarg($config["iptchain"])); 418 | @system("ip6tables -F " . escapeshellarg($config["ip6tchain"])); 419 | @system("iptables -X " . escapeshellarg($config["iptchain"])); 420 | @system("ip6tables -X " . escapeshellarg($config["ip6tchain"])); 421 | } 422 | ?> -------------------------------------------------------------------------------- /client/support/utf_utils.php: -------------------------------------------------------------------------------- 1 | = 0x0300 && $val <= 0x036F) || ($val >= 0x1DC0 && $val <= 0x1DFF) || ($val >= 0x20D0 && $val <= 0x20FF) || ($val >= 0xFE20 && $val <= 0xFE2F)); 21 | } 22 | 23 | public static function Convert($data, $srctype, $desttype) 24 | { 25 | $arr = is_array($data); 26 | if ($arr) $srctype = self::UTF32_ARRAY; 27 | $x = 0; 28 | $y = ($arr ? count($data) : strlen($data)); 29 | $result = ($desttype === self::UTF32_ARRAY ? array() : ""); 30 | if (!$arr && $srctype === self::UTF32_ARRAY) return $result; 31 | 32 | $first = true; 33 | 34 | if ($srctype === self::UTF8_BOM) 35 | { 36 | if (substr($data, 0, 3) === "\xEF\xBB\xBF") $x = 3; 37 | 38 | $srctype = self::UTF8; 39 | } 40 | 41 | if ($srctype === self::UTF16_BOM) 42 | { 43 | if (substr($data, 0, 2) === "\xFE\xFF") 44 | { 45 | $srctype = self::UTF16_BE; 46 | $x = 2; 47 | } 48 | else if (substr($data, 0, 2) === "\xFF\xFE") 49 | { 50 | $srctype = self::UTF16_LE; 51 | $x = 2; 52 | } 53 | else 54 | { 55 | $srctype = self::UTF16_LE; 56 | } 57 | } 58 | 59 | if ($srctype === self::UTF32_BOM) 60 | { 61 | if (substr($data, 0, 4) === "\x00\x00\xFE\xFF") 62 | { 63 | $srctype = self::UTF32_BE; 64 | $x = 4; 65 | } 66 | else if (substr($data, 0, 4) === "\xFF\xFE\x00\x00") 67 | { 68 | $srctype = self::UTF32_LE; 69 | $x = 4; 70 | } 71 | else 72 | { 73 | $srctype = self::UTF32_LE; 74 | } 75 | } 76 | 77 | while ($x < $y) 78 | { 79 | // Read the next valid code point. 80 | $val = false; 81 | 82 | switch ($srctype) 83 | { 84 | case self::UTF8: 85 | { 86 | $tempchr = ord($data[$x]); 87 | if ($tempchr <= 0x7F) 88 | { 89 | $val = $tempchr; 90 | $x++; 91 | } 92 | else if ($tempchr < 0xC2) $x++; 93 | else 94 | { 95 | $left = $y - $x; 96 | if ($left < 2) $x++; 97 | else 98 | { 99 | $tempchr2 = ord($data[$x + 1]); 100 | 101 | if (($tempchr >= 0xC2 && $tempchr <= 0xDF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) 102 | { 103 | $val = (($tempchr & 0x1F) << 6) | ($tempchr2 & 0x3F); 104 | $x += 2; 105 | } 106 | else if ($left < 3) $x++; 107 | else 108 | { 109 | $tempchr3 = ord($data[$x + 2]); 110 | 111 | if ($tempchr3 < 0x80 || $tempchr3 > 0xBF) $x++; 112 | else 113 | { 114 | if (($tempchr == 0xE0 && ($tempchr2 >= 0xA0 && $tempchr2 <= 0xBF)) || ((($tempchr >= 0xE1 && $tempchr <= 0xEC) || $tempchr == 0xEE || $tempchr == 0xEF) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) || ($tempchr == 0xED && ($tempchr2 >= 0x80 && $tempchr2 <= 0x9F))) 115 | { 116 | $val = (($tempchr & 0x0F) << 12) | (($tempchr2 & 0x3F) << 6) | ($tempchr3 & 0x3F); 117 | $x += 3; 118 | } 119 | else if ($left < 4) $x++; 120 | else 121 | { 122 | $tempchr4 = ord($data[$x + 3]); 123 | 124 | if ($tempchr4 < 0x80 || $tempchr4 > 0xBF) $x++; 125 | else if (($tempchr == 0xF0 && ($tempchr2 >= 0x90 && $tempchr2 <= 0xBF)) || (($tempchr >= 0xF1 && $tempchr <= 0xF3) && ($tempchr2 >= 0x80 && $tempchr2 <= 0xBF)) || ($tempchr == 0xF4 && ($tempchr2 >= 0x80 && $tempchr2 <= 0x8F))) 126 | { 127 | $val = (($tempchr & 0x07) << 18) | (($tempchr2 & 0x3F) << 12) | (($tempchr3 & 0x3F) << 6) | ($tempchr4 & 0x3F); 128 | $x += 4; 129 | } 130 | else 131 | { 132 | $x++; 133 | } 134 | } 135 | } 136 | } 137 | } 138 | } 139 | 140 | break; 141 | } 142 | case self::UTF16_LE: 143 | { 144 | if ($x + 1 >= $y) $x = $y; 145 | else 146 | { 147 | $val = unpack("v", substr($data, $x, 2))[1]; 148 | $x += 2; 149 | 150 | if ($val >= 0xD800 && $val <= 0xDBFF) 151 | { 152 | if ($x + 1 >= $y) 153 | { 154 | $x = $y; 155 | $val = false; 156 | } 157 | else 158 | { 159 | $val2 = unpack("v", substr($data, $x, 2))[1]; 160 | 161 | if ($val2 < 0xDC00 || $val2 > 0xDFFF) $val = false; 162 | else 163 | { 164 | $val = ((($val - 0xD800) << 10) | ($val2 - 0xDC00)) + 0x10000; 165 | $x += 2; 166 | } 167 | } 168 | } 169 | } 170 | 171 | break; 172 | } 173 | case self::UTF16_BE: 174 | { 175 | if ($x + 1 >= $y) $x = $y; 176 | else 177 | { 178 | $val = unpack("n", substr($data, $x, 2))[1]; 179 | $x += 2; 180 | 181 | if ($val >= 0xD800 && $val <= 0xDBFF) 182 | { 183 | if ($x + 1 >= $y) 184 | { 185 | $x = $y; 186 | $val = false; 187 | } 188 | else 189 | { 190 | $val2 = unpack("n", substr($data, $x, 2))[1]; 191 | 192 | if ($val2 < 0xDC00 || $val2 > 0xDFFF) $val = false; 193 | else 194 | { 195 | $val = ((($val - 0xD800) << 10) | ($val2 - 0xDC00)) + 0x10000; 196 | $x += 2; 197 | } 198 | } 199 | } 200 | } 201 | 202 | break; 203 | } 204 | case self::UTF32_LE: 205 | { 206 | if ($x + 3 >= $y) $x = $y; 207 | else 208 | { 209 | $val = unpack("V", substr($data, $x, 4))[1]; 210 | $x += 4; 211 | } 212 | 213 | break; 214 | } 215 | case self::UTF32_BE: 216 | { 217 | if ($x + 3 >= $y) $x = $y; 218 | else 219 | { 220 | $val = unpack("N", substr($data, $x, 4))[1]; 221 | $x += 4; 222 | } 223 | 224 | break; 225 | } 226 | case self::UTF32_ARRAY: 227 | { 228 | $val = (int)$data[$x]; 229 | $x++; 230 | 231 | break; 232 | } 233 | default: $x = $y; break; 234 | } 235 | 236 | // Make sure it is a valid Unicode value. 237 | // 0xD800-0xDFFF are for UTF-16 surrogate pairs. Invalid characters. 238 | // 0xFDD0-0xFDEF are non-characters. 239 | // 0x*FFFE and 0x*FFFF are reserved. 240 | // The largest possible character is 0x10FFFF. 241 | // First character can't be a combining code point. 242 | if ($val !== false && !($val < 0 || ($val >= 0xD800 && $val <= 0xDFFF) || ($val >= 0xFDD0 && $val <= 0xFDEF) || ($val & 0xFFFE) == 0xFFFE || $val > 0x10FFFF || ($first && self::IsCombiningCodePoint($val)))) 243 | { 244 | if ($first) 245 | { 246 | if ($desttype === self::UTF8_BOM) 247 | { 248 | $result .= "\xEF\xBB\xBF"; 249 | 250 | $desttype = self::UTF8; 251 | } 252 | 253 | if ($desttype === self::UTF16_BOM) 254 | { 255 | $result .= "\xFF\xFE"; 256 | 257 | $desttype = self::UTF16_LE; 258 | } 259 | 260 | if ($srctype === self::UTF32_BOM) 261 | { 262 | $result .= "\xFF\xFE\x00\x00"; 263 | 264 | $desttype = self::UTF32_LE; 265 | } 266 | 267 | $first = false; 268 | } 269 | 270 | switch ($desttype) 271 | { 272 | case self::UTF8: 273 | { 274 | if ($val <= 0x7F) $result .= chr($val); 275 | else if ($val <= 0x7FF) $result .= chr(0xC0 | ($val >> 6)) . chr(0x80 | ($val & 0x3F)); 276 | else if ($val <= 0xFFFF) $result .= chr(0xE0 | ($val >> 12)) . chr(0x80 | (($val >> 6) & 0x3F)) . chr(0x80 | ($val & 0x3F)); 277 | else if ($val <= 0x10FFFF) $result .= chr(0xF0 | ($val >> 18)) . chr(0x80 | (($val >> 12) & 0x3F)) . chr(0x80 | (($val >> 6) & 0x3F)) . chr(0x80 | ($val & 0x3F)); 278 | 279 | break; 280 | } 281 | case self::UTF16_LE: 282 | { 283 | if ($val <= 0xFFFF) $result .= pack("v", $val); 284 | else 285 | { 286 | $val -= 0x10000; 287 | $result .= pack("v", ((($val >> 10) & 0x3FF) + 0xD800)); 288 | $result .= pack("v", (($val & 0x3FF) + 0xDC00)); 289 | } 290 | 291 | break; 292 | } 293 | case self::UTF16_BE: 294 | { 295 | if ($val <= 0xFFFF) $result .= pack("n", $val); 296 | else 297 | { 298 | $val -= 0x10000; 299 | $result .= pack("n", ((($val >> 10) & 0x3FF) + 0xD800)); 300 | $result .= pack("n", (($val & 0x3FF) + 0xDC00)); 301 | } 302 | 303 | break; 304 | } 305 | case self::UTF32_LE: 306 | { 307 | $result .= pack("V", $val); 308 | 309 | break; 310 | } 311 | case self::UTF32_BE: 312 | { 313 | $result .= pack("N", $val); 314 | 315 | break; 316 | } 317 | case self::UTF32_ARRAY: 318 | { 319 | $result[] = $val; 320 | 321 | break; 322 | } 323 | default: $x = $y; break; 324 | } 325 | } 326 | } 327 | 328 | return $result; 329 | } 330 | 331 | 332 | protected const PUNYCODE_BASE = 36; 333 | protected const PUNYCODE_TMIN = 1; 334 | protected const PUNYCODE_TMAX = 26; 335 | protected const PUNYCODE_SKEW = 38; 336 | protected const PUNYCODE_DAMP = 700; 337 | protected const PUNYCODE_INITIAL_BIAS = 72; 338 | protected const PUNYCODE_INITIAL_N = 0x80; 339 | protected const PUNYCODE_DIGIT_MAP = "abcdefghijklmnopqrstuvwxyz0123456789"; 340 | 341 | public static function ConvertToPunycode($domain) 342 | { 343 | // Reject invalid domain name lengths. 344 | if (strlen($domain) > 255) return false; 345 | 346 | $parts = explode(".", $domain); 347 | 348 | foreach ($parts as $num => $part) 349 | { 350 | // Reject invalid label lengths. 351 | $y = strlen($part); 352 | if ($y > 63) return false; 353 | 354 | // Skip already encoded portions. 355 | if (substr($part, 0, 4) === "xn--") continue; 356 | 357 | // Convert UTF-8 to UTF-32 code points. 358 | $data = self::Convert($part, self::UTF8, self::UTF32_ARRAY); 359 | 360 | // Handle ASCII code points. 361 | $part2 = ""; 362 | foreach ($data as $cp) 363 | { 364 | if ($cp <= 0x7F) $part2 .= strtolower(chr($cp)); 365 | } 366 | 367 | $numhandled = strlen($part2); 368 | $y = count($data); 369 | 370 | if ($numhandled >= $y) 371 | { 372 | $parts[$num] = $part2; 373 | 374 | continue; 375 | } 376 | 377 | if ($numhandled) $part2 .= "-"; 378 | 379 | $part2 = "xn--" . $part2; 380 | 381 | if (strlen($part2) > 63) return false; 382 | 383 | $bias = self::PUNYCODE_INITIAL_BIAS; 384 | $n = self::PUNYCODE_INITIAL_N; 385 | $delta = 0; 386 | $first = true; 387 | 388 | while ($numhandled < $y) 389 | { 390 | // Find the next largest unhandled code point. 391 | $cp2 = 0x01000000; 392 | foreach ($data as $cp) 393 | { 394 | if ($cp >= $n && $cp2 > $cp) $cp2 = $cp; 395 | } 396 | 397 | // Increase delta but prevent overflow. 398 | $delta += ($cp2 - $n) * ($numhandled + 1); 399 | if ($delta < 0) return false; 400 | $n = $cp2; 401 | 402 | foreach ($data as $cp) 403 | { 404 | if ($cp < $n) 405 | { 406 | $delta++; 407 | 408 | if ($delta < 0) return false; 409 | } 410 | else if ($cp === $n) 411 | { 412 | // Calculate and encode a variable length integer from the delta. 413 | $q = $delta; 414 | $x = 0; 415 | do 416 | { 417 | $x += self::PUNYCODE_BASE; 418 | 419 | if ($x <= $bias) $t = self::PUNYCODE_TMIN; 420 | else if ($x >= $bias + self::PUNYCODE_TMAX) $t = self::PUNYCODE_TMAX; 421 | else $t = $x - $bias; 422 | 423 | if ($q < $t) break; 424 | 425 | $part2 .= self::PUNYCODE_DIGIT_MAP[$t + (($q - $t) % (self::PUNYCODE_BASE - $t))]; 426 | 427 | $q = (int)(($q - $t) / (self::PUNYCODE_BASE - $t)); 428 | 429 | if (strlen($part2) > 63) return false; 430 | } while (1); 431 | 432 | $part2 .= self::PUNYCODE_DIGIT_MAP[$q]; 433 | if (strlen($part2) > 63) return false; 434 | 435 | // Adapt bias. 436 | $numhandled++; 437 | $bias = self::InternalPunycodeAdapt($delta, $numhandled, $first); 438 | $delta = 0; 439 | $first = false; 440 | } 441 | } 442 | 443 | $delta++; 444 | $n++; 445 | } 446 | 447 | $parts[$num] = $part2; 448 | } 449 | 450 | return implode(".", $parts); 451 | } 452 | 453 | public static function ConvertFromPunycode($domain) 454 | { 455 | // Reject invalid domain name lengths. 456 | if (strlen($domain) > 255) return false; 457 | 458 | $parts = explode(".", $domain); 459 | 460 | foreach ($parts as $num => $part) 461 | { 462 | // Reject invalid label lengths. 463 | $y = strlen($part); 464 | if ($y > 63) return false; 465 | 466 | // Skip unencoded portions. 467 | if (substr($part, 0, 4) !== "xn--") continue; 468 | 469 | $part = substr($part, 4); 470 | 471 | // Convert UTF-8 to UTF-32 code points. 472 | $data = self::Convert($part, self::UTF8, self::UTF32_ARRAY); 473 | 474 | // Handle ASCII code points. 475 | $hyphen = ord("-"); 476 | for ($x = count($data); $x && $data[$x - 1] !== $hyphen; $x--); 477 | if (!$x) $data2 = array(); 478 | else 479 | { 480 | $data2 = array_splice($data, 0, $x - 1); 481 | 482 | array_shift($data); 483 | } 484 | 485 | $numhandled = count($data2); 486 | 487 | $bias = self::PUNYCODE_INITIAL_BIAS; 488 | $n = self::PUNYCODE_INITIAL_N; 489 | $delta = 0; 490 | $first = true; 491 | 492 | $pos = 0; 493 | $y = count($data); 494 | while ($pos < $y) 495 | { 496 | // Calculate and decode a delta from the variable length integer. 497 | $olddelta = $delta; 498 | $w = 1; 499 | $x = 0; 500 | do 501 | { 502 | $x += self::PUNYCODE_BASE; 503 | 504 | $cp = $data[$pos]; 505 | $pos++; 506 | 507 | if ($cp >= ord("a") && $cp <= ord("z")) $digit = $cp - ord("a"); 508 | else if ($cp >= ord("A") && $cp <= ord("Z")) $digit = $cp - ord("A"); 509 | else if ($cp >= ord("0") && $cp <= ord("9")) $digit = $cp - ord("0") + 26; 510 | else return false; 511 | 512 | $delta += $digit * $w; 513 | if ($delta < 0) return false; 514 | 515 | if ($x <= $bias) $t = self::PUNYCODE_TMIN; 516 | else if ($x >= $bias + self::PUNYCODE_TMAX) $t = self::PUNYCODE_TMAX; 517 | else $t = $x - $bias; 518 | 519 | if ($digit < $t) break; 520 | 521 | $w *= (self::PUNYCODE_BASE - $t); 522 | if ($w < 0) return false; 523 | } while (1); 524 | 525 | // Adapt bias. 526 | $numhandled++; 527 | $bias = self::InternalPunycodeAdapt($delta - $olddelta, $numhandled, $first); 528 | $first = false; 529 | 530 | // Delta was supposed to wrap around from $numhandled to 0, incrementing $n each time, so fix that now. 531 | $n += (int)($delta / $numhandled); 532 | $delta %= $numhandled; 533 | 534 | // Insert $n (the code point) at the delta position. 535 | array_splice($data2, $delta, 0, array($n)); 536 | $delta++; 537 | } 538 | 539 | $parts[$num] = self::Convert($data2, self::UTF32_ARRAY, self::UTF8); 540 | } 541 | 542 | return implode(".", $parts); 543 | } 544 | 545 | // RFC3492 adapt() function. 546 | protected static function InternalPunycodeAdapt($delta, $numpoints, $first) 547 | { 548 | $delta = ($first ? (int)($delta / self::PUNYCODE_DAMP) : $delta >> 1); 549 | $delta += (int)($delta / $numpoints); 550 | 551 | $y = self::PUNYCODE_BASE - self::PUNYCODE_TMIN; 552 | 553 | $condval = (int)(($y * self::PUNYCODE_TMAX) / 2); 554 | for ($x = 0; $delta > $condval; $x += self::PUNYCODE_BASE) $delta = (int)($delta / $y); 555 | 556 | return (int)($x + ((($y + 1) * $delta) / ($delta + self::PUNYCODE_SKEW))); 557 | } 558 | } 559 | ?> -------------------------------------------------------------------------------- /client/support/phpseclib/Crypt/Rijndael.php: -------------------------------------------------------------------------------- 1 | explicit_key_length) { 45 | $length = strlen($key); 46 | switch (true) { 47 | case $length <= 16: 48 | $this->key_size = 16; 49 | break; 50 | case $length <= 20: 51 | $this->key_size = 20; 52 | break; 53 | case $length <= 24: 54 | $this->key_size = 24; 55 | break; 56 | case $length <= 28: 57 | $this->key_size = 28; 58 | break; 59 | default: 60 | $this->key_size = 32; 61 | } 62 | } 63 | parent::setKey($key); 64 | } 65 | 66 | function setKeyLength($length) 67 | { 68 | switch (true) { 69 | case $length <= 128: 70 | $this->key_length = 16; 71 | break; 72 | case $length <= 160: 73 | $this->key_length = 20; 74 | break; 75 | case $length <= 192: 76 | $this->key_length = 24; 77 | break; 78 | case $length <= 224: 79 | $this->key_length = 28; 80 | break; 81 | default: 82 | $this->key_length = 32; 83 | } 84 | 85 | parent::setKeyLength($length); 86 | } 87 | 88 | function setBlockLength($length) 89 | { 90 | $length >>= 5; 91 | if ($length > 8) { 92 | $length = 8; 93 | } elseif ($length < 4) { 94 | $length = 4; 95 | } 96 | $this->Nb = $length; 97 | $this->block_size = $length << 2; 98 | $this->changed = true; 99 | $this->_setEngine(); 100 | } 101 | 102 | function isValidEngine($engine) 103 | { 104 | switch ($engine) { 105 | case CRYPT_ENGINE_OPENSSL: 106 | if ($this->block_size != 16) { 107 | return false; 108 | } 109 | $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb'; 110 | $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode(); 111 | break; 112 | case CRYPT_ENGINE_MCRYPT: 113 | $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); 114 | if ($this->key_length % 8) { return false; 115 | } 116 | } 117 | 118 | return parent::isValidEngine($engine); 119 | } 120 | 121 | function _encryptBlock($in) 122 | { 123 | static $tables; 124 | if (empty($tables)) { 125 | $tables = &$this->_getTables(); 126 | } 127 | $t0 = $tables[0]; 128 | $t1 = $tables[1]; 129 | $t2 = $tables[2]; 130 | $t3 = $tables[3]; 131 | $sbox = $tables[4]; 132 | 133 | $state = array(); 134 | $words = unpack('N*', $in); 135 | 136 | $c = $this->c; 137 | $w = $this->w; 138 | $Nb = $this->Nb; 139 | $Nr = $this->Nr; 140 | 141 | $wc = $Nb - 1; 142 | foreach ($words as $word) { 143 | $state[] = $word ^ $w[++$wc]; 144 | } 145 | 146 | $temp = array(); 147 | for ($round = 1; $round < $Nr; ++$round) { 148 | $i = 0; $j = $c[1]; 149 | $k = $c[2]; 150 | $l = $c[3]; 151 | 152 | while ($i < $Nb) { 153 | $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^ 154 | $t1[$state[$j] >> 16 & 0x000000FF] ^ 155 | $t2[$state[$k] >> 8 & 0x000000FF] ^ 156 | $t3[$state[$l] & 0x000000FF] ^ 157 | $w[++$wc]; 158 | ++$i; 159 | $j = ($j + 1) % $Nb; 160 | $k = ($k + 1) % $Nb; 161 | $l = ($l + 1) % $Nb; 162 | } 163 | $state = $temp; 164 | } 165 | 166 | for ($i = 0; $i < $Nb; ++$i) { 167 | $state[$i] = $sbox[$state[$i] & 0x000000FF] | 168 | ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | 169 | ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | 170 | ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); 171 | } 172 | 173 | $i = 0; $j = $c[1]; 174 | $k = $c[2]; 175 | $l = $c[3]; 176 | while ($i < $Nb) { 177 | $temp[$i] = ($state[$i] & 0xFF000000) ^ 178 | ($state[$j] & 0x00FF0000) ^ 179 | ($state[$k] & 0x0000FF00) ^ 180 | ($state[$l] & 0x000000FF) ^ 181 | $w[$i]; 182 | ++$i; 183 | $j = ($j + 1) % $Nb; 184 | $k = ($k + 1) % $Nb; 185 | $l = ($l + 1) % $Nb; 186 | } 187 | 188 | switch ($Nb) { 189 | case 8: 190 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); 191 | case 7: 192 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); 193 | case 6: 194 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); 195 | case 5: 196 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); 197 | default: 198 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); 199 | } 200 | } 201 | 202 | function _decryptBlock($in) 203 | { 204 | static $invtables; 205 | if (empty($invtables)) { 206 | $invtables = &$this->_getInvTables(); 207 | } 208 | $dt0 = $invtables[0]; 209 | $dt1 = $invtables[1]; 210 | $dt2 = $invtables[2]; 211 | $dt3 = $invtables[3]; 212 | $isbox = $invtables[4]; 213 | 214 | $state = array(); 215 | $words = unpack('N*', $in); 216 | 217 | $c = $this->c; 218 | $dw = $this->dw; 219 | $Nb = $this->Nb; 220 | $Nr = $this->Nr; 221 | 222 | $wc = $Nb - 1; 223 | foreach ($words as $word) { 224 | $state[] = $word ^ $dw[++$wc]; 225 | } 226 | 227 | $temp = array(); 228 | for ($round = $Nr - 1; $round > 0; --$round) { 229 | $i = 0; $j = $Nb - $c[1]; 230 | $k = $Nb - $c[2]; 231 | $l = $Nb - $c[3]; 232 | 233 | while ($i < $Nb) { 234 | $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^ 235 | $dt1[$state[$j] >> 16 & 0x000000FF] ^ 236 | $dt2[$state[$k] >> 8 & 0x000000FF] ^ 237 | $dt3[$state[$l] & 0x000000FF] ^ 238 | $dw[++$wc]; 239 | ++$i; 240 | $j = ($j + 1) % $Nb; 241 | $k = ($k + 1) % $Nb; 242 | $l = ($l + 1) % $Nb; 243 | } 244 | $state = $temp; 245 | } 246 | 247 | $i = 0; $j = $Nb - $c[1]; 248 | $k = $Nb - $c[2]; 249 | $l = $Nb - $c[3]; 250 | 251 | while ($i < $Nb) { 252 | $word = ($state[$i] & 0xFF000000) | 253 | ($state[$j] & 0x00FF0000) | 254 | ($state[$k] & 0x0000FF00) | 255 | ($state[$l] & 0x000000FF); 256 | 257 | $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] | 258 | ($isbox[$word >> 8 & 0x000000FF] << 8) | 259 | ($isbox[$word >> 16 & 0x000000FF] << 16) | 260 | ($isbox[$word >> 24 & 0x000000FF] << 24)); 261 | ++$i; 262 | $j = ($j + 1) % $Nb; 263 | $k = ($k + 1) % $Nb; 264 | $l = ($l + 1) % $Nb; 265 | } 266 | 267 | switch ($Nb) { 268 | case 8: 269 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); 270 | case 7: 271 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); 272 | case 6: 273 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); 274 | case 5: 275 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); 276 | default: 277 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); 278 | } 279 | } 280 | 281 | function _setupKey() 282 | { 283 | static $rcon = array(0, 284 | 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 285 | 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 286 | 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, 287 | 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, 288 | 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, 289 | 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 290 | ); 291 | 292 | if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) { 293 | return; 294 | } 295 | $this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size); 296 | 297 | $this->Nk = $this->key_length >> 2; 298 | $this->Nr = max($this->Nk, $this->Nb) + 6; 299 | 300 | switch ($this->Nb) { 301 | case 4: 302 | case 5: 303 | case 6: 304 | $this->c = array(0, 1, 2, 3); 305 | break; 306 | case 7: 307 | $this->c = array(0, 1, 2, 4); 308 | break; 309 | case 8: 310 | $this->c = array(0, 1, 3, 4); 311 | } 312 | 313 | $w = array_values(unpack('N*words', $this->key)); 314 | 315 | $length = $this->Nb * ($this->Nr + 1); 316 | for ($i = $this->Nk; $i < $length; $i++) { 317 | $temp = $w[$i - 1]; 318 | if ($i % $this->Nk == 0) { 319 | $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; 320 | } elseif ($this->Nk > 6 && $i % $this->Nk == 4) { 321 | $temp = $this->_subWord($temp); 322 | } 323 | $w[$i] = $w[$i - $this->Nk] ^ $temp; 324 | } 325 | 326 | list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables(); 327 | $temp = $this->w = $this->dw = array(); 328 | for ($i = $row = $col = 0; $i < $length; $i++, $col++) { 329 | if ($col == $this->Nb) { 330 | if ($row == 0) { 331 | $this->dw[0] = $this->w[0]; 332 | } else { 333 | $j = 0; 334 | while ($j < $this->Nb) { 335 | $dw = $this->_subWord($this->w[$row][$j]); 336 | $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^ 337 | $dt1[$dw >> 16 & 0x000000FF] ^ 338 | $dt2[$dw >> 8 & 0x000000FF] ^ 339 | $dt3[$dw & 0x000000FF]; 340 | $j++; 341 | } 342 | $this->dw[$row] = $temp; 343 | } 344 | 345 | $col = 0; 346 | $row++; 347 | } 348 | $this->w[$row][$col] = $w[$i]; 349 | } 350 | 351 | $this->dw[$row] = $this->w[$row]; 352 | 353 | $this->dw = array_reverse($this->dw); 354 | $w = array_pop($this->w); 355 | $dw = array_pop($this->dw); 356 | foreach ($this->w as $r => $wr) { 357 | foreach ($wr as $c => $wc) { 358 | $w[] = $wc; 359 | $dw[] = $this->dw[$r][$c]; 360 | } 361 | } 362 | $this->w = $w; 363 | $this->dw = $dw; 364 | } 365 | 366 | function _subWord($word) 367 | { 368 | static $sbox; 369 | if (empty($sbox)) { 370 | list(, , , , $sbox) = $this->_getTables(); 371 | } 372 | 373 | return $sbox[$word & 0x000000FF] | 374 | ($sbox[$word >> 8 & 0x000000FF] << 8) | 375 | ($sbox[$word >> 16 & 0x000000FF] << 16) | 376 | ($sbox[$word >> 24 & 0x000000FF] << 24); 377 | } 378 | 379 | function &_getTables() 380 | { 381 | static $tables; 382 | if (empty($tables)) { 383 | $t3 = array_map('intval', array( 384 | 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 385 | 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 386 | 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, 387 | 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, 388 | 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 389 | 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, 390 | 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, 391 | 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 392 | 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, 393 | 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, 394 | 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 395 | 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, 396 | 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, 397 | 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 398 | 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, 399 | 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, 400 | 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 401 | 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, 402 | 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, 403 | 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 404 | 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, 405 | 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, 406 | 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 407 | 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, 408 | 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, 409 | 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 410 | 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, 411 | 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, 412 | 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 413 | 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, 414 | 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, 415 | 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C 416 | )); 417 | 418 | foreach ($t3 as $t3i) { 419 | $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF); 420 | $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF); 421 | $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF); 422 | } 423 | 424 | $tables = array( 425 | $t0, 426 | $t1, 427 | $t2, 428 | $t3, 429 | array( 430 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 431 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 432 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 433 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 434 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 435 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 436 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 437 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 438 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 439 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 440 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 441 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 442 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 443 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 444 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 445 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 446 | ) 447 | ); 448 | } 449 | return $tables; 450 | } 451 | 452 | function &_getInvTables() 453 | { 454 | static $tables; 455 | if (empty($tables)) { 456 | $dt3 = array_map('intval', array( 457 | 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 458 | 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 459 | 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, 460 | 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, 461 | 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 462 | 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, 463 | 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, 464 | 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 465 | 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, 466 | 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, 467 | 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 468 | 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, 469 | 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, 470 | 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 471 | 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, 472 | 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, 473 | 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 474 | 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, 475 | 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, 476 | 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 477 | 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, 478 | 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, 479 | 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 480 | 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, 481 | 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, 482 | 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 483 | 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, 484 | 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, 485 | 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 486 | 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, 487 | 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, 488 | 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 489 | )); 490 | 491 | foreach ($dt3 as $dt3i) { 492 | $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF); 493 | $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF); 494 | $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF); 495 | }; 496 | 497 | $tables = array( 498 | $dt0, 499 | $dt1, 500 | $dt2, 501 | $dt3, 502 | array( 503 | 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 504 | 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 505 | 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 506 | 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 507 | 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 508 | 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 509 | 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 510 | 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 511 | 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 512 | 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 513 | 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 514 | 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 515 | 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 516 | 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 517 | 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 518 | 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D 519 | ) 520 | ); 521 | } 522 | return $tables; 523 | } 524 | 525 | function _setupInlineCrypt() 526 | { 527 | 528 | $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); 529 | 530 | $gen_hi_opt_code = (bool)(count($lambda_functions) < 10); 531 | 532 | $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}"; 533 | if ($gen_hi_opt_code) { 534 | $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); 535 | } 536 | 537 | if (!isset($lambda_functions[$code_hash])) { 538 | switch (true) { 539 | case $gen_hi_opt_code: 540 | $w = $this->w; 541 | $dw = $this->dw; 542 | $init_encrypt = ''; 543 | $init_decrypt = ''; 544 | break; 545 | default: 546 | for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { 547 | $w[] = '$w[' . $i . ']'; 548 | $dw[] = '$dw[' . $i . ']'; 549 | } 550 | $init_encrypt = '$w = $self->w;'; 551 | $init_decrypt = '$dw = $self->dw;'; 552 | } 553 | 554 | $Nr = $this->Nr; 555 | $Nb = $this->Nb; 556 | $c = $this->c; 557 | 558 | $init_encrypt.= ' 559 | static $tables; 560 | if (empty($tables)) { 561 | $tables = &$self->_getTables(); 562 | } 563 | $t0 = $tables[0]; 564 | $t1 = $tables[1]; 565 | $t2 = $tables[2]; 566 | $t3 = $tables[3]; 567 | $sbox = $tables[4]; 568 | '; 569 | 570 | $s = 'e'; 571 | $e = 's'; 572 | $wc = $Nb - 1; 573 | 574 | $encrypt_block = '$in = unpack("N*", $in);'."\n"; 575 | for ($i = 0; $i < $Nb; ++$i) { 576 | $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; 577 | } 578 | 579 | for ($round = 1; $round < $Nr; ++$round) { 580 | list($s, $e) = array($e, $s); 581 | for ($i = 0; $i < $Nb; ++$i) { 582 | $encrypt_block.= 583 | '$'.$e.$i.' = 584 | $t0[($'.$s.$i .' >> 24) & 0xff] ^ 585 | $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ 586 | $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^ 587 | $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^ 588 | '.$w[++$wc].";\n"; 589 | } 590 | } 591 | 592 | for ($i = 0; $i < $Nb; ++$i) { 593 | $encrypt_block.= 594 | '$'.$e.$i.' = 595 | $sbox[ $'.$e.$i.' & 0xff] | 596 | ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | 597 | ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | 598 | ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; 599 | } 600 | $encrypt_block .= '$in = pack("N*"'."\n"; 601 | for ($i = 0; $i < $Nb; ++$i) { 602 | $encrypt_block.= ', 603 | ($'.$e.$i .' & '.((int)0xFF000000).') ^ 604 | ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^ 605 | ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^ 606 | ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^ 607 | '.$w[$i]."\n"; 608 | } 609 | $encrypt_block .= ');'; 610 | 611 | $init_decrypt.= ' 612 | static $invtables; 613 | if (empty($invtables)) { 614 | $invtables = &$self->_getInvTables(); 615 | } 616 | $dt0 = $invtables[0]; 617 | $dt1 = $invtables[1]; 618 | $dt2 = $invtables[2]; 619 | $dt3 = $invtables[3]; 620 | $isbox = $invtables[4]; 621 | '; 622 | 623 | $s = 'e'; 624 | $e = 's'; 625 | $wc = $Nb - 1; 626 | 627 | $decrypt_block = '$in = unpack("N*", $in);'."\n"; 628 | for ($i = 0; $i < $Nb; ++$i) { 629 | $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; 630 | } 631 | 632 | for ($round = 1; $round < $Nr; ++$round) { 633 | list($s, $e) = array($e, $s); 634 | for ($i = 0; $i < $Nb; ++$i) { 635 | $decrypt_block.= 636 | '$'.$e.$i.' = 637 | $dt0[($'.$s.$i .' >> 24) & 0xff] ^ 638 | $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ 639 | $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^ 640 | $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^ 641 | '.$dw[++$wc].";\n"; 642 | } 643 | } 644 | 645 | for ($i = 0; $i < $Nb; ++$i) { 646 | $decrypt_block.= 647 | '$'.$e.$i.' = 648 | $isbox[ $'.$e.$i.' & 0xff] | 649 | ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | 650 | ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | 651 | ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; 652 | } 653 | $decrypt_block .= '$in = pack("N*"'."\n"; 654 | for ($i = 0; $i < $Nb; ++$i) { 655 | $decrypt_block.= ', 656 | ($'.$e.$i. ' & '.((int)0xFF000000).') ^ 657 | ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^ 658 | ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^ 659 | ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^ 660 | '.$dw[$i]."\n"; 661 | } 662 | $decrypt_block .= ');'; 663 | 664 | $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( 665 | array( 666 | 'init_crypt' => '', 667 | 'init_encrypt' => $init_encrypt, 668 | 'init_decrypt' => $init_decrypt, 669 | 'encrypt_block' => $encrypt_block, 670 | 'decrypt_block' => $decrypt_block 671 | ) 672 | ); 673 | } 674 | $this->inline_crypt = $lambda_functions[$code_hash]; 675 | } 676 | }} -------------------------------------------------------------------------------- /server/support/phpseclib/Crypt/Rijndael.php: -------------------------------------------------------------------------------- 1 | explicit_key_length) { 45 | $length = strlen($key); 46 | switch (true) { 47 | case $length <= 16: 48 | $this->key_size = 16; 49 | break; 50 | case $length <= 20: 51 | $this->key_size = 20; 52 | break; 53 | case $length <= 24: 54 | $this->key_size = 24; 55 | break; 56 | case $length <= 28: 57 | $this->key_size = 28; 58 | break; 59 | default: 60 | $this->key_size = 32; 61 | } 62 | } 63 | parent::setKey($key); 64 | } 65 | 66 | function setKeyLength($length) 67 | { 68 | switch (true) { 69 | case $length <= 128: 70 | $this->key_length = 16; 71 | break; 72 | case $length <= 160: 73 | $this->key_length = 20; 74 | break; 75 | case $length <= 192: 76 | $this->key_length = 24; 77 | break; 78 | case $length <= 224: 79 | $this->key_length = 28; 80 | break; 81 | default: 82 | $this->key_length = 32; 83 | } 84 | 85 | parent::setKeyLength($length); 86 | } 87 | 88 | function setBlockLength($length) 89 | { 90 | $length >>= 5; 91 | if ($length > 8) { 92 | $length = 8; 93 | } elseif ($length < 4) { 94 | $length = 4; 95 | } 96 | $this->Nb = $length; 97 | $this->block_size = $length << 2; 98 | $this->changed = true; 99 | $this->_setEngine(); 100 | } 101 | 102 | function isValidEngine($engine) 103 | { 104 | switch ($engine) { 105 | case CRYPT_ENGINE_OPENSSL: 106 | if ($this->block_size != 16) { 107 | return false; 108 | } 109 | $this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb'; 110 | $this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode(); 111 | break; 112 | case CRYPT_ENGINE_MCRYPT: 113 | $this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3); 114 | if ($this->key_length % 8) { return false; 115 | } 116 | } 117 | 118 | return parent::isValidEngine($engine); 119 | } 120 | 121 | function _encryptBlock($in) 122 | { 123 | static $tables; 124 | if (empty($tables)) { 125 | $tables = &$this->_getTables(); 126 | } 127 | $t0 = $tables[0]; 128 | $t1 = $tables[1]; 129 | $t2 = $tables[2]; 130 | $t3 = $tables[3]; 131 | $sbox = $tables[4]; 132 | 133 | $state = array(); 134 | $words = unpack('N*', $in); 135 | 136 | $c = $this->c; 137 | $w = $this->w; 138 | $Nb = $this->Nb; 139 | $Nr = $this->Nr; 140 | 141 | $wc = $Nb - 1; 142 | foreach ($words as $word) { 143 | $state[] = $word ^ $w[++$wc]; 144 | } 145 | 146 | $temp = array(); 147 | for ($round = 1; $round < $Nr; ++$round) { 148 | $i = 0; $j = $c[1]; 149 | $k = $c[2]; 150 | $l = $c[3]; 151 | 152 | while ($i < $Nb) { 153 | $temp[$i] = $t0[$state[$i] >> 24 & 0x000000FF] ^ 154 | $t1[$state[$j] >> 16 & 0x000000FF] ^ 155 | $t2[$state[$k] >> 8 & 0x000000FF] ^ 156 | $t3[$state[$l] & 0x000000FF] ^ 157 | $w[++$wc]; 158 | ++$i; 159 | $j = ($j + 1) % $Nb; 160 | $k = ($k + 1) % $Nb; 161 | $l = ($l + 1) % $Nb; 162 | } 163 | $state = $temp; 164 | } 165 | 166 | for ($i = 0; $i < $Nb; ++$i) { 167 | $state[$i] = $sbox[$state[$i] & 0x000000FF] | 168 | ($sbox[$state[$i] >> 8 & 0x000000FF] << 8) | 169 | ($sbox[$state[$i] >> 16 & 0x000000FF] << 16) | 170 | ($sbox[$state[$i] >> 24 & 0x000000FF] << 24); 171 | } 172 | 173 | $i = 0; $j = $c[1]; 174 | $k = $c[2]; 175 | $l = $c[3]; 176 | while ($i < $Nb) { 177 | $temp[$i] = ($state[$i] & 0xFF000000) ^ 178 | ($state[$j] & 0x00FF0000) ^ 179 | ($state[$k] & 0x0000FF00) ^ 180 | ($state[$l] & 0x000000FF) ^ 181 | $w[$i]; 182 | ++$i; 183 | $j = ($j + 1) % $Nb; 184 | $k = ($k + 1) % $Nb; 185 | $l = ($l + 1) % $Nb; 186 | } 187 | 188 | switch ($Nb) { 189 | case 8: 190 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); 191 | case 7: 192 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); 193 | case 6: 194 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); 195 | case 5: 196 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); 197 | default: 198 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); 199 | } 200 | } 201 | 202 | function _decryptBlock($in) 203 | { 204 | static $invtables; 205 | if (empty($invtables)) { 206 | $invtables = &$this->_getInvTables(); 207 | } 208 | $dt0 = $invtables[0]; 209 | $dt1 = $invtables[1]; 210 | $dt2 = $invtables[2]; 211 | $dt3 = $invtables[3]; 212 | $isbox = $invtables[4]; 213 | 214 | $state = array(); 215 | $words = unpack('N*', $in); 216 | 217 | $c = $this->c; 218 | $dw = $this->dw; 219 | $Nb = $this->Nb; 220 | $Nr = $this->Nr; 221 | 222 | $wc = $Nb - 1; 223 | foreach ($words as $word) { 224 | $state[] = $word ^ $dw[++$wc]; 225 | } 226 | 227 | $temp = array(); 228 | for ($round = $Nr - 1; $round > 0; --$round) { 229 | $i = 0; $j = $Nb - $c[1]; 230 | $k = $Nb - $c[2]; 231 | $l = $Nb - $c[3]; 232 | 233 | while ($i < $Nb) { 234 | $temp[$i] = $dt0[$state[$i] >> 24 & 0x000000FF] ^ 235 | $dt1[$state[$j] >> 16 & 0x000000FF] ^ 236 | $dt2[$state[$k] >> 8 & 0x000000FF] ^ 237 | $dt3[$state[$l] & 0x000000FF] ^ 238 | $dw[++$wc]; 239 | ++$i; 240 | $j = ($j + 1) % $Nb; 241 | $k = ($k + 1) % $Nb; 242 | $l = ($l + 1) % $Nb; 243 | } 244 | $state = $temp; 245 | } 246 | 247 | $i = 0; $j = $Nb - $c[1]; 248 | $k = $Nb - $c[2]; 249 | $l = $Nb - $c[3]; 250 | 251 | while ($i < $Nb) { 252 | $word = ($state[$i] & 0xFF000000) | 253 | ($state[$j] & 0x00FF0000) | 254 | ($state[$k] & 0x0000FF00) | 255 | ($state[$l] & 0x000000FF); 256 | 257 | $temp[$i] = $dw[$i] ^ ($isbox[$word & 0x000000FF] | 258 | ($isbox[$word >> 8 & 0x000000FF] << 8) | 259 | ($isbox[$word >> 16 & 0x000000FF] << 16) | 260 | ($isbox[$word >> 24 & 0x000000FF] << 24)); 261 | ++$i; 262 | $j = ($j + 1) % $Nb; 263 | $k = ($k + 1) % $Nb; 264 | $l = ($l + 1) % $Nb; 265 | } 266 | 267 | switch ($Nb) { 268 | case 8: 269 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6], $temp[7]); 270 | case 7: 271 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5], $temp[6]); 272 | case 6: 273 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4], $temp[5]); 274 | case 5: 275 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3], $temp[4]); 276 | default: 277 | return pack('N*', $temp[0], $temp[1], $temp[2], $temp[3]); 278 | } 279 | } 280 | 281 | function _setupKey() 282 | { 283 | static $rcon = array(0, 284 | 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 285 | 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 286 | 0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000, 287 | 0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000, 288 | 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, 289 | 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 290 | ); 291 | 292 | if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) { 293 | return; 294 | } 295 | $this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size); 296 | 297 | $this->Nk = $this->key_length >> 2; 298 | $this->Nr = max($this->Nk, $this->Nb) + 6; 299 | 300 | switch ($this->Nb) { 301 | case 4: 302 | case 5: 303 | case 6: 304 | $this->c = array(0, 1, 2, 3); 305 | break; 306 | case 7: 307 | $this->c = array(0, 1, 2, 4); 308 | break; 309 | case 8: 310 | $this->c = array(0, 1, 3, 4); 311 | } 312 | 313 | $w = array_values(unpack('N*words', $this->key)); 314 | 315 | $length = $this->Nb * ($this->Nr + 1); 316 | for ($i = $this->Nk; $i < $length; $i++) { 317 | $temp = $w[$i - 1]; 318 | if ($i % $this->Nk == 0) { 319 | $temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); $temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk]; 320 | } elseif ($this->Nk > 6 && $i % $this->Nk == 4) { 321 | $temp = $this->_subWord($temp); 322 | } 323 | $w[$i] = $w[$i - $this->Nk] ^ $temp; 324 | } 325 | 326 | list($dt0, $dt1, $dt2, $dt3) = $this->_getInvTables(); 327 | $temp = $this->w = $this->dw = array(); 328 | for ($i = $row = $col = 0; $i < $length; $i++, $col++) { 329 | if ($col == $this->Nb) { 330 | if ($row == 0) { 331 | $this->dw[0] = $this->w[0]; 332 | } else { 333 | $j = 0; 334 | while ($j < $this->Nb) { 335 | $dw = $this->_subWord($this->w[$row][$j]); 336 | $temp[$j] = $dt0[$dw >> 24 & 0x000000FF] ^ 337 | $dt1[$dw >> 16 & 0x000000FF] ^ 338 | $dt2[$dw >> 8 & 0x000000FF] ^ 339 | $dt3[$dw & 0x000000FF]; 340 | $j++; 341 | } 342 | $this->dw[$row] = $temp; 343 | } 344 | 345 | $col = 0; 346 | $row++; 347 | } 348 | $this->w[$row][$col] = $w[$i]; 349 | } 350 | 351 | $this->dw[$row] = $this->w[$row]; 352 | 353 | $this->dw = array_reverse($this->dw); 354 | $w = array_pop($this->w); 355 | $dw = array_pop($this->dw); 356 | foreach ($this->w as $r => $wr) { 357 | foreach ($wr as $c => $wc) { 358 | $w[] = $wc; 359 | $dw[] = $this->dw[$r][$c]; 360 | } 361 | } 362 | $this->w = $w; 363 | $this->dw = $dw; 364 | } 365 | 366 | function _subWord($word) 367 | { 368 | static $sbox; 369 | if (empty($sbox)) { 370 | list(, , , , $sbox) = $this->_getTables(); 371 | } 372 | 373 | return $sbox[$word & 0x000000FF] | 374 | ($sbox[$word >> 8 & 0x000000FF] << 8) | 375 | ($sbox[$word >> 16 & 0x000000FF] << 16) | 376 | ($sbox[$word >> 24 & 0x000000FF] << 24); 377 | } 378 | 379 | function &_getTables() 380 | { 381 | static $tables; 382 | if (empty($tables)) { 383 | $t3 = array_map('intval', array( 384 | 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, 385 | 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, 386 | 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, 387 | 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, 388 | 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, 389 | 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, 390 | 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, 391 | 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, 392 | 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, 393 | 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, 394 | 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, 395 | 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, 396 | 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, 397 | 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, 398 | 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, 399 | 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, 400 | 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, 401 | 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, 402 | 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, 403 | 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, 404 | 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, 405 | 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, 406 | 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, 407 | 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, 408 | 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, 409 | 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, 410 | 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, 411 | 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, 412 | 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, 413 | 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, 414 | 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, 415 | 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C 416 | )); 417 | 418 | foreach ($t3 as $t3i) { 419 | $t0[] = (($t3i << 24) & 0xFF000000) | (($t3i >> 8) & 0x00FFFFFF); 420 | $t1[] = (($t3i << 16) & 0xFFFF0000) | (($t3i >> 16) & 0x0000FFFF); 421 | $t2[] = (($t3i << 8) & 0xFFFFFF00) | (($t3i >> 24) & 0x000000FF); 422 | } 423 | 424 | $tables = array( 425 | $t0, 426 | $t1, 427 | $t2, 428 | $t3, 429 | array( 430 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 431 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 432 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 433 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 434 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 435 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 436 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 437 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 438 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 439 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 440 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 441 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 442 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 443 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 444 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 445 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 446 | ) 447 | ); 448 | } 449 | return $tables; 450 | } 451 | 452 | function &_getInvTables() 453 | { 454 | static $tables; 455 | if (empty($tables)) { 456 | $dt3 = array_map('intval', array( 457 | 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 458 | 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 459 | 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, 460 | 0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E, 461 | 0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D, 462 | 0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9, 463 | 0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66, 464 | 0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED, 465 | 0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4, 466 | 0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD, 467 | 0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60, 468 | 0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79, 469 | 0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C, 470 | 0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24, 471 | 0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C, 472 | 0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814, 473 | 0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B, 474 | 0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084, 475 | 0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077, 476 | 0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22, 477 | 0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F, 478 | 0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582, 479 | 0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB, 480 | 0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF, 481 | 0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035, 482 | 0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17, 483 | 0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46, 484 | 0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D, 485 | 0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A, 486 | 0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678, 487 | 0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF, 488 | 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 489 | )); 490 | 491 | foreach ($dt3 as $dt3i) { 492 | $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF); 493 | $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF); 494 | $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF); 495 | }; 496 | 497 | $tables = array( 498 | $dt0, 499 | $dt1, 500 | $dt2, 501 | $dt3, 502 | array( 503 | 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 504 | 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 505 | 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 506 | 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 507 | 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 508 | 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 509 | 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 510 | 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 511 | 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 512 | 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 513 | 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 514 | 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 515 | 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 516 | 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 517 | 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 518 | 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D 519 | ) 520 | ); 521 | } 522 | return $tables; 523 | } 524 | 525 | function _setupInlineCrypt() 526 | { 527 | 528 | $lambda_functions =& Crypt_Rijndael::_getLambdaFunctions(); 529 | 530 | $gen_hi_opt_code = (bool)(count($lambda_functions) < 10); 531 | 532 | $code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}"; 533 | if ($gen_hi_opt_code) { 534 | $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); 535 | } 536 | 537 | if (!isset($lambda_functions[$code_hash])) { 538 | switch (true) { 539 | case $gen_hi_opt_code: 540 | $w = $this->w; 541 | $dw = $this->dw; 542 | $init_encrypt = ''; 543 | $init_decrypt = ''; 544 | break; 545 | default: 546 | for ($i = 0, $cw = count($this->w); $i < $cw; ++$i) { 547 | $w[] = '$w[' . $i . ']'; 548 | $dw[] = '$dw[' . $i . ']'; 549 | } 550 | $init_encrypt = '$w = $self->w;'; 551 | $init_decrypt = '$dw = $self->dw;'; 552 | } 553 | 554 | $Nr = $this->Nr; 555 | $Nb = $this->Nb; 556 | $c = $this->c; 557 | 558 | $init_encrypt.= ' 559 | static $tables; 560 | if (empty($tables)) { 561 | $tables = &$self->_getTables(); 562 | } 563 | $t0 = $tables[0]; 564 | $t1 = $tables[1]; 565 | $t2 = $tables[2]; 566 | $t3 = $tables[3]; 567 | $sbox = $tables[4]; 568 | '; 569 | 570 | $s = 'e'; 571 | $e = 's'; 572 | $wc = $Nb - 1; 573 | 574 | $encrypt_block = '$in = unpack("N*", $in);'."\n"; 575 | for ($i = 0; $i < $Nb; ++$i) { 576 | $encrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$w[++$wc].";\n"; 577 | } 578 | 579 | for ($round = 1; $round < $Nr; ++$round) { 580 | list($s, $e) = array($e, $s); 581 | for ($i = 0; $i < $Nb; ++$i) { 582 | $encrypt_block.= 583 | '$'.$e.$i.' = 584 | $t0[($'.$s.$i .' >> 24) & 0xff] ^ 585 | $t1[($'.$s.(($i + $c[1]) % $Nb).' >> 16) & 0xff] ^ 586 | $t2[($'.$s.(($i + $c[2]) % $Nb).' >> 8) & 0xff] ^ 587 | $t3[ $'.$s.(($i + $c[3]) % $Nb).' & 0xff] ^ 588 | '.$w[++$wc].";\n"; 589 | } 590 | } 591 | 592 | for ($i = 0; $i < $Nb; ++$i) { 593 | $encrypt_block.= 594 | '$'.$e.$i.' = 595 | $sbox[ $'.$e.$i.' & 0xff] | 596 | ($sbox[($'.$e.$i.' >> 8) & 0xff] << 8) | 597 | ($sbox[($'.$e.$i.' >> 16) & 0xff] << 16) | 598 | ($sbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; 599 | } 600 | $encrypt_block .= '$in = pack("N*"'."\n"; 601 | for ($i = 0; $i < $Nb; ++$i) { 602 | $encrypt_block.= ', 603 | ($'.$e.$i .' & '.((int)0xFF000000).') ^ 604 | ($'.$e.(($i + $c[1]) % $Nb).' & 0x00FF0000 ) ^ 605 | ($'.$e.(($i + $c[2]) % $Nb).' & 0x0000FF00 ) ^ 606 | ($'.$e.(($i + $c[3]) % $Nb).' & 0x000000FF ) ^ 607 | '.$w[$i]."\n"; 608 | } 609 | $encrypt_block .= ');'; 610 | 611 | $init_decrypt.= ' 612 | static $invtables; 613 | if (empty($invtables)) { 614 | $invtables = &$self->_getInvTables(); 615 | } 616 | $dt0 = $invtables[0]; 617 | $dt1 = $invtables[1]; 618 | $dt2 = $invtables[2]; 619 | $dt3 = $invtables[3]; 620 | $isbox = $invtables[4]; 621 | '; 622 | 623 | $s = 'e'; 624 | $e = 's'; 625 | $wc = $Nb - 1; 626 | 627 | $decrypt_block = '$in = unpack("N*", $in);'."\n"; 628 | for ($i = 0; $i < $Nb; ++$i) { 629 | $decrypt_block .= '$s'.$i.' = $in['.($i + 1).'] ^ '.$dw[++$wc].';'."\n"; 630 | } 631 | 632 | for ($round = 1; $round < $Nr; ++$round) { 633 | list($s, $e) = array($e, $s); 634 | for ($i = 0; $i < $Nb; ++$i) { 635 | $decrypt_block.= 636 | '$'.$e.$i.' = 637 | $dt0[($'.$s.$i .' >> 24) & 0xff] ^ 638 | $dt1[($'.$s.(($Nb + $i - $c[1]) % $Nb).' >> 16) & 0xff] ^ 639 | $dt2[($'.$s.(($Nb + $i - $c[2]) % $Nb).' >> 8) & 0xff] ^ 640 | $dt3[ $'.$s.(($Nb + $i - $c[3]) % $Nb).' & 0xff] ^ 641 | '.$dw[++$wc].";\n"; 642 | } 643 | } 644 | 645 | for ($i = 0; $i < $Nb; ++$i) { 646 | $decrypt_block.= 647 | '$'.$e.$i.' = 648 | $isbox[ $'.$e.$i.' & 0xff] | 649 | ($isbox[($'.$e.$i.' >> 8) & 0xff] << 8) | 650 | ($isbox[($'.$e.$i.' >> 16) & 0xff] << 16) | 651 | ($isbox[($'.$e.$i.' >> 24) & 0xff] << 24);'."\n"; 652 | } 653 | $decrypt_block .= '$in = pack("N*"'."\n"; 654 | for ($i = 0; $i < $Nb; ++$i) { 655 | $decrypt_block.= ', 656 | ($'.$e.$i. ' & '.((int)0xFF000000).') ^ 657 | ($'.$e.(($Nb + $i - $c[1]) % $Nb).' & 0x00FF0000 ) ^ 658 | ($'.$e.(($Nb + $i - $c[2]) % $Nb).' & 0x0000FF00 ) ^ 659 | ($'.$e.(($Nb + $i - $c[3]) % $Nb).' & 0x000000FF ) ^ 660 | '.$dw[$i]."\n"; 661 | } 662 | $decrypt_block .= ');'; 663 | 664 | $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( 665 | array( 666 | 'init_crypt' => '', 667 | 'init_encrypt' => $init_encrypt, 668 | 'init_decrypt' => $init_decrypt, 669 | 'encrypt_block' => $encrypt_block, 670 | 'decrypt_block' => $decrypt_block 671 | ) 672 | ); 673 | } 674 | $this->inline_crypt = $lambda_functions[$code_hash]; 675 | } 676 | }} --------------------------------------------------------------------------------