use random iv so we finally have strong encryption now
This commit is contained in:
parent
0aa252e2b0
commit
9a6a934261
5 changed files with 65 additions and 30 deletions
|
@ -1,13 +1,16 @@
|
||||||
shadowsocks
|
shadowsocks
|
||||||
===========
|
===========
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/clowwindy/shadowsocks.png)](https://travis-ci.org/clowwindy/shadowsocks)
|
[![Build Status](https://travis-ci.org/clowwindy/shadowsocks.png)](https://travis-ci.org/clowwindy/shadowsocks)
|
||||||
Current version: 1.1.1
|
Current version: 1.1.1
|
||||||
|
|
||||||
shadowsocks is a lightweight tunnel proxy which can help you get through firewalls
|
shadowsocks is a lightweight tunnel proxy which can help you get through firewalls
|
||||||
|
|
||||||
Other ports and clients can be found [here](https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients).
|
Other ports and clients can be found [here](https://github.com/clowwindy/shadowsocks/wiki/Ports-and-Clients).
|
||||||
|
|
||||||
|
Warning: AES, DES, blowfish encryption methods are not implemented the same as other versions(Nodejs, etc) yet, please don't use those methods
|
||||||
|
if you want to use Python version together with other versions!
|
||||||
|
|
||||||
usage
|
usage
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|
|
@ -3,5 +3,6 @@
|
||||||
"server_port":8388,
|
"server_port":8388,
|
||||||
"local_port":1080,
|
"local_port":1080,
|
||||||
"password":"barfoo!",
|
"password":"barfoo!",
|
||||||
"timeout":600
|
"timeout":600,
|
||||||
|
"method":null
|
||||||
}
|
}
|
||||||
|
|
68
encrypt.py
68
encrypt.py
|
@ -27,6 +27,11 @@ import struct
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
def random_string(length):
|
||||||
|
import M2Crypto.Rand
|
||||||
|
return M2Crypto.Rand.rand_bytes(length)
|
||||||
|
|
||||||
|
|
||||||
def get_table(key):
|
def get_table(key):
|
||||||
m = hashlib.md5()
|
m = hashlib.md5()
|
||||||
m.update(key)
|
m.update(key)
|
||||||
|
@ -55,7 +60,7 @@ def init_table(key, method=None):
|
||||||
encrypt_table = ''.join(get_table(key))
|
encrypt_table = ''.join(get_table(key))
|
||||||
decrypt_table = string.maketrans(encrypt_table, string.maketrans('', ''))
|
decrypt_table = string.maketrans(encrypt_table, string.maketrans('', ''))
|
||||||
else:
|
else:
|
||||||
get_cipher(key, method, 1)
|
Encryptor(key, method) # make an Encryptor to test if the settings if OK
|
||||||
|
|
||||||
|
|
||||||
def EVP_BytesToKey(password, key_len, iv_len):
|
def EVP_BytesToKey(password, key_len, iv_len):
|
||||||
|
@ -89,39 +94,62 @@ method_supported = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def get_cipher(password, method, op):
|
|
||||||
import M2Crypto.EVP
|
|
||||||
password = password.encode('utf-8')
|
|
||||||
method = method.lower()
|
|
||||||
m = method_supported.get(method, None)
|
|
||||||
if m:
|
|
||||||
key, iv = EVP_BytesToKey(password, m[0], m[1])
|
|
||||||
return M2Crypto.EVP.Cipher(method.replace('-', '_'), key, iv, op, key_as_bytes=0, d='md5', salt=None, i=1, padding=1)
|
|
||||||
|
|
||||||
logging.error('method %s not supported' % method)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
class Encryptor(object):
|
class Encryptor(object):
|
||||||
def __init__(self, key, method=None):
|
def __init__(self, key, method=None):
|
||||||
if method == 'table':
|
if method == 'table':
|
||||||
method = None
|
method = None
|
||||||
|
self.key = key
|
||||||
self.method = method
|
self.method = method
|
||||||
|
self.iv = None
|
||||||
|
self.iv_sent = False
|
||||||
|
self.cipher_iv = ''
|
||||||
|
self.decipher = None
|
||||||
if method is not None:
|
if method is not None:
|
||||||
self.cipher = get_cipher(key, method, 1)
|
self.cipher = self.get_cipher(key, method, 1, iv=random_string(32))
|
||||||
self.decipher = get_cipher(key, method, 0)
|
|
||||||
else:
|
else:
|
||||||
self.cipher = None
|
self.cipher = None
|
||||||
self.decipher = None
|
|
||||||
|
def get_cipher_len(self, method):
|
||||||
|
method = method.lower()
|
||||||
|
m = method_supported.get(method, None)
|
||||||
|
return m
|
||||||
|
|
||||||
|
def iv_len(self):
|
||||||
|
return len(self.cipher_iv)
|
||||||
|
|
||||||
|
def get_cipher(self, password, method, op, iv=None):
|
||||||
|
import M2Crypto.EVP
|
||||||
|
password = password.encode('utf-8')
|
||||||
|
method = method.lower()
|
||||||
|
m = self.get_cipher_len(method)
|
||||||
|
if m:
|
||||||
|
key, iv_ = EVP_BytesToKey(password, m[0], m[1])
|
||||||
|
if iv is None:
|
||||||
|
iv = iv_[:m[1]]
|
||||||
|
if op == 1:
|
||||||
|
self.cipher_iv = iv[:m[1]] # this iv is for cipher, not decipher
|
||||||
|
return M2Crypto.EVP.Cipher(method.replace('-', '_'), key, iv, op, key_as_bytes=0, d='md5', salt=None, i=1, padding=1)
|
||||||
|
|
||||||
|
logging.error('method %s not supported' % method)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
def encrypt(self, buf):
|
def encrypt(self, buf):
|
||||||
if self.cipher is None:
|
if self.method is None:
|
||||||
return string.translate(buf, encrypt_table)
|
return string.translate(buf, encrypt_table)
|
||||||
else:
|
else:
|
||||||
return self.cipher.update(buf)
|
if self.iv_sent:
|
||||||
|
return self.cipher.update(buf)
|
||||||
|
else:
|
||||||
|
self.iv_sent = True
|
||||||
|
return self.cipher_iv + self.cipher.update(buf)
|
||||||
|
|
||||||
def decrypt(self, buf):
|
def decrypt(self, buf):
|
||||||
if self.cipher is None:
|
if self.method is None:
|
||||||
return string.translate(buf, decrypt_table)
|
return string.translate(buf, decrypt_table)
|
||||||
else:
|
else:
|
||||||
|
if self.decipher is None:
|
||||||
|
decipher_iv_len = self.get_cipher_len(self.method)[1]
|
||||||
|
decipher_iv = buf[:decipher_iv_len]
|
||||||
|
self.decipher = self.get_cipher(self.key, self.method, 0, iv=decipher_iv)
|
||||||
|
buf = buf[decipher_iv_len:]
|
||||||
return self.decipher.update(buf)
|
return self.decipher.update(buf)
|
||||||
|
|
8
local.py
8
local.py
|
@ -67,18 +67,18 @@ class Socks5Server(SocketServer.StreamRequestHandler):
|
||||||
while True:
|
while True:
|
||||||
r, w, e = select.select(fdset, [], [])
|
r, w, e = select.select(fdset, [], [])
|
||||||
if sock in r:
|
if sock in r:
|
||||||
data = sock.recv(4096)
|
data = self.encrypt(sock.recv(4096))
|
||||||
if len(data) <= 0:
|
if len(data) <= 0:
|
||||||
break
|
break
|
||||||
result = send_all(remote, self.encrypt(data))
|
result = send_all(remote, data)
|
||||||
if result < len(data):
|
if result < len(data):
|
||||||
raise Exception('failed to send all data')
|
raise Exception('failed to send all data')
|
||||||
|
|
||||||
if remote in r:
|
if remote in r:
|
||||||
data = remote.recv(4096)
|
data = self.decrypt(remote.recv(4096))
|
||||||
if len(data) <= 0:
|
if len(data) <= 0:
|
||||||
break
|
break
|
||||||
result = send_all(sock, self.decrypt(data))
|
result = send_all(sock, data)
|
||||||
if result < len(data):
|
if result < len(data):
|
||||||
raise Exception('failed to send all data')
|
raise Exception('failed to send all data')
|
||||||
finally:
|
finally:
|
||||||
|
|
11
server.py
11
server.py
|
@ -67,17 +67,17 @@ class Socks5Server(SocketServer.StreamRequestHandler):
|
||||||
while True:
|
while True:
|
||||||
r, w, e = select.select(fdset, [], [])
|
r, w, e = select.select(fdset, [], [])
|
||||||
if sock in r:
|
if sock in r:
|
||||||
data = sock.recv(4096)
|
data = self.decrypt(sock.recv(4096))
|
||||||
if len(data) <= 0:
|
if len(data) <= 0:
|
||||||
break
|
break
|
||||||
result = send_all(remote, self.decrypt(data))
|
result = send_all(remote, data)
|
||||||
if result < len(data):
|
if result < len(data):
|
||||||
raise Exception('failed to send all data')
|
raise Exception('failed to send all data')
|
||||||
if remote in r:
|
if remote in r:
|
||||||
data = remote.recv(4096)
|
data = self.encrypt(remote.recv(4096))
|
||||||
if len(data) <= 0:
|
if len(data) <= 0:
|
||||||
break
|
break
|
||||||
result = send_all(sock, self.encrypt(data))
|
result = send_all(sock, data)
|
||||||
if result < len(data):
|
if result < len(data):
|
||||||
raise Exception('failed to send all data')
|
raise Exception('failed to send all data')
|
||||||
|
|
||||||
|
@ -95,6 +95,9 @@ class Socks5Server(SocketServer.StreamRequestHandler):
|
||||||
try:
|
try:
|
||||||
self.encryptor = encrypt.Encryptor(KEY, METHOD)
|
self.encryptor = encrypt.Encryptor(KEY, METHOD)
|
||||||
sock = self.connection
|
sock = self.connection
|
||||||
|
iv_len = self.encryptor.iv_len()
|
||||||
|
if iv_len:
|
||||||
|
self.decrypt(sock.recv(iv_len))
|
||||||
addrtype = ord(self.decrypt(sock.recv(1)))
|
addrtype = ord(self.decrypt(sock.recv(1)))
|
||||||
if addrtype == 1:
|
if addrtype == 1:
|
||||||
addr = socket.inet_ntoa(self.decrypt(self.rfile.read(4)))
|
addr = socket.inet_ntoa(self.decrypt(self.rfile.read(4)))
|
||||||
|
|
Loading…
Reference in a new issue