Compare commits

..

111 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
8957cd6a04 Key export doesnt need protection tpye because DER format has default: PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:11:53 +02:00
81ea634b3a 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:09:51 +02:00
5e1e9f3e69 Duplicate row in auth 2021-04-25 18:09:43 +02:00
42fff36545 unresolved reference
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:08:21 +02:00
621c59dce2 fix decode
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:05:49 +02:00
a5490854af no return, send message
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 18:02:29 +02:00
4bd161de54 create init function
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:55:05 +02:00
0874645719 Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server into master 2021-04-25 17:51:08 +02:00
f6461273ab Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:50:50 +02:00
8d7754edc2 oops 2021-04-25 17:50:43 +02:00
7628156340 server execute 2021-04-25 17:50:39 +02:00
f8161f34fa no message
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:45:22 +02:00
7c0e66c450 add main
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:36:19 +02:00
c091532f74 comment pszeudoprogramming meme
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:35:39 +02:00
c5d89d8b13 invoke server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:29:50 +02:00
15bd2b13ca things
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:20:19 +02:00
75f6e77668 remove unresolved reference
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:15:11 +02:00
edfd2bd889 do the magic, this will not run
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:12:20 +02:00
e3d1280cb6 some cleanup
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:09:37 +02:00
904c01db47 use ascii
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 17:06:25 +02:00
f1220dd49e Netwrapper key gen
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 16:38:46 +02:00
3dbde8fbb8 Authentication_test corrections
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 16:06:56 +02:00
c69241249e Source address
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 15:40:08 +02:00
f0c5281697 Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 15:24:27 +02:00
b87e2c3b3d Init script extension and key loading for netwrapper 2021-04-25 15:24:24 +02:00
bfdec0e727 Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 14:38:08 +02:00
977b87634c login, logout in server, invoke server's logout in netwrapper 2021-04-25 14:28:29 +02:00
d526063dcf linerror
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 13:24:23 +02:00
a5b77d0306 finish netwrapper of server and executor improvements
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 00:42:36 +02:00
90396c2826 user login
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-25 00:35:23 +02:00
4fae36ff79 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-23 18:54:20 +02:00
6157c68c30 fix login 2021-04-23 18:54:05 +02:00
02ef40a303 Merge branch 'master' of https://git.kmlabz.com/BiztProtoBois/server
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-23 18:13:25 +02:00
4005a86058 Netwrapper 2021-04-23 18:13:18 +02:00
1b802f9b6b optimize import
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-23 17:27:41 +02:00
3ca93438e6 1: config init in separate file
All checks were successful
continuous-integration/drone/push Build is passing
2: auth_test doesnt generate production state
2021-04-22 14:35:58 +02:00
be21d4100d Hexa format
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-21 18:30:18 +02:00
a2e09b3656 networkwrapper skeleton done
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-19 18:50:22 +02:00
dd2f24f112 server skeleton done
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-19 18:46:23 +02:00
893f264a5e server skeleton done
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-19 18:19:34 +02:00
cf46944e50 Testing directory structure
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-18 23:06:20 +02:00
c8c1b560e8 os.path.sep
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-18 22:53:38 +02:00
094c1bcf35 os.path.sep
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-18 22:52:14 +02:00
23925d4b39 generatePrivateKeyForUser now accept the server's public key for easier testing (the output file will contain the keyphrase, client_private_key, server_public_key)
All checks were successful
continuous-integration/drone/push Build is passing
2021-04-18 19:15:54 +02:00
81211b1dd5 On running test the sript generates 3 user where password == username
All checks were successful
continuous-integration/drone/push Build is passing
->  user1: 'alma' with passphrase: 'amla'
    ->  user2: 'citrom' with passphrase: 'mortic'
    ->  user1: 'dinnye' with passphrase: 'eynnid'

The private keys are envrypted in DER format with pkcs#8 using the passphrase.
The private keys are temporarly stored under config/{homeDir}
The public keys are stored in the config file without encryption
2021-04-18 18:59:01 +02:00
12 changed files with 564 additions and 57 deletions

