Compare commits

...

6 Commits

14 changed files with 158 additions and 121 deletions

5
.gitignore vendored
View File

@ -1,6 +1 @@
data/decrypted/group_files/*
data/decrypted/user_files/*
data/encrypted/group_files/*
data/encrypted/user_files/*
accumulated.json*
__pycache__

View File

@ -18,13 +18,12 @@ echo2 foxtrott
asfdasd@sdskjd.de
street in strasdlasöd
END_OF_INPUTS
python scripts/main.py --mode decrypt --master-password "ewrwerwerew" &&
python scripts/main.py --mode decrypt --user "1"
python scripts/main.py --mode decrypt --master-password "ewrwerwerew"
python scripts/main.py --mode cleanup --file-types decrypted && python scripts/main.py --mode decrypt --user "1" --user-password "O3ITMWXZED9FKYQ0PB2WNVRWSCSCYVXCD00PJ6GQ4MFPIUWBVDCYSSSX9ZDBW5QU" << END_OF_INPUTS
python scripts/main.py --mode cleanup --file-types decrypted && python scripts/main.py --mode decrypt --user "1" --user-password "DDB2QYHP4X0PDR0ZX9LBLACNL6VAXLXMNEZJDOOGUTENSI6UDYGPOR5CV01YLI49" << END_OF_INPUTS
2
YGC6FLI5FIFL4WV4JPZZI7RVOZTWLROCLY4HVGDMWWSTAIQJTLUQK1VBBY0E24PN
EOQXCYGEY2IMKAJP5VOCRVRH9LPYAPK9IC0ID0GMSJ5KXNXJHPNUBUKEVLE2WHQJ
END_OF_INPUTS
```
# Requirements to know
@ -39,14 +38,16 @@ END_OF_INPUTS
```bash
pip install numpy
gpg
ecryptfs-utils
ecryptfs-simple
python
pip
```
## todo
- implement tails setup script
- implement relativ call
- implement tmp mount for decrypted files
- add data-input attribut
- add data-output attribut
## Further Information
- https://www.tutorialspoint.com/python/python_command_line_arguments.htm
@ -55,3 +56,4 @@ END_OF_INPUTS
- https://pynative.com/python-generate-random-string/
- https://www.studimup.de/abitur/stochastik/anzahl-der-m%C3%B6glichketen-berechnen-kombinatorik/
- https://numpy.org/doc/stable/reference/generated/numpy.base_repr.html?highlight=base_repr#numpy.base_repr
- https://linuxconfig.org/how-to-create-compressed-encrypted-archives-with-tar-and-gpg

2
data/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.gpg
*.txt

3
data/decrypted/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
main_data/*
*.json
*.txt

1
data/decrypted/group_files/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.txt

1
data/decrypted/user_files/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.json

1
data/encrypted/group_files/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.gpg

1
data/encrypted/user_files/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.gpg

View File

@ -1,45 +0,0 @@
from .Cli import Cli
class AbstractSplittedSecret(Cli):
USER_PASSWORD_LENGTHS = 64
OVERALL_PASSWORD_LENGTHS = 128
# At the moment the programm can used deal with one digit numbers.
MAXIMUM_SECRET_HOLDERS = 9
MINIMUM_SECRET_HOLDERS = 2
TYPE_ENCRYPTED="encrypted"
TYPE_DECRYPTED="decrypted"
def __init__(self):
super(Cli, self).__init__()
self.data_folder = "data/"
def getCoSecretHoldersRange():
return range(AbstractSplittedSecret.MINIMUM_SECRET_HOLDERS,AbstractSplittedSecret.MAXIMUM_SECRET_HOLDERS)
def getSecretHoldersRange():
return range(1,AbstractSplittedSecret.MAXIMUM_SECRET_HOLDERS)
def getFolderPath(self,folder_type):
return self.data_folder + folder_type + "/"
def getGroupFilesFolderPath(self,folder_type):
return self.getFolderPath(folder_type) + "group_files/"
def getUserFilesFolderPath(self,folder_type):
return self.getFolderPath(folder_type) + "user_files/"
def getFileExtension(self,file_type):
if file_type == AbstractSplittedSecret.TYPE_ENCRYPTED:
return '.gpg'
return ''
def getUserFilePath(self,user_id,file_type):
return self.getUserFilesFolderPath(file_type)+user_id+'.json' + self.getFileExtension(file_type);
def getGroupFilePath(self,group_id,file_type):
return self.getGroupFilesFolderPath(file_type) + str(group_id) + '.txt' + self.getFileExtension(file_type);
def getAccumulatedFilePath(self,file_type):
return self.getFolderPath(file_type) + 'accumulated.json' + self.getFileExtension(file_type);

View File

@ -1,20 +1,25 @@
from .AbstractSplittedSecret import AbstractSplittedSecret
class Cleanup(AbstractSplittedSecret):
def __init__(self):
super(Cleanup, self).__init__()
from .Paths import Paths
class Cleanup():
def __init__(self,cli,paths):
self.cli = cli
self.paths = paths
def getAllFilePaths(self,file_type):
return [
self.getGroupFilesFolderPath(file_type),
self.getUserFilesFolderPath(file_type),
self.getAccumulatedFilePath(file_type)
all_file_paths = [
self.paths.getGroupFilesFolderPath(file_type),
self.paths.getUserFilesFolderPath(file_type),
self.paths.getAccumulatedFilePath(file_type)
]
if file_type == Paths.TYPE_DECRYPTED:
all_file_paths.append(self.paths.getDecryptedMainDataStandartFolder())
return all_file_paths
def deleteAllFilesInFolder(self,folder_path):
try:
self.executeCommand('rm -v ' + folder_path + '*')
except:
pass
self.cli.executeCommand('rm -r ' + folder_path + '*')
except Exception as error:
print(error)
def cleanupFiles(self,file_type):
for folder_path in self.getAllFilePaths(file_type):
@ -22,11 +27,11 @@ class Cleanup(AbstractSplittedSecret):
def cleanupForUser(self,user):
try:
self.executeCommand('find "' + self.getFolderPath(AbstractSplittedSecret.TYPE_ENCRYPTED) + '" -not -name "*' + str(user) +'*" -type f -print | xargs rm -v')
except:
pass
self.cleanupFiles(AbstractSplittedSecret.TYPE_DECRYPTED)
self.cli.executeCommand('find "' + self.paths.getDataFolderPath(Paths.TYPE_ENCRYPTED) + '" -not -name "*' + str(user) +'*" -type f -print | xargs rm -v')
except Exception as error:
print(error)
self.cleanupFiles(Paths.TYPE_DECRYPTED)
def deleteAll(self):
self.cleanupFiles(AbstractSplittedSecret.TYPE_ENCRYPTED)
self.cleanupFiles(AbstractSplittedSecret.TYPE_DECRYPTED)
self.cleanupFiles(Paths.TYPE_ENCRYPTED)
self.cleanupFiles(Paths.TYPE_DECRYPTED)

View File

@ -1,16 +1,17 @@
from .AbstractSplittedSecret import AbstractSplittedSecret
import json
from pathlib import Path
class Decryption(AbstractSplittedSecret):
def __init__(self):
class Decryption():
def __init__(self,cli,paths):
self.user_id='0';
self.user_password=''
super(Decryption, self).__init__()
self.cli = cli
self.paths = paths
def initializeUser(self,user_id):
self.user_id=str(user_id)
self.user_file_decrypted_path = self.getUserFilePath(self.user_id,AbstractSplittedSecret.TYPE_DECRYPTED)
self.user_file_decrypted_path = self.paths.getUserFilePath(self.user_id,self.paths.TYPE_DECRYPTED)
def initializeUserDataDecryption(self):
self.decryptUserFile()
@ -20,9 +21,9 @@ class Decryption(AbstractSplittedSecret):
def initializeGroupDataEncryption(self):
self.group_name = self.getDecryptersGroupName()
self.encrypted_group_file_path = self.getGroupFilePath(self.group_name, AbstractSplittedSecret.TYPE_DECRYPTED)
self.encrypted_group_file_path = self.paths.getGroupFilePath(self.group_name, self.paths.TYPE_DECRYPTED)
self.decryptGroupFile()
self.master_password = self.loadTxtFile(self.encrypted_group_file_path)
self.master_password = self.loadTxtFile(self.encrypted_group_file_path).strip()
def initializeNeededDecryptersAmount(self):
self.needed_decrypters_amount = len(str(list(self.user_data['groups'].keys())[0]))
@ -97,17 +98,20 @@ class Decryption(AbstractSplittedSecret):
return data
def decryptFile(self,password,input_file_path,output_file_path):
self.executeCommand('gpg --batch --passphrase "'+ password + '" -o "' + output_file_path +'" "'+ input_file_path+'"')
self.cli.executeCommand('gpg --batch --passphrase "'+ password + '" -o "' + output_file_path +'" "'+ input_file_path+'"')
def decryptUserFile(self):
input_file_path = self.getUserFilePath(self.user_id,AbstractSplittedSecret.TYPE_ENCRYPTED)
input_file_path = self.paths.getUserFilePath(self.user_id,self.paths.TYPE_ENCRYPTED)
self.decryptFile(self.user_password, input_file_path, self.user_file_decrypted_path)
def decryptGroupFile(self):
input_file_path = self.getGroupFilePath(self.group_name, AbstractSplittedSecret.TYPE_ENCRYPTED)
input_file_path = self.paths.getGroupFilePath(self.group_name, self.paths.TYPE_ENCRYPTED)
self.decryptFile(self.getGroupPassword(), input_file_path, self.encrypted_group_file_path)
def decryptAccumulatedFile(self):
input_file_path = self.getAccumulatedFilePath(AbstractSplittedSecret.TYPE_ENCRYPTED)
output_file_path = self.getAccumulatedFilePath(AbstractSplittedSecret.TYPE_DECRYPTED)
input_file_path = self.paths.getAccumulatedFilePath(self.paths.TYPE_ENCRYPTED)
output_file_path = self.paths.getAccumulatedFilePath(self.paths.TYPE_DECRYPTED)
self.decryptFile(self.user_password, input_file_path, output_file_path)
def decryptMainData(self):
self.cli.executeCommand('gpg --batch --passphrase "' + self.getMasterPassword() + '" -d "' + self.paths.getEncryptedMainDataFile() + '" | tar -xvzf - "' + self.paths.getDecryptedMainDataStandartFolder() + '"')

View File

@ -4,12 +4,18 @@ import math
import numpy
import re
import json
from .AbstractSplittedSecret import AbstractSplittedSecret
from .Paths import Paths
class Encryption(AbstractSplittedSecret):
class Encryption():
def __init__(self, amount_of_secret_holders, decryption_quota,master_password):
super(Encryption, self).__init__()
USER_PASSWORD_LENGTHS = 64
OVERALL_PASSWORD_LENGTHS = 128
# At the moment the programm can only deal with one digit numbers.
MAXIMUM_SECRET_HOLDERS = 9
MINIMUM_SECRET_HOLDERS = 2
def __init__(self, cli, paths, amount_of_secret_holders, decryption_quota,master_password):
self.amount_of_secret_holders = amount_of_secret_holders
self.decryption_quota = decryption_quota
self.master_password = master_password
@ -17,6 +23,8 @@ class Encryption(AbstractSplittedSecret):
self.group_members_amount=math.ceil(self.amount_of_secret_holders * self.quota_factor)
self.initializeUserData()
self.initializeGroupData()
self.cli = cli
self.paths = paths
def initializeUserData(self):
self.user_mapped_data = {}
@ -31,6 +39,12 @@ class Encryption(AbstractSplittedSecret):
def addInformationToUser(self,user_id,label,content):
self.user_mapped_data[user_id]['about'][label] = content;
def getCoSecretHoldersRange():
return range(Encryption.MINIMUM_SECRET_HOLDERS,Encryption.MAXIMUM_SECRET_HOLDERS)
def getSecretHoldersRange():
return range(1,Encryption.MAXIMUM_SECRET_HOLDERS)
def getStartnumber(self):
index = 0
start_number = ''
@ -90,29 +104,33 @@ class Encryption(AbstractSplittedSecret):
index += 1
def encryptStringToFile(self,text,output_file,password):
self.executeCommand('echo \'' + text + '\' | gpg --symmetric --armor --batch --passphrase "' + password + '" -o "' + output_file + '"')
self.cli.executeCommand('echo \'' + text + '\' | gpg --symmetric --armor --batch --passphrase "' + password + '" -o "' + output_file + '"')
def encryptGroupFiles(self):
for password_group_index_int in self.group_mapped_data:
encrypted_group_password_file_path = self.getGroupFilePath(password_group_index_int,AbstractSplittedSecret.TYPE_ENCRYPTED)
encrypted_group_password_file_path = self.paths.getGroupFilePath(password_group_index_int,Paths.TYPE_ENCRYPTED)
self.encryptStringToFile(self.master_password,encrypted_group_password_file_path,self.group_mapped_data[password_group_index_int]['password'])
def encryptToJsonFile(self,data,file_path,password):
self.encryptStringToFile(json.dumps(data,ensure_ascii=False), file_path, password)
def encryptUserData(self):
def encryptUserFile(self):
for user_id in self.user_mapped_data:
file_path=self.getUserFilePath(user_id,AbstractSplittedSecret.TYPE_ENCRYPTED)
file_path=self.paths.getUserFilePath(user_id,Paths.TYPE_ENCRYPTED)
data=self.user_mapped_data[user_id]
password=self.user_mapped_data[user_id]['user_password']
self.encryptToJsonFile(data,file_path,password)
def encryptAccumulatedData(self):
file_path=self.getAccumulatedFilePath(AbstractSplittedSecret.TYPE_ENCRYPTED)
def encryptAccumulatedFile(self):
file_path=self.paths.getAccumulatedFilePath(Paths.TYPE_ENCRYPTED)
data={"user_mapped": self.user_mapped_data, "group_mapped": self.group_mapped_data}
self.encryptToJsonFile(data,file_path,self.master_password)
def encrypt(self):
self.encryptUserData()
self.encryptAccumulatedData()
def encryptMainData(self):
self.cli.executeCommand('tar -cvzf - "' + self.paths.getDecryptedMainDataStandartFolder() + '" | gpg -c --batch --passphrase "' + self.master_password +'" > "' + self.paths.getEncryptedMainDataFile() + '"');
def encryptAll(self):
self.encryptUserFile()
self.encryptAccumulatedFile()
self.encryptGroupFiles()
self.encryptMainData()

40
scripts/classes/Paths.py Normal file
View File

@ -0,0 +1,40 @@
import os
class Paths():
TYPE_ENCRYPTED="encrypted"
TYPE_DECRYPTED="decrypted"
ROOT_PATH= os.path.join(os.path.dirname(os.path.abspath(__file__)),"../","../")
def __init__(self):
self.data_folder = os.path.join(self.ROOT_PATH,"data") + '/'
def getDataFolderPath(self,folder_type):
return self.data_folder + folder_type + "/"
def getGroupFilesFolderPath(self,folder_type):
return self.getDataFolderPath(folder_type) + "group_files/"
def getUserFilesFolderPath(self,folder_type):
return self.getDataFolderPath(folder_type) + "user_files/"
def getEncryptedMainDataFile(self):
return self.getDataFolderPath(Paths.TYPE_ENCRYPTED) + "main_data.tar.gz.gpg"
def getDecryptedMainDataStandartFolder(self):
return self.getDataFolderPath(Paths.TYPE_DECRYPTED) + "main_data/"
def getFileExtension(self,file_type):
if file_type == Paths.TYPE_ENCRYPTED:
return '.gpg'
return ''
def getUserFilePath(self,user_id,file_type):
return self.getUserFilesFolderPath(file_type)+user_id+'.json' + self.getFileExtension(file_type);
def getGroupFilePath(self,group_id,file_type):
return self.getGroupFilesFolderPath(file_type) + str(group_id) + '.txt' + self.getFileExtension(file_type);
def getAccumulatedFilePath(self,file_type):
return self.getDataFolderPath(file_type) + 'accumulated.json' + self.getFileExtension(file_type);

View File

@ -3,23 +3,28 @@ from classes.Encryption import Encryption
from classes.Cleanup import Cleanup
from classes.Decryption import Decryption
from getpass import getpass
from classes.AbstractSplittedSecret import AbstractSplittedSecret
import traceback
from classes.Cli import Cli
from classes.Paths import Paths
cleanup = Cleanup()
cli = Cli()
paths = Paths()
cleanup = Cleanup(cli,paths)
def clean_exit():
print("Cleaning up.")
try:
cleanup.cleanupFiles(AbstractSplittedSecret.TYPE_DECRYPTED)
cleanup.cleanupFiles(Paths.TYPE_DECRYPTED)
except:
pass
print("Leaving program.")
exit()
standard_exit()
def dirty_exit():
print("ATTENTION: SECURITY RISK !!!\nPROGRAM DIDN'T CLEAN UP DECRYPTED DATA. \nDECRYPTED DATA EXISTS AND CAN BE READ BY EVERYBODY!")
print("TO REMOVE DECRYPTED DATA EXECUTE:\nmain.py --mode cleanup --file-types " + AbstractSplittedSecret.TYPE_DECRYPTED)
print("TO REMOVE DECRYPTED DATA EXECUTE:\nmain.py --mode cleanup --file-types " + Paths.TYPE_DECRYPTED)
standard_exit()
def standard_exit():
print("Leaving program.")
exit()
@ -27,12 +32,12 @@ try:
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--mode',type=str, dest='mode',required=True,choices=['cleanup','encrypt','decrypt'])
parser.add_argument('--file-types',type=str, dest='file_types',required=False,choices=[AbstractSplittedSecret.TYPE_DECRYPTED, AbstractSplittedSecret.TYPE_ENCRYPTED])
parser.add_argument('--amount',type=int, dest='amount_of_secret_holders',required=False,choices=AbstractSplittedSecret.getCoSecretHoldersRange())
parser.add_argument('--file-types',type=str, dest='file_types',required=False,choices=[Paths.TYPE_DECRYPTED, Paths.TYPE_ENCRYPTED])
parser.add_argument('--amount',type=int, dest='amount_of_secret_holders',required=False,choices=Encryption.getCoSecretHoldersRange())
parser.add_argument('--quota', type=int, dest='decryption_quota', choices=range(1,101),required=False)
parser.add_argument('--master-password',type=str, dest='master_password',required=False)
parser.add_argument('--user-password',type=str, dest='user_password',required=False)
parser.add_argument('--user',type=int, dest='user',choices=AbstractSplittedSecret.getSecretHoldersRange(),required=False)
parser.add_argument('--user',type=int, dest='user',choices=Encryption.getSecretHoldersRange(),required=False)
parser.add_argument('--add-user-information',type=bool, dest='add_user_information', default=False, required=False, action=argparse.BooleanOptionalAction)
args = parser.parse_args()
@ -45,16 +50,16 @@ try:
if args.user is None:
print("Deleting all encrypted and decrypted files.")
cleanup.deleteAll()
clean_exit()
standard_exit()
print("Deleting all files which aren't related to user: " + str(args.user));
cleanup.cleanupForUser(args.user)
clean_exit()
standard_exit()
print("Deleting all " + args.file_types + " files.")
cleanup.cleanupFiles(args.file_types)
clean_exit()
standard_exit()
if args.mode == 'decrypt':
decrypt = Decryption()
decrypt = Decryption(cli,paths)
if args.master_password is None:
if args.user is None:
print("Type in the user id:")
@ -120,11 +125,14 @@ try:
break;
except:
print("An unexpected error occured: \n" + traceback.format_exc())
print("Decrypting main data.")
decrypt.decryptMainData()
print("All data decrypted.")
dirty_exit()
print("Decrypting accumulated file...")
print("Decrypting accumulated data.")
decrypt.setUserPassword(args.master_password)
decrypt.decryptAccumulatedFile()
clean_exit()
dirty_exit()
if args.mode == 'encrypt':
if args.master_password is None:
@ -132,15 +140,16 @@ try:
master_password = getpass()
else:
master_password = args.master_password
encrypt = Encryption(args.amount_of_secret_holders, args.decryption_quota, master_password)
encrypt = Encryption(cli,paths,args.amount_of_secret_holders, args.decryption_quota, master_password)
if args.add_user_information is not None:
for user_id in encrypt.user_mapped_data:
for label in ['name','phone','email','address']:
print("Enter attribut <<" + label + ">> for user <<" + user_id+ ">>:" )
encrypt.addInformationToUser(user_id, label, str(input()))
encrypt.compileData()
encrypt.encrypt()
clean_exit()
encrypt.encryptAll()
dirty_exit()
except KeyboardInterrupt:
print("Program interrupted by user.")
clean_exit()