Compare commits

...

4 Commits

8 changed files with 120 additions and 76 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
__pycache__ __pycache__
testcases.txt

115
Readme.md
View File

@ -1,66 +1,77 @@
# Splitted Secret # Splitted Secret
The purpose of this software is to splitt a secret over multiple people. Just if a defined amount of this people meet together they can encrypt the secret and have access to it. The purpose of this software is to splitt a secret over multiple people. Just if a defined amount of this people meet together they can encrypt the secret and have access to it.
# testing ## requirements
```bash
python scripts/main.py --mode cleanup &&
echo "werewrw" > data/decrypted/main_data/test123.txt
echo "werewrw" > data/decrypted/main_data/test124.txt
mkdir data/decrypted/main_data/folder
echo "werewrw" > data/decrypted/main_data/folder/test124.txt
python scripts/main.py --amount 3 --quota 50 --mode encrypt --add-user-information --master-password "ewrwerwerew" << END_OF_INPUTS ### system
alpha bravo This software is developed for and on an [Arch Linux](https://archlinux.org/) system.
123123812908
asfdasd@asdskjd.de
street in straat
charlie delta
1888888
sadasfdasd@asdskjd.de
street in strutt
echo2 foxtrott
99999999
asfdasd@sdskjd.de
street in strasdlasöd
END_OF_INPUTS
python scripts/main.py --mode decrypt --master-password "ewrwerwerew"
### setup
python scripts/main.py --mode cleanup --file-types decrypted && Before executing the script it may be necessary to install the following software packages:
python scripts/main.py --mode decrypt --user "1" --user-password "Y4GYTEW80SCQQDTIKOJ6YNCIP6MBBEM68SCKBAA1VWAQFRSPNGHEBKHSFZQENDRB" << END_OF_INPUTS
2 ```bash
VGCQPW2LIKJ7SDFFLUZXBXGFPZ6L8RGPTS7TLCNN9GLR82RPHRSN34YZUXF0L27V pacman -S gpg tar python pip python-pip
END_OF_INPUTS pip install numpy
``` ```
# Requirements to know ## commands
- Amount of People
- How much people need to reunite for decrypting
# Requirements to implement ## cleanup data
- Plattform independend
- easy to use ### delete all data
To delete all data execute:
# required software
```bash ```bash
pip install numpy python scripts/main.py --mode cleanup
gpg ```
ecryptfs-utils
ecryptfs-simple ### delete decrypted data
python To delete all encrypted data execute:
pip
```bash
python scripts/main.py --mode cleanup --file-types decrypted
```
### delete all encrypted data
To delete all encrypted data execute:
```bash
python scripts/main.py --mode cleanup --file-types encrypted
```
## decrypt
### decrypt automatic
To decrypt the data execute:
```bash
python scripts/main.py --mode decrypt
```
### decrypt defined user
To decrypt the data for a defined user execute:
```bash
python scripts/main.py --mode decrypt --user "<<user_id>>"
```
## encrypt
### encrypt main data
```bash
python scripts/main.py --secret-holders-amount "<<amount>>" --quota "<<quota>>" --mode encrypt --master-password "<<master_password>>" --input-directory "<<input_directory>>"
```
### encrypt master password
To encrypt the master-password file and to create the neccessary encrypted meta data execute:
```bash
python scripts/main.py --secret-holders-amount "<<amount>>" --quota "<<quota>>" --mode encrypt --add-user-information --master-password "<<master_password>>" --create-meta-data
``` ```
## todo ## todo
- implement tails setup script
- add data-input attribut - add data-input attribut
- add data-output attribut - add data-output attribut
- write scenario test
## Further Information
- https://www.tutorialspoint.com/python/python_command_line_arguments.htm
- https://docs.python.org/3/library/argparse.html#module-argparse
- https://wiki.ubuntuusers.de/GoCryptFS/
- 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

View File

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

View File

@ -8,7 +8,7 @@ class Cleanup():
def getAllFilePaths(self,file_type): def getAllFilePaths(self,file_type):
all_file_paths = [ all_file_paths = [
self.paths.getGroupFilesFolderPath(file_type), self.paths.getGroupFilesFolderPath(file_type),
self.paths.getUserFilesFolderPath(file_type), self.paths.getUserFilesPath(file_type),
self.paths.getAccumulatedFilePath(file_type) self.paths.getAccumulatedFilePath(file_type)
] ]
if file_type == Paths.TYPE_DECRYPTED: if file_type == Paths.TYPE_DECRYPTED:
@ -19,7 +19,7 @@ class Cleanup():
try: try:
self.cli.executeCommand('rm -r ' + folder_path + '*') self.cli.executeCommand('rm -r ' + folder_path + '*')
except Exception as error: except Exception as error:
print(error) pass
def cleanupFiles(self,file_type): def cleanupFiles(self,file_type):
for folder_path in self.getAllFilePaths(file_type): for folder_path in self.getAllFilePaths(file_type):
@ -29,7 +29,7 @@ class Cleanup():
try: try:
self.cli.executeCommand('find "' + self.paths.getDataFolderPath(Paths.TYPE_ENCRYPTED) + '" -not -name "*' + str(user) +'*" -type f -print | xargs rm -v') self.cli.executeCommand('find "' + self.paths.getDataFolderPath(Paths.TYPE_ENCRYPTED) + '" -not -name "*' + str(user) +'*" -type f -print | xargs rm -v')
except Exception as error: except Exception as error:
print(error) pass
self.cleanupFiles(Paths.TYPE_DECRYPTED) self.cleanupFiles(Paths.TYPE_DECRYPTED)
def deleteAll(self): def deleteAll(self):