View File

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

View File

@ -1,3 +1,5 @@
#!/usr/bin/env python3
import json
import logging
import os
@ -7,17 +9,22 @@ from base64 import b64encode
from Crypto.Hash import SHA256
from Crypto.Protocol.KDF import bcrypt, bcrypt_check
from Crypto.PublicKey import RSA
from Crypto.PublicKey.RSA import RsaKey
from Crypto.Random import get_random_bytes
auth_logger = logging.getLogger('AUTH APPLICATION ')
auth_logger.root.setLevel(logging.INFO)
auth_logger.setLevel(logging.INFO)
class Authetication:
ABSOLUTE_PATH = os.path.abspath(os.path.dirname(sys.argv[0]))
HOME_DIRECTORY_LOCATION = ABSOLUTE_PATH + "\\home"
CONFIG_DIRECTORY_LOCATION = ABSOLUTE_PATH + "\\config"
HOME_DIRECTORY_LOCATION = ABSOLUTE_PATH + os.path.sep + "home"
CONFIG_DIRECTORY_LOCATION = ABSOLUTE_PATH + os.path.sep + "config"
CONFIG_FILE_LOCATION = ABSOLUTE_PATH + os.path.sep + "config" + os.path.sep + "config.txt"
PRIVATE_KEY_DIRECTORY_LOCATION = CONFIG_DIRECTORY_LOCATION + os.path.sep + "private_keys"
USER_INDEX = 0
def __init__(self):
if not os.path.isdir(self.HOME_DIRECTORY_LOCATION):
os.mkdir(self.HOME_DIRECTORY_LOCATION)
@ -25,30 +32,36 @@ class Authetication:
if not os.path.isdir(self.CONFIG_DIRECTORY_LOCATION):
os.mkdir(self.CONFIG_DIRECTORY_LOCATION)
if not os.path.isfile(self.CONFIG_DIRECTORY_LOCATION + "\\config.txt") or os.stat(
self.CONFIG_DIRECTORY_LOCATION + "\\config.txt").st_size == 0:
if not os.path.isdir(self.PRIVATE_KEY_DIRECTORY_LOCATION):
os.mkdir(self.PRIVATE_KEY_DIRECTORY_LOCATION)
if not os.path.isfile(self.CONFIG_FILE_LOCATION) or os.stat(
self.CONFIG_FILE_LOCATION).st_size == 0:
data = {'index': 0, 'user': []}
with open(self.CONFIG_DIRECTORY_LOCATION + "\\config.txt", 'w+') as outfile:
with open(self.CONFIG_FILE_LOCATION, 'w+') as outfile:
json.dump(data, outfile)
def login(self, username: str, password: str) -> str:
with open(self.CONFIG_DIRECTORY_LOCATION + '\\config.txt') as json_file:
with open(self.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file)
for user in data['user']:
if username == user['username']:
b64pwd = b64encode(SHA256.new(password.encode('utf-8')).digest())
try:
b64pwd = b64encode(SHA256.new(password.encode('utf-8')).digest())
bcrypt_check(b64pwd, user['password'].encode('utf-8'))
auth_logger.debug("User logged in: " + username)
return self.HOME_DIRECTORY_LOCATION + os.path.sep + user['homeDir']
except ValueError:
auth_logger.debug("User NOT logged in: " + username)
return ''
auth_logger.debug("User logged in: " + username)
return user['homeDir']
else:
auth_logger.error("User not found")
return ''
def checkUserExists(self, username: str) -> bool:
with open(self.CONFIG_DIRECTORY_LOCATION + '\\config.txt') as json_file:
with open(self.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file)
for user in data['user']:
@ -56,41 +69,82 @@ class Authetication:
return True
return False
def initConfig(self):
data = {'index': 0, 'user': []}
with open(self.CONFIG_DIRECTORY_LOCATION + "\\config.txt", 'w+') as outfile:
with open(self.CONFIG_FILE_LOCATION, 'w+') as outfile:
json.dump(data, outfile)
shutil.rmtree(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)
os.mkdir(self.PRIVATE_KEY_DIRECTORY_LOCATION)
def saveUser(self, username: str, password: str) -> bool:
user_salt = get_random_bytes(16)
bytePass = password.encode('utf-8')
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_DIRECTORY_LOCATION + '\\config.txt') as json_file:
with open(self.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file)
user = {
'username': username,
'password': bcrypt_hash.decode('utf-8'),
'homeDir': str(data['index'] + 1)
}
data['index'] = data['index'] + 1
if self.checkUserExists(username):
auth_logger.debug("User NOT saved! This username already exists!")
return False
else:
if not os.path.isdir(self.HOME_DIRECTORY_LOCATION + "\\" + str(user['homeDir'])):
os.mkdir(self.HOME_DIRECTORY_LOCATION + "\\" + str(user['homeDir']))
if not os.path.isdir(self.HOME_DIRECTORY_LOCATION + os.path.sep + str(data['index'] + 1)):
data['index'] = data['index'] + 1
user = {
'username': username,
'password': bcrypt_hash.decode('utf-8'),
'homeDir': str(data['index']),
'publicKey': ''
}
##Create user HOME directory with index as name
os.mkdir(self.HOME_DIRECTORY_LOCATION + os.path.sep + str(data['index']))
##Save user data
data['user'].append(user)
with open(self.CONFIG_DIRECTORY_LOCATION + '\\config.txt', 'w') as outfile:
with open(self.CONFIG_FILE_LOCATION, 'w') as outfile:
json.dump(data, outfile)
auth_logger.debug("User saved!")
else:
auth_logger.debug("User NOT saved! Home directory already exists")
return True
def loadUserPublicKeys(self) -> dict:
with open(self.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file)
dictionary = dict()
for user in data['user']:
key = user['publicKey']
key = bytes.fromhex(key)
try:
rsaKey = RSA.import_key(key)
dictionary[user['username']] = rsaKey
except ValueError:
print('Invalid server public key!')
return dictionary
def loadServerPrivateKey(self, passphrase: str) -> RsaKey:
with open(self.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file)
key = data['serverPrivateKey']
key = bytes.fromhex(key)
try:
rsaKey = RSA.import_key(key, passphrase)
except ValueError:
print('Invalid server private key!')
return rsaKey

