Compare commits

...

66 Commits

Author SHA1 Message Date
228230bb1b Config
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-30 11:00:16 +02:00
9d3c011816 Config files
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-29 20:15:27 +02:00
18bfac4a86 Bcrypt salting
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 20:09:37 +02:00
6d2441d931 dirty workaround
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 18:05:37 +02:00
841c5d4c20 asd
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:52:54 +02:00
0e3ba17a8e basedir
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:52:34 +02:00
ec5a36c700 do not allow getting out
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:45:23 +02:00
fe26bd1727 asd
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:38:28 +02:00
4466ee6172 use unipath
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:33:15 +02:00
7f1a5f1013 now
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:22:14 +02:00
3bcb7e18ce maybe this
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:18:41 +02:00
37d2e06a18 OK
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:16:08 +02:00
978d7cf092 Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:11:41 +02:00
73c91d1426 OK 2021-04-29 17:11:33 +02:00
fc5385af63 seb
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:07:42 +02:00
fd4434f504 listdir
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:06:25 +02:00
152177473d better things
Some checks failed
continuous-integration/drone/push Build is failing
2021-04-29 17:00:50 +02:00
00d4542404 remove more redundant try
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 23:22:45 +02:00
09c376debf remove redundant try
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 23:16:47 +02:00
8acd49fe09 omg
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:59:23 +02:00
034f1e3403 fail better
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:56:06 +02:00
c4333ed827 remove autism
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:48:11 +02:00
784f065478 return error
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:41:37 +02:00
2d426a9f73 some niceness2
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:40:04 +02:00
cced3c49ef error
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:33:44 +02:00
3d1178d8ac do the magic
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:33:04 +02:00
62dd8872d6 hatvannegyedik bazis
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:23:20 +02:00
66877d52a1 lets see
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:19:09 +02:00
b4a9ccb334 szezon meg a fazon
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:06:07 +02:00
d40b20e753 fix public key shittery
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 22:02:06 +02:00
90969aeadb better append to dict
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 21:52:11 +02:00
101a8ab8d6 fixie wuxie
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 21:41:45 +02:00
540044c259 some printing, should replace with logger
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 20:37:32 +02:00
1616150c2f minor mistake
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 19:35:03 +02:00
c682fe1e2a missing comma
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 19:33:33 +02:00
4837948fba refactor and better crypto
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 19:31:55 +02:00
56d77f0476 refactor chacha
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 18:13:38 +02:00
a8730ceac3 foggyos vagyok
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 17:19:36 +02:00
f409aefdc0 use authenticated chacha20
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 16:58:50 +02:00
b08da25d21 Test for MKD / RMD works like a charm
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 14:40:32 +02:00
3e0afb0d45 copypaste went wild
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 13:50:28 +02:00
df79776ede move
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 13:31:00 +02:00
0c6c1c6622 memes
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 13:30:17 +02:00
a14e0414b6 fail less
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 13:28:57 +02:00
ae743cde15 some more login rework
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 13:18:50 +02:00
772a9e6d2c encode
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 00:26:23 +02:00
6bf93241f1 pep8
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 00:24:24 +02:00
63733a317f cipherkey is now guaranteed to be 32 characters strong
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-26 00:22:05 +02:00
ded1968f26 fail harder
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 20:27:37 +02:00
4fc32ddeea key
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 19:23:07 +02:00
45bab9c9f3 Long key
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 19:15:08 +02:00
c5d4859326 Error in auth
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:42:38 +02:00
149c206830 fix circular dependency
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:40:41 +02:00
798b74e5d8 fix server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:35:01 +02:00
3ad96cf71a Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server into master
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:34:09 +02:00
56a77f9c7e fix import 2021-04-25 18:33:50 +02:00
ccc664e0ea Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:29:55 +02:00
4e5634eb1d DNL 2021-04-25 18:29:49 +02:00
b6d46ea1bf return bytes
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:29:00 +02:00
b70c214584 fix cascading memes
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:25:27 +02:00
b6b3dd3a35 fixd
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:20:55 +02:00
f345d4b961 Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:19:18 +02:00
487f5ec772 UPL 2021-04-25 18:19:08 +02:00
5378ec8cdc better recievemessage
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:18:37 +02:00
89e8bd1295 Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server into master
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:13:24 +02:00
dc43cc3056 use bytes 2021-04-25 18:13:14 +02:00
11 changed files with 212 additions and 148 deletions

View File

@ -1,2 +1,3 @@
pycryptodome pycryptodome
pydh pydh
unipath

View File

