Skip to content

Instantly share code, notes, and snippets.

@zither
Last active August 29, 2015 14:15
Show Gist options
  • Save zither/e35888cbb98e56f59dd4 to your computer and use it in GitHub Desktop.
Save zither/e35888cbb98e56f59dd4 to your computer and use it in GitHub Desktop.
Simple Shadowsocks Client
<?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);
}
}
<?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);
}
}
<?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);
<?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 <mjsabby@gmail.com>
* @version $Id: class.rc4crypt.php,v 3.2 2006/03/10 05:47:24 mukul Exp $
* @copyright Copyright &copy; 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