View File

@ -1,6 +1,8 @@
from authentication import Authetication
import config_init as init
import json
import logging
import os
test_logger = logging.getLogger('TEST ')
test_logger.root.setLevel(logging.INFO)
@ -33,7 +35,7 @@ def testAuth(username: str, password: str):
auth.saveUser(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')
else:
test_logger.info('TEST 1 --> Authentication test with VALID :: FAILED')
@ -62,7 +64,58 @@ def testUserExists(username: str, password: str):
logging.info('TEST 2 --> User exists with INVALID user :: PASSED')
def testPersistency():
logging.info('PERSISTENCY TEST')
auth = Authetication()
auth.initConfig()
serverPublicKey = init.generatePrivateKeyForServer(auth, 'admin')
auth.saveUser('alma','alma')
homeDir = auth.login('alma','alma')
init.generatePrivateKeyForUser(auth, 'alma', 'amla', serverPublicKey, init.generateSourceAddress(homeDir))
auth.saveUser('citrom','citrom')
homeDir = auth.login('citrom','citrom')
init.generatePrivateKeyForUser(auth, 'citrom', 'mortic', serverPublicKey, init.generateSourceAddress(homeDir))
auth2 = Authetication()
if auth2.checkUserExists('alma'):
logging.info('TEST 1 --> Persictency test :: PASSED')
else:
logging.info('TEST 1 --> Persictency test :: FAILED')
if auth2.checkUserExists(""):
logging.info('TEST 2 --> Persictency test :: FAILED')
else:
logging.info('TEST 2 --> Persictency test :: PASSED')
if os.path.isdir(auth.HOME_DIRECTORY_LOCATION):
logging.info('TEST 3 --> Persictency test :: PASSED')
else:
logging.info('TEST 3 --> Persictency test :: FAILED')
if os.path.isdir(auth.CONFIG_DIRECTORY_LOCATION):
logging.info('TEST 4 --> Persictency test :: PASSED')
else:
logging.info('TEST 4 --> Persictency test :: FAILED')
if os.path.isfile(auth.CONFIG_FILE_LOCATION):
logging.info('TEST 5 --> Persictency test :: PASSED')
else:
logging.info('TEST 5 --> Persictency test :: FAILED')
if os.stat(auth.CONFIG_FILE_LOCATION).st_size > 0:
logging.info('TEST 6 --> Persictency test :: PASSED')
else:
logging.info('TEST 6 --> Persictency test :: FAILED')
if os.path.isdir(auth.PRIVATE_KEY_DIRECTORY_LOCATION):
logging.info('TEST 7 --> Persictency test :: PASSED')
else:
logging.info('TEST 7 --> Persictency test :: FAILED')
if __name__ == '__main__':
testSaveUser("Diósbejglia", "Diósbejgli")
testAuth("Diósbejglia", "Diósbejgli")
testUserExists("Diósbejglia", "Diósbejgli")
#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

72
server/config_init.py Normal file
View File

@ -0,0 +1,72 @@
#!/usr/bin/env python3
import json
import os
from Crypto.PublicKey import RSA
from authentication import Authetication
def generatePrivateKeyForUser(auth: Authetication,username: str, user_passphrase: str, public_server_key: str,address: str) -> bool:
if auth.checkUserExists(username):
with open(auth.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file)
private_key = RSA.generate(8192)
public_key = private_key.publickey()
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))
##Save private key in separate file
user_privatekey = {'address': address,
'privateClientKey': private_key_value,
'publicServerKey': public_server_key}
with open(auth.PRIVATE_KEY_DIRECTORY_LOCATION + os.path.sep + str(data['index']) + '.txt',
'w+') as outfile:
json.dump(user_privatekey, outfile)
outfile.close()
##Save public key in users
for user in data['user']:
if username == user['username']:
user['publicKey'] = public_key_value
with open(auth.CONFIG_FILE_LOCATION, 'w+') as outfile:
json.dump(data, outfile)
break
outfile.close()
return True
else:
return False
def generatePrivateKeyForServer(auth: Authetication,passphrase: str) -> str:
with open(auth.CONFIG_FILE_LOCATION) as json_file:
data = json.load(json_file)
json_file.close()
private_key = RSA.generate(8192)
public_key = private_key.publickey()
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))
data['serverPrivateKey'] = private_key_value
with open(auth.CONFIG_FILE_LOCATION, 'w+') as outfile:
json.dump(data, outfile)
return public_key_value
def generateSourceAddress(index: str) -> chr:
return chr(ord(index[0]) + 17)
if __name__ == '__main__':
auth = Authetication()
auth.initConfig()
serverPublicKey = generatePrivateKeyForServer(auth, 'admin')
auth.saveUser('alma', 'alma')
homeDir = auth.login('alma', 'alma')
generatePrivateKeyForUser(auth, 'alma', 'amla', serverPublicKey, generateSourceAddress(homeDir))
auth.saveUser('citrom', 'citrom')
homeDir = auth.login('citrom', 'citrom')
generatePrivateKeyForUser(auth, 'citrom', 'mortic', serverPublicKey, generateSourceAddress(homeDir))

