Compare commits

..

No commits in common. "42a5b93d67c77802deb864c67e5bed4551aff8c0" and "4caec4e1dc2db6fc850121b2287017a8a3487c1a" have entirely different histories.

8 changed files with 78 additions and 122 deletions

3
.gitignore vendored
View File

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

119
Readme.md
View File

@ -1,77 +1,66 @@
# 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.
## requirements # testing
### system
This software is developed for and on an [Arch Linux](https://archlinux.org/) system.
### setup
Before executing the script it may be necessary to install the following software packages:
```bash
pacman -S gpg tar python pip python-pip
pip install numpy
```
## commands
## cleanup data
### delete all data
To delete all data execute:
```bash ```bash
python scripts/main.py --mode cleanup 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
alpha bravo
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"
python scripts/main.py --mode cleanup --file-types decrypted &&
python scripts/main.py --mode decrypt --user "1" --user-password "Y4GYTEW80SCQQDTIKOJ6YNCIP6MBBEM68SCKBAA1VWAQFRSPNGHEBKHSFZQENDRB" << END_OF_INPUTS
2
VGCQPW2LIKJ7SDFFLUZXBXGFPZ6L8RGPTS7TLCNN9GLR82RPHRSN34YZUXF0L27V
END_OF_INPUTS
``` ```
# Requirements to know
- Amount of People
- How much people need to reunite for decrypting
### delete decrypted data # Requirements to implement
To delete all encrypted data execute: - Plattform independend
- easy to use
# required software
```bash ```bash
python scripts/main.py --mode cleanup --file-types decrypted pip install numpy
``` gpg
ecryptfs-utils
### delete all encrypted data ecryptfs-simple
To delete all encrypted data execute: python
pip
```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

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

@ -0,0 +1 @@
*.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.getUserFilesPath(file_type), self.paths.getUserFilesFolderPath(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:
pass print(error)
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:
pass print(error)
self.cleanupFiles(Paths.TYPE_DECRYPTED) self.cleanupFiles(Paths.TYPE_DECRYPTED)
def deleteAll(self): def deleteAll(self):

View File

@ -1,10 +1,6 @@
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):
@ -13,18 +9,6 @@ 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+1)) return range(Encryption.MINIMUM_SECRET_HOLDERS,Encryption.MAXIMUM_SECRET_HOLDERS)
def getSecretHoldersRange(): def getSecretHoldersRange():
return range(1,(Encryption.MAXIMUM_SECRET_HOLDERS+1)) return range(1,Encryption.MAXIMUM_SECRET_HOLDERS)
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,10 +126,11 @@ 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,input_directory): def encryptMainData(self):
self.cli.executeCommand('tar -C"' + input_directory + '" -cvzf - ./ | gpg -c --batch --passphrase "' + self.master_password +'" > "' + self.paths.getEncryptedMainDataFile() + '"') self.cli.executeCommand('tar -C"' + self.paths.getDecryptedMainDataStandartFolder() + '" -cvzf - ./ | gpg -c --batch --passphrase "' + self.master_password +'" > "' + self.paths.getEncryptedMainDataFile() + '"')
def encryptMetaData(self): def encryptAll(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 getUserFilesPath(self,folder_type): def getUserFilesFolderPath(self,folder_type):
return self.getDataFolderPath(folder_type) + "user_files/" return self.getDataFolderPath(folder_type) + "user_files/"
def getEncryptedMainDataFile(self): def getEncryptedMainDataFile(self):
@ -29,12 +29,9 @@ 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.getUserFilesPath(file_type) + user_id + self.getUserFileSuffix(file_type); return self.getUserFilesFolderPath(file_type)+user_id+'.json' + self.getFileExtension(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, AutomaticIdentificationImpossibleException from classes.Decryption import Decryption
from getpass import getpass from getpass import getpass
import traceback import traceback
from classes.Cli import Cli from classes.Cli import Cli
@ -33,18 +33,15 @@ 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('--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('--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('--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, help="Add additional information to users.") parser.add_argument('--add-user-information',type=bool, dest='add_user_information', default=False, required=False, action=argparse.BooleanOptionalAction)
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':
@ -64,16 +61,9 @@ 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:
try: print("Type in the user id:")
print("Attempt to identify user.") decrypt.initializeUser(input())
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:
@ -151,18 +141,13 @@ 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 True: if args.add_user_information is not None:
for user_id in encrypt.user_mapped_data: for user_id in encrypt.user_mapped_data:
for label in ['name','phone','email','address','notes']: for label in ['name','phone','email','address']:
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()
if args.create_meta_data is True: encrypt.encryptAll()
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.")