@ -11,6 +11,7 @@ from Crypto.Hash import SHA256
from Crypto.Protocol.KDF import bcrypt, bcrypt_check from Crypto.Protocol.KDF import bcrypt, bcrypt_check
from Crypto.PublicKey import RSA from Crypto.PublicKey import RSA
from Crypto.PublicKey.RSA import RsaKey from Crypto.PublicKey.RSA import RsaKey
from Crypto.Random import get_random_bytes
auth_logger = logging.getLogger('AUTH APPLICATION ') auth_logger = logging.getLogger('AUTH APPLICATION ')
auth_logger.setLevel(logging.INFO) auth_logger.setLevel(logging.INFO)
@ -51,7 +52,7 @@ class Authetication:
b64pwd = b64encode(SHA256.new(password.encode('utf-8')).digest()) b64pwd = b64encode(SHA256.new(password.encode('utf-8')).digest())
bcrypt_check(b64pwd, user['password'].encode('utf-8')) bcrypt_check(b64pwd, user['password'].encode('utf-8'))
auth_logger.debug("User logged in: " + username) auth_logger.debug("User logged in: " + username)
return user['homeDir'] return self.HOME_DIRECTORY_LOCATION + os.path.sep + user['homeDir']
except ValueError: except ValueError:
auth_logger.debug("User NOT logged in: " + username) auth_logger.debug("User NOT logged in: " + username)
return '' return ''
@ -76,14 +77,16 @@ class Authetication:
shutil.rmtree(self.HOME_DIRECTORY_LOCATION) shutil.rmtree(self.HOME_DIRECTORY_LOCATION)
os.mkdir(self.HOME_DIRECTORY_LOCATION) os.mkdir(self.HOME_DIRECTORY_LOCATION)
os.mkdir(self.HOME_DIRECTORY_LOCATION + os.path.sep + '0')
shutil.rmtree(self.PRIVATE_KEY_DIRECTORY_LOCATION) shutil.rmtree(self.PRIVATE_KEY_DIRECTORY_LOCATION)
os.mkdir(self.PRIVATE_KEY_DIRECTORY_LOCATION) os.mkdir(self.PRIVATE_KEY_DIRECTORY_LOCATION)
def saveUser(self, username: str, password: str) -> bool: def saveUser(self, username: str, password: str) -> bool:
user_salt = get_random_bytes(16)
bytePass = password.encode('utf-8') bytePass = password.encode('utf-8')
b64pwd = b64encode(SHA256.new(bytePass).digest()) b64pwd = b64encode(SHA256.new(bytePass).digest())
bcrypt_hash = bcrypt(b64pwd, 12) bcrypt_hash = bcrypt(password=b64pwd, cost=12, salt=user_salt)
with open(self.CONFIG_FILE_LOCATION) as json_file: with open(self.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file) data = json.load(json_file)
@ -123,7 +126,7 @@ class Authetication:
dictionary = dict() dictionary = dict()
for user in data['user']: for user in data['user']:
key = data['publicKey'] key = user['publicKey']
key = bytes.fromhex(key) key = bytes.fromhex(key)
try: try:
rsaKey = RSA.import_key(key) rsaKey = RSA.import_key(key)

View File

@ -35,7 +35,7 @@ def testAuth(username: str, password: str):
auth.saveUser(username, password) auth.saveUser(username, password)
homeDir = auth.login(username, password) homeDir = auth.login(username, password)
if homeDir == '1': if homeDir == auth.HOME_DIRECTORY_LOCATION + os.path.sep + '1':
test_logger.info('TEST 1 --> Authentication test with VALID :: PASSED') test_logger.info('TEST 1 --> Authentication test with VALID :: PASSED')
else: else:
test_logger.info('TEST 1 --> Authentication test with VALID :: FAILED') test_logger.info('TEST 1 --> Authentication test with VALID :: FAILED')
@ -118,4 +118,4 @@ if __name__ == '__main__':
testSaveUser("Diósbejglia", "Diósbejgli") testSaveUser("Diósbejglia", "Diósbejgli")
testAuth("Diósbejglia", "Diósbejgli") testAuth("Diósbejglia", "Diósbejgli")
testUserExists("Diósbejglia", "Diósbejgli") testUserExists("Diósbejglia", "Diósbejgli")
testPersistency() #testPersistency()

View File

