delivery1 finished
- tests added - changes - decryption not fully working Co-authored-by: Tiago Garcia <tiago.rgarcia@ua.pt> Co-authored-by: João Bastos <joaop.bastos@ua.pt>
This commit is contained in:
parent
7bef5b468c
commit
e00c032df8
|
@ -51,13 +51,14 @@ def addDoc(args):
|
|||
args.session = json.load(f)
|
||||
|
||||
#Encrypt content
|
||||
key, nonce = encrypt_file(BASE_DIR + args.file, BASE_DIR + 'encryptedText')
|
||||
key, content, nonce = encrypt_file(BASE_DIR + args.file, BASE_DIR + 'encryptedText')
|
||||
|
||||
#Upload document metadata
|
||||
doc = {'document_name' : args.name, 'key' : key, 'alg' : 'AES-CFB', 'nonce' : nonce }
|
||||
doc = {'document_name' : args.name, 'key' : key.hex(), 'alg' : 'AES-CFB', 'nonce' : nonce.hex() }
|
||||
|
||||
try:
|
||||
req = requests.post(f'http://{state['REP_ADDRESS']}/file/upload', json=json.dumps(doc), headers={'Authorization': args.session['token']})
|
||||
req = requests.post(f'http://{state['REP_ADDRESS']}/file/upload/metadata', json=json.dumps(doc),
|
||||
headers={'Authorization': args.session['token']})
|
||||
req.raise_for_status()
|
||||
|
||||
except requests.exceptions.RequestException as errex:
|
||||
|
@ -65,16 +66,12 @@ def addDoc(args):
|
|||
sys.exit(-1)
|
||||
|
||||
#Upload Document content
|
||||
|
||||
with open(BASE_DIR + 'encryptedText', 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
file = {'file' : open(BASE_DIR + args.file, 'rb')}
|
||||
file = {'file' : (BASE_DIR + args.file, content)}
|
||||
|
||||
try:
|
||||
req = requests.post(f'http://{state['REP_ADDRESS']}/file/upload',
|
||||
req = requests.post(f'http://{state['REP_ADDRESS']}/file/upload/content',
|
||||
files=file,
|
||||
headers={'Authorization': args.session['token'], 'File-Checksum' : content.hex()})
|
||||
headers={'Authorization': args.session['token'], 'File-Checksum' : digest.get_hash(content)})
|
||||
req.raise_for_status()
|
||||
|
||||
except requests.exceptions.RequestException as errex:
|
||||
|
|
|
@ -8,7 +8,8 @@ import argparse
|
|||
|
||||
from subject import main
|
||||
|
||||
from lib import encryption_functs
|
||||
sys.path.append(os.path.abspath('../../'))
|
||||
from lib import asymmetric_functs
|
||||
|
||||
logging.basicConfig(format='%(levelname)s\t- %(message)s')
|
||||
logger = logging.getLogger()
|
||||
|
@ -50,7 +51,9 @@ def addSubject(args):
|
|||
logger.error("File '" + args.file + "' not found")
|
||||
sys.exit(1)
|
||||
|
||||
subject = {'username' : args.username, 'name' : args.name, 'email' : args.email, 'credentials_file' : args.credentials}
|
||||
pubKey = asymmetric_functs.load_public_key(BASE_DIR + args.credentials)
|
||||
|
||||
subject = {'username' : args.username, 'full_name' : args.name, 'email' : args.email, 'public_key' : pubKey}
|
||||
|
||||
try:
|
||||
req = requests.post(f'http://{state['REP_ADDRESS']}/user/create', json=json.dumps(subject), headers={'Authorization': args.session['token']})
|
||||
|
|
|
@ -56,7 +56,7 @@ def createSession(args):
|
|||
sys.exit(-1)
|
||||
|
||||
with open(BASE_DIR + args.session, 'w') as f:
|
||||
f.write(req.json())
|
||||
json.dump(req.json(), f)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import logging
|
|||
import argparse
|
||||
import json
|
||||
|
||||
sys.path.append(os.path.abspath("../../"))
|
||||
from lib import symmetric_encryption
|
||||
|
||||
logging.basicConfig(format='%(levelname)s\t- %(message)s')
|
||||
|
@ -33,14 +34,15 @@ def decryptFile(args):
|
|||
logger.error("File '" + args.encrypted + "' not found.")
|
||||
sys.exit(1)
|
||||
|
||||
if (not os.path.isfile(BASE_DIR + args.metadata)):
|
||||
logger.error("File '" + args.metadata + "' not found.")
|
||||
sys.exit(1)
|
||||
# if (not os.path.isfile(BASE_DIR + args.metadata)):
|
||||
# logger.error("File '" + args.metadata + "' not found.")
|
||||
# sys.exit(1)
|
||||
|
||||
#Decrypt file
|
||||
metadata = json.loads(BASE_DIR + args.metadata)
|
||||
print(args.metadata)
|
||||
metadata = json.loads(args.metadata)
|
||||
|
||||
content = symmetric_encryption.decrypt_file(args.encrypted)
|
||||
content = symmetric_encryption.decrypt_file(metadata['nonce'].encode(), metadata['key'].encode(), BASE_DIR + args.encrypted)
|
||||
|
||||
# Send decrypted content to stdout
|
||||
sys.stdout.write(content)
|
||||
|
|
|
@ -5,6 +5,8 @@ import logging
|
|||
import requests
|
||||
import json
|
||||
import argparse
|
||||
|
||||
sys.path.append(os.path.abspath("../../"))
|
||||
from lib import digest
|
||||
|
||||
from subject import main
|
||||
|
@ -43,7 +45,6 @@ def delDoc(args):
|
|||
args.session = json.load(f)
|
||||
|
||||
doc_name = digest.get_hash(bytes(args.name, encoding='utf-8'))
|
||||
doc = {'document_name' : doc_name}
|
||||
|
||||
try:
|
||||
req = requests.post(f'http://{state['REP_ADDRESS']}/file/delete/' + doc_name, headers={'Authorization': args.session['token']})
|
||||
|
|
|
@ -8,6 +8,7 @@ import argparse
|
|||
|
||||
from subject import main
|
||||
|
||||
sys.path.append(os.path.abspath("../../"))
|
||||
from lib import digest
|
||||
from lib import symmetric_encryption
|
||||
|
||||
|
@ -47,10 +48,10 @@ def getDoc(args):
|
|||
|
||||
# Get Document metadata
|
||||
|
||||
doc_name = digest.get_hash(args.name)
|
||||
doc_name = digest.get_hash(bytes(args.name, encoding='utf-8'))
|
||||
|
||||
try:
|
||||
metadata = requests.post(f'http://{state['REP_ADDRESS']}/file/' + doc_name, headers={'Authorization': args.session['token']})
|
||||
metadata = requests.get(f'http://{state['REP_ADDRESS']}/file/get/' + doc_name + '/metadata', headers={'Authorization': args.session['token']})
|
||||
metadata.raise_for_status()
|
||||
|
||||
except requests.exceptions.RequestException as errex:
|
||||
|
@ -76,7 +77,6 @@ def getDoc(args):
|
|||
|
||||
content = symmetric_encryption.decrypt_file(file)
|
||||
|
||||
|
||||
if args.output:
|
||||
with open(BASE_DIR + args.output, 'w') as f:
|
||||
f.write(content)
|
||||
|
|
|
@ -5,6 +5,8 @@ import logging
|
|||
import requests
|
||||
import json
|
||||
import argparse
|
||||
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
from lib import digest
|
||||
|
||||
from subject import main
|
||||
|
@ -46,16 +48,15 @@ def getDocMetadata(args):
|
|||
doc_name = digest.get_hash(bytes(args.name, encoding='utf-8'))
|
||||
|
||||
try:
|
||||
metadata = requests.post(f'http://{state['REP_ADDRESS']}/file/' + doc_name + '/metadata', headers={'Authorization': args.session['token']})
|
||||
metadata = requests.get(f'http://{state['REP_ADDRESS']}/file/get/' + doc_name + '/metadata', headers={'Authorization': args.session['token']})
|
||||
metadata.raise_for_status()
|
||||
|
||||
except requests.exceptions.RequestException as errex:
|
||||
logger.error("Failed to obtain response from server.")
|
||||
sys.exit(-1)
|
||||
|
||||
metadata = metadata.json()
|
||||
|
||||
sys.stdout.write(metadata)
|
||||
sys.stdout.write(json.dumps(metadata))
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
@ -37,26 +37,26 @@ def getFile(args):
|
|||
if not args.filehandle:
|
||||
logger.error("Need a file handle.")
|
||||
sys.exit(1)
|
||||
else:
|
||||
if not os.path.isfile(BASE_DIR + args.filehandle):
|
||||
logger.error("File '" + args.filehandle + "' not found" )
|
||||
sys.exit(1)
|
||||
#else:
|
||||
# if not os.path.isfile(BASE_DIR + args.filehandle):
|
||||
# logger.error("File '" + args.filehandle + "' not found" )
|
||||
# sys.exit(1)
|
||||
|
||||
#Get file
|
||||
try:
|
||||
file = requests.get(f'http://{state['REP_ADDRESS']}/get/' + args.file_handle + '/content')
|
||||
file = requests.get(f'http://{state['REP_ADDRESS']}/file/get/' + args.filehandle + '/content')
|
||||
file.raise_for_status()
|
||||
except requests.exceptions.RequestException as errex:
|
||||
logger.error("Failed to obtain response from server.")
|
||||
sys.exit(-1)
|
||||
|
||||
file = file.json()
|
||||
print(file)
|
||||
|
||||
if not args.file:
|
||||
sys.stdout.write(file)
|
||||
sys.stdout.write(file.text)
|
||||
else:
|
||||
with open(BASE_DIR + args.file, "wb") as f:
|
||||
f.write(file)
|
||||
f.write(file.content)
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
@ -65,9 +65,8 @@ def list_subjects(args):
|
|||
logger.error("Failed to obtain response from server.")
|
||||
sys.exit(-1)
|
||||
|
||||
for s in subjects.json():
|
||||
sys.stdout.write(s['id'] + " - " + s['username'])
|
||||
|
||||
for s,d in subjects.json().items():
|
||||
sys.stdout.write(s + " - " + d['username'] + "\n")
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
import json
|
||||
import os, subprocess, sys
|
||||
|
||||
import requests
|
||||
|
||||
DELIVERY_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
|
||||
FILES_PATH = os.path.join(os.path.expanduser('~'), '.sio/')
|
||||
|
||||
# !!! database.db must be deleted/reset before running the tests !!!
|
||||
requests.post("http://localhost:5000/reset", json={"password": "123"})
|
||||
os.system(f"rm {FILES_PATH}*")
|
||||
|
||||
def test_address_set():
|
||||
# Initialize the server path on state.json
|
||||
process = subprocess.Popen(f"python3 {DELIVERY_PATH}/client/bin/subject.py -r localhost:5000 ", shell=True)
|
||||
process.wait()
|
||||
assert os.path.exists(os.path.join(FILES_PATH, 'state.json'))
|
||||
|
||||
|
||||
def test_rep_subject_credentials():
|
||||
# Test the rep_subject_create command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_subject_credentials password pub.pem priv.pem ", shell=True)
|
||||
process.wait()
|
||||
assert os.path.exists(os.path.join(FILES_PATH, 'pub.pem')) and os.path.exists(os.path.join(FILES_PATH, 'priv.pem'))
|
||||
|
||||
|
||||
def test_rep_create_org():
|
||||
# Test the rep_create_org command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_create_org org1 username name email@org.com pub.pem", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
|
||||
def test_rep_list_orgs():
|
||||
# Test the list_orgs command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_list_orgs", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
|
||||
def test_rep_create_session():
|
||||
# Test the rep_create_session command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_create_session org1 username password pub.pem session.json", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
|
||||
def test_rep_list_subjects():
|
||||
#Test the rep_list_subjects command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_list_subjects session.json", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
def test_rep_add_subject():
|
||||
# Test the rep_subject_create command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_subject_credentials password pub_extra.pem priv_extra.pem ", shell=True)
|
||||
process.wait()
|
||||
assert os.path.exists(os.path.join(FILES_PATH, 'pub_extra.pem')) and os.path.exists(os.path.join(FILES_PATH, 'priv_extra.pem'))
|
||||
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_add_subject session.json username2 name2 name2@any.com pub_extra.pem", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
|
||||
def test_rep_suspend_subject():
|
||||
# Test the rep_suspend_subject command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_suspend_subject session.json username2", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
|
||||
def test_rep_activate_subject():
|
||||
# Test the rep_activate_subject command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_activate_subject session.json username2", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
|
||||
def test_rep_add_doc():
|
||||
# Test the rep_add_doc command
|
||||
process = subprocess.Popen(f"dd if=/dev/urandom of={FILES_PATH}test.txt bs=1024 count=1000 ", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_add_doc session.json doc test.txt ", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
metadata = {}
|
||||
|
||||
def test_rep_get_doc_metadata():
|
||||
# Test the rep_get_doc_metadata command
|
||||
global metadata
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_get_doc_metadata session.json doc", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
process.wait()
|
||||
stdout, stderr = process.communicate()
|
||||
metadata = json.loads(stdout)
|
||||
assert process.returncode == 0
|
||||
|
||||
def test_rep_get_file():
|
||||
# Test the rep_get_file command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_get_file {metadata['file_handle']} file.txt ", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
def test_decrypt_file():
|
||||
# Test the rep_decrypt_file command
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_decrypt_file file.txt '{json.dumps(metadata)}'", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
def test_rep_get_doc_file():
|
||||
# Test the rep_get_doc_file
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_get_doc_file session.json doc ", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
def test_rep_delete_doc():
|
||||
# Test the rep_get_doc_file
|
||||
process = subprocess.Popen(f"{DELIVERY_PATH}/client/bin/rep_delete_doc session.json doc ", shell=True)
|
||||
process.wait()
|
||||
assert process.returncode == 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -4,57 +4,43 @@ from cryptography.hazmat.primitives import hashes
|
|||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
|
||||
# Function to derive a 256-bit key from a password and salt
|
||||
def derive_key(salt):
|
||||
kdf = PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=salt,
|
||||
iterations=10000,
|
||||
backend=default_backend()
|
||||
)
|
||||
return kdf.derive(b'')
|
||||
|
||||
|
||||
# Function to encrypt a file using a salt
|
||||
def encrypt_file(input_file, output_file=None):
|
||||
salt = os.urandom(16)
|
||||
key = derive_key(salt)
|
||||
key = os.urandom(16)
|
||||
iv = os.urandom(16)
|
||||
nonce = os.urandom(16)
|
||||
|
||||
cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend())
|
||||
cipher = Cipher(algorithms.AES(key), modes.CFB(iv))
|
||||
encryptor = cipher.encryptor()
|
||||
|
||||
with open(input_file, 'rb') as f:
|
||||
plaintext = f.read()
|
||||
|
||||
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
|
||||
ciphertext = iv + ciphertext
|
||||
|
||||
if output_file is not None:
|
||||
with open(output_file, 'wb') as f:
|
||||
f.write(salt + iv + ciphertext)
|
||||
f.write(ciphertext)
|
||||
|
||||
return salt + iv + ciphertext, nonce
|
||||
print(iv.hex())
|
||||
|
||||
return key, ciphertext, iv
|
||||
|
||||
|
||||
# Function to decrypt a file
|
||||
def decrypt_file(input_file, output_file=None):
|
||||
def decrypt_file(nonce, key, input_file, output_file=None):
|
||||
with open(input_file, 'rb') as f:
|
||||
encrypted_data = f.read()
|
||||
|
||||
salt = encrypted_data[:16]
|
||||
iv = encrypted_data[16:32]
|
||||
ciphertext = encrypted_data[32:]
|
||||
ciphertext = encrypted_data
|
||||
|
||||
key = derive_key(salt)
|
||||
cipher = Cipher(algorithms.AES(key), modes.CFB(iv), backend=default_backend())
|
||||
cipher = Cipher(algorithms.AES(key), modes.CFB(nonce))
|
||||
decryptor = cipher.decryptor()
|
||||
|
||||
plaintext = decryptor.update(ciphertext) + decryptor.finalize()
|
||||
|
||||
if output_file is None:
|
||||
return plaintext
|
||||
else:
|
||||
if output_file is not None:
|
||||
with open(output_file, 'wb') as f:
|
||||
f.write(plaintext)
|
||||
|
||||
return plaintext.hex()
|
||||
|
|
|
@ -83,14 +83,16 @@ def file_upload_content():
|
|||
if not file:
|
||||
return jsonify({"error": "Invalid file data"}), 400
|
||||
|
||||
file_data = utils.get_hex_from_temp_file(file.stream)
|
||||
|
||||
file_sum = request.headers.get("File-Checksum")
|
||||
if not file_sum:
|
||||
return jsonify({"error": "No file checksum provided"}), 400
|
||||
|
||||
if file_sum != utils.get_hash(file.stream):
|
||||
if file_sum != str(utils.get_hash(file_data)):
|
||||
return jsonify({"error": "File checksum mismatch"}), 400
|
||||
|
||||
file = upload_service.write_file(session_token, file.stream)
|
||||
file = upload_service.write_file(session_token, file_sum, file_data)
|
||||
if isinstance(file, tuple):
|
||||
return file
|
||||
|
||||
|
|
|
@ -28,24 +28,24 @@ class FileService:
|
|||
creator = user
|
||||
)
|
||||
|
||||
self.current_requests[session_token] = file
|
||||
|
||||
db.add(file)
|
||||
db.commit()
|
||||
db.refresh(file)
|
||||
self.current_requests[session_token] = file.id
|
||||
|
||||
return file
|
||||
|
||||
|
||||
def write_file(self, session_token: str, file_data: bytes) -> File | tuple:
|
||||
def write_file(self, session_token: str, file_handle: str, file_data: bytes) -> File | tuple:
|
||||
if session_token not in self.current_requests:
|
||||
return jsonify({"error": "No file upload request found"}), 400
|
||||
|
||||
file = self.current_requests[session_token]
|
||||
file = db.query(File).filter(File.id == self.current_requests[session_token]).first()
|
||||
file_path = os.path.join(os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "repository"), file.org.name, file.document_handle)
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(file_data)
|
||||
|
||||
file.file_handle = get_hash(file_data)
|
||||
file.file_handle = file_handle
|
||||
db.commit()
|
||||
db.refresh(file)
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
from .checks import check_valid_time
|
||||
from .hashing import get_hash
|
||||
from .hashing import get_hash, get_hex_from_temp_file
|
|
@ -1,8 +1,16 @@
|
|||
from tempfile import SpooledTemporaryFile
|
||||
import cryptography.hazmat.primitives.hashes
|
||||
|
||||
|
||||
def get_hash(data):
|
||||
if isinstance(data, str):
|
||||
data = data.encode('utf-8')
|
||||
digest = cryptography.hazmat.primitives.hashes.Hash(cryptography.hazmat.primitives.hashes.SHA256())
|
||||
digest.update(data)
|
||||
return digest.finalize().hex()
|
||||
|
||||
|
||||
def get_hex_from_temp_file(temp_file: SpooledTemporaryFile) -> bytes:
|
||||
temp_file.seek(0)
|
||||
file_data = temp_file.read()
|
||||
return file_data
|
||||
|
|
Loading…
Reference in New Issue