Last active
August 29, 2015 14:15
-
-
Save zither/e35888cbb98e56f59dd4 to your computer and use it in GitHub Desktop.
Simple Shadowsocks Client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Cipher | |
{ | |
public function __construct($key, $method, $iv, $op, $keyAsBytes = 0, $d = null, $salt = null, $i = 1, $padding = 1) | |
{ | |
$this->key = $key; | |
$this->method = $method; | |
$this->op = $op; | |
$this->iv = $iv; | |
$this->keyAsBytes = $keyAsBytes; | |
$this->d = $d; | |
$this->salt = $salt; | |
$this->padding = $padding; | |
$this->rc4Key = md5($key . $iv, true); | |
} | |
public function encrypt($buffer) | |
{ | |
return Rc4crypt::encrypt($this->rc4Key, $buffer); | |
} | |
public function decrypt($buffer) | |
{ | |
return Rc4crypt::decrypt($this->rc4Key, $buffer); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Encryptor | |
{ | |
public $key; | |
public $method; | |
public $iv = null; | |
public $ivSent = false; | |
public $cipherIv; | |
public $decipher = null; | |
public $methodInfo = array(16, 16); | |
public function __construct($key, $method) | |
{ | |
$this->key = $key; | |
$this->method = $method; | |
$method = strtolower($method); | |
$this->methodInfo = $this->getMethodInfo($method); | |
if ($this->methodInfo) { | |
$this->cipher = $this->getCipher($key, $method, 1, $this->randomString(50)); | |
} else { | |
throw new Exception(sprintf("Does not support method %s!", $method)); | |
} | |
} | |
public function randomString($size) | |
{ | |
return mcrypt_create_iv($size, MCRYPT_DEV_URANDOM); | |
} | |
public function getMethodInfo($method) | |
{ | |
return $this->methodInfo; | |
} | |
public function ivLen() | |
{ | |
return strlen($this->iv); | |
} | |
public function getCipher($password, $method, $op, $iv) | |
{ | |
$m = $this->methodInfo; | |
if ($m[0] > 0) { | |
// 直接丢弃根据 $password 生成的 iv | |
list($key, $_) = $this->EVPBytesToKey($password, $m[0], $m[1]); | |
} else { | |
list($key, $iv) = array($password, pack("C", null)); | |
} | |
// 从随机 iv 中直接截取指定长度字符串做为 iv | |
$iv = substr($iv, 0, $m[1]); | |
if ($op == 1) { | |
$this->cipherIv = substr($iv, 0, $m[1]); | |
} | |
return new Cipher($key, $method, $iv, $op); | |
} | |
public function encrypt($data) | |
{ | |
if (strlen($data) == 0) { | |
return $data; | |
} | |
if ($this->ivSent) { | |
return $this->cipher->encrypt($data); | |
} | |
$this->ivSent = true; | |
return $this->cipherIv . $this->cipher->encrypt($data); | |
} | |
public function decrypt($data) | |
{ | |
if (strlen($data) == 0) { | |
return $data; | |
} | |
if (is_null($this->decipher)) { | |
$decipherIvLen = $this->methodInfo[1]; | |
$decipherIv = substr($data, 0, $decipherIvLen); | |
$this->decipher = $this->getCipher($this->key, $this->method, 0, $decipherIv); | |
$data = substr($data, $decipherIvLen); | |
if (strlen($data) == 0) { | |
return $data; | |
} | |
} | |
return $this->decipher->decrypt($data); | |
} | |
public function EVPBytesToKey($password, $keyLen, $ivLen) | |
{ | |
$m = array(); | |
$i = 0; | |
while (strlen($this->bytesJoin($m)) < ($keyLen + $ivLen)) { | |
$data = $password; | |
if ($i > 0) { | |
$data = $m[$i - 1] . $password; | |
} | |
array_push($m, md5($data, true)); | |
$i += 1; | |
} | |
$ms = $this->bytesJoin($m); | |
$key = substr($ms, 0, $keyLen); | |
$iv = substr($ms, $keyLen, $keyLen + $ivLen); | |
return array($key, $iv); | |
} | |
public function bytesJoin($array) | |
{ | |
return implode("", $array); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
require "Encryptor.php"; | |
require "Cipher.php"; | |
require "Rc4crypt.php"; | |
$domain = "www.google.com"; | |
$data = pack("C2", 0x03, strlen($domain)); | |
$data .= $domain . pack("n", 0x50); | |
$data .= sprintf("GET / HTTP/1.1\r\nHost:%s\r\nAccept:text/html\r\n\r\n", $domain); | |
$encryptor = new Encryptor("password", "RC4"); | |
$encryptedData = $encryptor->encrypt($data); | |
$remote = stream_socket_client("tcp://example.ss-server.com:50565", $errno, $errstr); | |
if (!$remote) { | |
throw new Exception($errstr, $errno); | |
} | |
$send = fwrite($remote, $encryptedData); | |
printf("Forward %d bytes data to remote.\n", $send); | |
$encryptedResponse = ""; | |
stream_set_timeout($remote, 1); | |
while(true) { | |
// 在阻塞模式中不能使用 stream_socket_recvfrom,stream_set_timeout 的设置对其无效 | |
// MTU 一般为 1500 | |
$buffer = fread($remote, 1500); | |
if ("" === $buffer || false === $buffer) { | |
break; | |
} | |
$encryptedResponse .= $buffer; | |
} | |
$response = $encryptor->decrypt($encryptedResponse); | |
printf( | |
"Receive %d bytes data from remote.\nResponse content:\n\n %s\n", | |
strlen($response), | |
$response | |
); | |
stream_socket_shutdown($remote, STREAM_SHUT_RDWR); | |
fclose($remote); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* vim: set expandtab shiftwidth=4 softtabstop=4 tabstop=4: */ | |
/** | |
* RC4Crypt 3.2 | |
* | |
* RC4Crypt is a petite library that allows you to use RC4 | |
* encryption easily in PHP. It's OO and can produce outputs | |
* in binary and hex. | |
* | |
* (C) Copyright 2006 Mukul Sabharwal [http://mjsabby.com] | |
* All Rights Reserved | |
* | |
* @link http://rc4crypt.devhome.org | |
* @author Mukul Sabharwal <[email protected]> | |
* @version $Id: class.rc4crypt.php,v 3.2 2006/03/10 05:47:24 mukul Exp $ | |
* @copyright Copyright © 2006 Mukul Sabharwal | |
* @license http://www.gnu.org/copyleft/gpl.html | |
* @package RC4Crypt | |
*/ | |
class Rc4crypt | |
{ | |
/** | |
* The symmetric encryption function | |
* | |
* @param string $pwd Key to encrypt with (can be binary of hex) | |
* @param string $data Content to be encrypted | |
* @param bool $ispwdHex Key passed is in hexadecimal or not | |
* @access public | |
* @return string | |
*/ | |
public static function encrypt ($pwd, $data, $ispwdHex = 0) | |
{ | |
if ($ispwdHex) | |
$pwd = @pack('H*', $pwd); // valid input, please! | |
$key[] = ''; | |
$box[] = ''; | |
$cipher = ''; | |
$pwd_length = strlen($pwd); | |
$data_length = strlen($data); | |
for ($i = 0; $i < 256; $i++) | |
{ | |
$key[$i] = ord($pwd[$i % $pwd_length]); | |
$box[$i] = $i; | |
} | |
for ($j = $i = 0; $i < 256; $i++) | |
{ | |
$j = ($j + $box[$i] + $key[$i]) % 256; | |
$tmp = $box[$i]; | |
$box[$i] = $box[$j]; | |
$box[$j] = $tmp; | |
} | |
for ($a = $j = $i = 0; $i < $data_length; $i++) | |
{ | |
$a = ($a + 1) % 256; | |
$j = ($j + $box[$a]) % 256; | |
$tmp = $box[$a]; | |
$box[$a] = $box[$j]; | |
$box[$j] = $tmp; | |
$k = $box[(($box[$a] + $box[$j]) % 256)]; | |
$cipher .= chr(ord($data[$i]) ^ $k); | |
} | |
return $cipher; | |
} | |
/** | |
* Decryption, recall encryption | |
* | |
* @param string $pwd Key to decrypt with (can be binary of hex) | |
* @param string $data Content to be decrypted | |
* @param bool $ispwdHex Key passed is in hexadecimal or not | |
* @access public | |
* @return string | |
*/ | |
public static function decrypt ($pwd, $data, $ispwdHex = 0) | |
{ | |
return rc4crypt::encrypt($pwd, $data, $ispwdHex); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment