├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── examples ├── exampleBots │ └── friendBot.php ├── exampleFunctional.php ├── registerTool.php └── verifyPhone.php └── src ├── Casper-API-PHP ├── CasperAPI.php ├── CasperAgent.php └── CasperException.php ├── Discover └── .gitkeep ├── authData └── .gitkeep ├── ca_bundle.crt ├── cache └── .gitkeep ├── fonts └── Helvetica.otf ├── func.php ├── phpseclib ├── Crypt │ ├── AES.php │ ├── Base.php │ ├── Blowfish.php │ ├── DES.php │ ├── Hash.php │ ├── RC2.php │ ├── RC4.php │ ├── RSA.php │ ├── Random.php │ ├── Rijndael.php │ ├── TripleDES.php │ └── Twofish.php ├── File │ ├── ANSI.php │ ├── ASN1.php │ └── X509.php ├── Math │ ├── BigInteger.php │ └── GMP.php ├── Net │ ├── SCP.php │ ├── SFTP.php │ ├── SFTP │ │ └── Stream.php │ ├── SSH1.php │ └── SSH2.php ├── System │ ├── SSH │ │ └── Agent.php │ └── SSH_Agent.php └── openssl.cnf ├── snapchat.php ├── snapchat_agent.php ├── snapchat_cache.php ├── snaps └── .gitkeep └── stories └── .gitkeep /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.jpg 3 | 4 | *.mp4 5 | 6 | *.zip 7 | 8 | *.png 9 | 10 | src/auth.dat 11 | 12 | *.dat 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 mgp25 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SC API [![Latest Stable Version](https://poser.pugx.org/mgp25/snapapi/v/stable)](https://packagist.org/packages/mgp25/snapapi) [![Total Downloads](https://poser.pugx.org/mgp25/snapapi/downloads)](https://packagist.org/packages/mgp25/snapapi) [![License](https://poser.pugx.org/mgp25/snapapi/license)](https://packagist.org/packages/mgp25/snapapi) ![CasperStatus](https://www.mgp25.com/cstatus/status.svg) 2 | 3 | **Read the [wiki](https://github.com/mgp25/SC-API/wiki)** and previous issues before opening a new one! Maybe your issue is already answered. 4 | 5 | ---------- 6 | 7 | ### Installation 8 | 9 | ```sh 10 | composer require mgp25/snapapi 11 | ``` 12 | 13 | ## Getting a Casper API Key 14 | 15 | This is required for the API to work. 16 | 17 | Go to https://clients.casper.io/login.php and create an account. 18 | 19 | Once you have created an account, go to `Projects` and create a new project. 20 | 21 | ![projects](http://s2.postimg.org/r7olutpah/projects.png) 22 | 23 | Now you will have your project with your API Key and API Secret. 24 | 25 | ![api](http://s2.postimg.org/vi39qeudl/api.png) 26 | 27 | You will need to set this data in the constructor, as shown in the [examples] (/examples). 28 | 29 | ### Special thanks 30 | 31 | - [teknogeek](https://github.com/teknogeek) 32 | - [liamcottle](https://github.com/liamcottle) (creator of [Casper](https://casper.io/)) 33 | - [JorgenPhi](https://github.com/JorgenPhi) 34 | - [hako](https://github.com/hako) 35 | - [0xTryCatch](https://github.com/0xTryCatch) 36 | - [kyleboyer](https://github.com/kyleboyer) 37 | 38 | Based on [JorgenPhi](https://github.com/JorgenPhi/php-snapchat) code. 39 | 40 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mgp25/SC-API) 41 | 42 | Do you like this project? Support it by donating 43 | 44 | - ![Paypal](https://raw.githubusercontent.com/reek/anti-adblock-killer/gh-pages/images/paypal.png) Paypal: [Donate](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=QZY4JX3P7278Y) 45 | - ![btc](https://camo.githubusercontent.com/4bc31b03fc4026aa2f14e09c25c09b81e06d5e71/687474703a2f2f7777772e6d6f6e747265616c626974636f696e2e636f6d2f696d672f66617669636f6e2e69636f) Bitcoin: 15NejBDahfe1eLAPSJh4iMfYLHYuKDrwJ2 46 | 47 | ## License 48 | MIT 49 | 50 | ## Legal 51 | 52 | This code is in no way affiliated with, authorized, maintained, sponsored or endorsed by Snapchat or any of its affiliates or subsidiaries. This is an independent and unofficial API. Use at your own risk. 53 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mgp25/snapapi", 3 | "description": "The php Snapchat library ", 4 | "license": "MIT", 5 | "keywords": [ 6 | "Snapchat", 7 | "SnapAPI" 8 | ], 9 | "authors": [ 10 | { 11 | "role": "Contributors", 12 | "name": "Snap API Contributing Team", 13 | "homepage": "https://github.com/mgp25/Snap-API/graphs/contributors" 14 | } 15 | ], 16 | "support": { 17 | "issues": "https://github.com/mgp25/Snap-API/issues", 18 | "wiki": "https://github.com/mgp25/Snap-API/wiki", 19 | "source": "https://github.com/mgp25/Snap-API" 20 | }, 21 | "autoload": { 22 | "classmap": [ 23 | "src/" 24 | ] 25 | }, 26 | "require": { 27 | "php": ">=5.3", 28 | "ext-curl": "*", 29 | "ext-gd" : "*", 30 | "ext-zip" : "*", 31 | "ext-mcrypt" : "*" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/exampleBots/friendBot.php: -------------------------------------------------------------------------------- 1 | login($password); 18 | 19 | // Get unconfirmed friends 20 | $unconfirmed = $snapchat->getUnconfirmedFriends(); 21 | 22 | // Add them 23 | if (!is_null($unconfirmed)) 24 | { 25 | print_r($unconfirmed); 26 | foreach($unconfirmed as $friend) 27 | $snapchat->addFriendBack($friend); 28 | } 29 | 30 | $snapchat->closeAppEvent(); 31 | -------------------------------------------------------------------------------- /examples/exampleFunctional.php: -------------------------------------------------------------------------------- 1 | login($password); 23 | 24 | // Get your friends in an array 25 | $friends = $snapchat->getFriends(); 26 | 27 | echo "My friends: "; 28 | print_r($friends); 29 | 30 | // Send snap adding text to your image and 10 seconds 31 | $snapchat->send($imagePath, $sendTo, "this is a test :D", 10); 32 | 33 | // Set a story 34 | // $snapchat->setStory($imagePath); 35 | 36 | // Set a story adding text to the image and 5 seconds 37 | $snapchat->setStory($imagePath, 5, "This is my story"); 38 | 39 | 40 | // Get snaps data (Without storing them) 41 | //$snapchat->getSnaps(); 42 | 43 | // Automatically downloads Snaps and store it in 'Snaps' folder 44 | $snapchat->getSnaps(true); 45 | 46 | // Download stories for a specific username 47 | $snapchat->getStoriesByUsername("homie", true); 48 | 49 | // Send chat message to "username" 50 | $snapchat->sendMessage("username", "hello from Snap-API!"); 51 | 52 | $snapchat->closeAppEvent(); 53 | 54 | ?> 55 | -------------------------------------------------------------------------------- /examples/registerTool.php: -------------------------------------------------------------------------------- 1 | register($username, $password, $email, $birthday); 34 | 35 | echo "\nYou should have a file called '{$id}' in your snap api folder, unzip it.\n"; 36 | echo "9 images. If there is a ghost in a image means 1, if not 0\n"; 37 | echo "The result should be like the following one: 110000101\n"; 38 | echo "After completion, the zip file will be deleted automatically.\n\n"; 39 | 40 | echo "\nResult: "; 41 | $result = trim(fgets(STDIN)); 42 | 43 | $result = $snapchat->sendCaptcha($result, $id); 44 | unlink(__DIR__.DIRECTORY_SEPARATOR."..".DIRECTORY_SEPARATOR."src".DIRECTORY_SEPARATOR.$id); 45 | if(property_exists($result, "error") && $result->error === 0 && property_exists($result->data, "find_friends_enabled")) 46 | { 47 | echo "Account successfully created\n"; 48 | echo "\nUsername: $username\n"; 49 | echo "Password: $password\n"; 50 | echo "Email: $email\n"; 51 | } 52 | else 53 | { 54 | echo "There was an error registering your account\n"; 55 | echo "Error code: " . $result['code']; 56 | } -------------------------------------------------------------------------------- /examples/verifyPhone.php: -------------------------------------------------------------------------------- 1 | login($password); 30 | 31 | $snapchat->sendPhoneVerification($phone); 32 | 33 | echo "\nCode: "; 34 | $code = trim(fgets(STDIN)); 35 | 36 | $snapchat->verifyPhoneNumber($code); 37 | -------------------------------------------------------------------------------- /src/Casper-API-PHP/CasperAPI.php: -------------------------------------------------------------------------------- 1 | $username, 45 | "password" => $password, 46 | "timestamp" => $timestamp, 47 | "snapchat_version" => self::SNAPCHAT_VERSION 48 | )); 49 | 50 | if(!isset($response->signature)){ 51 | throw new CasperException("Signature not found in Response"); 52 | } 53 | 54 | return $response->signature; 55 | 56 | } 57 | 58 | /** 59 | * Fetches an Attestation by making multiple API calls to the Google and Casper APIs. 60 | * 61 | * @param string $nonce 62 | * Base64 encoded value of the nonce 63 | * sha256(username|password|timestamp|/loq/login) 64 | * 65 | * @return string 66 | * The Client Auth Token 67 | * 68 | * @throws CasperException 69 | * An exception is thrown if an error occurs. 70 | */ 71 | public function getSnapchatAttestation($nonce){ 72 | 73 | $response = parent::get("/snapchat/attestation/create"); 74 | 75 | if(!isset($response->binary)){ 76 | throw new CasperException("Binary not found in Response"); 77 | } 78 | 79 | $binary = base64_decode($response->binary); 80 | 81 | $response = parent::externalRequest("https://www.googleapis.com/androidantiabuse/v1/x/create?alt=PROTO&key=AIzaSyBofcZsgLSS7BOnBjZPEkk4rYwzOIz-lTI", array( 82 | "Content-Type: application/x-protobuf", 83 | "User-Agent: SafetyNet/7899000 (klte KOT49H); gzip" 84 | ), $binary, true); 85 | 86 | $protobuf = base64_encode($response); 87 | 88 | $response = parent::post("/snapchat/attestation/attest", null, array( 89 | "protobuf" => $protobuf, 90 | "nonce" => $nonce, 91 | "snapchat_version" => self::SNAPCHAT_VERSION 92 | )); 93 | 94 | if(!isset($response->binary)){ 95 | throw new CasperException("Binary not found in Response"); 96 | } 97 | 98 | $binary = base64_decode($response->binary); 99 | 100 | $response = parent::externalRequest("https://www.googleapis.com/androidcheck/v1/attestations/attest?alt=JSON&key=AIzaSyDqVnJBjE5ymo--oBJt3On7HQx9xNm1RHA", array( 101 | "Content-Type: application/x-protobuf", 102 | "User-Agent: SafetyNet/7899000 (klte KOT49H); gzip" 103 | ), $binary, true); 104 | 105 | $json = json_decode($response); 106 | if($json == null){ 107 | throw new CasperException("Failed to decode response!"); 108 | } 109 | 110 | if(!isset($json->signedAttestation)){ 111 | throw new CasperException("Attestation not found in Response"); 112 | } 113 | 114 | return $json->signedAttestation; 115 | 116 | } 117 | 118 | /** 119 | * Generates an Nonce for Attestation requests. 120 | * 121 | * @param string $username 122 | * Snapchat Username 123 | * 124 | * @param string $password 125 | * Snapchat Password 126 | * 127 | * @param string $timestamp 128 | * Snapchat Login Timestamp 129 | * 130 | * @param string $endpoint 131 | * Snapchat Login Endpoint, always /loq/login at this stage. 132 | * 133 | * @return string 134 | * The Base64 Encoded Nonce 135 | * 136 | * @throws CasperException 137 | * An exception is thrown if an error occurs. 138 | */ 139 | public function generateSnapchatNonce($username, $password, $timestamp, $endpoint = "/loq/login"){ 140 | return base64_encode(hash("sha256", "{$username}|{$password}|{$timestamp}|{$endpoint}", true)); 141 | } 142 | 143 | } -------------------------------------------------------------------------------- /src/Casper-API-PHP/CasperAgent.php: -------------------------------------------------------------------------------- 1 | 10, 41 | CURLOPT_CONNECTTIMEOUT => 10, 42 | CURLOPT_USERAGENT => self::USER_AGENT, 43 | CURLOPT_HEADER => false, 44 | CURLINFO_HEADER_OUT => true, 45 | CURLOPT_RETURNTRANSFER => true, 46 | CURLOPT_ENCODING => "gzip" 47 | ); 48 | 49 | public function setAPIKey($api_key = null){ 50 | $this->API_KEY = $api_key; 51 | } 52 | 53 | public function setAPISecret($api_secret = null){ 54 | $this->API_SECRET = $api_secret; 55 | } 56 | 57 | /** 58 | * Performs a GET request. 59 | * 60 | * @param string $endpoint 61 | * Endpoint to make GET request to. 62 | * 63 | * @param array $headers 64 | * An array of parameters to send in the request. 65 | * 66 | * @return data 67 | * The response data. 68 | * 69 | * @throws CasperException 70 | * An exception is thrown if an error occurs. 71 | */ 72 | public function get($endpoint, $headers = array()){ 73 | return $this->request($endpoint, $headers); 74 | } 75 | 76 | /** 77 | * Performs a POST request. 78 | * 79 | * @param string $endpoint 80 | * Endpoint to make POST request to. 81 | * 82 | * @param array $headers 83 | * An array of parameters to send in the request. 84 | * 85 | * @param array $params 86 | * An array of parameters to send in the request. 87 | * 88 | * @return data 89 | * The response data. 90 | * 91 | * @throws CasperException 92 | * An exception is thrown if an error occurs. 93 | */ 94 | public function post($endpoint, $headers = array(), $params = array()){ 95 | return $this->request($endpoint, $headers, $params, true); 96 | } 97 | 98 | /** 99 | * Performs a POST request. 100 | * 101 | * @param string $endpoint 102 | * Endpoint to make request to. 103 | * 104 | * @param array $headers 105 | * An array of parameters to send in the request. 106 | * 107 | * @param array $params 108 | * An array of parameters to send in the request. 109 | * 110 | * @param boolean $post 111 | * true to make a POST request, else a GET request will be made. 112 | * 113 | * @return stdClass 114 | * The JSON data returned from the API. 115 | * 116 | * @throws CasperException 117 | * An exception is thrown if an error occurs. 118 | */ 119 | public function request($endpoint, $headers = array(), $params = array(), $post = false){ 120 | 121 | $ch = curl_init(); 122 | 123 | if($headers == null){ 124 | $headers = array(); 125 | } 126 | 127 | if($params == null){ 128 | $params = array(); 129 | } 130 | 131 | $headers = array_merge(self::$CURL_HEADERS, $headers); 132 | 133 | $headers[] = "X-Casper-API-Key: " . $this->API_KEY; 134 | $headers[] = "X-Casper-Signature: " . $this->generateRequestSignature($params, $this->API_SECRET); 135 | 136 | curl_setopt_array($ch, self::$CURL_OPTIONS); 137 | curl_setopt($ch, CURLOPT_URL, self::URL . $endpoint); 138 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 139 | 140 | //curl_setopt($ch, CURLOPT_PROXY, "http://localhost:8888"); 141 | 142 | if($post){ 143 | if(is_array($params)){ 144 | $params = http_build_query($params); 145 | } 146 | curl_setopt($ch, CURLOPT_POST, true); 147 | curl_setopt($ch, CURLOPT_POSTFIELDS, $params); 148 | } 149 | 150 | $result = curl_exec($ch); 151 | 152 | //If cURL doesn't have a bundle of root certificates handy, 153 | //we provide ours (see http://curl.haxx.se/docs/sslcerts.html). 154 | if(curl_errno($ch) == 60){ 155 | curl_setopt($ch, CURLOPT_CAINFO, __DIR__.DIRECTORY_SEPARATOR."..".DIRECTORY_SEPARATOR."ca_bundle.crt"); 156 | 157 | $result = curl_exec($ch); 158 | } 159 | 160 | //If the cURL request fails, return FALSE. 161 | if($result === FALSE){ 162 | $error = curl_error($ch); 163 | curl_close($ch); 164 | throw new CasperException($error); 165 | } 166 | 167 | $json = json_decode($result); 168 | if($json == null){ 169 | curl_close($ch); 170 | throw new CasperException("Failed to decode response!"); 171 | } 172 | 173 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 174 | if($code != 200){ 175 | 176 | curl_close($ch); 177 | 178 | if(isset($json->code) && isset($json->message)){ 179 | throw new CasperException("API Response: [{$json->code}] {$json->message}"); 180 | } else { 181 | throw new CasperException("API Response: [{$code}] Unknown Error Message"); 182 | } 183 | 184 | } 185 | 186 | curl_close($ch); 187 | 188 | return $json; 189 | 190 | } 191 | 192 | /** 193 | * Performs a POST request. 194 | * 195 | * @param string $url 196 | * Url to make request to. 197 | * 198 | * @param array $headers 199 | * An array of parameters to send in the request. 200 | * 201 | * @param array $params 202 | * An array of parameters to send in the request. 203 | * 204 | * @param boolean $post 205 | * true to make a POST request, else a GET request will be made. 206 | * 207 | * @return stdClass 208 | * The JSON data returned from the API. 209 | * 210 | * @throws CasperException 211 | * An exception is thrown if an error occurs. 212 | */ 213 | public function externalRequest($url, $headers = array(), $params = array(), $post = false){ 214 | 215 | $ch = curl_init(); 216 | 217 | if($headers == null){ 218 | $headers = array(); 219 | } 220 | 221 | if($params == null){ 222 | $params = array(); 223 | } 224 | 225 | curl_setopt_array($ch, self::$CURL_OPTIONS); 226 | curl_setopt($ch, CURLOPT_URL, $url); 227 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 228 | 229 | if($post){ 230 | if(is_array($params)){ 231 | $params = http_build_query($params); 232 | } 233 | curl_setopt($ch, CURLOPT_POST, true); 234 | curl_setopt($ch, CURLOPT_POSTFIELDS, $params); 235 | } 236 | 237 | $result = curl_exec($ch); 238 | 239 | //If cURL doesn't have a bundle of root certificates handy, 240 | //we provide ours (see http://curl.haxx.se/docs/sslcerts.html). 241 | if(curl_errno($ch) == 60){ 242 | curl_setopt($ch, CURLOPT_CAINFO, __DIR__.DIRECTORY_SEPARATOR."..".DIRECTORY_SEPARATOR."ca_bundle.crt"); 243 | $result = curl_exec($ch); 244 | } 245 | 246 | //If the cURL request fails, return FALSE. 247 | if($result === FALSE){ 248 | curl_close($ch); 249 | throw new CasperException("cURL request failed!"); 250 | } 251 | 252 | if(curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200){ 253 | 254 | curl_close($ch); 255 | throw new CasperException("External Request Failed!"); 256 | 257 | } 258 | 259 | curl_close($ch); 260 | 261 | return $result; 262 | 263 | } 264 | 265 | 266 | /** 267 | * 268 | * Generates an HMAC Signature of the Request Parameters 269 | * Parameter Keys need to be in alphabetical order. 270 | * Values are then appended to the end. 271 | * 272 | * @param array $parameters Parameters sent in your Request 273 | * @param string $secret Your Casper API Secret 274 | * @return string 275 | */ 276 | public function generateRequestSignature($parameters = array(), $secret){ 277 | 278 | ksort($parameters); 279 | 280 | $string = ""; 281 | foreach($parameters as $key => $value){ 282 | $string .= $key.$value; 283 | } 284 | return "v1:".hash_hmac("sha256", $string, $secret); 285 | } 286 | 287 | } 288 | -------------------------------------------------------------------------------- /src/Casper-API-PHP/CasperException.php: -------------------------------------------------------------------------------- 1 | 25 | * setKey('abcdefghijklmnop'); 31 | * 32 | * $size = 10 * 1024; 33 | * $plaintext = ''; 34 | * for ($i = 0; $i < $size; $i++) { 35 | * $plaintext.= 'a'; 36 | * } 37 | * 38 | * echo $aes->decrypt($aes->encrypt($plaintext)); 39 | * ?> 40 | * 41 | * 42 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy 43 | * of this software and associated documentation files (the "Software"), to deal 44 | * in the Software without restriction, including without limitation the rights 45 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 46 | * copies of the Software, and to permit persons to whom the Software is 47 | * furnished to do so, subject to the following conditions: 48 | * 49 | * The above copyright notice and this permission notice shall be included in 50 | * all copies or substantial portions of the Software. 51 | * 52 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 53 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 54 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 55 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 56 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 57 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 58 | * THE SOFTWARE. 59 | * 60 | * @category Crypt 61 | * @package Crypt_AES 62 | * @author Jim Wigginton 63 | * @copyright 2008 Jim Wigginton 64 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 65 | * @link http://phpseclib.sourceforge.net 66 | */ 67 | 68 | /** 69 | * Include Crypt_Rijndael 70 | */ 71 | if (!class_exists('Crypt_Rijndael')) { 72 | include_once 'Rijndael.php'; 73 | } 74 | 75 | /**#@+ 76 | * @access public 77 | * @see Crypt_AES::encrypt() 78 | * @see Crypt_AES::decrypt() 79 | */ 80 | /** 81 | * Encrypt / decrypt using the Counter mode. 82 | * 83 | * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. 84 | * 85 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 86 | */ 87 | define('CRYPT_AES_MODE_CTR', CRYPT_MODE_CTR); 88 | /** 89 | * Encrypt / decrypt using the Electronic Code Book mode. 90 | * 91 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 92 | */ 93 | define('CRYPT_AES_MODE_ECB', CRYPT_MODE_ECB); 94 | /** 95 | * Encrypt / decrypt using the Code Book Chaining mode. 96 | * 97 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 98 | */ 99 | define('CRYPT_AES_MODE_CBC', CRYPT_MODE_CBC); 100 | /** 101 | * Encrypt / decrypt using the Cipher Feedback mode. 102 | * 103 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 104 | */ 105 | define('CRYPT_AES_MODE_CFB', CRYPT_MODE_CFB); 106 | /** 107 | * Encrypt / decrypt using the Cipher Feedback mode. 108 | * 109 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 110 | */ 111 | define('CRYPT_AES_MODE_OFB', CRYPT_MODE_OFB); 112 | /**#@-*/ 113 | 114 | /** 115 | * Pure-PHP implementation of AES. 116 | * 117 | * @package Crypt_AES 118 | * @author Jim Wigginton 119 | * @access public 120 | */ 121 | class Crypt_AES extends Crypt_Rijndael 122 | { 123 | /** 124 | * The namespace used by the cipher for its constants. 125 | * 126 | * @see Crypt_Base::const_namespace 127 | * @var String 128 | * @access private 129 | */ 130 | var $const_namespace = 'AES'; 131 | 132 | /** 133 | * Dummy function 134 | * 135 | * Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything. 136 | * 137 | * @see Crypt_Rijndael::setBlockLength() 138 | * @access public 139 | * @param Integer $length 140 | */ 141 | function setBlockLength($length) 142 | { 143 | return; 144 | } 145 | 146 | /** 147 | * Sets the key length 148 | * 149 | * Valid key lengths are 128, 192, and 256. If the length is less than 128, it will be rounded up to 150 | * 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount. 151 | * 152 | * @see Crypt_Rijndael:setKeyLength() 153 | * @access public 154 | * @param Integer $length 155 | */ 156 | function setKeyLength($length) 157 | { 158 | switch ($length) { 159 | case 160: 160 | $length = 192; 161 | break; 162 | case 224: 163 | $length = 256; 164 | } 165 | parent::setKeyLength($length); 166 | } 167 | 168 | /** 169 | * Sets the key. 170 | * 171 | * Rijndael supports five different key lengths, AES only supports three. 172 | * 173 | * @see Crypt_Rijndael:setKey() 174 | * @see setKeyLength() 175 | * @access public 176 | * @param String $key 177 | */ 178 | function setKey($key) 179 | { 180 | parent::setKey($key); 181 | 182 | if (!$this->explicit_key_length) { 183 | $length = strlen($key); 184 | switch (true) { 185 | case $length <= 16: 186 | $this->key_size = 16; 187 | break; 188 | case $length <= 24: 189 | $this->key_size = 24; 190 | break; 191 | default: 192 | $this->key_size = 32; 193 | } 194 | $this->_setEngine(); 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/phpseclib/Crypt/RC2.php: -------------------------------------------------------------------------------- 1 | 16 | * setKey('abcdefgh'); 22 | * 23 | * $plaintext = str_repeat('a', 1024); 24 | * 25 | * echo $rc2->decrypt($rc2->encrypt($plaintext)); 26 | * ?> 27 | * 28 | * 29 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy 30 | * of this software and associated documentation files (the "Software"), to deal 31 | * in the Software without restriction, including without limitation the rights 32 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 33 | * copies of the Software, and to permit persons to whom the Software is 34 | * furnished to do so, subject to the following conditions: 35 | * 36 | * The above copyright notice and this permission notice shall be included in 37 | * all copies or substantial portions of the Software. 38 | * 39 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 40 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 41 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 42 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 43 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 44 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 45 | * THE SOFTWARE. 46 | * 47 | * @category Crypt 48 | * @package Crypt_RC2 49 | * @author Patrick Monnerat 50 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 51 | * @link http://phpseclib.sourceforge.net 52 | */ 53 | 54 | /** 55 | * Include Crypt_Base 56 | * 57 | * Base cipher class 58 | */ 59 | if (!class_exists('Crypt_Base')) { 60 | include_once 'Base.php'; 61 | } 62 | 63 | /**#@+ 64 | * @access public 65 | * @see Crypt_RC2::encrypt() 66 | * @see Crypt_RC2::decrypt() 67 | */ 68 | /** 69 | * Encrypt / decrypt using the Counter mode. 70 | * 71 | * Set to -1 since that's what Crypt/Random.php uses to index the CTR mode. 72 | * 73 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29 74 | */ 75 | define('CRYPT_RC2_MODE_CTR', CRYPT_MODE_CTR); 76 | /** 77 | * Encrypt / decrypt using the Electronic Code Book mode. 78 | * 79 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29 80 | */ 81 | define('CRYPT_RC2_MODE_ECB', CRYPT_MODE_ECB); 82 | /** 83 | * Encrypt / decrypt using the Code Book Chaining mode. 84 | * 85 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29 86 | */ 87 | define('CRYPT_RC2_MODE_CBC', CRYPT_MODE_CBC); 88 | /** 89 | * Encrypt / decrypt using the Cipher Feedback mode. 90 | * 91 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29 92 | */ 93 | define('CRYPT_RC2_MODE_CFB', CRYPT_MODE_CFB); 94 | /** 95 | * Encrypt / decrypt using the Cipher Feedback mode. 96 | * 97 | * @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29 98 | */ 99 | define('CRYPT_RC2_MODE_OFB', CRYPT_MODE_OFB); 100 | /**#@-*/ 101 | 102 | /** 103 | * Pure-PHP implementation of RC2. 104 | * 105 | * @package Crypt_RC2 106 | * @access public 107 | */ 108 | class Crypt_RC2 extends Crypt_Base 109 | { 110 | /** 111 | * Block Length of the cipher 112 | * 113 | * @see Crypt_Base::block_size 114 | * @var Integer 115 | * @access private 116 | */ 117 | var $block_size = 8; 118 | 119 | /** 120 | * The Key 121 | * 122 | * @see Crypt_Base::key 123 | * @see setKey() 124 | * @var String 125 | * @access private 126 | */ 127 | var $key; 128 | 129 | /** 130 | * The Original (unpadded) Key 131 | * 132 | * @see Crypt_Base::key 133 | * @see setKey() 134 | * @see encrypt() 135 | * @see decrypt() 136 | * @var String 137 | * @access private 138 | */ 139 | var $orig_key; 140 | 141 | /** 142 | * The default password key_size used by setPassword() 143 | * 144 | * @see Crypt_Base::password_key_size 145 | * @see Crypt_Base::setPassword() 146 | * @var Integer 147 | * @access private 148 | */ 149 | var $password_key_size = 16; // = 128 bits 150 | 151 | /** 152 | * The namespace used by the cipher for its constants. 153 | * 154 | * @see Crypt_Base::const_namespace 155 | * @var String 156 | * @access private 157 | */ 158 | var $const_namespace = 'RC2'; 159 | 160 | /** 161 | * The mcrypt specific name of the cipher 162 | * 163 | * @see Crypt_Base::cipher_name_mcrypt 164 | * @var String 165 | * @access private 166 | */ 167 | var $cipher_name_mcrypt = 'rc2'; 168 | 169 | /** 170 | * Optimizing value while CFB-encrypting 171 | * 172 | * @see Crypt_Base::cfb_init_len 173 | * @var Integer 174 | * @access private 175 | */ 176 | var $cfb_init_len = 500; 177 | 178 | /** 179 | * The key length in bits. 180 | * 181 | * @see Crypt_RC2::setKeyLength() 182 | * @see Crypt_RC2::setKey() 183 | * @var Integer 184 | * @access private 185 | * @internal Should be in range [1..1024]. 186 | * @internal Changing this value after setting the key has no effect. 187 | */ 188 | var $default_key_length = 1024; 189 | 190 | /** 191 | * The key length in bits. 192 | * 193 | * @see Crypt_RC2::isValidEnine() 194 | * @see Crypt_RC2::setKey() 195 | * @var Integer 196 | * @access private 197 | * @internal Should be in range [1..1024]. 198 | */ 199 | var $current_key_length; 200 | 201 | /** 202 | * The Key Schedule 203 | * 204 | * @see Crypt_RC2::_setupKey() 205 | * @var Array 206 | * @access private 207 | */ 208 | var $keys; 209 | 210 | /** 211 | * Key expansion randomization table. 212 | * Twice the same 256-value sequence to save a modulus in key expansion. 213 | * 214 | * @see Crypt_RC2::setKey() 215 | * @var Array 216 | * @access private 217 | */ 218 | var $pitable = array( 219 | 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 220 | 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, 221 | 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, 222 | 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 223 | 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, 224 | 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, 225 | 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 226 | 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, 227 | 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, 228 | 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 229 | 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, 230 | 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, 231 | 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 232 | 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, 233 | 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, 234 | 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 235 | 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, 236 | 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, 237 | 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 238 | 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, 239 | 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, 240 | 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 241 | 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, 242 | 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, 243 | 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 244 | 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, 245 | 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, 246 | 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 247 | 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, 248 | 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, 249 | 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 250 | 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD, 251 | 0xD9, 0x78, 0xF9, 0xC4, 0x19, 0xDD, 0xB5, 0xED, 252 | 0x28, 0xE9, 0xFD, 0x79, 0x4A, 0xA0, 0xD8, 0x9D, 253 | 0xC6, 0x7E, 0x37, 0x83, 0x2B, 0x76, 0x53, 0x8E, 254 | 0x62, 0x4C, 0x64, 0x88, 0x44, 0x8B, 0xFB, 0xA2, 255 | 0x17, 0x9A, 0x59, 0xF5, 0x87, 0xB3, 0x4F, 0x13, 256 | 0x61, 0x45, 0x6D, 0x8D, 0x09, 0x81, 0x7D, 0x32, 257 | 0xBD, 0x8F, 0x40, 0xEB, 0x86, 0xB7, 0x7B, 0x0B, 258 | 0xF0, 0x95, 0x21, 0x22, 0x5C, 0x6B, 0x4E, 0x82, 259 | 0x54, 0xD6, 0x65, 0x93, 0xCE, 0x60, 0xB2, 0x1C, 260 | 0x73, 0x56, 0xC0, 0x14, 0xA7, 0x8C, 0xF1, 0xDC, 261 | 0x12, 0x75, 0xCA, 0x1F, 0x3B, 0xBE, 0xE4, 0xD1, 262 | 0x42, 0x3D, 0xD4, 0x30, 0xA3, 0x3C, 0xB6, 0x26, 263 | 0x6F, 0xBF, 0x0E, 0xDA, 0x46, 0x69, 0x07, 0x57, 264 | 0x27, 0xF2, 0x1D, 0x9B, 0xBC, 0x94, 0x43, 0x03, 265 | 0xF8, 0x11, 0xC7, 0xF6, 0x90, 0xEF, 0x3E, 0xE7, 266 | 0x06, 0xC3, 0xD5, 0x2F, 0xC8, 0x66, 0x1E, 0xD7, 267 | 0x08, 0xE8, 0xEA, 0xDE, 0x80, 0x52, 0xEE, 0xF7, 268 | 0x84, 0xAA, 0x72, 0xAC, 0x35, 0x4D, 0x6A, 0x2A, 269 | 0x96, 0x1A, 0xD2, 0x71, 0x5A, 0x15, 0x49, 0x74, 270 | 0x4B, 0x9F, 0xD0, 0x5E, 0x04, 0x18, 0xA4, 0xEC, 271 | 0xC2, 0xE0, 0x41, 0x6E, 0x0F, 0x51, 0xCB, 0xCC, 272 | 0x24, 0x91, 0xAF, 0x50, 0xA1, 0xF4, 0x70, 0x39, 273 | 0x99, 0x7C, 0x3A, 0x85, 0x23, 0xB8, 0xB4, 0x7A, 274 | 0xFC, 0x02, 0x36, 0x5B, 0x25, 0x55, 0x97, 0x31, 275 | 0x2D, 0x5D, 0xFA, 0x98, 0xE3, 0x8A, 0x92, 0xAE, 276 | 0x05, 0xDF, 0x29, 0x10, 0x67, 0x6C, 0xBA, 0xC9, 277 | 0xD3, 0x00, 0xE6, 0xCF, 0xE1, 0x9E, 0xA8, 0x2C, 278 | 0x63, 0x16, 0x01, 0x3F, 0x58, 0xE2, 0x89, 0xA9, 279 | 0x0D, 0x38, 0x34, 0x1B, 0xAB, 0x33, 0xFF, 0xB0, 280 | 0xBB, 0x48, 0x0C, 0x5F, 0xB9, 0xB1, 0xCD, 0x2E, 281 | 0xC5, 0xF3, 0xDB, 0x47, 0xE5, 0xA5, 0x9C, 0x77, 282 | 0x0A, 0xA6, 0x20, 0x68, 0xFE, 0x7F, 0xC1, 0xAD 283 | ); 284 | 285 | /** 286 | * Inverse key expansion randomization table. 287 | * 288 | * @see Crypt_RC2::setKey() 289 | * @var Array 290 | * @access private 291 | */ 292 | var $invpitable = array( 293 | 0xD1, 0xDA, 0xB9, 0x6F, 0x9C, 0xC8, 0x78, 0x66, 294 | 0x80, 0x2C, 0xF8, 0x37, 0xEA, 0xE0, 0x62, 0xA4, 295 | 0xCB, 0x71, 0x50, 0x27, 0x4B, 0x95, 0xD9, 0x20, 296 | 0x9D, 0x04, 0x91, 0xE3, 0x47, 0x6A, 0x7E, 0x53, 297 | 0xFA, 0x3A, 0x3B, 0xB4, 0xA8, 0xBC, 0x5F, 0x68, 298 | 0x08, 0xCA, 0x8F, 0x14, 0xD7, 0xC0, 0xEF, 0x7B, 299 | 0x5B, 0xBF, 0x2F, 0xE5, 0xE2, 0x8C, 0xBA, 0x12, 300 | 0xE1, 0xAF, 0xB2, 0x54, 0x5D, 0x59, 0x76, 0xDB, 301 | 0x32, 0xA2, 0x58, 0x6E, 0x1C, 0x29, 0x64, 0xF3, 302 | 0xE9, 0x96, 0x0C, 0x98, 0x19, 0x8D, 0x3E, 0x26, 303 | 0xAB, 0xA5, 0x85, 0x16, 0x40, 0xBD, 0x49, 0x67, 304 | 0xDC, 0x22, 0x94, 0xBB, 0x3C, 0xC1, 0x9B, 0xEB, 305 | 0x45, 0x28, 0x18, 0xD8, 0x1A, 0x42, 0x7D, 0xCC, 306 | 0xFB, 0x65, 0x8E, 0x3D, 0xCD, 0x2A, 0xA3, 0x60, 307 | 0xAE, 0x93, 0x8A, 0x48, 0x97, 0x51, 0x15, 0xF7, 308 | 0x01, 0x0B, 0xB7, 0x36, 0xB1, 0x2E, 0x11, 0xFD, 309 | 0x84, 0x2D, 0x3F, 0x13, 0x88, 0xB3, 0x34, 0x24, 310 | 0x1B, 0xDE, 0xC5, 0x1D, 0x4D, 0x2B, 0x17, 0x31, 311 | 0x74, 0xA9, 0xC6, 0x43, 0x6D, 0x39, 0x90, 0xBE, 312 | 0xC3, 0xB0, 0x21, 0x6B, 0xF6, 0x0F, 0xD5, 0x99, 313 | 0x0D, 0xAC, 0x1F, 0x5C, 0x9E, 0xF5, 0xF9, 0x4C, 314 | 0xD6, 0xDF, 0x89, 0xE4, 0x8B, 0xFF, 0xC7, 0xAA, 315 | 0xE7, 0xED, 0x46, 0x25, 0xB6, 0x06, 0x5E, 0x35, 316 | 0xB5, 0xEC, 0xCE, 0xE8, 0x6C, 0x30, 0x55, 0x61, 317 | 0x4A, 0xFE, 0xA0, 0x79, 0x03, 0xF0, 0x10, 0x72, 318 | 0x7C, 0xCF, 0x52, 0xA6, 0xA7, 0xEE, 0x44, 0xD3, 319 | 0x9A, 0x57, 0x92, 0xD0, 0x5A, 0x7A, 0x41, 0x7F, 320 | 0x0E, 0x00, 0x63, 0xF2, 0x4F, 0x05, 0x83, 0xC9, 321 | 0xA1, 0xD4, 0xDD, 0xC4, 0x56, 0xF4, 0xD2, 0x77, 322 | 0x81, 0x09, 0x82, 0x33, 0x9F, 0x07, 0x86, 0x75, 323 | 0x38, 0x4E, 0x69, 0xF1, 0xAD, 0x23, 0x73, 0x87, 324 | 0x70, 0x02, 0xC2, 0x1E, 0xB8, 0x0A, 0xFC, 0xE6 325 | ); 326 | 327 | /** 328 | * Default Constructor. 329 | * 330 | * Determines whether or not the mcrypt extension should be used. 331 | * 332 | * $mode could be: 333 | * 334 | * - CRYPT_RC2_MODE_ECB 335 | * 336 | * - CRYPT_RC2_MODE_CBC 337 | * 338 | * - CRYPT_RC2_MODE_CTR 339 | * 340 | * - CRYPT_RC2_MODE_CFB 341 | * 342 | * - CRYPT_RC2_MODE_OFB 343 | * 344 | * If not explicitly set, CRYPT_RC2_MODE_CBC will be used. 345 | * 346 | * @see Crypt_Base::Crypt_Base() 347 | * @param optional Integer $mode 348 | * @access public 349 | */ 350 | function Crypt_RC2($mode = CRYPT_RC2_MODE_CBC) 351 | { 352 | parent::Crypt_Base($mode); 353 | } 354 | 355 | /** 356 | * Test for engine validity 357 | * 358 | * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() 359 | * 360 | * @see Crypt_Base::Crypt_Base() 361 | * @param Integer $engine 362 | * @access public 363 | * @return Boolean 364 | */ 365 | function isValidEngine($engine) 366 | { 367 | switch ($engine) { 368 | case CRYPT_ENGINE_OPENSSL: 369 | if ($this->current_key_length != 128 || strlen($this->orig_key) != 16) { 370 | return false; 371 | } 372 | $this->cipher_name_openssl_ecb = 'rc2-ecb'; 373 | $this->cipher_name_openssl = 'rc2-' . $this->_openssl_translate_mode(); 374 | } 375 | 376 | return parent::isValidEngine($engine); 377 | } 378 | 379 | /** 380 | * Sets the key length 381 | * 382 | * Valid key lengths are 1 to 1024. 383 | * Calling this function after setting the key has no effect until the next 384 | * Crypt_RC2::setKey() call. 385 | * 386 | * @access public 387 | * @param Integer $length in bits 388 | */ 389 | function setKeyLength($length) 390 | { 391 | if ($length >= 1 && $length <= 1024) { 392 | $this->default_key_length = $length; 393 | } 394 | } 395 | 396 | /** 397 | * Sets the key. 398 | * 399 | * Keys can be of any length. RC2, itself, uses 1 to 1024 bit keys (eg. 400 | * strlen($key) <= 128), however, we only use the first 128 bytes if $key 401 | * has more then 128 bytes in it, and set $key to a single null byte if 402 | * it is empty. 403 | * 404 | * If the key is not explicitly set, it'll be assumed to be a single 405 | * null byte. 406 | * 407 | * @see Crypt_Base::setKey() 408 | * @access public 409 | * @param String $key 410 | * @param Integer $t1 optional Effective key length in bits. 411 | */ 412 | function setKey($key, $t1 = 0) 413 | { 414 | $this->orig_key = $key; 415 | 416 | if ($t1 <= 0) { 417 | $t1 = $this->default_key_length; 418 | } else if ($t1 > 1024) { 419 | $t1 = 1024; 420 | } 421 | $this->current_key_length = $t1; 422 | // Key byte count should be 1..128. 423 | $key = strlen($key) ? substr($key, 0, 128) : "\x00"; 424 | $t = strlen($key); 425 | 426 | // The mcrypt RC2 implementation only supports effective key length 427 | // of 1024 bits. It is however possible to handle effective key 428 | // lengths in range 1..1024 by expanding the key and applying 429 | // inverse pitable mapping to the first byte before submitting it 430 | // to mcrypt. 431 | 432 | // Key expansion. 433 | $l = array_values(unpack('C*', $key)); 434 | $t8 = ($t1 + 7) >> 3; 435 | $tm = 0xFF >> (8 * $t8 - $t1); 436 | 437 | // Expand key. 438 | $pitable = $this->pitable; 439 | for ($i = $t; $i < 128; $i++) { 440 | $l[$i] = $pitable[$l[$i - 1] + $l[$i - $t]]; 441 | } 442 | $i = 128 - $t8; 443 | $l[$i] = $pitable[$l[$i] & $tm]; 444 | while ($i--) { 445 | $l[$i] = $pitable[$l[$i + 1] ^ $l[$i + $t8]]; 446 | } 447 | 448 | // Prepare the key for mcrypt. 449 | $l[0] = $this->invpitable[$l[0]]; 450 | array_unshift($l, 'C*'); 451 | parent::setKey(call_user_func_array('pack', $l)); 452 | } 453 | 454 | /** 455 | * Encrypts a message. 456 | * 457 | * Mostly a wrapper for Crypt_Base::encrypt, with some additional OpenSSL handling code 458 | * 459 | * @see decrypt() 460 | * @access public 461 | * @param String $plaintext 462 | * @return String $ciphertext 463 | */ 464 | function encrypt($plaintext) 465 | { 466 | if ($this->engine == CRYPT_ENGINE_OPENSSL) { 467 | $temp = $this->key; 468 | $this->key = $this->orig_key; 469 | $result = parent::encrypt($plaintext); 470 | $this->key = $temp; 471 | return $result; 472 | } 473 | 474 | return parent::encrypt($plaintext); 475 | } 476 | 477 | /** 478 | * Decrypts a message. 479 | * 480 | * Mostly a wrapper for Crypt_Base::decrypt, with some additional OpenSSL handling code 481 | * 482 | * @see encrypt() 483 | * @access public 484 | * @param String $ciphertext 485 | * @return String $plaintext 486 | */ 487 | function decrypt($ciphertext) 488 | { 489 | if ($this->engine == CRYPT_ENGINE_OPENSSL) { 490 | $temp = $this->key; 491 | $this->key = $this->orig_key; 492 | $result = parent::decrypt($ciphertext); 493 | $this->key = $temp; 494 | return $result; 495 | } 496 | 497 | return parent::encrypt($ciphertext); 498 | } 499 | 500 | /** 501 | * Encrypts a block 502 | * 503 | * @see Crypt_Base::_encryptBlock() 504 | * @see Crypt_Base::encrypt() 505 | * @access private 506 | * @param String $in 507 | * @return String 508 | */ 509 | function _encryptBlock($in) 510 | { 511 | list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); 512 | $keys = $this->keys; 513 | $limit = 20; 514 | $actions = array($limit => 44, 44 => 64); 515 | $j = 0; 516 | 517 | for (;;) { 518 | // Mixing round. 519 | $r0 = (($r0 + $keys[$j++] + ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; 520 | $r0 |= $r0 >> 16; 521 | $r1 = (($r1 + $keys[$j++] + ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; 522 | $r1 |= $r1 >> 16; 523 | $r2 = (($r2 + $keys[$j++] + ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; 524 | $r2 |= $r2 >> 16; 525 | $r3 = (($r3 + $keys[$j++] + ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; 526 | $r3 |= $r3 >> 16; 527 | 528 | if ($j === $limit) { 529 | if ($limit === 64) { 530 | break; 531 | } 532 | 533 | // Mashing round. 534 | $r0 += $keys[$r3 & 0x3F]; 535 | $r1 += $keys[$r0 & 0x3F]; 536 | $r2 += $keys[$r1 & 0x3F]; 537 | $r3 += $keys[$r2 & 0x3F]; 538 | $limit = $actions[$limit]; 539 | } 540 | } 541 | 542 | return pack('vvvv', $r0, $r1, $r2, $r3); 543 | } 544 | 545 | /** 546 | * Decrypts a block 547 | * 548 | * @see Crypt_Base::_decryptBlock() 549 | * @see Crypt_Base::decrypt() 550 | * @access private 551 | * @param String $in 552 | * @return String 553 | */ 554 | function _decryptBlock($in) 555 | { 556 | list($r0, $r1, $r2, $r3) = array_values(unpack('v*', $in)); 557 | $keys = $this->keys; 558 | $limit = 44; 559 | $actions = array($limit => 20, 20 => 0); 560 | $j = 64; 561 | 562 | for (;;) { 563 | // R-mixing round. 564 | $r3 = ($r3 | ($r3 << 16)) >> 5; 565 | $r3 = ($r3 - $keys[--$j] - ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; 566 | $r2 = ($r2 | ($r2 << 16)) >> 3; 567 | $r2 = ($r2 - $keys[--$j] - ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; 568 | $r1 = ($r1 | ($r1 << 16)) >> 2; 569 | $r1 = ($r1 - $keys[--$j] - ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; 570 | $r0 = ($r0 | ($r0 << 16)) >> 1; 571 | $r0 = ($r0 - $keys[--$j] - ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF; 572 | 573 | if ($j === $limit) { 574 | if ($limit === 0) { 575 | break; 576 | } 577 | 578 | // R-mashing round. 579 | $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; 580 | $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; 581 | $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; 582 | $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF; 583 | $limit = $actions[$limit]; 584 | } 585 | } 586 | 587 | return pack('vvvv', $r0, $r1, $r2, $r3); 588 | } 589 | 590 | /** 591 | * Setup the CRYPT_ENGINE_MCRYPT $engine 592 | * 593 | * @see Crypt_Base::_setupMcrypt() 594 | * @access private 595 | */ 596 | function _setupMcrypt() 597 | { 598 | if (!isset($this->key)) { 599 | $this->setKey(''); 600 | } 601 | 602 | parent::_setupMcrypt(); 603 | } 604 | 605 | /** 606 | * Creates the key schedule 607 | * 608 | * @see Crypt_Base::_setupKey() 609 | * @access private 610 | */ 611 | function _setupKey() 612 | { 613 | if (!isset($this->key)) { 614 | $this->setKey(''); 615 | } 616 | 617 | // Key has already been expanded in Crypt_RC2::setKey(): 618 | // Only the first value must be altered. 619 | $l = unpack('Ca/Cb/v*', $this->key); 620 | array_unshift($l, $this->pitable[$l['a']] | ($l['b'] << 8)); 621 | unset($l['a']); 622 | unset($l['b']); 623 | $this->keys = $l; 624 | } 625 | 626 | /** 627 | * Setup the performance-optimized function for de/encrypt() 628 | * 629 | * @see Crypt_Base::_setupInlineCrypt() 630 | * @access private 631 | */ 632 | function _setupInlineCrypt() 633 | { 634 | $lambda_functions = &Crypt_RC2::_getLambdaFunctions(); 635 | 636 | // The first 10 generated $lambda_functions will use the $keys hardcoded as integers 637 | // for the mixing rounds, for better inline crypt performance [~20% faster]. 638 | // But for memory reason we have to limit those ultra-optimized $lambda_functions to an amount of 10. 639 | // (Currently, for Crypt_RC2, one generated $lambda_function cost on php5.5@32bit ~60kb unfreeable mem and ~100kb on php5.5@64bit) 640 | $gen_hi_opt_code = (bool)( count($lambda_functions) < 10 ); 641 | 642 | // Generation of a uniqe hash for our generated code 643 | $code_hash = "Crypt_RC2, {$this->mode}"; 644 | if ($gen_hi_opt_code) { 645 | $code_hash = str_pad($code_hash, 32) . $this->_hashInlineCryptFunction($this->key); 646 | } 647 | 648 | // Is there a re-usable $lambda_functions in there? 649 | // If not, we have to create it. 650 | if (!isset($lambda_functions[$code_hash])) { 651 | // Init code for both, encrypt and decrypt. 652 | $init_crypt = '$keys = $self->keys;'; 653 | 654 | switch (true) { 655 | case $gen_hi_opt_code: 656 | $keys = $this->keys; 657 | default: 658 | $keys = array(); 659 | foreach ($this->keys as $k => $v) { 660 | $keys[$k] = '$keys[' . $k . ']'; 661 | } 662 | } 663 | 664 | // $in is the current 8 bytes block which has to be en/decrypt 665 | $encrypt_block = $decrypt_block = ' 666 | $in = unpack("v4", $in); 667 | $r0 = $in[1]; 668 | $r1 = $in[2]; 669 | $r2 = $in[3]; 670 | $r3 = $in[4]; 671 | '; 672 | 673 | // Create code for encryption. 674 | $limit = 20; 675 | $actions = array($limit => 44, 44 => 64); 676 | $j = 0; 677 | 678 | for (;;) { 679 | // Mixing round. 680 | $encrypt_block .= ' 681 | $r0 = (($r0 + ' . $keys[$j++] . ' + 682 | ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF) << 1; 683 | $r0 |= $r0 >> 16; 684 | $r1 = (($r1 + ' . $keys[$j++] . ' + 685 | ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF) << 2; 686 | $r1 |= $r1 >> 16; 687 | $r2 = (($r2 + ' . $keys[$j++] . ' + 688 | ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF) << 3; 689 | $r2 |= $r2 >> 16; 690 | $r3 = (($r3 + ' . $keys[$j++] . ' + 691 | ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF) << 5; 692 | $r3 |= $r3 >> 16;'; 693 | 694 | if ($j === $limit) { 695 | if ($limit === 64) { 696 | break; 697 | } 698 | 699 | // Mashing round. 700 | $encrypt_block .= ' 701 | $r0 += $keys[$r3 & 0x3F]; 702 | $r1 += $keys[$r0 & 0x3F]; 703 | $r2 += $keys[$r1 & 0x3F]; 704 | $r3 += $keys[$r2 & 0x3F];'; 705 | $limit = $actions[$limit]; 706 | } 707 | } 708 | 709 | $encrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; 710 | 711 | // Create code for decryption. 712 | $limit = 44; 713 | $actions = array($limit => 20, 20 => 0); 714 | $j = 64; 715 | 716 | for (;;) { 717 | // R-mixing round. 718 | $decrypt_block .= ' 719 | $r3 = ($r3 | ($r3 << 16)) >> 5; 720 | $r3 = ($r3 - ' . $keys[--$j] . ' - 721 | ((($r0 ^ $r1) & $r2) ^ $r0)) & 0xFFFF; 722 | $r2 = ($r2 | ($r2 << 16)) >> 3; 723 | $r2 = ($r2 - ' . $keys[--$j] . ' - 724 | ((($r3 ^ $r0) & $r1) ^ $r3)) & 0xFFFF; 725 | $r1 = ($r1 | ($r1 << 16)) >> 2; 726 | $r1 = ($r1 - ' . $keys[--$j] . ' - 727 | ((($r2 ^ $r3) & $r0) ^ $r2)) & 0xFFFF; 728 | $r0 = ($r0 | ($r0 << 16)) >> 1; 729 | $r0 = ($r0 - ' . $keys[--$j] . ' - 730 | ((($r1 ^ $r2) & $r3) ^ $r1)) & 0xFFFF;'; 731 | 732 | if ($j === $limit) { 733 | if ($limit === 0) { 734 | break; 735 | } 736 | 737 | // R-mashing round. 738 | $decrypt_block .= ' 739 | $r3 = ($r3 - $keys[$r2 & 0x3F]) & 0xFFFF; 740 | $r2 = ($r2 - $keys[$r1 & 0x3F]) & 0xFFFF; 741 | $r1 = ($r1 - $keys[$r0 & 0x3F]) & 0xFFFF; 742 | $r0 = ($r0 - $keys[$r3 & 0x3F]) & 0xFFFF;'; 743 | $limit = $actions[$limit]; 744 | } 745 | } 746 | 747 | $decrypt_block .= '$in = pack("v4", $r0, $r1, $r2, $r3);'; 748 | 749 | // Creates the inline-crypt function 750 | $lambda_functions[$code_hash] = $this->_createInlineCryptFunction( 751 | array( 752 | 'init_crypt' => $init_crypt, 753 | 'encrypt_block' => $encrypt_block, 754 | 'decrypt_block' => $decrypt_block 755 | ) 756 | ); 757 | } 758 | 759 | // Set the inline-crypt function as callback in: $this->inline_crypt 760 | $this->inline_crypt = $lambda_functions[$code_hash]; 761 | } 762 | } 763 | -------------------------------------------------------------------------------- /src/phpseclib/Crypt/RC4.php: -------------------------------------------------------------------------------- 1 | 20 | * setKey('abcdefgh'); 26 | * 27 | * $size = 10 * 1024; 28 | * $plaintext = ''; 29 | * for ($i = 0; $i < $size; $i++) { 30 | * $plaintext.= 'a'; 31 | * } 32 | * 33 | * echo $rc4->decrypt($rc4->encrypt($plaintext)); 34 | * ?> 35 | * 36 | * 37 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy 38 | * of this software and associated documentation files (the "Software"), to deal 39 | * in the Software without restriction, including without limitation the rights 40 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 41 | * copies of the Software, and to permit persons to whom the Software is 42 | * furnished to do so, subject to the following conditions: 43 | * 44 | * The above copyright notice and this permission notice shall be included in 45 | * all copies or substantial portions of the Software. 46 | * 47 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 48 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 49 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 50 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 51 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 52 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 53 | * THE SOFTWARE. 54 | * 55 | * @category Crypt 56 | * @package Crypt_RC4 57 | * @author Jim Wigginton 58 | * @copyright 2007 Jim Wigginton 59 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 60 | * @link http://phpseclib.sourceforge.net 61 | */ 62 | 63 | /** 64 | * Include Crypt_Base 65 | * 66 | * Base cipher class 67 | */ 68 | if (!class_exists('Crypt_Base')) { 69 | include_once 'Base.php'; 70 | } 71 | 72 | /**#@+ 73 | * @access private 74 | * @see Crypt_RC4::_crypt() 75 | */ 76 | define('CRYPT_RC4_ENCRYPT', 0); 77 | define('CRYPT_RC4_DECRYPT', 1); 78 | /**#@-*/ 79 | 80 | /** 81 | * Pure-PHP implementation of RC4. 82 | * 83 | * @package Crypt_RC4 84 | * @author Jim Wigginton 85 | * @access public 86 | */ 87 | class Crypt_RC4 extends Crypt_Base 88 | { 89 | /** 90 | * Block Length of the cipher 91 | * 92 | * RC4 is a stream cipher 93 | * so we the block_size to 0 94 | * 95 | * @see Crypt_Base::block_size 96 | * @var Integer 97 | * @access private 98 | */ 99 | var $block_size = 0; 100 | 101 | /** 102 | * The default password key_size used by setPassword() 103 | * 104 | * @see Crypt_Base::password_key_size 105 | * @see Crypt_Base::setPassword() 106 | * @var Integer 107 | * @access private 108 | */ 109 | var $password_key_size = 128; // = 1024 bits 110 | 111 | /** 112 | * The namespace used by the cipher for its constants. 113 | * 114 | * @see Crypt_Base::const_namespace 115 | * @var String 116 | * @access private 117 | */ 118 | var $const_namespace = 'RC4'; 119 | 120 | /** 121 | * The mcrypt specific name of the cipher 122 | * 123 | * @see Crypt_Base::cipher_name_mcrypt 124 | * @var String 125 | * @access private 126 | */ 127 | var $cipher_name_mcrypt = 'arcfour'; 128 | 129 | /** 130 | * Holds whether performance-optimized $inline_crypt() can/should be used. 131 | * 132 | * @see Crypt_Base::inline_crypt 133 | * @var mixed 134 | * @access private 135 | */ 136 | var $use_inline_crypt = false; // currently not available 137 | 138 | /** 139 | * The Key 140 | * 141 | * @see Crypt_RC4::setKey() 142 | * @var String 143 | * @access private 144 | */ 145 | var $key = "\0"; 146 | 147 | /** 148 | * The Key Stream for decryption and encryption 149 | * 150 | * @see Crypt_RC4::setKey() 151 | * @var Array 152 | * @access private 153 | */ 154 | var $stream; 155 | 156 | /** 157 | * Default Constructor. 158 | * 159 | * Determines whether or not the mcrypt extension should be used. 160 | * 161 | * @see Crypt_Base::Crypt_Base() 162 | * @return Crypt_RC4 163 | * @access public 164 | */ 165 | function Crypt_RC4() 166 | { 167 | parent::Crypt_Base(CRYPT_MODE_STREAM); 168 | } 169 | 170 | /** 171 | * Test for engine validity 172 | * 173 | * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() 174 | * 175 | * @see Crypt_Base::Crypt_Base() 176 | * @param Integer $engine 177 | * @access public 178 | * @return Boolean 179 | */ 180 | function isValidEngine($engine) 181 | { 182 | switch ($engine) { 183 | case CRYPT_ENGINE_OPENSSL: 184 | switch (strlen($this->key)) { 185 | case 5: 186 | $this->cipher_name_openssl = 'rc4-40'; 187 | break; 188 | case 8: 189 | $this->cipher_name_openssl = 'rc4-64'; 190 | break; 191 | case 16: 192 | $this->cipher_name_openssl = 'rc4'; 193 | break; 194 | default: 195 | return false; 196 | } 197 | } 198 | 199 | return parent::isValidEngine($engine); 200 | } 201 | 202 | /** 203 | * Dummy function. 204 | * 205 | * Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1]. 206 | * If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before 207 | * calling setKey(). 208 | * 209 | * [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol, 210 | * the IV's are relatively easy to predict, an attack described by 211 | * {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir} 212 | * can be used to quickly guess at the rest of the key. The following links elaborate: 213 | * 214 | * {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009} 215 | * {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack} 216 | * 217 | * @param String $iv 218 | * @see Crypt_RC4::setKey() 219 | * @access public 220 | */ 221 | function setIV($iv) 222 | { 223 | } 224 | 225 | /** 226 | * Sets the key. 227 | * 228 | * Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will 229 | * be used. If no key is explicitly set, it'll be assumed to be a single null byte. 230 | * 231 | * @access public 232 | * @see Crypt_Base::setKey() 233 | * @param String $key 234 | */ 235 | function setKey($key) 236 | { 237 | parent::setKey(substr($key, 0, 256)); 238 | } 239 | 240 | /** 241 | * Encrypts a message. 242 | * 243 | * @see Crypt_Base::decrypt() 244 | * @see Crypt_RC4::_crypt() 245 | * @access public 246 | * @param String $plaintext 247 | * @return String $ciphertext 248 | */ 249 | function encrypt($plaintext) 250 | { 251 | if ($this->engine != CRYPT_ENGINE_INTERNAL) { 252 | return parent::encrypt($plaintext); 253 | } 254 | return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT); 255 | } 256 | 257 | /** 258 | * Decrypts a message. 259 | * 260 | * $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)). 261 | * At least if the continuous buffer is disabled. 262 | * 263 | * @see Crypt_Base::encrypt() 264 | * @see Crypt_RC4::_crypt() 265 | * @access public 266 | * @param String $ciphertext 267 | * @return String $plaintext 268 | */ 269 | function decrypt($ciphertext) 270 | { 271 | if ($this->engine != CRYPT_ENGINE_INTERNAL) { 272 | return parent::decrypt($ciphertext); 273 | } 274 | return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT); 275 | } 276 | 277 | 278 | /** 279 | * Setup the key (expansion) 280 | * 281 | * @see Crypt_Base::_setupKey() 282 | * @access private 283 | */ 284 | function _setupKey() 285 | { 286 | $key = $this->key; 287 | $keyLength = strlen($key); 288 | $keyStream = range(0, 255); 289 | $j = 0; 290 | for ($i = 0; $i < 256; $i++) { 291 | $j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255; 292 | $temp = $keyStream[$i]; 293 | $keyStream[$i] = $keyStream[$j]; 294 | $keyStream[$j] = $temp; 295 | } 296 | 297 | $this->stream = array(); 298 | $this->stream[CRYPT_RC4_DECRYPT] = $this->stream[CRYPT_RC4_ENCRYPT] = array( 299 | 0, // index $i 300 | 0, // index $j 301 | $keyStream 302 | ); 303 | } 304 | 305 | /** 306 | * Encrypts or decrypts a message. 307 | * 308 | * @see Crypt_RC4::encrypt() 309 | * @see Crypt_RC4::decrypt() 310 | * @access private 311 | * @param String $text 312 | * @param Integer $mode 313 | * @return String $text 314 | */ 315 | function _crypt($text, $mode) 316 | { 317 | if ($this->changed) { 318 | $this->_setup(); 319 | $this->changed = false; 320 | } 321 | 322 | $stream = &$this->stream[$mode]; 323 | if ($this->continuousBuffer) { 324 | $i = &$stream[0]; 325 | $j = &$stream[1]; 326 | $keyStream = &$stream[2]; 327 | } else { 328 | $i = $stream[0]; 329 | $j = $stream[1]; 330 | $keyStream = $stream[2]; 331 | } 332 | 333 | $len = strlen($text); 334 | for ($k = 0; $k < $len; ++$k) { 335 | $i = ($i + 1) & 255; 336 | $ksi = $keyStream[$i]; 337 | $j = ($j + $ksi) & 255; 338 | $ksj = $keyStream[$j]; 339 | 340 | $keyStream[$i] = $ksj; 341 | $keyStream[$j] = $ksi; 342 | $text[$k] = $text[$k] ^ chr($keyStream[($ksj + $ksi) & 255]); 343 | } 344 | 345 | return $text; 346 | } 347 | } 348 | -------------------------------------------------------------------------------- /src/phpseclib/Crypt/Random.php: -------------------------------------------------------------------------------- 1 | 13 | * 18 | * 19 | * 20 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy 21 | * of this software and associated documentation files (the "Software"), to deal 22 | * in the Software without restriction, including without limitation the rights 23 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 24 | * copies of the Software, and to permit persons to whom the Software is 25 | * furnished to do so, subject to the following conditions: 26 | * 27 | * The above copyright notice and this permission notice shall be included in 28 | * all copies or substantial portions of the Software. 29 | * 30 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 31 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 32 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 33 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 34 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 35 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 36 | * THE SOFTWARE. 37 | * 38 | * @category Crypt 39 | * @package Crypt_Random 40 | * @author Jim Wigginton 41 | * @copyright 2007 Jim Wigginton 42 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 43 | * @link http://phpseclib.sourceforge.net 44 | */ 45 | 46 | // laravel is a PHP framework that utilizes phpseclib. laravel workbenches may, independently, 47 | // have phpseclib as a requirement as well. if you're developing such a program you may encounter 48 | // a "Cannot redeclare crypt_random_string()" error. 49 | if (!function_exists('crypt_random_string')) { 50 | /** 51 | * "Is Windows" test 52 | * 53 | * @access private 54 | */ 55 | define('CRYPT_RANDOM_IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN'); 56 | 57 | /** 58 | * Generate a random string. 59 | * 60 | * Although microoptimizations are generally discouraged as they impair readability this function is ripe with 61 | * microoptimizations because this function has the potential of being called a huge number of times. 62 | * eg. for RSA key generation. 63 | * 64 | * @param Integer $length 65 | * @return String 66 | * @access public 67 | */ 68 | function crypt_random_string($length) 69 | { 70 | if (CRYPT_RANDOM_IS_WINDOWS) { 71 | // method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call. 72 | // ie. class_alias is a function that was introduced in PHP 5.3 73 | if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) { 74 | return mcrypt_create_iv($length); 75 | } 76 | // method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was, 77 | // to quote , "possible blocking behavior". as of 5.3.4 78 | // openssl_random_pseudo_bytes and mcrypt_create_iv do the exact same thing on Windows. ie. they both 79 | // call php_win32_get_random_bytes(): 80 | // 81 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/openssl/openssl.c#L5008 82 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1392 83 | // 84 | // php_win32_get_random_bytes() is defined thusly: 85 | // 86 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80 87 | // 88 | // we're calling it, all the same, in the off chance that the mcrypt extension is not available 89 | if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) { 90 | return openssl_random_pseudo_bytes($length); 91 | } 92 | } else { 93 | // method 1. the fastest 94 | if (function_exists('openssl_random_pseudo_bytes')) { 95 | return openssl_random_pseudo_bytes($length); 96 | } 97 | // method 2 98 | static $fp = true; 99 | if ($fp === true) { 100 | // warning's will be output unles the error suppression operator is used. errors such as 101 | // "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc. 102 | $fp = @fopen('/dev/urandom', 'rb'); 103 | } 104 | if ($fp !== true && $fp !== false) { // surprisingly faster than !is_bool() or is_resource() 105 | return fread($fp, $length); 106 | } 107 | // method 3. pretty much does the same thing as method 2 per the following url: 108 | // https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/ext/mcrypt/mcrypt.c#L1391 109 | // surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're 110 | // not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir 111 | // restrictions or some such 112 | if (function_exists('mcrypt_create_iv')) { 113 | return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM); 114 | } 115 | } 116 | // at this point we have no choice but to use a pure-PHP CSPRNG 117 | 118 | // cascade entropy across multiple PHP instances by fixing the session and collecting all 119 | // environmental variables, including the previous session data and the current session 120 | // data. 121 | // 122 | // mt_rand seeds itself by looking at the PID and the time, both of which are (relatively) 123 | // easy to guess at. linux uses mouse clicks, keyboard timings, etc, as entropy sources, but 124 | // PHP isn't low level to be able to use those as sources and on a web server there's not likely 125 | // going to be a ton of keyboard or mouse action. web servers do have one thing that we can use 126 | // however, a ton of people visiting the website. obviously you don't want to base your seeding 127 | // soley on parameters a potential attacker sends but (1) not everything in $_SERVER is controlled 128 | // by the user and (2) this isn't just looking at the data sent by the current user - it's based 129 | // on the data sent by all users. one user requests the page and a hash of their info is saved. 130 | // another user visits the page and the serialization of their data is utilized along with the 131 | // server envirnment stuff and a hash of the previous http request data (which itself utilizes 132 | // a hash of the session data before that). certainly an attacker should be assumed to have 133 | // full control over his own http requests. he, however, is not going to have control over 134 | // everyone's http requests. 135 | static $crypto = false, $v; 136 | if ($crypto === false) { 137 | // save old session data 138 | $old_session_id = session_id(); 139 | $old_use_cookies = ini_get('session.use_cookies'); 140 | $old_session_cache_limiter = session_cache_limiter(); 141 | $_OLD_SESSION = isset($_SESSION) ? $_SESSION : false; 142 | if ($old_session_id != '') { 143 | session_write_close(); 144 | } 145 | 146 | session_id(1); 147 | ini_set('session.use_cookies', 0); 148 | session_cache_limiter(''); 149 | session_start(); 150 | 151 | $v = $seed = $_SESSION['seed'] = pack('H*', sha1( 152 | serialize($_SERVER) . 153 | serialize($_POST) . 154 | serialize($_GET) . 155 | serialize($_COOKIE) . 156 | serialize($GLOBALS) . 157 | serialize($_SESSION) . 158 | serialize($_OLD_SESSION) 159 | )); 160 | if (!isset($_SESSION['count'])) { 161 | $_SESSION['count'] = 0; 162 | } 163 | $_SESSION['count']++; 164 | 165 | session_write_close(); 166 | 167 | // restore old session data 168 | if ($old_session_id != '') { 169 | session_id($old_session_id); 170 | session_start(); 171 | ini_set('session.use_cookies', $old_use_cookies); 172 | session_cache_limiter($old_session_cache_limiter); 173 | } else { 174 | if ($_OLD_SESSION !== false) { 175 | $_SESSION = $_OLD_SESSION; 176 | unset($_OLD_SESSION); 177 | } else { 178 | unset($_SESSION); 179 | } 180 | } 181 | 182 | // in SSH2 a shared secret and an exchange hash are generated through the key exchange process. 183 | // the IV client to server is the hash of that "nonce" with the letter A and for the encryption key it's the letter C. 184 | // if the hash doesn't produce enough a key or an IV that's long enough concat successive hashes of the 185 | // original hash and the current hash. we'll be emulating that. for more info see the following URL: 186 | // 187 | // http://tools.ietf.org/html/rfc4253#section-7.2 188 | // 189 | // see the is_string($crypto) part for an example of how to expand the keys 190 | $key = pack('H*', sha1($seed . 'A')); 191 | $iv = pack('H*', sha1($seed . 'C')); 192 | 193 | // ciphers are used as per the nist.gov link below. also, see this link: 194 | // 195 | // http://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator#Designs_based_on_cryptographic_primitives 196 | switch (true) { 197 | case phpseclib_resolve_include_path('Crypt/AES.php'): 198 | if (!class_exists('Crypt_AES')) { 199 | include_once 'AES.php'; 200 | } 201 | $crypto = new Crypt_AES(CRYPT_AES_MODE_CTR); 202 | break; 203 | case phpseclib_resolve_include_path('Crypt/Twofish.php'): 204 | if (!class_exists('Crypt_Twofish')) { 205 | include_once 'Twofish.php'; 206 | } 207 | $crypto = new Crypt_Twofish(CRYPT_TWOFISH_MODE_CTR); 208 | break; 209 | case phpseclib_resolve_include_path('Crypt/Blowfish.php'): 210 | if (!class_exists('Crypt_Blowfish')) { 211 | include_once 'Blowfish.php'; 212 | } 213 | $crypto = new Crypt_Blowfish(CRYPT_BLOWFISH_MODE_CTR); 214 | break; 215 | case phpseclib_resolve_include_path('Crypt/TripleDES.php'): 216 | if (!class_exists('Crypt_TripleDES')) { 217 | include_once 'TripleDES.php'; 218 | } 219 | $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR); 220 | break; 221 | case phpseclib_resolve_include_path('Crypt/DES.php'): 222 | if (!class_exists('Crypt_DES')) { 223 | include_once 'DES.php'; 224 | } 225 | $crypto = new Crypt_DES(CRYPT_DES_MODE_CTR); 226 | break; 227 | case phpseclib_resolve_include_path('Crypt/RC4.php'): 228 | if (!class_exists('Crypt_RC4')) { 229 | include_once 'RC4.php'; 230 | } 231 | $crypto = new Crypt_RC4(); 232 | break; 233 | default: 234 | user_error('crypt_random_string requires at least one symmetric cipher be loaded'); 235 | return false; 236 | } 237 | 238 | $crypto->setKey($key); 239 | $crypto->setIV($iv); 240 | $crypto->enableContinuousBuffer(); 241 | } 242 | 243 | //return $crypto->encrypt(str_repeat("\0", $length)); 244 | 245 | // the following is based off of ANSI X9.31: 246 | // 247 | // http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf 248 | // 249 | // OpenSSL uses that same standard for it's random numbers: 250 | // 251 | // http://www.opensource.apple.com/source/OpenSSL/OpenSSL-38/openssl/fips-1.0/rand/fips_rand.c 252 | // (do a search for "ANS X9.31 A.2.4") 253 | $result = ''; 254 | while (strlen($result) < $length) { 255 | $i = $crypto->encrypt(microtime()); // strlen(microtime()) == 21 256 | $r = $crypto->encrypt($i ^ $v); // strlen($v) == 20 257 | $v = $crypto->encrypt($r ^ $i); // strlen($r) == 20 258 | $result.= $r; 259 | } 260 | return substr($result, 0, $length); 261 | } 262 | } 263 | 264 | if (!function_exists('phpseclib_resolve_include_path')) { 265 | /** 266 | * Resolve filename against the include path. 267 | * 268 | * Wrapper around stream_resolve_include_path() (which was introduced in 269 | * PHP 5.3.2) with fallback implementation for earlier PHP versions. 270 | * 271 | * @param string $filename 272 | * @return mixed Filename (string) on success, false otherwise. 273 | * @access public 274 | */ 275 | function phpseclib_resolve_include_path($filename) 276 | { 277 | if (function_exists('stream_resolve_include_path')) { 278 | return stream_resolve_include_path($filename); 279 | } 280 | 281 | // handle non-relative paths 282 | if (file_exists($filename)) { 283 | return realpath($filename); 284 | } 285 | 286 | $paths = PATH_SEPARATOR == ':' ? 287 | preg_split('#(? 12 | * setKey('abcdefghijklmnopqrstuvwx'); 18 | * 19 | * $size = 10 * 1024; 20 | * $plaintext = ''; 21 | * for ($i = 0; $i < $size; $i++) { 22 | * $plaintext.= 'a'; 23 | * } 24 | * 25 | * echo $des->decrypt($des->encrypt($plaintext)); 26 | * ?> 27 | * 28 | * 29 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy 30 | * of this software and associated documentation files (the "Software"), to deal 31 | * in the Software without restriction, including without limitation the rights 32 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 33 | * copies of the Software, and to permit persons to whom the Software is 34 | * furnished to do so, subject to the following conditions: 35 | * 36 | * The above copyright notice and this permission notice shall be included in 37 | * all copies or substantial portions of the Software. 38 | * 39 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 40 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 41 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 42 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 43 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 44 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 45 | * THE SOFTWARE. 46 | * 47 | * @category Crypt 48 | * @package Crypt_TripleDES 49 | * @author Jim Wigginton 50 | * @copyright 2007 Jim Wigginton 51 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 52 | * @link http://phpseclib.sourceforge.net 53 | */ 54 | 55 | /** 56 | * Include Crypt_DES 57 | */ 58 | if (!class_exists('Crypt_DES')) { 59 | include_once 'DES.php'; 60 | } 61 | 62 | /**#@+ 63 | * @access public 64 | * @see Crypt_TripleDES::Crypt_TripleDES() 65 | */ 66 | /** 67 | * Encrypt / decrypt using inner chaining 68 | * 69 | * Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3). 70 | */ 71 | define('CRYPT_MODE_3CBC', -2); 72 | /** 73 | * BC version of the above. 74 | */ 75 | define('CRYPT_DES_MODE_3CBC', -2); 76 | /** 77 | * Encrypt / decrypt using outer chaining 78 | * 79 | * Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC. 80 | */ 81 | define('CRYPT_MODE_CBC3', CRYPT_MODE_CBC); 82 | /** 83 | * BC version of the above. 84 | */ 85 | define('CRYPT_DES_MODE_CBC3', CRYPT_MODE_CBC3); 86 | /**#@-*/ 87 | 88 | /** 89 | * Pure-PHP implementation of Triple DES. 90 | * 91 | * @package Crypt_TripleDES 92 | * @author Jim Wigginton 93 | * @access public 94 | */ 95 | class Crypt_TripleDES extends Crypt_DES 96 | { 97 | /** 98 | * The default password key_size used by setPassword() 99 | * 100 | * @see Crypt_DES::password_key_size 101 | * @see Crypt_Base::password_key_size 102 | * @see Crypt_Base::setPassword() 103 | * @var Integer 104 | * @access private 105 | */ 106 | var $password_key_size = 24; 107 | 108 | /** 109 | * The default salt used by setPassword() 110 | * 111 | * @see Crypt_Base::password_default_salt 112 | * @see Crypt_Base::setPassword() 113 | * @var String 114 | * @access private 115 | */ 116 | var $password_default_salt = 'phpseclib'; 117 | 118 | /** 119 | * The namespace used by the cipher for its constants. 120 | * 121 | * @see Crypt_DES::const_namespace 122 | * @see Crypt_Base::const_namespace 123 | * @var String 124 | * @access private 125 | */ 126 | var $const_namespace = 'DES'; 127 | 128 | /** 129 | * The mcrypt specific name of the cipher 130 | * 131 | * @see Crypt_DES::cipher_name_mcrypt 132 | * @see Crypt_Base::cipher_name_mcrypt 133 | * @var String 134 | * @access private 135 | */ 136 | var $cipher_name_mcrypt = 'tripledes'; 137 | 138 | /** 139 | * Optimizing value while CFB-encrypting 140 | * 141 | * @see Crypt_Base::cfb_init_len 142 | * @var Integer 143 | * @access private 144 | */ 145 | var $cfb_init_len = 750; 146 | 147 | /** 148 | * max possible size of $key 149 | * 150 | * @see Crypt_TripleDES::setKey() 151 | * @see Crypt_DES::setKey() 152 | * @var String 153 | * @access private 154 | */ 155 | var $key_size_max = 24; 156 | 157 | /** 158 | * Internal flag whether using CRYPT_DES_MODE_3CBC or not 159 | * 160 | * @var Boolean 161 | * @access private 162 | */ 163 | var $mode_3cbc; 164 | 165 | /** 166 | * The Crypt_DES objects 167 | * 168 | * Used only if $mode_3cbc === true 169 | * 170 | * @var Array 171 | * @access private 172 | */ 173 | var $des; 174 | 175 | /** 176 | * Default Constructor. 177 | * 178 | * Determines whether or not the mcrypt extension should be used. 179 | * 180 | * $mode could be: 181 | * 182 | * - CRYPT_DES_MODE_ECB 183 | * 184 | * - CRYPT_DES_MODE_CBC 185 | * 186 | * - CRYPT_DES_MODE_CTR 187 | * 188 | * - CRYPT_DES_MODE_CFB 189 | * 190 | * - CRYPT_DES_MODE_OFB 191 | * 192 | * - CRYPT_DES_MODE_3CBC 193 | * 194 | * If not explicitly set, CRYPT_DES_MODE_CBC will be used. 195 | * 196 | * @see Crypt_DES::Crypt_DES() 197 | * @see Crypt_Base::Crypt_Base() 198 | * @param optional Integer $mode 199 | * @access public 200 | */ 201 | function Crypt_TripleDES($mode = CRYPT_MODE_CBC) 202 | { 203 | switch ($mode) { 204 | // In case of CRYPT_DES_MODE_3CBC, we init as CRYPT_DES_MODE_CBC 205 | // and additional flag us internally as 3CBC 206 | case CRYPT_DES_MODE_3CBC: 207 | parent::Crypt_Base(CRYPT_MODE_CBC); 208 | $this->mode_3cbc = true; 209 | 210 | // This three $des'es will do the 3CBC work (if $key > 64bits) 211 | $this->des = array( 212 | new Crypt_DES(CRYPT_MODE_CBC), 213 | new Crypt_DES(CRYPT_MODE_CBC), 214 | new Crypt_DES(CRYPT_MODE_CBC), 215 | ); 216 | 217 | // we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects 218 | $this->des[0]->disablePadding(); 219 | $this->des[1]->disablePadding(); 220 | $this->des[2]->disablePadding(); 221 | break; 222 | // If not 3CBC, we init as usual 223 | default: 224 | parent::Crypt_Base($mode); 225 | } 226 | } 227 | 228 | /** 229 | * Test for engine validity 230 | * 231 | * This is mainly just a wrapper to set things up for Crypt_Base::isValidEngine() 232 | * 233 | * @see Crypt_Base::Crypt_Base() 234 | * @param Integer $engine 235 | * @access public 236 | * @return Boolean 237 | */ 238 | function isValidEngine($engine) 239 | { 240 | if ($engine == CRYPT_ENGINE_OPENSSL) { 241 | $this->cipher_name_openssl_ecb = 'des-ede3'; 242 | $mode = $this->_openssl_translate_mode(); 243 | $this->cipher_name_openssl = $mode == 'ecb' ? 'des-ede3' : 'des-ede3-' . $mode; 244 | } 245 | 246 | return parent::isValidEngine($engine); 247 | } 248 | 249 | /** 250 | * Sets the initialization vector. (optional) 251 | * 252 | * SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explicitly set, it'll be assumed 253 | * to be all zero's. 254 | * 255 | * @see Crypt_Base::setIV() 256 | * @access public 257 | * @param String $iv 258 | */ 259 | function setIV($iv) 260 | { 261 | parent::setIV($iv); 262 | if ($this->mode_3cbc) { 263 | $this->des[0]->setIV($iv); 264 | $this->des[1]->setIV($iv); 265 | $this->des[2]->setIV($iv); 266 | } 267 | } 268 | 269 | /** 270 | * Sets the key. 271 | * 272 | * Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or 273 | * 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate. 274 | * 275 | * DES also requires that every eighth bit be a parity bit, however, we'll ignore that. 276 | * 277 | * If the key is not explicitly set, it'll be assumed to be all null bytes. 278 | * 279 | * @access public 280 | * @see Crypt_DES::setKey() 281 | * @see Crypt_Base::setKey() 282 | * @param String $key 283 | */ 284 | function setKey($key) 285 | { 286 | $length = strlen($key); 287 | if ($length > 8) { 288 | $key = str_pad(substr($key, 0, 24), 24, chr(0)); 289 | // if $key is between 64 and 128-bits, use the first 64-bits as the last, per this: 290 | // http://php.net/function.mcrypt-encrypt#47973 291 | $key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24); 292 | } else { 293 | $key = str_pad($key, 8, chr(0)); 294 | } 295 | parent::setKey($key); 296 | 297 | // And in case of CRYPT_DES_MODE_3CBC: 298 | // if key <= 64bits we not need the 3 $des to work, 299 | // because we will then act as regular DES-CBC with just a <= 64bit key. 300 | // So only if the key > 64bits (> 8 bytes) we will call setKey() for the 3 $des. 301 | if ($this->mode_3cbc && $length > 8) { 302 | $this->des[0]->setKey(substr($key, 0, 8)); 303 | $this->des[1]->setKey(substr($key, 8, 8)); 304 | $this->des[2]->setKey(substr($key, 16, 8)); 305 | } 306 | } 307 | 308 | /** 309 | * Encrypts a message. 310 | * 311 | * @see Crypt_Base::encrypt() 312 | * @access public 313 | * @param String $plaintext 314 | * @return String $cipertext 315 | */ 316 | function encrypt($plaintext) 317 | { 318 | // parent::en/decrypt() is able to do all the work for all modes and keylengths, 319 | // except for: CRYPT_MODE_3CBC (inner chaining CBC) with a key > 64bits 320 | 321 | // if the key is smaller then 8, do what we'd normally do 322 | if ($this->mode_3cbc && strlen($this->key) > 8) { 323 | return $this->des[2]->encrypt( 324 | $this->des[1]->decrypt( 325 | $this->des[0]->encrypt( 326 | $this->_pad($plaintext) 327 | ) 328 | ) 329 | ); 330 | } 331 | 332 | return parent::encrypt($plaintext); 333 | } 334 | 335 | /** 336 | * Decrypts a message. 337 | * 338 | * @see Crypt_Base::decrypt() 339 | * @access public 340 | * @param String $ciphertext 341 | * @return String $plaintext 342 | */ 343 | function decrypt($ciphertext) 344 | { 345 | if ($this->mode_3cbc && strlen($this->key) > 8) { 346 | return $this->_unpad( 347 | $this->des[0]->decrypt( 348 | $this->des[1]->encrypt( 349 | $this->des[2]->decrypt( 350 | str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, "\0") 351 | ) 352 | ) 353 | ) 354 | ); 355 | } 356 | 357 | return parent::decrypt($ciphertext); 358 | } 359 | 360 | /** 361 | * Treat consecutive "packets" as if they are a continuous buffer. 362 | * 363 | * Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets 364 | * will yield different outputs: 365 | * 366 | * 367 | * echo $des->encrypt(substr($plaintext, 0, 8)); 368 | * echo $des->encrypt(substr($plaintext, 8, 8)); 369 | * 370 | * 371 | * echo $des->encrypt($plaintext); 372 | * 373 | * 374 | * The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates 375 | * another, as demonstrated with the following: 376 | * 377 | * 378 | * $des->encrypt(substr($plaintext, 0, 8)); 379 | * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); 380 | * 381 | * 382 | * echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8))); 383 | * 384 | * 385 | * With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different 386 | * outputs. The reason is due to the fact that the initialization vector's change after every encryption / 387 | * decryption round when the continuous buffer is enabled. When it's disabled, they remain constant. 388 | * 389 | * Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each 390 | * encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that 391 | * continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them), 392 | * however, they are also less intuitive and more likely to cause you problems. 393 | * 394 | * @see Crypt_Base::enableContinuousBuffer() 395 | * @see Crypt_TripleDES::disableContinuousBuffer() 396 | * @access public 397 | */ 398 | function enableContinuousBuffer() 399 | { 400 | parent::enableContinuousBuffer(); 401 | if ($this->mode_3cbc) { 402 | $this->des[0]->enableContinuousBuffer(); 403 | $this->des[1]->enableContinuousBuffer(); 404 | $this->des[2]->enableContinuousBuffer(); 405 | } 406 | } 407 | 408 | /** 409 | * Treat consecutive packets as if they are a discontinuous buffer. 410 | * 411 | * The default behavior. 412 | * 413 | * @see Crypt_Base::disableContinuousBuffer() 414 | * @see Crypt_TripleDES::enableContinuousBuffer() 415 | * @access public 416 | */ 417 | function disableContinuousBuffer() 418 | { 419 | parent::disableContinuousBuffer(); 420 | if ($this->mode_3cbc) { 421 | $this->des[0]->disableContinuousBuffer(); 422 | $this->des[1]->disableContinuousBuffer(); 423 | $this->des[2]->disableContinuousBuffer(); 424 | } 425 | } 426 | 427 | /** 428 | * Creates the key schedule 429 | * 430 | * @see Crypt_DES::_setupKey() 431 | * @see Crypt_Base::_setupKey() 432 | * @access private 433 | */ 434 | function _setupKey() 435 | { 436 | switch (true) { 437 | // if $key <= 64bits we configure our internal pure-php cipher engine 438 | // to act as regular [1]DES, not as 3DES. mcrypt.so::tripledes does the same. 439 | case strlen($this->key) <= 8: 440 | $this->des_rounds = 1; 441 | break; 442 | 443 | // otherwise, if $key > 64bits, we configure our engine to work as 3DES. 444 | default: 445 | $this->des_rounds = 3; 446 | 447 | // (only) if 3CBC is used we have, of course, to setup the $des[0-2] keys also separately. 448 | if ($this->mode_3cbc) { 449 | $this->des[0]->_setupKey(); 450 | $this->des[1]->_setupKey(); 451 | $this->des[2]->_setupKey(); 452 | 453 | // because $des[0-2] will, now, do all the work we can return here 454 | // not need unnecessary stress parent::_setupKey() with our, now unused, $key. 455 | return; 456 | } 457 | } 458 | // setup our key 459 | parent::_setupKey(); 460 | } 461 | 462 | /** 463 | * Sets the internal crypt engine 464 | * 465 | * @see Crypt_Base::Crypt_Base() 466 | * @see Crypt_Base::setPreferredEngine() 467 | * @param Integer $engine 468 | * @access public 469 | * @return Integer 470 | */ 471 | function setPreferredEngine($engine) 472 | { 473 | if ($this->mode_3cbc) { 474 | $this->des[0]->setPreferredEngine($engine); 475 | $this->des[1]->setPreferredEngine($engine); 476 | $this->des[2]->setPreferredEngine($engine); 477 | } 478 | 479 | return parent::setPreferredEngine($engine); 480 | } 481 | } 482 | -------------------------------------------------------------------------------- /src/phpseclib/File/ANSI.php: -------------------------------------------------------------------------------- 1 | 34 | * @copyright 2012 Jim Wigginton 35 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 36 | * @link http://phpseclib.sourceforge.net 37 | */ 38 | 39 | /** 40 | * Pure-PHP ANSI Decoder 41 | * 42 | * @package File_ANSI 43 | * @author Jim Wigginton 44 | * @access public 45 | */ 46 | class File_ANSI 47 | { 48 | /** 49 | * Max Width 50 | * 51 | * @var Integer 52 | * @access private 53 | */ 54 | var $max_x; 55 | 56 | /** 57 | * Max Height 58 | * 59 | * @var Integer 60 | * @access private 61 | */ 62 | var $max_y; 63 | 64 | /** 65 | * Max History 66 | * 67 | * @var Integer 68 | * @access private 69 | */ 70 | var $max_history; 71 | 72 | /** 73 | * History 74 | * 75 | * @var Array 76 | * @access private 77 | */ 78 | var $history; 79 | 80 | /** 81 | * History Attributes 82 | * 83 | * @var Array 84 | * @access private 85 | */ 86 | var $history_attrs; 87 | 88 | /** 89 | * Current Column 90 | * 91 | * @var Integer 92 | * @access private 93 | */ 94 | var $x; 95 | 96 | /** 97 | * Current Row 98 | * 99 | * @var Integer 100 | * @access private 101 | */ 102 | var $y; 103 | 104 | /** 105 | * Old Column 106 | * 107 | * @var Integer 108 | * @access private 109 | */ 110 | var $old_x; 111 | 112 | /** 113 | * Old Row 114 | * 115 | * @var Integer 116 | * @access private 117 | */ 118 | var $old_y; 119 | 120 | /** 121 | * An empty attribute row 122 | * 123 | * @var Array 124 | * @access private 125 | */ 126 | var $attr_row; 127 | 128 | /** 129 | * The current screen text 130 | * 131 | * @var Array 132 | * @access private 133 | */ 134 | var $screen; 135 | 136 | /** 137 | * The current screen attributes 138 | * 139 | * @var Array 140 | * @access private 141 | */ 142 | var $attrs; 143 | 144 | /** 145 | * The current foreground color 146 | * 147 | * @var String 148 | * @access private 149 | */ 150 | var $foreground; 151 | 152 | /** 153 | * The current background color 154 | * 155 | * @var String 156 | * @access private 157 | */ 158 | var $background; 159 | 160 | /** 161 | * Bold flag 162 | * 163 | * @var Boolean 164 | * @access private 165 | */ 166 | var $bold; 167 | 168 | /** 169 | * Underline flag 170 | * 171 | * @var Boolean 172 | * @access private 173 | */ 174 | var $underline; 175 | 176 | /** 177 | * Blink flag 178 | * 179 | * @var Boolean 180 | * @access private 181 | */ 182 | var $blink; 183 | 184 | /** 185 | * Reverse flag 186 | * 187 | * @var Boolean 188 | * @access private 189 | */ 190 | var $reverse; 191 | 192 | /** 193 | * Color flag 194 | * 195 | * @var Boolean 196 | * @access private 197 | */ 198 | var $color; 199 | 200 | /** 201 | * Current ANSI code 202 | * 203 | * @var String 204 | * @access private 205 | */ 206 | var $ansi; 207 | 208 | /** 209 | * Default Constructor. 210 | * 211 | * @return File_ANSI 212 | * @access public 213 | */ 214 | function File_ANSI() 215 | { 216 | $this->setHistory(200); 217 | $this->setDimensions(80, 24); 218 | } 219 | 220 | /** 221 | * Set terminal width and height 222 | * 223 | * Resets the screen as well 224 | * 225 | * @param Integer $x 226 | * @param Integer $y 227 | * @access public 228 | */ 229 | function setDimensions($x, $y) 230 | { 231 | $this->max_x = $x - 1; 232 | $this->max_y = $y - 1; 233 | $this->x = $this->y = 0; 234 | $this->history = $this->history_attrs = array(); 235 | $this->attr_row = array_fill(0, $this->max_x + 1, ''); 236 | $this->screen = array_fill(0, $this->max_y + 1, ''); 237 | $this->attrs = array_fill(0, $this->max_y + 1, $this->attr_row); 238 | $this->foreground = 'white'; 239 | $this->background = 'black'; 240 | $this->bold = false; 241 | $this->underline = false; 242 | $this->blink = false; 243 | $this->reverse = false; 244 | $this->color = false; 245 | 246 | $this->ansi = ''; 247 | } 248 | 249 | /** 250 | * Set the number of lines that should be logged past the terminal height 251 | * 252 | * @param Integer $x 253 | * @param Integer $y 254 | * @access public 255 | */ 256 | function setHistory($history) 257 | { 258 | $this->max_history = $history; 259 | } 260 | 261 | /** 262 | * Load a string 263 | * 264 | * @param String $source 265 | * @access public 266 | */ 267 | function loadString($source) 268 | { 269 | $this->setDimensions($this->max_x + 1, $this->max_y + 1); 270 | $this->appendString($source); 271 | } 272 | 273 | /** 274 | * Appdend a string 275 | * 276 | * @param String $source 277 | * @access public 278 | */ 279 | function appendString($source) 280 | { 281 | for ($i = 0; $i < strlen($source); $i++) { 282 | if (strlen($this->ansi)) { 283 | $this->ansi.= $source[$i]; 284 | $chr = ord($source[$i]); 285 | // http://en.wikipedia.org/wiki/ANSI_escape_code#Sequence_elements 286 | // single character CSI's not currently supported 287 | switch (true) { 288 | case $this->ansi == "\x1B=": 289 | $this->ansi = ''; 290 | continue 2; 291 | case strlen($this->ansi) == 2 && $chr >= 64 && $chr <= 95 && $chr != ord('['): 292 | case strlen($this->ansi) > 2 && $chr >= 64 && $chr <= 126: 293 | break; 294 | default: 295 | continue 2; 296 | } 297 | // http://ascii-table.com/ansi-escape-sequences-vt-100.php 298 | switch ($this->ansi) { 299 | case "\x1B[H": // Move cursor to upper left corner 300 | $this->old_x = $this->x; 301 | $this->old_y = $this->y; 302 | $this->x = $this->y = 0; 303 | break; 304 | case "\x1B[J": // Clear screen from cursor down 305 | $this->history = array_merge($this->history, array_slice(array_splice($this->screen, $this->y + 1), 0, $this->old_y)); 306 | $this->screen = array_merge($this->screen, array_fill($this->y, $this->max_y, '')); 307 | 308 | $this->history_attrs = array_merge($this->history_attrs, array_slice(array_splice($this->attrs, $this->y + 1), 0, $this->old_y)); 309 | $this->attrs = array_merge($this->attrs, array_fill($this->y, $this->max_y, $this->attr_row)); 310 | 311 | if (count($this->history) == $this->max_history) { 312 | array_shift($this->history); 313 | array_shift($this->history_attrs); 314 | } 315 | case "\x1B[K": // Clear screen from cursor right 316 | $this->screen[$this->y] = substr($this->screen[$this->y], 0, $this->x); 317 | 318 | array_splice($this->attrs[$this->y], $this->x + 1); 319 | break; 320 | case "\x1B[2K": // Clear entire line 321 | $this->screen[$this->y] = str_repeat(' ', $this->x); 322 | $this->attrs[$this->y] = $this->attr_row; 323 | break; 324 | case "\x1B[?1h": // set cursor key to application 325 | case "\x1B[?25h": // show the cursor 326 | break; 327 | case "\x1BE": // Move to next line 328 | $this->_newLine(); 329 | $this->x = 0; 330 | break; 331 | default: 332 | switch (true) { 333 | case preg_match('#\x1B\[(\d+);(\d+)H#', $this->ansi, $match): // Move cursor to screen location v,h 334 | $this->old_x = $this->x; 335 | $this->old_y = $this->y; 336 | $this->x = $match[2] - 1; 337 | $this->y = $match[1] - 1; 338 | break; 339 | case preg_match('#\x1B\[(\d+)C#', $this->ansi, $match): // Move cursor right n lines 340 | $this->old_x = $this->x; 341 | $x = $match[1] - 1; 342 | break; 343 | case preg_match('#\x1B\[(\d+);(\d+)r#', $this->ansi, $match): // Set top and bottom lines of a window 344 | break; 345 | case preg_match('#\x1B\[(\d*(?:;\d*)*)m#', $this->ansi, $match): // character attributes 346 | $mods = explode(';', $match[1]); 347 | foreach ($mods as $mod) { 348 | switch ($mod) { 349 | case 0: // Turn off character attributes 350 | $this->attrs[$this->y][$this->x] = ''; 351 | 352 | if ($this->bold) $this->attrs[$this->y][$this->x].= ''; 353 | if ($this->underline) $this->attrs[$this->y][$this->x].= ''; 354 | if ($this->blink) $this->attrs[$this->y][$this->x].= ''; 355 | if ($this->color) $this->attrs[$this->y][$this->x].= ''; 356 | 357 | if ($this->reverse) { 358 | $temp = $this->background; 359 | $this->background = $this->foreground; 360 | $this->foreground = $temp; 361 | } 362 | 363 | $this->bold = $this->underline = $this->blink = $this->color = $this->reverse = false; 364 | break; 365 | case 1: // Turn bold mode on 366 | if (!$this->bold) { 367 | $this->attrs[$this->y][$this->x] = ''; 368 | $this->bold = true; 369 | } 370 | break; 371 | case 4: // Turn underline mode on 372 | if (!$this->underline) { 373 | $this->attrs[$this->y][$this->x] = ''; 374 | $this->underline = true; 375 | } 376 | break; 377 | case 5: // Turn blinking mode on 378 | if (!$this->blink) { 379 | $this->attrs[$this->y][$this->x] = ''; 380 | $this->blink = true; 381 | } 382 | break; 383 | case 7: // Turn reverse video on 384 | $this->reverse = !$this->reverse; 385 | $temp = $this->background; 386 | $this->background = $this->foreground; 387 | $this->foreground = $temp; 388 | $this->attrs[$this->y][$this->x] = ''; 389 | if ($this->color) { 390 | $this->attrs[$this->y][$this->x] = '' . $this->attrs[$this->y][$this->x]; 391 | } 392 | $this->color = true; 393 | break; 394 | default: // set colors 395 | //$front = $this->reverse ? &$this->background : &$this->foreground; 396 | $front = &$this->{ $this->reverse ? 'background' : 'foreground' }; 397 | //$back = $this->reverse ? &$this->foreground : &$this->background; 398 | $back = &$this->{ $this->reverse ? 'foreground' : 'background' }; 399 | switch ($mod) { 400 | case 30: $front = 'black'; break; 401 | case 31: $front = 'red'; break; 402 | case 32: $front = 'green'; break; 403 | case 33: $front = 'yellow'; break; 404 | case 34: $front = 'blue'; break; 405 | case 35: $front = 'magenta'; break; 406 | case 36: $front = 'cyan'; break; 407 | case 37: $front = 'white'; break; 408 | 409 | case 40: $back = 'black'; break; 410 | case 41: $back = 'red'; break; 411 | case 42: $back = 'green'; break; 412 | case 43: $back = 'yellow'; break; 413 | case 44: $back = 'blue'; break; 414 | case 45: $back = 'magenta'; break; 415 | case 46: $back = 'cyan'; break; 416 | case 47: $back = 'white'; break; 417 | 418 | default: 419 | user_error('Unsupported attribute: ' . $mod); 420 | $this->ansi = ''; 421 | break 2; 422 | } 423 | 424 | unset($temp); 425 | $this->attrs[$this->y][$this->x] = ''; 426 | if ($this->color) { 427 | $this->attrs[$this->y][$this->x] = '' . $this->attrs[$this->y][$this->x]; 428 | } 429 | $this->color = true; 430 | } 431 | } 432 | break; 433 | default: 434 | user_error("{$this->ansi} unsupported\r\n"); 435 | } 436 | } 437 | $this->ansi = ''; 438 | continue; 439 | } 440 | 441 | switch ($source[$i]) { 442 | case "\r": 443 | $this->x = 0; 444 | break; 445 | case "\n": 446 | $this->_newLine(); 447 | break; 448 | case "\x0F": // shift 449 | break; 450 | case "\x1B": // start ANSI escape code 451 | $this->ansi.= "\x1B"; 452 | break; 453 | default: 454 | $this->screen[$this->y] = substr_replace( 455 | $this->screen[$this->y], 456 | $source[$i], 457 | $this->x, 458 | 1 459 | ); 460 | 461 | if ($this->x > $this->max_x) { 462 | $this->x = 0; 463 | $this->y++; 464 | } else { 465 | $this->x++; 466 | } 467 | } 468 | } 469 | } 470 | 471 | /** 472 | * Add a new line 473 | * 474 | * Also update the $this->screen and $this->history buffers 475 | * 476 | * @access private 477 | */ 478 | function _newLine() 479 | { 480 | //if ($this->y < $this->max_y) { 481 | // $this->y++; 482 | //} 483 | 484 | while ($this->y >= $this->max_y) { 485 | $this->history = array_merge($this->history, array(array_shift($this->screen))); 486 | $this->screen[] = ''; 487 | 488 | $this->history_attrs = array_merge($this->history_attrs, array(array_shift($this->attrs))); 489 | $this->attrs[] = $this->attr_row; 490 | 491 | if (count($this->history) >= $this->max_history) { 492 | array_shift($this->history); 493 | array_shift($this->history_attrs); 494 | } 495 | 496 | $this->y--; 497 | } 498 | $this->y++; 499 | } 500 | 501 | /** 502 | * Returns the current screen without preformating 503 | * 504 | * @access private 505 | * @return String 506 | */ 507 | function _getScreen() 508 | { 509 | $output = ''; 510 | for ($i = 0; $i <= $this->max_y; $i++) { 511 | for ($j = 0; $j <= $this->max_x + 1; $j++) { 512 | if (isset($this->attrs[$i][$j])) { 513 | $output.= $this->attrs[$i][$j]; 514 | } 515 | if (isset($this->screen[$i][$j])) { 516 | $output.= htmlspecialchars($this->screen[$i][$j]); 517 | } 518 | } 519 | $output.= "\r\n"; 520 | } 521 | return rtrim($output); 522 | } 523 | 524 | /** 525 | * Returns the current screen 526 | * 527 | * @access public 528 | * @return String 529 | */ 530 | function getScreen() 531 | { 532 | return '
' . $this->_getScreen() . '
'; 533 | } 534 | 535 | /** 536 | * Returns the current screen and the x previous lines 537 | * 538 | * @access public 539 | * @return String 540 | */ 541 | function getHistory() 542 | { 543 | $scrollback = ''; 544 | for ($i = 0; $i < count($this->history); $i++) { 545 | for ($j = 0; $j <= $this->max_x + 1; $j++) { 546 | if (isset($this->history_attrs[$i][$j])) { 547 | $scrollback.= $this->history_attrs[$i][$j]; 548 | } 549 | if (isset($this->history[$i][$j])) { 550 | $scrollback.= htmlspecialchars($this->history[$i][$j]); 551 | } 552 | } 553 | $scrollback.= "\r\n"; 554 | } 555 | $scrollback.= $this->_getScreen(); 556 | 557 | return '
' . $scrollback . '
'; 558 | } 559 | } 560 | -------------------------------------------------------------------------------- /src/phpseclib/Math/GMP.php: -------------------------------------------------------------------------------- 1 | 19 | * @copyright 2005, 2006 Alexander Valyalkin 20 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 21 | * @version 1.2.0b 22 | * @link http://pear.php.net/package/Crypt_RSA 23 | */ 24 | 25 | /** 26 | * Crypt_RSA_Math_GMP class. 27 | * 28 | * Provides set of math functions, which are used by Crypt_RSA package 29 | * This class is a wrapper for PHP GMP extension. 30 | * See http://php.net/gmp for details. 31 | * 32 | * @category Encryption 33 | * @package Crypt_RSA 34 | * @author Alexander Valyalkin 35 | * @copyright 2005, 2006 Alexander Valyalkin 36 | * @license http://www.php.net/license/3_0.txt PHP License 3.0 37 | * @link http://pear.php.net/package/Crypt_RSA 38 | * @version @package_version@ 39 | * @access public 40 | */ 41 | class Crypt_RSA_Math_GMP 42 | { 43 | /** 44 | * error description 45 | * 46 | * @var string 47 | * @access public 48 | */ 49 | var $errstr = ''; 50 | 51 | /** 52 | * Crypt_RSA_Math_GMP constructor. 53 | * Checks an existance of PHP GMP package. 54 | * See http://php.net/gmp for details. 55 | * 56 | * On failure saves error description in $this->errstr 57 | * 58 | * @access public 59 | */ 60 | function Crypt_RSA_Math_GMP() 61 | { 62 | if (!extension_loaded('gmp')) { 63 | if (!@dl('gmp.' . PHP_SHLIB_SUFFIX) && !@dl('php_gmp.' . PHP_SHLIB_SUFFIX)) { 64 | // cannot load GMP extension 65 | $this->errstr = 'Crypt_RSA package requires PHP GMP package. ' . 66 | 'See http://php.net/gmp for details'; 67 | return; 68 | } 69 | } 70 | } 71 | 72 | /** 73 | * Transforms binary representation of large integer into its native form. 74 | * 75 | * Example of transformation: 76 | * $str = "\x12\x34\x56\x78\x90"; 77 | * $num = 0x9078563412; 78 | * 79 | * @param string $str 80 | * @return gmp resource 81 | * @access public 82 | */ 83 | function bin2int($str) 84 | { 85 | $result = 0; 86 | $n = strlen($str); 87 | do { 88 | // dirty hack: GMP returns FALSE, when second argument equals to int(0). 89 | // so, it must be converted to string '0' 90 | $result = gmp_add(gmp_mul($result, 256), strval(ord($str{--$n}))); 91 | } while ($n > 0); 92 | return $result; 93 | } 94 | 95 | /** 96 | * Transforms large integer into binary representation. 97 | * 98 | * Example of transformation: 99 | * $num = 0x9078563412; 100 | * $str = "\x12\x34\x56\x78\x90"; 101 | * 102 | * @param gmp resource $num 103 | * @return string 104 | * @access public 105 | */ 106 | function int2bin($num) 107 | { 108 | $result = ''; 109 | do { 110 | $result .= chr(gmp_intval(gmp_mod($num, 256))); 111 | $num = gmp_div($num, 256); 112 | } while (gmp_cmp($num, 0)); 113 | return $result; 114 | } 115 | 116 | /** 117 | * Calculates pow($num, $pow) (mod $mod) 118 | * 119 | * @param gmp resource $num 120 | * @param gmp resource $pow 121 | * @param gmp resource $mod 122 | * @return gmp resource 123 | * @access public 124 | */ 125 | function powmod($num, $pow, $mod) 126 | { 127 | return gmp_powm($num, $pow, $mod); 128 | } 129 | 130 | /** 131 | * Calculates $num1 * $num2 132 | * 133 | * @param gmp resource $num1 134 | * @param gmp resource $num2 135 | * @return gmp resource 136 | * @access public 137 | */ 138 | function mul($num1, $num2) 139 | { 140 | return gmp_mul($num1, $num2); 141 | } 142 | 143 | /** 144 | * Calculates $num1 % $num2 145 | * 146 | * @param string $num1 147 | * @param string $num2 148 | * @return string 149 | * @access public 150 | */ 151 | function mod($num1, $num2) 152 | { 153 | return gmp_mod($num1, $num2); 154 | } 155 | 156 | /** 157 | * Compares abs($num1) to abs($num2). 158 | * Returns: 159 | * -1, if abs($num1) < abs($num2) 160 | * 0, if abs($num1) == abs($num2) 161 | * 1, if abs($num1) > abs($num2) 162 | * 163 | * @param gmp resource $num1 164 | * @param gmp resource $num2 165 | * @return int 166 | * @access public 167 | */ 168 | function cmpAbs($num1, $num2) 169 | { 170 | return gmp_cmp($num1, $num2); 171 | } 172 | 173 | /** 174 | * Tests $num on primality. Returns true, if $num is strong pseudoprime. 175 | * Else returns false. 176 | * 177 | * @param string $num 178 | * @return bool 179 | * @access private 180 | */ 181 | function isPrime($num) 182 | { 183 | return gmp_prob_prime($num) ? true : false; 184 | } 185 | 186 | /** 187 | * Generates prime number with length $bits_cnt 188 | * using $random_generator as random generator function. 189 | * 190 | * @param int $bits_cnt 191 | * @param string $rnd_generator 192 | * @access public 193 | */ 194 | function getPrime($bits_cnt, $random_generator) 195 | { 196 | $bytes_n = intval($bits_cnt / 8); 197 | $bits_n = $bits_cnt % 8; 198 | do { 199 | $str = ''; 200 | for ($i = 0; $i < $bytes_n; $i++) { 201 | $str .= chr(call_user_func($random_generator) & 0xff); 202 | } 203 | $n = call_user_func($random_generator) & 0xff; 204 | $n |= 0x80; 205 | $n >>= 8 - $bits_n; 206 | $str .= chr($n); 207 | $num = $this->bin2int($str); 208 | 209 | // search for the next closest prime number after [$num] 210 | if (!gmp_cmp(gmp_mod($num, '2'), '0')) { 211 | $num = gmp_add($num, '1'); 212 | } 213 | while (!gmp_prob_prime($num)) { 214 | $num = gmp_add($num, '2'); 215 | } 216 | } while ($this->bitLen($num) != $bits_cnt); 217 | return $num; 218 | } 219 | 220 | /** 221 | * Calculates $num - 1 222 | * 223 | * @param gmp resource $num 224 | * @return gmp resource 225 | * @access public 226 | */ 227 | function dec($num) 228 | { 229 | return gmp_sub($num, 1); 230 | } 231 | 232 | /** 233 | * Returns true, if $num is equal to one. Else returns false 234 | * 235 | * @param gmp resource $num 236 | * @return bool 237 | * @access public 238 | */ 239 | function isOne($num) 240 | { 241 | return !gmp_cmp($num, 1); 242 | } 243 | 244 | /** 245 | * Finds greatest common divider (GCD) of $num1 and $num2 246 | * 247 | * @param gmp resource $num1 248 | * @param gmp resource $num2 249 | * @return gmp resource 250 | * @access public 251 | */ 252 | function GCD($num1, $num2) 253 | { 254 | return gmp_gcd($num1, $num2); 255 | } 256 | 257 | /** 258 | * Finds inverse number $inv for $num by modulus $mod, such as: 259 | * $inv * $num = 1 (mod $mod) 260 | * 261 | * @param gmp resource $num 262 | * @param gmp resource $mod 263 | * @return gmp resource 264 | * @access public 265 | */ 266 | function invmod($num, $mod) 267 | { 268 | return gmp_invert($num, $mod); 269 | } 270 | 271 | /** 272 | * Returns bit length of number $num 273 | * 274 | * @param gmp resource $num 275 | * @return int 276 | * @access public 277 | */ 278 | function bitLen($num) 279 | { 280 | $tmp = $this->int2bin($num); 281 | $bit_len = strlen($tmp) * 8; 282 | $tmp = ord($tmp{strlen($tmp) - 1}); 283 | if (!$tmp) { 284 | $bit_len -= 8; 285 | } 286 | else { 287 | while (!($tmp & 0x80)) { 288 | $bit_len--; 289 | $tmp <<= 1; 290 | } 291 | } 292 | return $bit_len; 293 | } 294 | 295 | /** 296 | * Calculates bitwise or of $num1 and $num2, 297 | * starting from bit $start_pos for number $num1 298 | * 299 | * @param gmp resource $num1 300 | * @param gmp resource $num2 301 | * @param int $start_pos 302 | * @return gmp resource 303 | * @access public 304 | */ 305 | function bitOr($num1, $num2, $start_pos) 306 | { 307 | $start_byte = intval($start_pos / 8); 308 | $start_bit = $start_pos % 8; 309 | $tmp1 = $this->int2bin($num1); 310 | 311 | $num2 = gmp_mul($num2, 1 << $start_bit); 312 | $tmp2 = $this->int2bin($num2); 313 | if ($start_byte < strlen($tmp1)) { 314 | $tmp2 |= substr($tmp1, $start_byte); 315 | $tmp1 = substr($tmp1, 0, $start_byte) . $tmp2; 316 | } 317 | else { 318 | $tmp1 = str_pad($tmp1, $start_byte, "\0") . $tmp2; 319 | } 320 | return $this->bin2int($tmp1); 321 | } 322 | 323 | /** 324 | * Returns part of number $num, starting at bit 325 | * position $start with length $length 326 | * 327 | * @param gmp resource $num 328 | * @param int start 329 | * @param int length 330 | * @return gmp resource 331 | * @access public 332 | */ 333 | function subint($num, $start, $length) 334 | { 335 | $start_byte = intval($start / 8); 336 | $start_bit = $start % 8; 337 | $byte_length = intval($length / 8); 338 | $bit_length = $length % 8; 339 | if ($bit_length) { 340 | $byte_length++; 341 | } 342 | $num = gmp_div($num, 1 << $start_bit); 343 | $tmp = substr($this->int2bin($num), $start_byte, $byte_length); 344 | $tmp = str_pad($tmp, $byte_length, "\0"); 345 | $tmp = substr_replace($tmp, $tmp{$byte_length - 1} & chr(0xff >> (8 - $bit_length)), $byte_length - 1, 1); 346 | return $this->bin2int($tmp); 347 | } 348 | 349 | /** 350 | * Returns name of current wrapper 351 | * 352 | * @return string name of current wrapper 353 | * @access public 354 | */ 355 | function getWrapperName() 356 | { 357 | return 'GMP'; 358 | } 359 | } 360 | 361 | ?> -------------------------------------------------------------------------------- /src/phpseclib/Net/SCP.php: -------------------------------------------------------------------------------- 1 | 12 | * login('username', 'password')) { 18 | * exit('bad login'); 19 | * } 20 | * 21 | * $scp = new Net_SCP($ssh); 22 | * $scp->put('abcd', str_repeat('x', 1024*1024)); 23 | * ?> 24 | * 25 | * 26 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy 27 | * of this software and associated documentation files (the "Software"), to deal 28 | * in the Software without restriction, including without limitation the rights 29 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 30 | * copies of the Software, and to permit persons to whom the Software is 31 | * furnished to do so, subject to the following conditions: 32 | * 33 | * The above copyright notice and this permission notice shall be included in 34 | * all copies or substantial portions of the Software. 35 | * 36 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 40 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 41 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 42 | * THE SOFTWARE. 43 | * 44 | * @category Net 45 | * @package Net_SCP 46 | * @author Jim Wigginton 47 | * @copyright 2010 Jim Wigginton 48 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 49 | * @link http://phpseclib.sourceforge.net 50 | */ 51 | 52 | /**#@+ 53 | * @access public 54 | * @see Net_SCP::put() 55 | */ 56 | /** 57 | * Reads data from a local file. 58 | */ 59 | define('NET_SCP_LOCAL_FILE', 1); 60 | /** 61 | * Reads data from a string. 62 | */ 63 | define('NET_SCP_STRING', 2); 64 | /**#@-*/ 65 | 66 | /**#@+ 67 | * @access private 68 | * @see Net_SCP::_send() 69 | * @see Net_SCP::_receive() 70 | */ 71 | /** 72 | * SSH1 is being used. 73 | */ 74 | define('NET_SCP_SSH1', 1); 75 | /** 76 | * SSH2 is being used. 77 | */ 78 | define('NET_SCP_SSH2', 2); 79 | /**#@-*/ 80 | 81 | /** 82 | * Pure-PHP implementations of SCP. 83 | * 84 | * @package Net_SCP 85 | * @author Jim Wigginton 86 | * @access public 87 | */ 88 | class Net_SCP 89 | { 90 | /** 91 | * SSH Object 92 | * 93 | * @var Object 94 | * @access private 95 | */ 96 | var $ssh; 97 | 98 | /** 99 | * Packet Size 100 | * 101 | * @var Integer 102 | * @access private 103 | */ 104 | var $packet_size; 105 | 106 | /** 107 | * Mode 108 | * 109 | * @var Integer 110 | * @access private 111 | */ 112 | var $mode; 113 | 114 | /** 115 | * Default Constructor. 116 | * 117 | * Connects to an SSH server 118 | * 119 | * @param String $host 120 | * @param optional Integer $port 121 | * @param optional Integer $timeout 122 | * @return Net_SCP 123 | * @access public 124 | */ 125 | function Net_SCP($ssh) 126 | { 127 | if (!is_object($ssh)) { 128 | return; 129 | } 130 | 131 | switch (strtolower(get_class($ssh))) { 132 | case 'net_ssh2': 133 | $this->mode = NET_SCP_SSH2; 134 | break; 135 | case 'net_ssh1': 136 | $this->packet_size = 50000; 137 | $this->mode = NET_SCP_SSH1; 138 | break; 139 | default: 140 | return; 141 | } 142 | 143 | $this->ssh = $ssh; 144 | } 145 | 146 | /** 147 | * Uploads a file to the SCP server. 148 | * 149 | * By default, Net_SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. 150 | * So, for example, if you set $data to 'filename.ext' and then do Net_SCP::get(), you will get a file, twelve bytes 151 | * long, containing 'filename.ext' as its contents. 152 | * 153 | * Setting $mode to NET_SCP_LOCAL_FILE will change the above behavior. With NET_SCP_LOCAL_FILE, $remote_file will 154 | * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how 155 | * large $remote_file will be, as well. 156 | * 157 | * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take 158 | * care of that, yourself. 159 | * 160 | * @param String $remote_file 161 | * @param String $data 162 | * @param optional Integer $mode 163 | * @param optional Callable $callback 164 | * @return Boolean 165 | * @access public 166 | */ 167 | function put($remote_file, $data, $mode = NET_SCP_STRING, $callback = null) 168 | { 169 | if (!isset($this->ssh)) { 170 | return false; 171 | } 172 | 173 | if (!$this->ssh->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to 174 | return false; 175 | } 176 | 177 | $temp = $this->_receive(); 178 | if ($temp !== chr(0)) { 179 | return false; 180 | } 181 | 182 | if ($this->mode == NET_SCP_SSH2) { 183 | $this->packet_size = $this->ssh->packet_size_client_to_server[NET_SSH2_CHANNEL_EXEC] - 4; 184 | } 185 | 186 | $remote_file = basename($remote_file); 187 | 188 | if ($mode == NET_SCP_STRING) { 189 | $size = strlen($data); 190 | } else { 191 | if (!is_file($data)) { 192 | user_error("$data is not a valid file", E_USER_NOTICE); 193 | return false; 194 | } 195 | 196 | $fp = @fopen($data, 'rb'); 197 | if (!$fp) { 198 | return false; 199 | } 200 | $size = filesize($data); 201 | } 202 | 203 | $this->_send('C0644 ' . $size . ' ' . $remote_file . "\n"); 204 | 205 | $temp = $this->_receive(); 206 | if ($temp !== chr(0)) { 207 | return false; 208 | } 209 | 210 | $sent = 0; 211 | while ($sent < $size) { 212 | $temp = $mode & NET_SCP_STRING ? substr($data, $sent, $this->packet_size) : fread($fp, $this->packet_size); 213 | $this->_send($temp); 214 | $sent+= strlen($temp); 215 | 216 | if (is_callable($callback)) { 217 | call_user_func($callback, $sent); 218 | } 219 | } 220 | $this->_close(); 221 | 222 | if ($mode != NET_SCP_STRING) { 223 | fclose($fp); 224 | } 225 | 226 | return true; 227 | } 228 | 229 | /** 230 | * Downloads a file from the SCP server. 231 | * 232 | * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if 233 | * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the 234 | * operation 235 | * 236 | * @param String $remote_file 237 | * @param optional String $local_file 238 | * @return Mixed 239 | * @access public 240 | */ 241 | function get($remote_file, $local_file = false) 242 | { 243 | if (!isset($this->ssh)) { 244 | return false; 245 | } 246 | 247 | if (!$this->ssh->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from 248 | return false; 249 | } 250 | 251 | $this->_send("\0"); 252 | 253 | if (!preg_match('#(?[^ ]+) (?\d+) (?.+)#', rtrim($this->_receive()), $info)) { 254 | return false; 255 | } 256 | 257 | $this->_send("\0"); 258 | 259 | $size = 0; 260 | 261 | if ($local_file !== false) { 262 | $fp = @fopen($local_file, 'wb'); 263 | if (!$fp) { 264 | return false; 265 | } 266 | } 267 | 268 | $content = ''; 269 | while ($size < $info['size']) { 270 | $data = $this->_receive(); 271 | // SCP usually seems to split stuff out into 16k chunks 272 | $size+= strlen($data); 273 | 274 | if ($local_file === false) { 275 | $content.= $data; 276 | } else { 277 | fputs($fp, $data); 278 | } 279 | } 280 | 281 | $this->_close(); 282 | 283 | if ($local_file !== false) { 284 | fclose($fp); 285 | return true; 286 | } 287 | 288 | return $content; 289 | } 290 | 291 | /** 292 | * Sends a packet to an SSH server 293 | * 294 | * @param String $data 295 | * @access private 296 | */ 297 | function _send($data) 298 | { 299 | switch ($this->mode) { 300 | case NET_SCP_SSH2: 301 | $this->ssh->_send_channel_packet(NET_SSH2_CHANNEL_EXEC, $data); 302 | break; 303 | case NET_SCP_SSH1: 304 | $data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($data), $data); 305 | $this->ssh->_send_binary_packet($data); 306 | } 307 | } 308 | 309 | /** 310 | * Receives a packet from an SSH server 311 | * 312 | * @return String 313 | * @access private 314 | */ 315 | function _receive() 316 | { 317 | switch ($this->mode) { 318 | case NET_SCP_SSH2: 319 | return $this->ssh->_get_channel_packet(NET_SSH2_CHANNEL_EXEC, true); 320 | case NET_SCP_SSH1: 321 | if (!$this->ssh->bitmap) { 322 | return false; 323 | } 324 | while (true) { 325 | $response = $this->ssh->_get_binary_packet(); 326 | switch ($response[NET_SSH1_RESPONSE_TYPE]) { 327 | case NET_SSH1_SMSG_STDOUT_DATA: 328 | extract(unpack('Nlength', $response[NET_SSH1_RESPONSE_DATA])); 329 | return $this->ssh->_string_shift($response[NET_SSH1_RESPONSE_DATA], $length); 330 | case NET_SSH1_SMSG_STDERR_DATA: 331 | break; 332 | case NET_SSH1_SMSG_EXITSTATUS: 333 | $this->ssh->_send_binary_packet(chr(NET_SSH1_CMSG_EXIT_CONFIRMATION)); 334 | fclose($this->ssh->fsock); 335 | $this->ssh->bitmap = 0; 336 | return false; 337 | default: 338 | user_error('Unknown packet received', E_USER_NOTICE); 339 | return false; 340 | } 341 | } 342 | } 343 | } 344 | 345 | /** 346 | * Closes the connection to an SSH server 347 | * 348 | * @access private 349 | */ 350 | function _close() 351 | { 352 | switch ($this->mode) { 353 | case NET_SCP_SSH2: 354 | $this->ssh->_close_channel(NET_SSH2_CHANNEL_EXEC, true); 355 | break; 356 | case NET_SCP_SSH1: 357 | $this->ssh->disconnect(); 358 | } 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /src/phpseclib/Net/SFTP/Stream.php: -------------------------------------------------------------------------------- 1 | 31 | * @copyright 2013 Jim Wigginton 32 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 33 | * @link http://phpseclib.sourceforge.net 34 | */ 35 | 36 | /** 37 | * SFTP Stream Wrapper 38 | * 39 | * @package Net_SFTP_Stream 40 | * @author Jim Wigginton 41 | * @access public 42 | */ 43 | class Net_SFTP_Stream 44 | { 45 | /** 46 | * SFTP instances 47 | * 48 | * Rather than re-create the connection we re-use instances if possible 49 | * 50 | * @var Array 51 | */ 52 | static $instances; 53 | 54 | /** 55 | * SFTP instance 56 | * 57 | * @var Object 58 | * @access private 59 | */ 60 | var $sftp; 61 | 62 | /** 63 | * Path 64 | * 65 | * @var String 66 | * @access private 67 | */ 68 | var $path; 69 | 70 | /** 71 | * Mode 72 | * 73 | * @var String 74 | * @access private 75 | */ 76 | var $mode; 77 | 78 | /** 79 | * Position 80 | * 81 | * @var Integer 82 | * @access private 83 | */ 84 | var $pos; 85 | 86 | /** 87 | * Size 88 | * 89 | * @var Integer 90 | * @access private 91 | */ 92 | var $size; 93 | 94 | /** 95 | * Directory entries 96 | * 97 | * @var Array 98 | * @access private 99 | */ 100 | var $entries; 101 | 102 | /** 103 | * EOF flag 104 | * 105 | * @var Boolean 106 | * @access private 107 | */ 108 | var $eof; 109 | 110 | /** 111 | * Context resource 112 | * 113 | * Technically this needs to be publically accessible so PHP can set it directly 114 | * 115 | * @var Resource 116 | * @access public 117 | */ 118 | var $context; 119 | 120 | /** 121 | * Notification callback function 122 | * 123 | * @var Callable 124 | * @access public 125 | */ 126 | var $notification; 127 | 128 | /** 129 | * Registers this class as a URL wrapper. 130 | * 131 | * @param optional String $protocol The wrapper name to be registered. 132 | * @return Boolean True on success, false otherwise. 133 | * @access public 134 | */ 135 | static function register($protocol = 'sftp') 136 | { 137 | if (in_array($protocol, stream_get_wrappers(), true)) { 138 | return false; 139 | } 140 | $class = function_exists('get_called_class') ? get_called_class() : __CLASS__; 141 | return stream_wrapper_register($protocol, $class); 142 | } 143 | 144 | /** 145 | * The Constructor 146 | * 147 | * @access public 148 | */ 149 | function Net_SFTP_Stream() 150 | { 151 | if (defined('NET_SFTP_STREAM_LOGGING')) { 152 | echo "__construct()\r\n"; 153 | } 154 | 155 | if (!class_exists('Net_SFTP')) { 156 | include_once 'Net/SFTP.php'; 157 | } 158 | } 159 | 160 | /** 161 | * Path Parser 162 | * 163 | * Extract a path from a URI and actually connect to an SSH server if appropriate 164 | * 165 | * If "notification" is set as a context parameter the message code for successful login is 166 | * NET_SSH2_MSG_USERAUTH_SUCCESS. For a failed login it's NET_SSH2_MSG_USERAUTH_FAILURE. 167 | * 168 | * @param String $path 169 | * @return String 170 | * @access private 171 | */ 172 | function _parse_path($path) 173 | { 174 | extract(parse_url($path) + array('port' => 22)); 175 | 176 | if (!isset($host)) { 177 | return false; 178 | } 179 | 180 | if (isset($this->context)) { 181 | $context = stream_context_get_params($this->context); 182 | if (isset($context['notification'])) { 183 | $this->notification = $context['notification']; 184 | } 185 | } 186 | 187 | if ($host[0] == '$') { 188 | $host = substr($host, 1); 189 | global $$host; 190 | if (!is_object($$host) || get_class($$host) != 'Net_SFTP') { 191 | return false; 192 | } 193 | $this->sftp = $$host; 194 | } else { 195 | if (isset($this->context)) { 196 | $context = stream_context_get_options($this->context); 197 | } 198 | if (isset($context[$scheme]['session'])) { 199 | $sftp = $context[$scheme]['session']; 200 | } 201 | if (isset($context[$scheme]['sftp'])) { 202 | $sftp = $context[$scheme]['sftp']; 203 | } 204 | if (isset($sftp) && is_object($sftp) && get_class($sftp) == 'Net_SFTP') { 205 | $this->sftp = $sftp; 206 | return $path; 207 | } 208 | if (isset($context[$scheme]['username'])) { 209 | $user = $context[$scheme]['username']; 210 | } 211 | if (isset($context[$scheme]['password'])) { 212 | $pass = $context[$scheme]['password']; 213 | } 214 | if (isset($context[$scheme]['privkey']) && is_object($context[$scheme]['privkey']) && get_Class($context[$scheme]['privkey']) == 'Crypt_RSA') { 215 | $pass = $context[$scheme]['privkey']; 216 | } 217 | 218 | if (!isset($user) || !isset($pass)) { 219 | return false; 220 | } 221 | 222 | // casting $pass to a string is necessary in the event that it's a Crypt_RSA object 223 | if (isset(self::$instances[$host][$port][$user][(string) $pass])) { 224 | $this->sftp = self::$instances[$host][$port][$user][(string) $pass]; 225 | } else { 226 | $this->sftp = new Net_SFTP($host, $port); 227 | $this->sftp->disableStatCache(); 228 | if (isset($this->notification) && is_callable($this->notification)) { 229 | /* if !is_callable($this->notification) we could do this: 230 | 231 | user_error('fopen(): failed to call user notifier', E_USER_WARNING); 232 | 233 | the ftp wrapper gives errors like that when the notifier isn't callable. 234 | i've opted not to do that, however, since the ftp wrapper gives the line 235 | on which the fopen occurred as the line number - not the line that the 236 | user_error is on. 237 | */ 238 | call_user_func($this->notification, STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); 239 | call_user_func($this->notification, STREAM_NOTIFY_AUTH_REQUIRED, STREAM_NOTIFY_SEVERITY_INFO, '', 0, 0, 0); 240 | if (!$this->sftp->login($user, $pass)) { 241 | call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_ERR, 'Login Failure', NET_SSH2_MSG_USERAUTH_FAILURE, 0, 0); 242 | return false; 243 | } 244 | call_user_func($this->notification, STREAM_NOTIFY_AUTH_RESULT, STREAM_NOTIFY_SEVERITY_INFO, 'Login Success', NET_SSH2_MSG_USERAUTH_SUCCESS, 0, 0); 245 | } else { 246 | if (!$this->sftp->login($user, $pass)) { 247 | return false; 248 | } 249 | } 250 | self::$instances[$host][$port][$user][(string) $pass] = $this->sftp; 251 | } 252 | } 253 | 254 | return $path; 255 | } 256 | 257 | /** 258 | * Opens file or URL 259 | * 260 | * @param String $path 261 | * @param String $mode 262 | * @param Integer $options 263 | * @param String $opened_path 264 | * @return Boolean 265 | * @access public 266 | */ 267 | function _stream_open($path, $mode, $options, &$opened_path) 268 | { 269 | $path = $this->_parse_path($path); 270 | 271 | if ($path === false) { 272 | return false; 273 | } 274 | $this->path = $path; 275 | 276 | $this->size = $this->sftp->size($path); 277 | $this->mode = preg_replace('#[bt]$#', '', $mode); 278 | $this->eof = false; 279 | 280 | if ($this->size === false) { 281 | if ($this->mode[0] == 'r') { 282 | return false; 283 | } 284 | } else { 285 | switch ($this->mode[0]) { 286 | case 'x': 287 | return false; 288 | case 'w': 289 | case 'c': 290 | $this->sftp->truncate($path, 0); 291 | } 292 | } 293 | 294 | $this->pos = $this->mode[0] != 'a' ? 0 : $this->size; 295 | 296 | return true; 297 | } 298 | 299 | /** 300 | * Read from stream 301 | * 302 | * @param Integer $count 303 | * @return Mixed 304 | * @access public 305 | */ 306 | function _stream_read($count) 307 | { 308 | switch ($this->mode) { 309 | case 'w': 310 | case 'a': 311 | case 'x': 312 | case 'c': 313 | return false; 314 | } 315 | 316 | // commented out because some files - eg. /dev/urandom - will say their size is 0 when in fact it's kinda infinite 317 | //if ($this->pos >= $this->size) { 318 | // $this->eof = true; 319 | // return false; 320 | //} 321 | 322 | $result = $this->sftp->get($this->path, false, $this->pos, $count); 323 | if (isset($this->notification) && is_callable($this->notification)) { 324 | if ($result === false) { 325 | call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); 326 | return 0; 327 | } 328 | // seems that PHP calls stream_read in 8k chunks 329 | call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($result), $this->size); 330 | } 331 | 332 | if (empty($result)) { // ie. false or empty string 333 | $this->eof = true; 334 | return false; 335 | } 336 | $this->pos+= strlen($result); 337 | 338 | return $result; 339 | } 340 | 341 | /** 342 | * Write to stream 343 | * 344 | * @param String $data 345 | * @return Mixed 346 | * @access public 347 | */ 348 | function _stream_write($data) 349 | { 350 | switch ($this->mode) { 351 | case 'r': 352 | return false; 353 | } 354 | 355 | $result = $this->sftp->put($this->path, $data, NET_SFTP_STRING, $this->pos); 356 | if (isset($this->notification) && is_callable($this->notification)) { 357 | if (!$result) { 358 | call_user_func($this->notification, STREAM_NOTIFY_FAILURE, STREAM_NOTIFY_SEVERITY_ERR, $this->sftp->getLastSFTPError(), NET_SFTP_OPEN, 0, 0); 359 | return 0; 360 | } 361 | // seems that PHP splits up strings into 8k blocks before calling stream_write 362 | call_user_func($this->notification, STREAM_NOTIFY_PROGRESS, STREAM_NOTIFY_SEVERITY_INFO, '', 0, strlen($data), strlen($data)); 363 | } 364 | 365 | if ($result === false) { 366 | return false; 367 | } 368 | $this->pos+= strlen($data); 369 | if ($this->pos > $this->size) { 370 | $this->size = $this->pos; 371 | } 372 | $this->eof = false; 373 | return strlen($data); 374 | } 375 | 376 | /** 377 | * Retrieve the current position of a stream 378 | * 379 | * @return Integer 380 | * @access public 381 | */ 382 | function _stream_tell() 383 | { 384 | return $this->pos; 385 | } 386 | 387 | /** 388 | * Tests for end-of-file on a file pointer 389 | * 390 | * In my testing there are four classes functions that normally effect the pointer: 391 | * fseek, fputs / fwrite, fgets / fread and ftruncate. 392 | * 393 | * Only fgets / fread, however, results in feof() returning true. do fputs($fp, 'aaa') on a blank file and feof() 394 | * will return false. do fread($fp, 1) and feof() will then return true. do fseek($fp, 10) on ablank file and feof() 395 | * will return false. do fread($fp, 1) and feof() will then return true. 396 | * 397 | * @return Boolean 398 | * @access public 399 | */ 400 | function _stream_eof() 401 | { 402 | return $this->eof; 403 | } 404 | 405 | /** 406 | * Seeks to specific location in a stream 407 | * 408 | * @param Integer $offset 409 | * @param Integer $whence 410 | * @return Boolean 411 | * @access public 412 | */ 413 | function _stream_seek($offset, $whence) 414 | { 415 | switch ($whence) { 416 | case SEEK_SET: 417 | if ($offset >= $this->size || $offset < 0) { 418 | return false; 419 | } 420 | break; 421 | case SEEK_CUR: 422 | $offset+= $this->pos; 423 | break; 424 | case SEEK_END: 425 | $offset+= $this->size; 426 | } 427 | 428 | $this->pos = $offset; 429 | $this->eof = false; 430 | return true; 431 | } 432 | 433 | /** 434 | * Change stream options 435 | * 436 | * @param String $path 437 | * @param Integer $option 438 | * @param Mixed $var 439 | * @return Boolean 440 | * @access public 441 | */ 442 | function _stream_metadata($path, $option, $var) 443 | { 444 | $path = $this->_parse_path($path); 445 | if ($path === false) { 446 | return false; 447 | } 448 | 449 | // stream_metadata was introduced in PHP 5.4.0 but as of 5.4.11 the constants haven't been defined 450 | // see http://www.php.net/streamwrapper.stream-metadata and https://bugs.php.net/64246 451 | // and https://github.com/php/php-src/blob/master/main/php_streams.h#L592 452 | switch ($option) { 453 | case 1: // PHP_STREAM_META_TOUCH 454 | return $this->sftp->touch($path, $var[0], $var[1]); 455 | case 2: // PHP_STREAM_OWNER_NAME 456 | case 3: // PHP_STREAM_GROUP_NAME 457 | return false; 458 | case 4: // PHP_STREAM_META_OWNER 459 | return $this->sftp->chown($path, $var); 460 | case 5: // PHP_STREAM_META_GROUP 461 | return $this->sftp->chgrp($path, $var); 462 | case 6: // PHP_STREAM_META_ACCESS 463 | return $this->sftp->chmod($path, $var) !== false; 464 | } 465 | } 466 | 467 | /** 468 | * Retrieve the underlaying resource 469 | * 470 | * @param Integer $cast_as 471 | * @return Resource 472 | * @access public 473 | */ 474 | function _stream_cast($cast_as) 475 | { 476 | return $this->sftp->fsock; 477 | } 478 | 479 | /** 480 | * Advisory file locking 481 | * 482 | * @param Integer $operation 483 | * @return Boolean 484 | * @access public 485 | */ 486 | function _stream_lock($operation) 487 | { 488 | return false; 489 | } 490 | 491 | /** 492 | * Renames a file or directory 493 | * 494 | * Attempts to rename oldname to newname, moving it between directories if necessary. 495 | * If newname exists, it will be overwritten. This is a departure from what Net_SFTP 496 | * does. 497 | * 498 | * @param String $path_from 499 | * @param String $path_to 500 | * @return Boolean 501 | * @access public 502 | */ 503 | function _rename($path_from, $path_to) 504 | { 505 | $path1 = parse_url($path_from); 506 | $path2 = parse_url($path_to); 507 | unset($path1['path'], $path2['path']); 508 | if ($path1 != $path2) { 509 | return false; 510 | } 511 | 512 | $path_from = $this->_parse_path($path_from); 513 | $path_to = parse_url($path_to); 514 | if ($path_from === false) { 515 | return false; 516 | } 517 | 518 | $path_to = $path_to['path']; // the $component part of parse_url() was added in PHP 5.1.2 519 | // "It is an error if there already exists a file with the name specified by newpath." 520 | // -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-6.5 521 | if (!$this->sftp->rename($path_from, $path_to)) { 522 | if ($this->sftp->stat($path_to)) { 523 | return $this->sftp->delete($path_to, true) && $this->sftp->rename($path_from, $path_to); 524 | } 525 | return false; 526 | } 527 | 528 | return true; 529 | } 530 | 531 | /** 532 | * Open directory handle 533 | * 534 | * The only $options is "whether or not to enforce safe_mode (0x04)". Since safe mode was deprecated in 5.3 and 535 | * removed in 5.4 I'm just going to ignore it. 536 | * 537 | * Also, nlist() is the best that this function is realistically going to be able to do. When an SFTP client 538 | * sends a SSH_FXP_READDIR packet you don't generally get info on just one file but on multiple files. Quoting 539 | * the SFTP specs: 540 | * 541 | * The SSH_FXP_NAME response has the following format: 542 | * 543 | * uint32 id 544 | * uint32 count 545 | * repeats count times: 546 | * string filename 547 | * string longname 548 | * ATTRS attrs 549 | * 550 | * @param String $path 551 | * @param Integer $options 552 | * @return Boolean 553 | * @access public 554 | */ 555 | function _dir_opendir($path, $options) 556 | { 557 | $path = $this->_parse_path($path); 558 | if ($path === false) { 559 | return false; 560 | } 561 | $this->pos = 0; 562 | $this->entries = $this->sftp->nlist($path); 563 | return $this->entries !== false; 564 | } 565 | 566 | /** 567 | * Read entry from directory handle 568 | * 569 | * @return Mixed 570 | * @access public 571 | */ 572 | function _dir_readdir() 573 | { 574 | if (isset($this->entries[$this->pos])) { 575 | return $this->entries[$this->pos++]; 576 | } 577 | return false; 578 | } 579 | 580 | /** 581 | * Rewind directory handle 582 | * 583 | * @return Boolean 584 | * @access public 585 | */ 586 | function _dir_rewinddir() 587 | { 588 | $this->pos = 0; 589 | return true; 590 | } 591 | 592 | /** 593 | * Close directory handle 594 | * 595 | * @return Boolean 596 | * @access public 597 | */ 598 | function _dir_closedir() 599 | { 600 | return true; 601 | } 602 | 603 | /** 604 | * Create a directory 605 | * 606 | * Only valid $options is STREAM_MKDIR_RECURSIVE 607 | * 608 | * @param String $path 609 | * @param Integer $mode 610 | * @param Integer $options 611 | * @return Boolean 612 | * @access public 613 | */ 614 | function _mkdir($path, $mode, $options) 615 | { 616 | $path = $this->_parse_path($path); 617 | if ($path === false) { 618 | return false; 619 | } 620 | 621 | return $this->sftp->mkdir($path, $mode, $options & STREAM_MKDIR_RECURSIVE); 622 | } 623 | 624 | /** 625 | * Removes a directory 626 | * 627 | * Only valid $options is STREAM_MKDIR_RECURSIVE per , however, 628 | * does not have a $recursive parameter as mkdir() does so I don't know how 629 | * STREAM_MKDIR_RECURSIVE is supposed to be set. Also, when I try it out with rmdir() I get 8 as 630 | * $options. What does 8 correspond to? 631 | * 632 | * @param String $path 633 | * @param Integer $mode 634 | * @param Integer $options 635 | * @return Boolean 636 | * @access public 637 | */ 638 | function _rmdir($path, $options) 639 | { 640 | $path = $this->_parse_path($path); 641 | if ($path === false) { 642 | return false; 643 | } 644 | 645 | return $this->sftp->rmdir($path); 646 | } 647 | 648 | /** 649 | * Flushes the output 650 | * 651 | * See . Always returns true because Net_SFTP doesn't cache stuff before writing 652 | * 653 | * @return Boolean 654 | * @access public 655 | */ 656 | function _stream_flush() 657 | { 658 | return true; 659 | } 660 | 661 | /** 662 | * Retrieve information about a file resource 663 | * 664 | * @return Mixed 665 | * @access public 666 | */ 667 | function _stream_stat() 668 | { 669 | $results = $this->sftp->stat($this->path); 670 | if ($results === false) { 671 | return false; 672 | } 673 | return $results; 674 | } 675 | 676 | /** 677 | * Delete a file 678 | * 679 | * @param String $path 680 | * @return Boolean 681 | * @access public 682 | */ 683 | function _unlink($path) 684 | { 685 | $path = $this->_parse_path($path); 686 | if ($path === false) { 687 | return false; 688 | } 689 | 690 | return $this->sftp->delete($path, false); 691 | } 692 | 693 | /** 694 | * Retrieve information about a file 695 | * 696 | * Ignores the STREAM_URL_STAT_QUIET flag because the entirety of Net_SFTP_Stream is quiet by default 697 | * might be worthwhile to reconstruct bits 12-16 (ie. the file type) if mode doesn't have them but we'll 698 | * cross that bridge when and if it's reached 699 | * 700 | * @param String $path 701 | * @param Integer $flags 702 | * @return Mixed 703 | * @access public 704 | */ 705 | function _url_stat($path, $flags) 706 | { 707 | $path = $this->_parse_path($path); 708 | if ($path === false) { 709 | return false; 710 | } 711 | 712 | $results = $flags & STREAM_URL_STAT_LINK ? $this->sftp->lstat($path) : $this->sftp->stat($path); 713 | if ($results === false) { 714 | return false; 715 | } 716 | 717 | return $results; 718 | } 719 | 720 | /** 721 | * Truncate stream 722 | * 723 | * @param Integer $new_size 724 | * @return Boolean 725 | * @access public 726 | */ 727 | function _stream_truncate($new_size) 728 | { 729 | if (!$this->sftp->truncate($this->path, $new_size)) { 730 | return false; 731 | } 732 | 733 | $this->eof = false; 734 | $this->size = $new_size; 735 | 736 | return true; 737 | } 738 | 739 | /** 740 | * Change stream options 741 | * 742 | * STREAM_OPTION_WRITE_BUFFER isn't supported for the same reason stream_flush isn't. 743 | * The other two aren't supported because of limitations in Net_SFTP. 744 | * 745 | * @param Integer $option 746 | * @param Integer $arg1 747 | * @param Integer $arg2 748 | * @return Boolean 749 | * @access public 750 | */ 751 | function _stream_set_option($option, $arg1, $arg2) 752 | { 753 | return false; 754 | } 755 | 756 | /** 757 | * Close an resource 758 | * 759 | * @access public 760 | */ 761 | function _stream_close() 762 | { 763 | } 764 | 765 | /** 766 | * __call Magic Method 767 | * 768 | * When you're utilizing an SFTP stream you're not calling the methods in this class directly - PHP is calling them for you. 769 | * Which kinda begs the question... what methods is PHP calling and what parameters is it passing to them? This function 770 | * lets you figure that out. 771 | * 772 | * If NET_SFTP_STREAM_LOGGING is defined all calls will be output on the screen and then (regardless of whether or not 773 | * NET_SFTP_STREAM_LOGGING is enabled) the parameters will be passed through to the appropriate method. 774 | * 775 | * @param String 776 | * @param Array 777 | * @return Mixed 778 | * @access public 779 | */ 780 | function __call($name, $arguments) 781 | { 782 | if (defined('NET_SFTP_STREAM_LOGGING')) { 783 | echo $name . '('; 784 | $last = count($arguments) - 1; 785 | foreach ($arguments as $i => $argument) { 786 | var_export($argument); 787 | if ($i != $last) { 788 | echo ','; 789 | } 790 | } 791 | echo ")\r\n"; 792 | } 793 | $name = '_' . $name; 794 | if (!method_exists($this, $name)) { 795 | return false; 796 | } 797 | return call_user_func_array(array($this, $name), $arguments); 798 | } 799 | } 800 | 801 | Net_SFTP_Stream::register(); 802 | -------------------------------------------------------------------------------- /src/phpseclib/System/SSH/Agent.php: -------------------------------------------------------------------------------- 1 | 10 | * login('username', $agent)) { 18 | * exit('Login Failed'); 19 | * } 20 | * 21 | * echo $ssh->exec('pwd'); 22 | * echo $ssh->exec('ls -la'); 23 | * ?> 24 | * 25 | * 26 | * LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy 27 | * of this software and associated documentation files (the "Software"), to deal 28 | * in the Software without restriction, including without limitation the rights 29 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 30 | * copies of the Software, and to permit persons to whom the Software is 31 | * furnished to do so, subject to the following conditions: 32 | * 33 | * The above copyright notice and this permission notice shall be included in 34 | * all copies or substantial portions of the Software. 35 | * 36 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 37 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 38 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 39 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 40 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 41 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 42 | * THE SOFTWARE. 43 | * 44 | * @category System 45 | * @package System_SSH_Agent 46 | * @author Jim Wigginton 47 | * @copyright 2014 Jim Wigginton 48 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 49 | * @link http://phpseclib.sourceforge.net 50 | * @internal See http://api.libssh.org/rfc/PROTOCOL.agent 51 | */ 52 | 53 | /**#@+ 54 | * Message numbers 55 | * 56 | * @access private 57 | */ 58 | // to request SSH1 keys you have to use SSH_AGENTC_REQUEST_RSA_IDENTITIES (1) 59 | define('SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES', 11); 60 | // this is the SSH2 response; the SSH1 response is SSH_AGENT_RSA_IDENTITIES_ANSWER (2). 61 | define('SYSTEM_SSH_AGENT_IDENTITIES_ANSWER', 12); 62 | define('SYSTEM_SSH_AGENT_FAILURE', 5); 63 | // the SSH1 request is SSH_AGENTC_RSA_CHALLENGE (3) 64 | define('SYSTEM_SSH_AGENTC_SIGN_REQUEST', 13); 65 | // the SSH1 response is SSH_AGENT_RSA_RESPONSE (4) 66 | define('SYSTEM_SSH_AGENT_SIGN_RESPONSE', 14); 67 | 68 | 69 | /**@+ 70 | * Agent forwarding status 71 | * 72 | * @access private 73 | */ 74 | // no forwarding requested and not active 75 | define('SYSTEM_SSH_AGENT_FORWARD_NONE', 0); 76 | // request agent forwarding when opportune 77 | define('SYSTEM_SSH_AGENT_FORWARD_REQUEST', 1); 78 | // forwarding has been request and is active 79 | define('SYSTEM_SSH_AGENT_FORWARD_ACTIVE', 2); 80 | 81 | /**#@-*/ 82 | 83 | /** 84 | * Pure-PHP ssh-agent client identity object 85 | * 86 | * Instantiation should only be performed by System_SSH_Agent class. 87 | * This could be thought of as implementing an interface that Crypt_RSA 88 | * implements. ie. maybe a Net_SSH_Auth_PublicKey interface or something. 89 | * The methods in this interface would be getPublicKey, setSignatureMode 90 | * and sign since those are the methods phpseclib looks for to perform 91 | * public key authentication. 92 | * 93 | * @package System_SSH_Agent 94 | * @author Jim Wigginton 95 | * @access internal 96 | */ 97 | class System_SSH_Agent_Identity 98 | { 99 | /** 100 | * Key Object 101 | * 102 | * @var Crypt_RSA 103 | * @access private 104 | * @see System_SSH_Agent_Identity::getPublicKey() 105 | */ 106 | var $key; 107 | 108 | /** 109 | * Key Blob 110 | * 111 | * @var String 112 | * @access private 113 | * @see System_SSH_Agent_Identity::sign() 114 | */ 115 | var $key_blob; 116 | 117 | /** 118 | * Socket Resource 119 | * 120 | * @var Resource 121 | * @access private 122 | * @see System_SSH_Agent_Identity::sign() 123 | */ 124 | var $fsock; 125 | 126 | /** 127 | * Default Constructor. 128 | * 129 | * @param Resource $fsock 130 | * @return System_SSH_Agent_Identity 131 | * @access private 132 | */ 133 | function System_SSH_Agent_Identity($fsock) 134 | { 135 | $this->fsock = $fsock; 136 | } 137 | 138 | /** 139 | * Set Public Key 140 | * 141 | * Called by System_SSH_Agent::requestIdentities() 142 | * 143 | * @param Crypt_RSA $key 144 | * @access private 145 | */ 146 | function setPublicKey($key) 147 | { 148 | $this->key = $key; 149 | $this->key->setPublicKey(); 150 | } 151 | 152 | /** 153 | * Set Public Key 154 | * 155 | * Called by System_SSH_Agent::requestIdentities(). The key blob could be extracted from $this->key 156 | * but this saves a small amount of computation. 157 | * 158 | * @param String $key_blob 159 | * @access private 160 | */ 161 | function setPublicKeyBlob($key_blob) 162 | { 163 | $this->key_blob = $key_blob; 164 | } 165 | 166 | /** 167 | * Get Public Key 168 | * 169 | * Wrapper for $this->key->getPublicKey() 170 | * 171 | * @param Integer $format optional 172 | * @return Mixed 173 | * @access public 174 | */ 175 | function getPublicKey($format = null) 176 | { 177 | return !isset($format) ? $this->key->getPublicKey() : $this->key->getPublicKey($format); 178 | } 179 | 180 | /** 181 | * Set Signature Mode 182 | * 183 | * Doesn't do anything as ssh-agent doesn't let you pick and choose the signature mode. ie. 184 | * ssh-agent's only supported mode is CRYPT_RSA_SIGNATURE_PKCS1 185 | * 186 | * @param Integer $mode 187 | * @access public 188 | */ 189 | function setSignatureMode($mode) 190 | { 191 | } 192 | 193 | /** 194 | * Create a signature 195 | * 196 | * See "2.6.2 Protocol 2 private key signature request" 197 | * 198 | * @param String $message 199 | * @return String 200 | * @access public 201 | */ 202 | function sign($message) 203 | { 204 | // the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE 205 | $packet = pack('CNa*Na*N', SYSTEM_SSH_AGENTC_SIGN_REQUEST, strlen($this->key_blob), $this->key_blob, strlen($message), $message, 0); 206 | $packet = pack('Na*', strlen($packet), $packet); 207 | if (strlen($packet) != fputs($this->fsock, $packet)) { 208 | user_error('Connection closed during signing'); 209 | } 210 | 211 | $length = current(unpack('N', fread($this->fsock, 4))); 212 | $type = ord(fread($this->fsock, 1)); 213 | if ($type != SYSTEM_SSH_AGENT_SIGN_RESPONSE) { 214 | user_error('Unable to retreive signature'); 215 | } 216 | 217 | $signature_blob = fread($this->fsock, $length - 1); 218 | // the only other signature format defined - ssh-dss - is the same length as ssh-rsa 219 | // the + 12 is for the other various SSH added length fields 220 | return substr($signature_blob, strlen('ssh-rsa') + 12); 221 | } 222 | } 223 | 224 | /** 225 | * Pure-PHP ssh-agent client identity factory 226 | * 227 | * requestIdentities() method pumps out System_SSH_Agent_Identity objects 228 | * 229 | * @package System_SSH_Agent 230 | * @author Jim Wigginton 231 | * @access internal 232 | */ 233 | class System_SSH_Agent 234 | { 235 | /** 236 | * Socket Resource 237 | * 238 | * @var Resource 239 | * @access private 240 | */ 241 | var $fsock; 242 | 243 | /** 244 | * Agent forwarding status 245 | * 246 | * @access private 247 | */ 248 | var $forward_status = SYSTEM_SSH_AGENT_FORWARD_NONE; 249 | 250 | /** 251 | * Buffer for accumulating forwarded authentication 252 | * agent data arriving on SSH data channel destined 253 | * for agent unix socket 254 | * 255 | * @access private 256 | */ 257 | var $socket_buffer = ''; 258 | 259 | /** 260 | * Tracking the number of bytes we are expecting 261 | * to arrive for the agent socket on the SSH data 262 | * channel 263 | */ 264 | var $expected_bytes = 0; 265 | 266 | /** 267 | * Default Constructor 268 | * 269 | * @return System_SSH_Agent 270 | * @access public 271 | */ 272 | function System_SSH_Agent() 273 | { 274 | switch (true) { 275 | case isset($_SERVER['SSH_AUTH_SOCK']): 276 | $address = $_SERVER['SSH_AUTH_SOCK']; 277 | break; 278 | case isset($_ENV['SSH_AUTH_SOCK']): 279 | $address = $_ENV['SSH_AUTH_SOCK']; 280 | break; 281 | default: 282 | user_error('SSH_AUTH_SOCK not found'); 283 | return false; 284 | } 285 | 286 | $this->fsock = fsockopen('unix://' . $address, 0, $errno, $errstr); 287 | if (!$this->fsock) { 288 | user_error("Unable to connect to ssh-agent (Error $errno: $errstr)"); 289 | } 290 | } 291 | 292 | /** 293 | * Request Identities 294 | * 295 | * See "2.5.2 Requesting a list of protocol 2 keys" 296 | * Returns an array containing zero or more System_SSH_Agent_Identity objects 297 | * 298 | * @return Array 299 | * @access public 300 | */ 301 | function requestIdentities() 302 | { 303 | if (!$this->fsock) { 304 | return array(); 305 | } 306 | 307 | $packet = pack('NC', 1, SYSTEM_SSH_AGENTC_REQUEST_IDENTITIES); 308 | if (strlen($packet) != fputs($this->fsock, $packet)) { 309 | user_error('Connection closed while requesting identities'); 310 | } 311 | 312 | $length = current(unpack('N', fread($this->fsock, 4))); 313 | $type = ord(fread($this->fsock, 1)); 314 | if ($type != SYSTEM_SSH_AGENT_IDENTITIES_ANSWER) { 315 | user_error('Unable to request identities'); 316 | } 317 | 318 | $identities = array(); 319 | $keyCount = current(unpack('N', fread($this->fsock, 4))); 320 | for ($i = 0; $i < $keyCount; $i++) { 321 | $length = current(unpack('N', fread($this->fsock, 4))); 322 | $key_blob = fread($this->fsock, $length); 323 | $length = current(unpack('N', fread($this->fsock, 4))); 324 | $key_comment = fread($this->fsock, $length); 325 | $length = current(unpack('N', substr($key_blob, 0, 4))); 326 | $key_type = substr($key_blob, 4, $length); 327 | switch ($key_type) { 328 | case 'ssh-rsa': 329 | if (!class_exists('Crypt_RSA')) { 330 | include_once 'Crypt/RSA.php'; 331 | } 332 | $key = new Crypt_RSA(); 333 | $key->loadKey('ssh-rsa ' . base64_encode($key_blob) . ' ' . $key_comment); 334 | break; 335 | case 'ssh-dss': 336 | // not currently supported 337 | break; 338 | } 339 | // resources are passed by reference by default 340 | if (isset($key)) { 341 | $identity = new System_SSH_Agent_Identity($this->fsock); 342 | $identity->setPublicKey($key); 343 | $identity->setPublicKeyBlob($key_blob); 344 | $identities[] = $identity; 345 | unset($key); 346 | } 347 | } 348 | 349 | return $identities; 350 | } 351 | 352 | /** 353 | * Signal that agent forwarding should 354 | * be requested when a channel is opened 355 | * 356 | * @param Net_SSH2 $ssh 357 | * @return Boolean 358 | * @access public 359 | */ 360 | function startSSHForwarding($ssh) 361 | { 362 | if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_NONE) { 363 | $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_REQUEST; 364 | } 365 | } 366 | 367 | /** 368 | * Request agent forwarding of remote server 369 | * 370 | * @param Net_SSH2 $ssh 371 | * @return Boolean 372 | * @access private 373 | */ 374 | function _request_forwarding($ssh) 375 | { 376 | $request_channel = $ssh->_get_open_channel(); 377 | if ($request_channel === false) { 378 | return false; 379 | } 380 | 381 | $packet = pack('CNNa*C', 382 | NET_SSH2_MSG_CHANNEL_REQUEST, $ssh->server_channels[$request_channel], strlen('auth-agent-req@openssh.com'), 'auth-agent-req@openssh.com', 1); 383 | 384 | $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_REQUEST; 385 | 386 | if (!$ssh->_send_binary_packet($packet)) { 387 | return false; 388 | } 389 | 390 | $response = $ssh->_get_channel_packet($request_channel); 391 | if ($response === false) { 392 | return false; 393 | } 394 | 395 | $ssh->channel_status[$request_channel] = NET_SSH2_MSG_CHANNEL_OPEN; 396 | $this->forward_status = SYSTEM_SSH_AGENT_FORWARD_ACTIVE; 397 | 398 | return true; 399 | } 400 | 401 | /** 402 | * On successful channel open 403 | * 404 | * This method is called upon successful channel 405 | * open to give the SSH Agent an opportunity 406 | * to take further action. i.e. request agent forwarding 407 | * 408 | * @param Net_SSH2 $ssh 409 | * @access private 410 | */ 411 | function _on_channel_open($ssh) 412 | { 413 | if ($this->forward_status == SYSTEM_SSH_AGENT_FORWARD_REQUEST) { 414 | $this->_request_forwarding($ssh); 415 | } 416 | } 417 | 418 | /** 419 | * Forward data to SSH Agent and return data reply 420 | * 421 | * @param String $data 422 | * @return data from SSH Agent 423 | * @access private 424 | */ 425 | function _forward_data($data) 426 | { 427 | if ($this->expected_bytes > 0) { 428 | $this->socket_buffer.= $data; 429 | $this->expected_bytes -= strlen($data); 430 | } else { 431 | $agent_data_bytes = current(unpack('N', $data)); 432 | $current_data_bytes = strlen($data); 433 | $this->socket_buffer = $data; 434 | if ($current_data_bytes != $agent_data_bytes + 4) { 435 | $this->expected_bytes = ($agent_data_bytes + 4) - $current_data_bytes; 436 | return false; 437 | } 438 | } 439 | 440 | if (strlen($this->socket_buffer) != fwrite($this->fsock, $this->socket_buffer)) { 441 | user_error('Connection closed attempting to forward data to SSH agent'); 442 | } 443 | 444 | $this->socket_buffer = ''; 445 | $this->expected_bytes = 0; 446 | 447 | $agent_reply_bytes = current(unpack('N', fread($this->fsock, 4))); 448 | 449 | $agent_reply_data = fread($this->fsock, $agent_reply_bytes); 450 | $agent_reply_data = current(unpack('a*', $agent_reply_data)); 451 | 452 | return pack('Na*', $agent_reply_bytes, $agent_reply_data); 453 | } 454 | } 455 | -------------------------------------------------------------------------------- /src/phpseclib/System/SSH_Agent.php: -------------------------------------------------------------------------------- 1 | 33 | * @copyright 2014 Jim Wigginton 34 | * @license http://www.opensource.org/licenses/mit-license.html MIT License 35 | * @link http://phpseclib.sourceforge.net 36 | * @internal See http://api.libssh.org/rfc/PROTOCOL.agent 37 | */ 38 | 39 | require_once 'SSH/Agent.php'; 40 | -------------------------------------------------------------------------------- /src/phpseclib/openssl.cnf: -------------------------------------------------------------------------------- 1 | # minimalist openssl.cnf file for use with phpseclib 2 | 3 | HOME = . 4 | RANDFILE = $ENV::HOME/.rnd 5 | 6 | [ v3_ca ] 7 | -------------------------------------------------------------------------------- /src/snapchat_agent.php: -------------------------------------------------------------------------------- 1 | 5, 56 | CURLOPT_RETURNTRANSFER => TRUE, 57 | CURLOPT_TIMEOUT => 10, 58 | CURLOPT_USERAGENT => self::USER_AGENT, 59 | CURLOPT_HTTPHEADER => array('Accept-Language: en', 'Accept-Locale: en_US'), 60 | ); 61 | public $gauth = ""; 62 | public static $CURL_HEADERS = array( 63 | 'Accept-Language: en', 64 | 'Accept-Locale: en_US' 65 | ); 66 | public function getGAuth(){ 67 | return (!empty($this->gauth) ? $this->gauth : ""); 68 | } 69 | public function setGAuth($auth) 70 | { 71 | if (is_array($auth)) 72 | $this->gauth = $auth['auth']; 73 | else 74 | $this->gauth = $auth; 75 | } 76 | /** 77 | * Returns the current timestamp. 78 | * 79 | * @return int 80 | * The current timestamp, expressed in milliseconds since epoch. 81 | */ 82 | public function timestamp() 83 | { 84 | return round(microtime(TRUE) * 1000); 85 | } 86 | 87 | /** 88 | * Pads data using PKCS5. 89 | * 90 | * @param data $data 91 | * The data to be padded. 92 | * @param int $blocksize 93 | * The block size to pad to. Defaults to 16. 94 | * 95 | * @return data 96 | * The padded data. 97 | */ 98 | public function pad($data, $blocksize = 16) 99 | { 100 | $pad = $blocksize - (strlen($data) % $blocksize); 101 | return $data . str_repeat(chr($pad), $pad); 102 | } 103 | 104 | /** 105 | * Decrypts blob data for standard images and videos. 106 | * 107 | * @param data $data 108 | * The data to decrypt. 109 | * 110 | * @return data 111 | * The decrypted data. 112 | */ 113 | public function decryptECB($data) 114 | { 115 | return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, self::BLOB_ENCRYPTION_KEY, self::pad($data), MCRYPT_MODE_ECB); 116 | } 117 | 118 | /** 119 | * Encrypts blob data for standard images and videos. 120 | * 121 | * @param data $data 122 | * The data to encrypt. 123 | * 124 | * @return data 125 | * The encrypted data. 126 | */ 127 | public function encryptECB($data) 128 | { 129 | return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, self::BLOB_ENCRYPTION_KEY, self::pad($data), MCRYPT_MODE_ECB); 130 | } 131 | 132 | /** 133 | * Decrypts blob data for stories. 134 | * 135 | * @param data $data 136 | * The data to decrypt. 137 | * @param string $key 138 | * The base64-encoded key. 139 | * @param string $iv 140 | * $iv The base64-encoded IV. 141 | * 142 | * @return data 143 | * The decrypted data. 144 | */ 145 | public function decryptCBC($data, $key, $iv) 146 | { 147 | // Decode the key and IV. 148 | $iv = base64_decode($iv); 149 | $key = base64_decode($key); 150 | 151 | // Decrypt the data. 152 | $data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv); 153 | $padding = ord($data[strlen($data) - 1]); 154 | 155 | return substr($data, 0, -$padding); 156 | } 157 | 158 | /** 159 | * Implementation of Snapchat's hashing algorithm. 160 | * 161 | * @param string $first 162 | * The first value to use in the hash. 163 | * @param string $second 164 | * The second value to use in the hash. 165 | * 166 | * @return string 167 | * The generated hash. 168 | */ 169 | public function hash($first, $second) 170 | { 171 | // Append the secret to the values. 172 | $first = self::SECRET . $first; 173 | $second = $second . self::SECRET; 174 | 175 | // Hash the values. 176 | $hash = hash_init('sha256'); 177 | hash_update($hash, $first); 178 | $hash1 = hash_final($hash); 179 | $hash = hash_init('sha256'); 180 | hash_update($hash, $second); 181 | $hash2 = hash_final($hash); 182 | 183 | // Create a new hash with pieces of the two we just made. 184 | $result = ''; 185 | for($i = 0; $i < strlen(self::HASH_PATTERN); $i++) 186 | { 187 | $result .= substr(self::HASH_PATTERN, $i, 1) ? $hash2[$i] : $hash1[$i]; 188 | } 189 | 190 | return $result; 191 | } 192 | 193 | /** 194 | * Checks to see if a blob looks like a media file. 195 | * 196 | * @param data $data 197 | * The blob data (or just the header). 198 | * 199 | * @return bool 200 | * TRUE if the blob looks like a media file, FALSE otherwise. 201 | */ 202 | function isMedia($data) 203 | { 204 | // Check for a JPG header. 205 | if($data[0] == chr(0xFF) && $data[1] == chr(0xD8)) 206 | { 207 | return TRUE; 208 | } 209 | 210 | // Check for a MP4 header. 211 | if($data[0] == chr(0x00) && $data[1] == chr(0x00)) 212 | { 213 | return TRUE; 214 | } 215 | 216 | return FALSE; 217 | } 218 | 219 | /** 220 | * Checks to see if a blob looks like a compressed file. 221 | * 222 | * @param data $data 223 | * The blob data (or just the header). 224 | * 225 | * @return bool 226 | * TRUE if the blob looks like a compressed file, FALSE otherwise. 227 | */ 228 | function isCompressed($data) 229 | { 230 | // Check for a PK header. 231 | if($data[0] == chr(0x50) && $data[1] == chr(0x4B)) 232 | { 233 | return TRUE; 234 | } 235 | 236 | return FALSE; 237 | } 238 | 239 | /** 240 | * Uncompress the blob and put the data into an Array. 241 | * Array( 242 | * overlay~zip-CE6F660A-4A9F-4BD6-8183-245C9C75B8A0 => overlay_file_data, 243 | * media~zip-CE6F660A-4A9F-4BD6-8183-245C9C75B8A0 => m4v_file_data 244 | * ) 245 | * 246 | * @param data $data 247 | * The blob data (or just the header). 248 | * 249 | * @return array 250 | * Array containing both file contents, or FALSE if couldn't extract. 251 | */ 252 | function unCompress($data) 253 | { 254 | if(!file_put_contents("./temp", $data)) 255 | { 256 | exit('Should have write access to own folder'); 257 | } 258 | $resource = zip_open("./temp"); 259 | $result = FALSE; 260 | if(is_resource($resource)) 261 | { 262 | while($zip_entry = zip_read($resource)) 263 | { 264 | $filename = zip_entry_name($zip_entry); 265 | if(zip_entry_open($resource, $zip_entry, "r")) 266 | { 267 | $result[$filename] = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry)); 268 | zip_entry_close($zip_entry); 269 | } 270 | else 271 | { 272 | unlink("./temp"); 273 | return FALSE; 274 | } 275 | } 276 | zip_close($resource); 277 | } 278 | unlink("./temp"); 279 | 280 | return $result; 281 | } 282 | 283 | /** 284 | * Performs a GET request. Currently only used for story blobs. 285 | * 286 | * @todo 287 | * cURL-ify this and maybe combine with the post function. 288 | * 289 | * @param string $endpoint 290 | * The address of the resource being requested (e.g. '/story_blob' or 291 | * '/story_thumbnail'). 292 | * 293 | * @return data 294 | * The retrieved data. 295 | */ 296 | public function get($endpoint) 297 | { 298 | $ch = curl_init(); 299 | curl_setopt_array($ch, array(CURLOPT_RETURNTRANSFER => 1, CURLOPT_USERAGENT => self::USER_AGENT, CURLOPT_HTTPHEADER => array('Accept-Language: en', 'Accept-Locale: en_US'),CURLOPT_URL => self::URL . $endpoint, CURLOPT_CAINFO => dirname(__FILE__) . '/ca_bundle.crt')); 300 | return curl_exec($ch); 301 | } 302 | 303 | /** 304 | * Performs a POST request. Used for pretty much everything. 305 | * 306 | * @todo 307 | * Replace the blob endpoint check with a more robust check for 308 | * application/octet-stream. 309 | * 310 | * @param string $endpoint 311 | * The address of the resource being requested (e.g. '/update_snaps' or 312 | * '/friend'). 313 | * @param array $data 314 | * An dictionary of values to send to the API. A request token is added 315 | * automatically. 316 | * @param array $params 317 | * An array containing the parameters used to generate the request token. 318 | * @param bool $multipart 319 | * If TRUE, sends the request as multipart/form-data. Defaults to FALSE. 320 | * 321 | * @return mixed 322 | * The data returned from the API (decoded if JSON). Returns FALSE if 323 | * the request failed. 324 | */ 325 | public function post($endpoint, $data, $params, $multipart = FALSE, $debug = FALSE) 326 | { 327 | $ch = curl_init(); 328 | 329 | $data['req_token'] = self::hash($params[0], $params[1]); 330 | $boundary = "Boundary+0xAbCdEfGbOuNdArY";//md5(time()); 331 | if(!$multipart) 332 | { 333 | $data = http_build_query($data); 334 | } 335 | else 336 | { 337 | 338 | $datas = "--".$boundary."\r\n" . 'Content-Disposition: form-data; name="req_token"' . "\r\n\r\n" . self::hash($params[0], $params[1]) . "\r\n"; 339 | foreach($data as $key => $value) 340 | { 341 | if($key == "req_token") continue; 342 | 343 | if($key != 'data') 344 | { 345 | $datas .= "--".$boundary."\r\n" . 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n" . $value . "\r\n"; 346 | } 347 | else 348 | { 349 | $datas .= "--".$boundary."\r\n" . 'Content-Disposition: form-data; name="data"; filename="data"'."\r\n" . 'Content-Type: application/octet-stream'."\r\n\r\n" . $value . "\r\n"; 350 | } 351 | } 352 | $data = $datas . "--".$boundary."--"; 353 | } 354 | $options = self::$CURL_OPTIONS; 355 | 356 | if($debug) 357 | { 358 | curl_setopt($ch, CURLINFO_HEADER_OUT, true); 359 | } 360 | 361 | if($endpoint == "/loq/login" || $endpoint == "/loq/register_username") 362 | { 363 | $headers = array_merge(self::$CURL_HEADERS, array( 364 | "X-Snapchat-Client-Auth-Token: Bearer {$params[2]}", 365 | "X-Snapchat-Client-Auth: {$params[3]}", 366 | "Accept-Encoding: gzip")); 367 | } 368 | else 369 | { 370 | $headers = array_merge(self::$CURL_HEADERS, array("X-Snapchat-Client-Auth-Token: Bearer ". $this->gauth)); 371 | } 372 | 373 | if($multipart) 374 | { 375 | $headers = array_merge($headers, array("X-Timestamp: 0","Content-Type: multipart/form-data; boundary=$boundary")); 376 | } 377 | 378 | if($endpoint == '/ph/blob' || $endpoint == '/bq/blob' || $endpoint == '/bq/chat_media') 379 | { 380 | $headers = array_merge($headers, array("X-Timestamp: " . $params[1])); 381 | $options += array( 382 | CURLOPT_URL => self::URL . $endpoint . "?{$data}" 383 | ); 384 | } 385 | else 386 | { 387 | $options += array( 388 | CURLOPT_POST => TRUE, 389 | CURLOPT_POSTFIELDS => $data, 390 | CURLOPT_URL => self::URL . $endpoint 391 | ); 392 | } 393 | curl_setopt_array($ch, $options); 394 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 395 | $headerBuff = tmpfile(); 396 | curl_setopt($ch, CURLOPT_WRITEHEADER, $headerBuff); 397 | curl_setopt($ch, CURLOPT_PROXY, $this->proxyServer); 398 | $result = curl_exec($ch); 399 | 400 | // If cURL doesn't have a bundle of root certificates handy, we provide 401 | // ours (see http://curl.haxx.se/docs/sslcerts.html). 402 | if (curl_errno($ch) == 60) { 403 | curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/ca_bundle.crt'); 404 | $result = curl_exec($ch); 405 | } 406 | 407 | if(strlen($result) > 0) //make sure curl worked. if not, keep going 408 | { 409 | if($endpoint == "/loq/login") $result = gzdecode($result); 410 | } 411 | 412 | if($debug) 413 | { 414 | $info = curl_getinfo($ch); 415 | echo "\nREQUEST TO: " .self::URL . $endpoint . "\n"; 416 | if(isset($info['request_header'])) 417 | echo "\nSent Request info: " .print_r($info['request_header'], true). "\n"; 418 | if(is_array($data)) 419 | { 420 | if ($multipart) 421 | echo 'DATA: ' . strlen($data) . " byte data\n"; 422 | else 423 | echo 'DATA: ' . print_r($data) . "\n"; 424 | } 425 | else 426 | { 427 | if ($multipart) 428 | echo 'DATA: ' . strlen($data) . " byte data\n"; 429 | else 430 | echo 'DATA: ' . $data . "\n"; 431 | } 432 | 433 | if($endpoint == "/loq/login" || $endpoint == "/all_updates") 434 | { 435 | if (strpos($result,'401 UNAUTHORIZED') !== false) 436 | { 437 | echo "\nRESULT: 401 UNAUTHORIZED\n"; 438 | exit(); 439 | } 440 | 441 | $jsonResult = json_decode($result); 442 | echo 'RESULT: ' . print_r($jsonResult) . "\n"; 443 | if (property_exists($jsonResult, "status") && $jsonResult->status == '-103') 444 | exit(); 445 | } 446 | else 447 | { 448 | if (strpos($result,'400 BAD_REQUEST') !== false) 449 | echo "\nRESULT: 400 BAD REQUEST\n"; 450 | else 451 | echo 'RESULT: ' . $result . "\n"; 452 | } 453 | 454 | if($endpoint == '/loq/register_username' || $endpoint == '/loq/register') 455 | { 456 | $jsonResult = json_decode($result); 457 | if(isset($jsonResult->logged) && $jsonResult->logged == false) 458 | { 459 | echo "\n" . 'ERROR: There was an error registering your account: ' . $jsonResult->message . "\n"; 460 | exit(); 461 | } 462 | } 463 | } 464 | 465 | if($endpoint == "/bq/get_captcha") 466 | { 467 | file_put_contents(__DIR__."/captcha.zip", $result); 468 | rewind($headerBuff); 469 | $headers = stream_get_contents($headerBuff); 470 | if(preg_match('/^Content-Disposition: .*?filename=(?[^\s]+|\x22[^\x22]+\x22)\x3B?.*$/m', $headers, $matches)) 471 | { 472 | $filename = trim($matches['f'],' ";'); 473 | rename(__DIR__."/captcha.zip", __DIR__."/{$filename}"); 474 | return $filename; 475 | } 476 | fclose($headerBuff); 477 | return "captcha.zip"; 478 | } 479 | 480 | $gi = curl_getinfo($ch); 481 | // If the cURL request fails, return FALSE. Also check the status code 482 | // since the API generally won't return friendly errors. 483 | if($result === FALSE) 484 | { 485 | 486 | curl_close($ch); 487 | 488 | return $result; 489 | } 490 | 491 | 492 | if(curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) 493 | { 494 | 495 | $return['data'] = $result; 496 | $return['test'] = 1; 497 | $return['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE); 498 | 499 | curl_close($ch); 500 | 501 | return $return; 502 | } 503 | 504 | curl_close($ch); 505 | 506 | $return['error'] = 0; 507 | 508 | if($endpoint == '/ph/blob' || $endpoint == '/bq/blob' || $endpoint == "/bq/snaptag_download" || $endpoint == '/bq/chat_media') 509 | { 510 | $return['data'] = $result; 511 | return $result; 512 | } 513 | 514 | // Add support for foreign characters in the JSON response. 515 | $result = iconv('UTF-8', 'UTF-8//IGNORE', utf8_encode($result)); 516 | 517 | $return['data'] = json_decode($result); 518 | return $return; 519 | } 520 | 521 | public function posttourl($url, $data) { 522 | $ch = curl_init(); 523 | $options = self::$CURL_OPTIONS + array( 524 | CURLOPT_POST => TRUE, 525 | CURLOPT_POSTFIELDS => $data, 526 | CURLOPT_URL => $url, 527 | ); 528 | curl_setopt_array($ch, $options); 529 | curl_setopt($ch, CURLOPT_HTTPHEADER, self::$CURL_HEADERS); 530 | 531 | $result = curl_exec($ch); 532 | if (curl_errno($ch) == 60) { 533 | curl_setopt($ch, CURLOPT_CAINFO, dirname(__FILE__) . '/ca_bundle.crt'); 534 | $result = curl_exec($ch); 535 | } 536 | if ($result === FALSE) 537 | { 538 | curl_close($ch); 539 | return $result; 540 | } 541 | if(curl_getinfo($ch, CURLINFO_HTTP_CODE) != 200) 542 | { 543 | $return['data'] = $result; 544 | $return['test'] = 1; 545 | $return['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE); 546 | curl_close($ch); 547 | return $return; 548 | } 549 | curl_close($ch); 550 | $return['error'] = 0; 551 | $result = iconv('UTF-8', 'UTF-8//IGNORE', utf8_encode($result)); 552 | $return['data'] = json_decode($result); 553 | return $return; 554 | } 555 | 556 | public function setProxyServer ($proxyServer) 557 | { 558 | $this->proxyServer = $proxyServer; 559 | } 560 | } 561 | -------------------------------------------------------------------------------- /src/snapchat_cache.php: -------------------------------------------------------------------------------- 1 | _cache[$key])) { 33 | return FALSE; 34 | } 35 | 36 | // Second, check its freshness. 37 | if ($this->_cache[$key]['time'] < time() - self::$_lifespan) { 38 | return FALSE; 39 | } 40 | 41 | return $this->_cache[$key]['data']; 42 | } 43 | 44 | /** 45 | * Adds a result to the cache. 46 | * 47 | * @param string $key 48 | * The key of the result to store. 49 | * @param mixed $data 50 | * The data to store. 51 | */ 52 | public function set($key, $data) { 53 | $this->_cache[$key] = array( 54 | 'time' => time(), 55 | 'data' => $data, 56 | ); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/snaps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgp25/SC-API/6fbccd787a79792701475f0872067c35880d69c6/src/snaps/.gitkeep -------------------------------------------------------------------------------- /src/stories/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mgp25/SC-API/6fbccd787a79792701475f0872067c35880d69c6/src/stories/.gitkeep --------------------------------------------------------------------------------