View File

@ -1,6 +1,10 @@
import json import json
import os
from pathlib import Path from pathlib import Path
class AutomaticIdentificationImpossibleException(Exception):
pass
class Decryption(): class Decryption():
def __init__(self,cli,paths): def __init__(self,cli,paths):
@ -9,6 +13,18 @@ class Decryption():
self.cli = cli self.cli = cli
self.paths = paths self.paths = paths
def identifyUser(self):
file_type = self.paths.TYPE_ENCRYPTED
file_names = next(os.walk(self.paths.getUserFilesPath(file_type)), (None, None, []))[2]
users = []
user_file_suffix = self.paths.getUserFileSuffix(file_type)
for file in file_names:
if user_file_suffix in file:
users.append(file.replace(user_file_suffix, ''))
if len(users) < 2:
return users[0]
raise AutomaticIdentificationImpossibleException()
def initializeUser(self,user_id): def initializeUser(self,user_id):
self.user_id=str(user_id) self.user_id=str(user_id)
self.user_file_decrypted_path = self.paths.getUserFilePath(self.user_id,self.paths.TYPE_DECRYPTED) self.user_file_decrypted_path = self.paths.getUserFilePath(self.user_id,self.paths.TYPE_DECRYPTED)

View File

@ -40,10 +40,10 @@ class Encryption():
self.user_mapped_data[user_id]['about'][label] = content; self.user_mapped_data[user_id]['about'][label] = content;
def getCoSecretHoldersRange(): def getCoSecretHoldersRange():
return range(Encryption.MINIMUM_SECRET_HOLDERS,Encryption.MAXIMUM_SECRET_HOLDERS) return range(Encryption.MINIMUM_SECRET_HOLDERS,(Encryption.MAXIMUM_SECRET_HOLDERS+1))
def getSecretHoldersRange(): def getSecretHoldersRange():
return range(1,Encryption.MAXIMUM_SECRET_HOLDERS) return range(1,(Encryption.MAXIMUM_SECRET_HOLDERS+1))
def getStartnumber(self): def getStartnumber(self):
index = 0 index = 0
@ -84,7 +84,7 @@ class Encryption():
def compileData(self): def compileData(self):
self.compileContacts() self.compileContacts()
index = self.getStartnumber() index = self.getStartnumber()
while index < self.getEndnumber(): while index <= self.getEndnumber():
password_group_name = ''.join(sorted(str(index))) password_group_name = ''.join(sorted(str(index)))
if self.isGroupValid(password_group_name): if self.isGroupValid(password_group_name):
password_group_index_int = int(password_group_name) password_group_index_int = int(password_group_name)
@ -126,11 +126,10 @@ class Encryption():
data={"user_mapped": self.user_mapped_data, "group_mapped": self.group_mapped_data} data={"user_mapped": self.user_mapped_data, "group_mapped": self.group_mapped_data}
self.encryptToJsonFile(data,file_path,self.master_password) self.encryptToJsonFile(data,file_path,self.master_password)
def encryptMainData(self): def encryptMainData(self,input_directory):
self.cli.executeCommand('tar -C"' + self.paths.getDecryptedMainDataStandartFolder() + '" -cvzf - ./ | gpg -c --batch --passphrase "' + self.master_password +'" > "' + self.paths.getEncryptedMainDataFile() + '"') self.cli.executeCommand('tar -C"' + input_directory + '" -cvzf - ./ | gpg -c --batch --passphrase "' + self.master_password +'" > "' + self.paths.getEncryptedMainDataFile() + '"')
def encryptAll(self): def encryptMetaData(self):
self.encryptUserFile() self.encryptUserFile()
self.encryptAccumulatedFile() self.encryptAccumulatedFile()
self.encryptGroupFiles() self.encryptGroupFiles()
self.encryptMainData()

View File