@ -1,2 +0,0 @@
#!/usr/bin/env python3

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12,7 +12,7 @@ def generatePrivateKeyForUser(auth: Authetication,username: str, user_passphrase
with open(auth.CONFIG_FILE_LOCATION) as json_file: with open(auth.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file) data = json.load(json_file)
private_key = RSA.generate(2048) private_key = RSA.generate(8192)
public_key = private_key.publickey() public_key = private_key.publickey()
private_key_value = bytes.hex(private_key.exportKey('DER', passphrase=user_passphrase, pkcs=8)) private_key_value = bytes.hex(private_key.exportKey('DER', passphrase=user_passphrase, pkcs=8))
public_key_value = bytes.hex(public_key.exportKey('DER', pkcs=8)) public_key_value = bytes.hex(public_key.exportKey('DER', pkcs=8))
@ -44,7 +44,7 @@ def generatePrivateKeyForServer(auth: Authetication,passphrase: str) -> str:
data = json.load(json_file) data = json.load(json_file)
json_file.close() json_file.close()
private_key = RSA.generate(2048) private_key = RSA.generate(8192)
public_key = private_key.publickey() public_key = private_key.publickey()
private_key_value = bytes.hex(private_key.exportKey('DER', passphrase=passphrase, pkcs=8, protection="scryptAndAES128-CBC")) private_key_value = bytes.hex(private_key.exportKey('DER', passphrase=passphrase, pkcs=8, protection="scryptAndAES128-CBC"))
public_key_value = bytes.hex(public_key.exportKey('DER', pkcs=8)) public_key_value = bytes.hex(public_key.exportKey('DER', pkcs=8))

View File

@ -3,16 +3,14 @@
import os import os
import re import re
from unipath import Path
class Executor: class Executor:
"""This class executes commands recieved by the server""" """This class executes commands recieved by the server"""
def __init__(self, currentDiectory: str, baseDir: str = ""): def __init__(self, baseDir: str):
self.currentDirectory = currentDiectory self.currentDirectory = ""
if baseDir == "": self.baseDir = baseDir + os.path.sep
self.baseDir = self.currentDirectory
else:
self.baseDir = baseDir
def sanitizeDirectory(self, inDirectory: str) -> str: def sanitizeDirectory(self, inDirectory: str) -> str:
return re.sub('[^a-zA-Z0-9]', '', inDirectory) return re.sub('[^a-zA-Z0-9]', '', inDirectory)
@ -22,13 +20,13 @@ class Executor:
def createDirectory(self, dirName: str) -> str: def createDirectory(self, dirName: str) -> str:
dirName = self.sanitizeDirectory(dirName) dirName = self.sanitizeDirectory(dirName)
actualDirName = os.path.join(self.currentDirectory, dirName) actualDirName: str = os.path.join(self.baseDir,self.currentDirectory,dirName)
os.mkdir(actualDirName) os.mkdir(actualDirName)
return actualDirName return actualDirName
def removeDirectory(self, dirName: str) -> str: def removeDirectory(self, dirName: str) -> str:
dirName = self.sanitizeDirectory(dirName) dirName = self.sanitizeDirectory(dirName)
actualDirName = os.path.join(self.currentDirectory, dirName) actualDirName: str = os.path.join(self.baseDir, self.currentDirectory, dirName)
if actualDirName: if actualDirName:
os.rmdir(actualDirName) os.rmdir(actualDirName)
return actualDirName return actualDirName
@ -38,51 +36,58 @@ class Executor:
def setCurrentDirectory(self, dirName: str) -> str: def setCurrentDirectory(self, dirName: str) -> str:
if dirName == "..": if dirName == "..":
if self.currentDirectory == self.baseDir: p = Path(os.path.join(self.baseDir, self.currentDirectory))
parentpath = p.parent
if (str(parentpath) + os.path.sep)== self.baseDir:
self.currentDirectory = ""
return self.currentDirectory return self.currentDirectory
else: else:
directories = self.currentDirectory.split(os.path.sep) if len(str(parentpath).split('/')) < len(self.baseDir.split('/')):
strdirectory = "" return self.currentDirectory
for dir in directories: newpath = str(parentpath).replace(self.baseDir,'')
strdirectory += dir + os.path.sep if os.path.exists(os.path.join(self.baseDir,newpath)):
strdirectory = strdirectory[:-3] self.currentDirectory = newpath
if os.path.exists(strdirectory):
self.currentDirectory = strdirectory
return self.currentDirectory return self.currentDirectory
else: else:
dirName = self.sanitizeDirectory(dirName) dirName = self.sanitizeDirectory(dirName)
joinedDir = os.path.join(self.currentDirectory, dirName) joinedDir = os.path.join(self.currentDirectory, dirName)
if os.path.exists(joinedDir): if os.path.join(self.baseDir, joinedDir):
self.currentDirectory = joinedDir self.currentDirectory = joinedDir
return self.currentDirectory return self.currentDirectory
def listCurrentDirectoryContent(self) -> str: def listCurrentDirectoryContent(self) -> str:
contents = os.listdir(self.currentDirectory) contents = os.listdir(os.path.join(self.baseDir, self.currentDirectory))
strdirectory = "" strdirectory = ""
for content in contents: for content in contents:
strdirectory += content + ", " strdirectory += content + ", "
strdirectory = strdirectory[:-1] strdirectory = strdirectory[:-1]
return strdirectory return strdirectory
def putFileInCurrentDirectory(self, filename: str, content) -> str: def putFileInCurrentDirectory(self, filename: str, content: bytes) -> str:
filename = self.sanitizeFile(filename) filename = self.sanitizeFile(filename)
currenctfile = os.path.join(self.currentDirectory, filename) currenctfile = os.path.join(self.baseDir, self.currentDirectory, filename)
f = open(currenctfile, "wb") f = open(currenctfile, "wb")
f.write(content) f.write(content)
f.close() f.close()
return currenctfile return currenctfile
def getFileInCurrentDirectory(self, file: str): def getFileInCurrentDirectory(self, file: str) -> bytes:
file = self.sanitizeFile(file) file = self.sanitizeFile(file)
currentfile = os.path.join(self.currentDirectory, file) currentfile = os.path.join(self.baseDir, self.currentDirectory, file)
if os.path.exists(currentfile): if os.path.exists(currentfile):
return open(currentfile, "r") f = open(currentfile, "rb")
content = f.read()
f.close()
return content
else: else:
raise Exception('File not found') raise Exception('File not found')
def removeFileInCurrentDirectory(self, file: str) -> str: def removeFileInCurrentDirectory(self, file: str) -> str:
file = self.sanitizeFile(file) file = self.sanitizeFile(file)
currentfile = os.path.join(self.currentDirectory, file) if self.currentDirectory == "":
currentfile = os.path.join(self.baseDir, file)
else:
currentfile = os.path.join(self.baseDir, self.currentDirectory, file)
if os.path.exists(currentfile): if os.path.exists(currentfile):
os.remove(currentfile) os.remove(currentfile)
return currentfile return currentfile

View File

@ -2,110 +2,150 @@
import json import json
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
import pyDH import pyDH
from Crypto.Hash import SHA512
from Crypto.Cipher import PKCS1_OAEP from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA from Crypto.Cipher import ChaCha20_Poly1305
from Crypto.Cipher import ChaCha20
from Crypto.PublicKey.RSA import RsaKey from Crypto.PublicKey.RSA import RsaKey
from Crypto.Random import get_random_bytes from Crypto.Signature import pkcs1_15
from netsim import network_interface from netsim import network_interface
from server.server import Server from authentication import Authetication
class NetWrapper: class NetWrapper:
def __init__(self, clientPublicKey: dict, serverPrivateKey: RsaKey, serverInstance: Server): def __init__(self, clientPublicKey: dict, serverPrivateKey: RsaKey, authenticationInstance: Authetication):
self.clientPublicKey = clientPublicKey self.clientPublicKey = clientPublicKey
self.currentClientPublicKey = "".encode('UTF-8') self.currentClientPublicKey = "".encode('UTF-8')
self.serverPrivateKey = serverPrivateKey self.serverPrivateKey = serverPrivateKey
self.cipherkey = "".encode('UTF-8') self.cipherkey = "".encode('UTF-8')
self.network = network_interface('./', 'A') self.network = network_interface('./../../netsim/network/', 'A')
self.clientAddr = "" self.clientAddr = ""
self.currentUser = "" self.currentUser = ""
self.serverInstance = serverInstance self.homeDirectory = ""
self.authenticationInstance = authenticationInstance
def encryptRSAMessage(self, message: bytes) -> bytes:
cipher_rsa = PKCS1_OAEP.new(self.currentClientPublicKey)
encrypted_msg = cipher_rsa.encrypt(message)
return encrypted_msg
def signRSAHeader(self, type: str, extradata: dict) -> (bytes, bytes):
mandatory = {'type': type, 'source': self.network.own_addr}
header = json.dumps({**mandatory, **extradata}).encode('UTF-8')
h = SHA512.new(header)
headersignature = pkcs1_15.new(self.serverPrivateKey).sign(h)
return header, headersignature
def verifyRSAHeaderSignature(self, header: bytes, headersignature: bytes) -> bool:
h = SHA512.new(header)
try:
pkcs1_15.new(self.currentClientPublicKey).verify(h, headersignature)
return True
except Exception:
return False
def decryptRSAMessage(self, message: bytes) -> bytes:
cipher_rsa = PKCS1_OAEP.new(self.serverPrivateKey)
return cipher_rsa.decrypt(message)
def serverIdentify(self, msg: bytes) -> None: def serverIdentify(self, msg: bytes) -> None:
incommingJson = json.loads(msg.decode('UTF-8')) incommingJson = json.loads(msg.decode('UTF-8'))
if incommingJson['type'] != "IDY": header = json.loads(b64decode(incommingJson['header']).decode('UTF-8'))
raise Exception('Wrong message type encountered') self.clientAddr = header['source']
self.clientAddr = incommingJson['source'] self.currentUser = header['username']
self.currentUser = incommingJson['username']
self.currentClientPublicKey = self.clientPublicKey[self.currentUser] self.currentClientPublicKey = self.clientPublicKey[self.currentUser]
cipher_rsa = PKCS1_OAEP.new(self.serverPrivateKey) if not self.verifyRSAHeaderSignature(b64decode(incommingJson['header']),
retmsg = cipher_rsa.decrypt(b64decode(incommingJson['message'])).decode('UTF-8') b64decode(incommingJson['headersignature'])) or header[
cipher = PKCS1_OAEP.new(self.currentClientPublicKey) 'type'] != 'IDY':
raise Exception('Bad initial message')
retheader, retheadersignature = self.signRSAHeader("IDY", {})
dcryptedmsg = self.decryptRSAMessage(b64decode(incommingJson['message']))
retmsg = self.encryptRSAMessage(dcryptedmsg)
identMsg = json.dumps( identMsg = json.dumps(
{'type': 'IDY', 'source': self.network.own_addr, {'header': b64encode(retheader).decode('UTF-8'),
'message': b64encode(cipher.encrypt(retmsg.encode('UTF-8'))).decode('ASCII')}).encode( 'headersignature': b64encode(retheadersignature).decode('UTF-8'),
'message': b64encode(retmsg).decode('UTF-8')}).encode(
'UTF-8') 'UTF-8')
self.network.send_msg(self.clientAddr, identMsg) self.network.send_msg(self.clientAddr, identMsg)
def sendMessage(self, message: bytes) -> None: def sendMessage(self, message: bytes) -> None:
cipher = ChaCha20.new(self.cipherkey, get_random_bytes(12)) self.sendTypedMessage(message, "CMD")
ciphertext = cipher.encrypt(message)
nonce = b64encode(cipher.nonce).decode('ASCII') def sendTypedMessage(self, message: bytes, type: str) -> None:
ct = b64encode(ciphertext).decode('ASCII') if not (type == "AUT" or type == "CMD"):
sendjson = json.dumps({'type': 'CMD', 'source': self.network.own_addr, 'nonce': nonce, 'message': ct}).encode( raise Exception('Unknown message type')
cipher = ChaCha20_Poly1305.new(key=self.cipherkey)
header = json.dumps({'source': self.network.own_addr, 'type': type}).encode('UTF-8')
cipher.update(header)
ciphertext, tag = cipher.encrypt_and_digest(message)
nonce = b64encode(cipher.nonce).decode('UTF-8')
ct = b64encode(ciphertext).decode('UTF-8')
b64tag = b64encode(tag).decode('UTF-8')
sendjson = json.dumps(
{'header': b64encode(header).decode('UTF-8'), 'nonce': nonce, 'message': ct, 'tag': b64tag}).encode(
'UTF-8') 'UTF-8')
self.network.send_msg(self.clientAddr, sendjson) self.network.send_msg(self.clientAddr, sendjson)
def keyExchange(self) -> None: def keyExchange(self) -> None:
dh = pyDH.DiffieHellman() dh = pyDH.DiffieHellman()
cipher = PKCS1_OAEP.new(self.currentClientPublicKey) mypubkey = self.encryptRSAMessage(str(dh.gen_public_key()).encode('UTF-8'))
mypubkey = b64encode(cipher.encrypt(str(dh.gen_public_key()).encode('UTF-8'))).decode('ASCII') header, headersignature = self.signRSAHeader("DH", {})
jsonmsg = json.dumps({'type': 'DH', 'source': self.network.own_addr, 'message': mypubkey}).encode('UTF-8') jsonmsg = json.dumps(
{'header': b64encode(header).decode('UTF-8'), 'headersignature': b64encode(headersignature).decode('UTF-8'),
'message': b64encode(mypubkey).decode('UTF-8')}).encode('UTF-8')
self.network.send_msg(self.clientAddr, jsonmsg) self.network.send_msg(self.clientAddr, jsonmsg)
decodedmsg = {'source': '', 'type': ''} status, msg = self.network.receive_msg(blocking=True)
while not (decodedmsg['source'] == self.clientAddr and decodedmsg['type'] == 'DH'): if not status:
status, msg = self.network.receive_msg(blocking=True) raise Exception('Network error during connection.')
if not status: decodedmsg = json.loads(msg.decode('UTF-8'))
raise Exception('Network error during connection.') header = json.loads(b64decode(decodedmsg['header']).decode('UTF-8'))
decodedmsg = json.loads(msg.decode('UTF-8')) if not self.verifyRSAHeaderSignature(b64decode(decodedmsg['header']),
cipher_rsa = PKCS1_OAEP.new(self.serverPrivateKey) b64decode(decodedmsg['headersignature'])) or not (
serverpubkey = int(cipher_rsa.decrypt(b64decode(decodedmsg['message'])).decode('UTF-8')) header['source'] == self.clientAddr and header['type'] == 'DH'):
self.cipherkey = dh.gen_shared_key(serverpubkey).encode('UTF-8') raise Exception('Header signature error')
clientpubkey = int(self.decryptRSAMessage(b64decode(decodedmsg['message'])).decode('UTF-8'))
cipherkey = dh.gen_shared_key(clientpubkey).encode('UTF-8')
hasher = SHA512.new()
hasher.update(cipherkey)
self.cipherkey = (hasher.hexdigest()[:32]).encode('UTF-8')
def login(self) -> bool: def login(self) -> bool:
b64 = {'source': '', 'type': ''} status, msg = self.network.receive_msg(blocking=True)
while not (b64['source'] == self.clientAddr and b64['type'] == 'AUT'): if not status:
status, msg = self.network.receive_msg(blocking=True) raise Exception('Network error during connection.')
if not status: cleartext = self.recieveEncryptedMessage(msg, "AUT").decode('UTF-8')
raise Exception('Network error during connection.') if cleartext == "ERROR":
b64 = json.loads(msg.decode('UTF-8')) return False
try: else:
retnonce = b64decode(b64['nonce']) plaintext = cleartext.split(' ')
retciphertext = b64decode(b64['message']) self.homeDirectory = self.authenticationInstance.login(plaintext[1], plaintext[2])
retcipher = ChaCha20.new(self.cipherkey, nonce=retnonce) linsuccess = (not (len(plaintext) != 3 or plaintext[0] != "LIN" or plaintext[
plaintext = retcipher.decrypt(retciphertext).decode('UTF-8').split(' ') 1] != self.currentUser)) and self.homeDirectory
linsuccess = (not (len(plaintext) != 3 or plaintext[0] != "LIN" or plaintext[ if linsuccess:
1] != self.currentUser)) and self.serverInstance.login(plaintext[1], plaintext[2]) message = "OK".encode('UTF-8')
if linsuccess: else:
message = "OK".encode('UTF-8') message = "ERROR".encode('UTF-8')
else: self.sendTypedMessage(message, "AUT")
message = "ERROR".encode('UTF-8') return linsuccess
cipher = ChaCha20.new(self.cipherkey, get_random_bytes(12))
ciphertext = cipher.encrypt(message)
nonce = b64encode(cipher.nonce).decode('ASCII')
ct = b64encode(ciphertext).decode('ASCII')
sendjson = json.dumps(
{'type': 'AUT', 'source': self.network.own_addr, 'nonce': nonce, 'message': ct}).encode(
'UTF-8')
self.network.send_msg(self.clientAddr, sendjson)
return linsuccess
except Exception:
print("Incorrect decryption")
def initClientConnection(self, msg: bytes) -> bytes: def initClientConnection(self, msg: bytes) -> bytes:
print('A client is trying to connect')
try: try:
print('Server and Client identity verification started')
self.serverIdentify(msg) self.serverIdentify(msg)
print('Key exchange started')
self.keyExchange() self.keyExchange()
print('Authorization started')
success = self.login() success = self.login()
print(f'Authorization completed, success: {success}')
if success: if success:
return "LINOK".encode('UTF-8') return "LINOK".encode('UTF-8')
else: else:
self.logout() self.logout()
return "LINERROR".encode('UTF-8') return "LINERROR".encode('UTF-8')
except Exception: except Exception:
print("Error ecountered, resetting")
self.logout() self.logout()
return "LINERROR".encode('UTF-8') return "LINERROR".encode('UTF-8')
@ -116,22 +156,31 @@ class NetWrapper:
if not self.clientAddr: if not self.clientAddr:
return self.initClientConnection(msg) return self.initClientConnection(msg)
else: else:
return self.recieveEncryptedMessage(msg) return self.recieveEncryptedMessage(msg, "CMD")
def logout(self) -> None: def logout(self) -> None:
self.serverInstance.logout()
self.clientAddr = "" self.clientAddr = ""
self.cipherkey = "".encode('UTF-8') self.cipherkey = "".encode('UTF-8')
self.currentClientPublicKey = "".encode('UTF-8') self.currentClientPublicKey = "".encode('UTF-8')
self.currentUser = "" self.currentUser = ""
self.homeDirectory = ""
def recieveEncryptedMessage(self, msg: bytes) -> bytes: def recieveEncryptedMessage(self, msg: bytes, type: str) -> bytes:
if not (type == "AUT" or type == "CMD"):
raise Exception('Unknown message type')
try: try:
b64 = json.loads(msg) b64 = json.loads(msg.decode('UTF-8'))
retheader = json.loads(b64decode(b64['header']).decode('UTF-8'))
retnonce = b64decode(b64['nonce']) retnonce = b64decode(b64['nonce'])
retciphertext = b64decode(b64['message']) retciphertext = b64decode(b64['message'])
retcipher = ChaCha20.new(self.cipherkey, nonce=retnonce) rettag = b64decode(b64['tag'])
plaintext = retcipher.decrypt(retciphertext) retcipher = ChaCha20_Poly1305.new(key=self.cipherkey, nonce=retnonce)
return plaintext retcipher.update(b64decode(b64['header']))
plaintext = retcipher.decrypt_and_verify(retciphertext, rettag)
if not (retheader['source'] == self.clientAddr and retheader['type'] == type):
return "ERROR".encode('UTF-8')
else:
return plaintext
except Exception: except Exception:
print("Incorrect decryption") print("Incorrect decryption")
return "ERROR".encode('UTF-8')

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
from authentication import Authetication from authentication import Authetication
from executor import Executor from executor import Executor
from netwrapper import NetWrapper from netwrapper import NetWrapper
@ -6,55 +7,59 @@ from netwrapper import NetWrapper
class Server: class Server:
def __init__(self, homeDirectory: str = "", sessionTimeout: int = 120, availableServer: bool = True): def __init__(self, sessionTimeout: int = 120, availableServer: bool = True):
self.isAuthenticated = False self.isAuthenticated = False
self.homeDirectory = homeDirectory
self.sessionTimeout = sessionTimeout self.sessionTimeout = sessionTimeout
self.availableServer = availableServer self.availableServer = availableServer
self.executor = Executor(homeDirectory) self.executor = Executor("")
self.auth = Authetication()
def initServer(self): def initServer(self):
print("Please enter your private key passphrase") print("Please enter your private key passphrase")
passphrase = input() passphrase = input()
self.auth = Authetication()
self.networkInstance = NetWrapper(self.auth.loadUserPublicKeys(), self.auth.loadServerPrivateKey(passphrase), self.networkInstance = NetWrapper(self.auth.loadUserPublicKeys(), self.auth.loadServerPrivateKey(passphrase),
self) self.auth)
def login(self, username: str, password: str) -> bool: def login(self, homeDir: str) -> None:
self.isAuthenticated = True self.isAuthenticated = True
home_directory = self.auth.login(username, password) self.executor = Executor(homeDir + os.path.sep)
self.executor.baseDir = Executor(home_directory)
if not home_directory:
return False
else:
return True
def logout(self) -> None: def logout(self) -> None:
self.networkInstance.logout()
self.isAuthenticated = False self.isAuthenticated = False
self.availableServer = False self.availableServer = False
self.homeDirectory = "" self.executor = Executor("")
self.executor.baseDir = Executor(self.homeDirectory)
def parseCommand(self, command: str) -> None: def parseCommand(self, command: str) -> None:
if command == "LINOK": if command == "LINOK":
self.networkInstance.sendMessage("LINOK".encode('UTF-8')) self.login(self.networkInstance.homeDirectory)
self.networkInstance.sendMessage("OK".encode('UTF-8'))
return None
elif command == "LINERROR": elif command == "LINERROR":
self.networkInstance.sendMessage("LINERROR".encode('UTF-8')) return None
elif command == "ERROR":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
return None
parsedCommand = command.split(" ") parsedCommand = command.split(" ")
if len(parsedCommand) > 3: if len(parsedCommand) > 3:
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
# TODO: Ez igy gecironda, ezt meg kene csinalni rendesen.
elif len(parsedCommand) == 1: elif len(parsedCommand) == 1:
return self.execute(parsedCommand[0]) self.execute(parsedCommand[0])
elif len(parsedCommand) == 2: elif len(parsedCommand) == 2:
return self.execute(parsedCommand[0], parsedCommand[1]) self.execute(parsedCommand[0], parsedCommand[1])
elif len(parsedCommand) == 3: elif len(parsedCommand) == 3:
return self.execute(parsedCommand[0], parsedCommand[1], parsedCommand[2]) self.execute(parsedCommand[0], parsedCommand[1], parsedCommand[2])
def execute(self, command: str, firstParam: str = "", secondParam: str = "") -> None: def execute(self, command: str, firstParam: str = "", secondParam: str = "") -> None:
if self.homeDirectory == "" or self.executor.currentDirectory == "" or self.executor.baseDir == "": if self.executor.baseDir == "":
raise Exception("Directories must not be empty string. Did the user log in?") raise Exception("Home directory must not be empty string. Did the user log in?")
if command == "MKD": if command == "LOUT":
if not (secondParam == "" and firstParam == ""):
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.networkInstance.sendMessage("OK".encode('UTF-8'))
self.logout()
elif command == "MKD":
if secondParam != "": if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else: else:
@ -67,11 +72,10 @@ class Server:
self.executor.removeDirectory(firstParam) self.executor.removeDirectory(firstParam)
self.networkInstance.sendMessage("OK".encode('UTF-8')) self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "GWD": elif command == "GWD":
if secondParam != "" or firstParam != "": if not (secondParam == "" and firstParam == ""):
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else: else:
self.executor.getCurrentDirectory() self.networkInstance.sendMessage(self.executor.getCurrentDirectory().encode('UTF-8'))
self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "CWD": elif command == "CWD":
if secondParam != "": if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
@ -79,11 +83,10 @@ class Server:
self.executor.setCurrentDirectory(firstParam) self.executor.setCurrentDirectory(firstParam)
self.networkInstance.sendMessage("OK".encode('UTF-8')) self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "LST": elif command == "LST":
if secondParam != "" or firstParam != "": if not (secondParam == "" and firstParam == ""):
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else: else:
self.executor.listCurrentDirectoryContent() self.networkInstance.sendMessage(self.executor.listCurrentDirectoryContent().encode('UTF-8'))
self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "RMF": elif command == "RMF":
if secondParam != "": if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
@ -94,28 +97,31 @@ class Server:
if secondParam != "": if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else: else:
# TODO fileMessage = self.networkInstance.recieveMessage()
# Megkapod a filenevet argumentumneknt eof = self.networkInstance.recieveMessage().decode('UTF-8')
# Fogadni kell egy uzenetet, ami a fajl tartalma if eof == "EOF":
# Fogadni kell egy uzenetet, ami "EOF" self.executor.putFileInCurrentDirectory(firstParam, fileMessage)
# Mindig minden legyen UTF-8-kent kodolva, kiveve a falj, az marard self.networkInstance.sendMessage("OK".encode('UTF-8'))
# Ha sikeres, OK kuldese, kulonben ERROR kuldese else:
pass self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
elif command == "DNL": elif command == "DNL":
if secondParam != "": if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else: else:
# TODO try:
# Megkapod a filenevet arguemntumkent file = self.executor.getFileInCurrentDirectory(firstParam)
# Kuldeni kell egy uzenetet, ami a falj tartalma self.networkInstance.sendMessage(file)
# Kuldeni kell egy uzenetet, ami EOF self.networkInstance.sendMessage("EOF".encode('UTF-8'))
# Mindig minden legyen UTF-8-kent kodolva, kiveve a falj, az marard except Exception:
# Ha sikeres, OK valaszt megkapod, kulonben ERROR valaszt megkapod self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
pass
else: else:
self.networkInstance.sendMessage("ERROR".encode('UTF-8')) self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
def startServer(self): def startServer(self):
while True: while True:
message = self.networkInstance.recieveMessage().decode('UTF-8') try:
self.parseCommand(message) message = self.networkInstance.recieveMessage().decode('UTF-8')
self.parseCommand(message)
except Exception as e:
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
print(e)