View File

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

View File

@ -1,4 +1,7 @@
#!/usr/bin/env python3
from server import Server
if __name__ == '__main__':
print("hi")
server = Server()
server.initServer()
server.startServer()

View File

@ -1 +1,186 @@
#!/usr/bin/env python3
import json
from base64 import b64encode, b64decode
import pyDH
from Crypto.Hash import SHA512
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Cipher import ChaCha20_Poly1305
from Crypto.PublicKey.RSA import RsaKey
from Crypto.Signature import pkcs1_15
from netsim import network_interface
from authentication import Authetication
class NetWrapper:
def __init__(self, clientPublicKey: dict, serverPrivateKey: RsaKey, authenticationInstance: Authetication):
self.clientPublicKey = clientPublicKey
self.currentClientPublicKey = "".encode('UTF-8')
self.serverPrivateKey = serverPrivateKey
self.cipherkey = "".encode('UTF-8')
self.network = network_interface('./../../netsim/network/', 'A')
self.clientAddr = ""
self.currentUser = ""
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:
incommingJson = json.loads(msg.decode('UTF-8'))
header = json.loads(b64decode(incommingJson['header']).decode('UTF-8'))
self.clientAddr = header['source']
self.currentUser = header['username']
self.currentClientPublicKey = self.clientPublicKey[self.currentUser]
if not self.verifyRSAHeaderSignature(b64decode(incommingJson['header']),
b64decode(incommingJson['headersignature'])) or header[
'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(
{'header': b64encode(retheader).decode('UTF-8'),
'headersignature': b64encode(retheadersignature).decode('UTF-8'),
'message': b64encode(retmsg).decode('UTF-8')}).encode(
'UTF-8')
self.network.send_msg(self.clientAddr, identMsg)
def sendMessage(self, message: bytes) -> None:
self.sendTypedMessage(message, "CMD")
def sendTypedMessage(self, message: bytes, type: str) -> None:
if not (type == "AUT" or type == "CMD"):
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')
self.network.send_msg(self.clientAddr, sendjson)
def keyExchange(self) -> None:
dh = pyDH.DiffieHellman()
mypubkey = self.encryptRSAMessage(str(dh.gen_public_key()).encode('UTF-8'))
header, headersignature = self.signRSAHeader("DH", {})
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)
status, msg = self.network.receive_msg(blocking=True)
if not status:
raise Exception('Network error during connection.')
decodedmsg = json.loads(msg.decode('UTF-8'))
header = json.loads(b64decode(decodedmsg['header']).decode('UTF-8'))
if not self.verifyRSAHeaderSignature(b64decode(decodedmsg['header']),
b64decode(decodedmsg['headersignature'])) or not (
header['source'] == self.clientAddr and header['type'] == 'DH'):
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:
status, msg = self.network.receive_msg(blocking=True)
if not status:
raise Exception('Network error during connection.')
cleartext = self.recieveEncryptedMessage(msg, "AUT").decode('UTF-8')
if cleartext == "ERROR":
return False
else:
plaintext = cleartext.split(' ')
self.homeDirectory = self.authenticationInstance.login(plaintext[1], plaintext[2])
linsuccess = (not (len(plaintext) != 3 or plaintext[0] != "LIN" or plaintext[
1] != self.currentUser)) and self.homeDirectory
if linsuccess:
message = "OK".encode('UTF-8')
else:
message = "ERROR".encode('UTF-8')
self.sendTypedMessage(message, "AUT")
return linsuccess
def initClientConnection(self, msg: bytes) -> bytes:
print('A client is trying to connect')
try:
print('Server and Client identity verification started')
self.serverIdentify(msg)
print('Key exchange started')
self.keyExchange()
print('Authorization started')
success = self.login()
print(f'Authorization completed, success: {success}')
if success:
return "LINOK".encode('UTF-8')
else:
self.logout()
return "LINERROR".encode('UTF-8')
except Exception:
print("Error ecountered, resetting")
self.logout()
return "LINERROR".encode('UTF-8')
def recieveMessage(self) -> bytes:
status, msg = self.network.receive_msg(blocking=True)
if not status:
raise Exception('Network error during connection.')
if not self.clientAddr:
return self.initClientConnection(msg)
else:
return self.recieveEncryptedMessage(msg, "CMD")
def logout(self) -> None:
self.clientAddr = ""
self.cipherkey = "".encode('UTF-8')
self.currentClientPublicKey = "".encode('UTF-8')
self.currentUser = ""
self.homeDirectory = ""
def recieveEncryptedMessage(self, msg: bytes, type: str) -> bytes:
if not (type == "AUT" or type == "CMD"):
raise Exception('Unknown message type')
try:
b64 = json.loads(msg.decode('UTF-8'))
retheader = json.loads(b64decode(b64['header']).decode('UTF-8'))
retnonce = b64decode(b64['nonce'])
retciphertext = b64decode(b64['message'])
rettag = b64decode(b64['tag'])
retcipher = ChaCha20_Poly1305.new(key=self.cipherkey, nonce=retnonce)
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:
print("Incorrect decryption")
return "ERROR".encode('UTF-8')