@ -16,7 +16,7 @@ class Paths():
def getGroupFilesFolderPath(self,folder_type): def getGroupFilesFolderPath(self,folder_type):
return self.getDataFolderPath(folder_type) + "group_files/" return self.getDataFolderPath(folder_type) + "group_files/"
def getUserFilesFolderPath(self,folder_type): def getUserFilesPath(self,folder_type):
return self.getDataFolderPath(folder_type) + "user_files/" return self.getDataFolderPath(folder_type) + "user_files/"
def getEncryptedMainDataFile(self): def getEncryptedMainDataFile(self):
@ -29,9 +29,12 @@ class Paths():
if file_type == Paths.TYPE_ENCRYPTED: if file_type == Paths.TYPE_ENCRYPTED:
return '.gpg' return '.gpg'
return '' return ''
def getUserFileSuffix(self,file_type):
return '.json' + self.getFileExtension(file_type)
def getUserFilePath(self,user_id,file_type): def getUserFilePath(self,user_id,file_type):
return self.getUserFilesFolderPath(file_type)+user_id+'.json' + self.getFileExtension(file_type); return self.getUserFilesPath(file_type) + user_id + self.getUserFileSuffix(file_type);
def getGroupFilePath(self,group_id,file_type): def getGroupFilePath(self,group_id,file_type):
return self.getGroupFilesFolderPath(file_type) + str(group_id) + '.txt' + self.getFileExtension(file_type); return self.getGroupFilesFolderPath(file_type) + str(group_id) + '.txt' + self.getFileExtension(file_type);

View File

@ -1,7 +1,7 @@
import argparse import argparse
from classes.Encryption import Encryption from classes.Encryption import Encryption
from classes.Cleanup import Cleanup from classes.Cleanup import Cleanup
from classes.Decryption import Decryption from classes.Decryption import Decryption, AutomaticIdentificationImpossibleException
from getpass import getpass from getpass import getpass
import traceback import traceback
from classes.Cli import Cli from classes.Cli import Cli
@ -33,15 +33,18 @@ try:
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--mode',type=str, dest='mode',required=True,choices=['cleanup','encrypt','decrypt']) 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=[Paths.TYPE_DECRYPTED, Paths.TYPE_ENCRYPTED]) 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('--secret-holders-amount',type=int, dest='amount_of_secret_holders',required=False,choices=Encryption.getCoSecretHoldersRange(),help="Needed for creating of encryption meta data.")
parser.add_argument('--quota', type=int, dest='decryption_quota', choices=range(1,101),required=False) 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('--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-password',type=str, dest='user_password',required=False)
parser.add_argument('--user',type=int, dest='user',choices=Encryption.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) parser.add_argument('--add-user-information',type=bool, dest='add_user_information', default=False, required=False, action=argparse.BooleanOptionalAction, help="Add additional information to users.")
parser.add_argument('--input-directory',type=str,dest='input_directory',required=False, help="The directory from which the data should be encrypted.")
parser.add_argument('--create-meta-data',type=bool, dest='create_meta_data', default=False, required=False, action=argparse.BooleanOptionalAction, help="When mode is encrypt and this flag is set, the encrypted meta data is created.")
args = parser.parse_args() args = parser.parse_args()
print("Application started.") print("Application started.")
print("To leave the appplication use the key kombination: <<Ctr>> + <<Alt>> + <<C>>")
print("Selected Mode: " + args.mode) print("Selected Mode: " + args.mode)
if args.mode == 'cleanup': if args.mode == 'cleanup':
@ -61,9 +64,16 @@ try:
if args.mode == 'decrypt': if args.mode == 'decrypt':
decrypt = Decryption(cli,paths) decrypt = Decryption(cli,paths)
if args.master_password is None: if args.master_password is None:
if args.user is None: if args.user is None:
print("Type in the user id:") try:
decrypt.initializeUser(input()) print("Attempt to identify user.")
user_id = decrypt.identifyUser()
print("The user id is: " + user_id)
except:
print("A automatic user id identification wasn't possible.")
print("Type in the user id:")
user_id = input()
decrypt.initializeUser(user_id)
else: else:
decrypt.initializeUser(args.user) decrypt.initializeUser(args.user)
if args.user_password is None: if args.user_password is None:
@ -141,13 +151,18 @@ try:
else: else:
master_password = args.master_password master_password = args.master_password
encrypt = Encryption(cli,paths,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: if args.add_user_information is True:
for user_id in encrypt.user_mapped_data: for user_id in encrypt.user_mapped_data:
for label in ['name','phone','email','address']: for label in ['name','phone','email','address','notes']:
print("Enter attribut <<" + label + ">> for user <<" + user_id+ ">>:" ) print("Enter attribut <<" + label + ">> for user <<" + user_id+ ">>:" )
encrypt.addInformationToUser(user_id, label, str(input())) encrypt.addInformationToUser(user_id, label, str(input()))
encrypt.compileData() encrypt.compileData()
encrypt.encryptAll() if args.create_meta_data is True:
print("Create and encrypt meta data.")
encrypt.encryptMetaData()
if args.input_directory is not None:
print("Encrypt main data.")
encrypt.encryptMainData(args.input_directory)
dirty_exit() dirty_exit()
except KeyboardInterrupt: except KeyboardInterrupt:
print("Program interrupted by user.") print("Program interrupted by user.")