View File

@ -1,2 +1,127 @@
#!/usr/bin/env python3
import os
from authentication import Authetication
from executor import Executor
from netwrapper import NetWrapper
class Server:
def __init__(self, sessionTimeout: int = 120, availableServer: bool = True):
self.isAuthenticated = False
self.sessionTimeout = sessionTimeout
self.availableServer = availableServer
self.executor = Executor("")
self.auth = Authetication()
def initServer(self):
print("Please enter your private key passphrase")
passphrase = input()
self.networkInstance = NetWrapper(self.auth.loadUserPublicKeys(), self.auth.loadServerPrivateKey(passphrase),
self.auth)
def login(self, homeDir: str) -> None:
self.isAuthenticated = True
self.executor = Executor(homeDir + os.path.sep)
def logout(self) -> None:
self.networkInstance.logout()
self.isAuthenticated = False
self.availableServer = False
self.executor = Executor("")
def parseCommand(self, command: str) -> None:
if command == "LINOK":
self.login(self.networkInstance.homeDirectory)
self.networkInstance.sendMessage("OK".encode('UTF-8'))
return None
elif command == "LINERROR":
return None
elif command == "ERROR":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
return None
parsedCommand = command.split(" ")
if len(parsedCommand) > 3:
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
elif len(parsedCommand) == 1:
self.execute(parsedCommand[0])
elif len(parsedCommand) == 2:
self.execute(parsedCommand[0], parsedCommand[1])
elif len(parsedCommand) == 3:
self.execute(parsedCommand[0], parsedCommand[1], parsedCommand[2])
def execute(self, command: str, firstParam: str = "", secondParam: str = "") -> None:
if self.executor.baseDir == "":
raise Exception("Home directory must not be empty string. Did the user log in?")
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 != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.executor.createDirectory(firstParam)
self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "RMD":
if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.executor.removeDirectory(firstParam)
self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "GWD":
if not (secondParam == "" and firstParam == ""):
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.networkInstance.sendMessage(self.executor.getCurrentDirectory().encode('UTF-8'))
elif command == "CWD":
if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.executor.setCurrentDirectory(firstParam)
self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "LST":
if not (secondParam == "" and firstParam == ""):
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.networkInstance.sendMessage(self.executor.listCurrentDirectoryContent().encode('UTF-8'))
elif command == "RMF":
if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.executor.removeFileInCurrentDirectory(firstParam)
self.networkInstance.sendMessage("OK".encode('UTF-8'))
elif command == "UPL":
if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
fileMessage = self.networkInstance.recieveMessage()
eof = self.networkInstance.recieveMessage().decode('UTF-8')
if eof == "EOF":
self.executor.putFileInCurrentDirectory(firstParam, fileMessage)
self.networkInstance.sendMessage("OK".encode('UTF-8'))
else:
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
elif command == "DNL":
if secondParam != "":
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
try:
file = self.executor.getFileInCurrentDirectory(firstParam)
self.networkInstance.sendMessage(file)
self.networkInstance.sendMessage("EOF".encode('UTF-8'))
except Exception:
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
else:
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
def startServer(self):
while True:
try:
message = self.networkInstance.recieveMessage().decode('UTF-8')
self.parseCommand(message)
except Exception as e:
self.networkInstance.sendMessage("ERROR".encode('UTF-8'))
print(e)