Compare commits

...

30 Commits

Author SHA1 Message Date
6f5c04ba11 Added Funding 2025-03-12 20:52:47 +01:00
a5ada012b6 Merge branch 'main' of github.com:kevinveenbirkenbach/splitted-secret 2025-03-12 11:14:39 +01:00
69d0592b05 Update README.md 2025-03-12 10:49:37 +01:00
5e4fe2c01a Update README.md 2025-03-04 21:27:09 +01:00
b939870c1d Create requirements.txt 2025-03-04 21:25:14 +01:00
44b2db0cbc Added funnier test tada for hack'n tell 2023-03-28 19:57:06 +02:00
960e14d59e Fixed error in documentation 2023-03-28 19:43:23 +02:00
62f51b449d Updated README.md 2022-12-15 09:33:30 +01:00
09bb6d1e31 Optimized cleanup for encryption 2022-12-14 00:31:46 +01:00
a0c17c9fd6 Refactored parameters to meta 2022-12-13 16:23:24 +01:00
b3bd3a0095 Merge branch 'main' of github.com:kevinveenbirkenbach/splitted-secret 2022-12-13 15:56:29 +01:00
11848ba222 Implemented escaping for passwords on bash level 2022-12-13 15:55:01 +01:00
a88ca6904a Update Readme.md 2022-12-12 13:12:44 +01:00
5ad38ab566 Solved variable naming bug 2022-12-12 13:09:03 +01:00
565c5d0961 Optimized decryption message 2022-12-12 11:45:29 +01:00
07ba9b2164 Added gitignore file 2022-12-11 23:55:39 +01:00
63f2d9fd18 Removed todos 2022-12-11 23:53:42 +01:00
cc943c8c12 Solved sh restrictions for accumulated file 2022-12-11 23:50:52 +01:00
42a5b93d67 Optimized code 2022-12-11 18:46:32 +01:00
591af85d82 Optimized usability 2022-12-11 16:47:07 +01:00
080b8d66e4 Implemented automatic user identification 2022-12-11 14:55:17 +01:00
260d7dfbb7 Updated Readme file 2022-12-11 13:55:55 +01:00
4caec4e1dc Removed debugging commands 2022-12-11 10:20:18 +01:00
4c3661de76 Solved decryption encryption bug 2022-12-11 10:19:35 +01:00
c85c108db5 Moved functions from Paths to Encryption 2022-12-10 22:27:28 +01:00
baefc461fa Changed paths to dependency injection 2022-12-10 22:19:57 +01:00
bfcda49660 Refactored class cli 2022-12-10 22:03:29 +01:00
c06d1d34d2 Implemented absolut paths 2022-12-10 21:48:24 +01:00
7b33c5420d Finished full encryption implementation 2022-12-10 21:20:26 +01:00
2b3e4932c2 In between commit implementation of main data encryption 2022-12-10 20:19:26 +01:00
17 changed files with 401 additions and 247 deletions

7
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
github: kevinveenbirkenbach
patreon: kevinveenbirkenbach
buy_me_a_coffee: kevinveenbirkenbach
custom: https://s.veen.world/paypaldonate

8
.gitignore vendored
View File

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

95
README.md Normal file
View File

@@ -0,0 +1,95 @@
# Split Secret (sisec) 🔐
[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-GitHub%20Sponsors-blue?logo=github)](https://github.com/sponsors/kevinveenbirkenbach) [![Patreon](https://img.shields.io/badge/Support-Patreon-orange?logo=patreon)](https://www.patreon.com/c/kevinveenbirkenbach) [![Buy Me a Coffee](https://img.shields.io/badge/Buy%20me%20a%20Coffee-Funding-yellow?logo=buymeacoffee)](https://buymeacoffee.com/kevinveenbirkenbach) [![PayPal](https://img.shields.io/badge/Donate-PayPal-blue?logo=paypal)](https://s.veen.world/paypaldonate)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![GitHub stars](https://img.shields.io/github/stars/kevinveenbirkenbach/split-secret.svg?style=social)](https://github.com/kevinveenbirkenbach/split-secret/stargazers)
Split Secret is a versatile command-line tool for securely splitting a master secret among multiple users. Only when a defined quorum of users combines their secret shares can the original secret be decrypted. The tool also supports robust encryption, decryption, and cleanup operations to ensure sensitive data is managed securely throughout the process.
---
## 🛠 Features
- **Secret Splitting:** Divide a master secret into shares distributed among users.
- **Encryption & Decryption:** Securely encrypt and decrypt data files using strong cryptographic methods.
- **User Management:** Add and manage user information along with their secret shares.
- **Cleanup Operations:** Remove decrypted files after processing to maintain security.
- **Interactive Modes:** Operate in active, preview, or interactive modes to match your workflow.
- **Parallel Processing:** Efficiently handles file operations using process pooling.
---
## 📥 Installation
Install Split Secret via [Kevin's Package Manager](https://github.com/kevinveenbirkenbach/package-manager) under the alias `sisec`:
```bash
package-manager install sisec
```
This command installs Split Secret globally, making it available as `sisec` in your terminal. 🚀
---
## 🚀 Usage
Split Secret offers several modes for managing your secrets. Here are a few example commands:
### Cleanup Data
To delete all unnecessary decrypted and encrypted files:
```bash
sisec --mode cleanup
```
### Encrypt Data & Generate Meta Data
Encrypt the master secret file and generate encrypted metadata with additional user information:
```bash
sisec --secret-holders-amount 3 --quota 50 --mode encrypt --add-user-information --master-password "your_master_password" --meta --add-user-information << EOL
Alan Turing
+12358
turing@turing-bomb.world
Bletchley Park
¯\_(ツ)_/¯
Ada Lovelace
+132134
best@algorythm.ai
Somewhere in London
:)
John von Neumann
+5488142
test@test3.de
Washington D.C.
<3 <3 <3
EOL
```
### Decrypt Meta Data File
To decrypt the accumulated metadata file:
```bash
sisec --mode decrypt --meta
```
For additional commands and options (such as user-specific decryption, file type filtering, or recursive processing), use:
```bash
sisec --help
```
---
## 🧑‍💻 Author
Developed by **Kevin Veen-Birkenbach**
- 📧 [kevin@veen.world](mailto:kevin@veen.world)
- 🌐 [https://www.veen.world](https://www.veen.world)
---
## 📜 License
This project is licensed under the **MIT License**.
---
## 🤝 Contributions
Contributions are welcome! Please feel free to fork the repository, submit pull requests, or open issues if you have suggestions or encounter any problems. Let's work together to make secure secret management accessible and efficient! 😊

View File

@@ -1,57 +0,0 @@
# 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.
# testing
```bash
python scripts/main.py --mode cleanup &&
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 decrypt --user "1"
python scripts/main.py --mode cleanup --file-types decrypted && python scripts/main.py --mode decrypt --user "1" --user-password "O3ITMWXZED9FKYQ0PB2WNVRWSCSCYVXCD00PJ6GQ4MFPIUWBVDCYSSSX9ZDBW5QU" << END_OF_INPUTS
2
YGC6FLI5FIFL4WV4JPZZI7RVOZTWLROCLY4HVGDMWWSTAIQJTLUQK1VBBY0E24PN
END_OF_INPUTS
```
# Requirements to know
- Amount of People
- How much people need to reunite for decrypting
# Requirements to implement
- Plattform independend
- easy to use
# required software
```bash
pip install numpy
gpg
python
pip
```
## todo
- implement tails setup script
- implement relativ call
- implement tmp mount for decrypted files
## 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

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 @@
*.json.pgp

2
requirements.txt Normal file
View File

@@ -0,0 +1,2 @@
pacman -S gpg tar python pip python-pip
pip install numpy

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,28 @@
from .AbstractSplittedSecret import AbstractSplittedSecret
class Cleanup(AbstractSplittedSecret):
def __init__(self):
super(Cleanup, self).__init__()
def getAllFilePaths(self,file_type):
from .Paths import Paths
class Cleanup():
def __init__(self,cli,paths):
self.cli = cli
self.paths = paths
def getMetaFilePaths(self,file_type):
return [
self.getGroupFilesFolderPath(file_type),
self.getUserFilesFolderPath(file_type),
self.getAccumulatedFilePath(file_type)
]
self.paths.getGroupFilesFolderPath(file_type),
self.paths.getUserFilesPath(file_type),
self.paths.getAccumulatedFilePath(file_type)
]
def getAllFilePaths(self,file_type):
all_file_paths = self.getMetaFilePaths(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:
pass
def cleanupFiles(self,file_type):
for folder_path in self.getAllFilePaths(file_type):
@@ -22,11 +30,15 @@ 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:
self.cli.executeCommand('find "' + self.paths.getDataFolderPath(Paths.TYPE_ENCRYPTED) + '" -not -name "*' + str(user) +'*" -type f -print | xargs rm -v')
except Exception as error:
pass
self.cleanupFiles(AbstractSplittedSecret.TYPE_DECRYPTED)
self.cleanupFiles(Paths.TYPE_DECRYPTED)
def cleanupMetaData(self,file_type):
for folder_path in self.getMetaFilePaths(file_type):
self.deleteAllFilesInFolder(folder_path)
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,34 @@
from .AbstractSplittedSecret import AbstractSplittedSecret
import json
import os
from pathlib import Path
class Decryption(AbstractSplittedSecret):
import shlex
class AutomaticIdentificationImpossibleException(Exception):
pass
class Decryption():
def __init__(self):
def __init__(self,cli,paths):
self.user_id='0';
self.user_password=''
super(Decryption, self).__init__()
self.cli = cli
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):
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()
@@ -18,11 +36,17 @@ class Decryption(AbstractSplittedSecret):
self.initializeNeededDecryptersAmount()
self.initializeValidDecrypterIds()
def getEscapedMasterPassword(self):
return shlex.quote(self.master_password)
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 getMasterPassword(self):
return self.master_password
def initializeNeededDecryptersAmount(self):
self.needed_decrypters_amount = len(str(list(self.user_data['groups'].keys())[0]))
@@ -53,9 +77,6 @@ class Decryption(AbstractSplittedSecret):
shared_password += str(self.password_parts[password_share_index])
return shared_password
def getMasterPassword(self):
return self.master_password
def addDecrypterId(self,decrypter_id):
decrypter_id = int(decrypter_id)
if decrypter_id not in self.valid_decrypter_ids:
@@ -97,17 +118,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 '+ shlex.quote(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)
self.decryptFile(self.user_password, input_file_path, output_file_path)
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 ' + shlex.quote(self.getMasterPassword()) + ' -d "' + self.paths.getEncryptedMainDataFile() + '" | tar --one-top-level="' + self.paths.getDecryptedMainDataStandartFolder() + '" -xvzf -')

View File

@@ -4,12 +4,19 @@ import math
import numpy
import re
import json
from .AbstractSplittedSecret import AbstractSplittedSecret
from .Paths import Paths
import shlex
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,7 +24,9 @@ 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 = {}
user_count = 1
@@ -30,7 +39,13 @@ 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+1))
def getSecretHoldersRange():
return range(1,(Encryption.MAXIMUM_SECRET_HOLDERS+1))
def getStartnumber(self):
index = 0
start_number = ''
@@ -70,7 +85,7 @@ class Encryption(AbstractSplittedSecret):
def compileData(self):
self.compileContacts()
index = self.getStartnumber()
while index < self.getEndnumber():
while index <= self.getEndnumber():
password_group_name = ''.join(sorted(str(index)))
if self.isGroupValid(password_group_name):
password_group_index_int = int(password_group_name)
@@ -90,29 +105,49 @@ 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 ' + shlex.quote(text) + ' | gpg --symmetric --armor --batch --passphrase ' + shlex.quote(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)
data={"user_mapped": self.user_mapped_data, "group_mapped": self.group_mapped_data}
self.encryptToJsonFile(data,file_path,self.master_password)
'''
This saving as decrypted file is necessary due to the reason that the shell can't deal with unlimited string length.
See: https://stackoverflow.com/questions/30650841/why-am-i-getting-errno-7-argument-list-too-long-and-oserror-errno-24-too-ma
'''
def encryptFileToFile(self,input_file,output_file,password):
self.cli.executeCommand('cat \'' + input_file + '\' | gpg --symmetric --armor --batch --passphrase ' + shlex.quote(password) + ' -o "' + output_file + '"')
def encrypt(self):
self.encryptUserData()
self.encryptAccumulatedData()
def deleteDecryptedAccumulatedFile(self):
self.cli.executeCommand('rm ' + self.paths.getAccumulatedFilePath(Paths.TYPE_DECRYPTED))
def saveDecryptedAccumulatedFile(self):
file_path=self.paths.getAccumulatedFilePath(Paths.TYPE_DECRYPTED)
data={"user_mapped": self.user_mapped_data, "group_mapped": self.group_mapped_data}
with open(file_path, 'w') as file:
json.dump(data, file)
def encryptAccumulatedFile(self):
self.saveDecryptedAccumulatedFile()
encrypted_file_path=self.paths.getAccumulatedFilePath(Paths.TYPE_ENCRYPTED)
decrypted_file_path=self.paths.getAccumulatedFilePath(Paths.TYPE_DECRYPTED)
self.encryptFileToFile(decrypted_file_path,encrypted_file_path,self.master_password)
self.deleteDecryptedAccumulatedFile()
def encryptMainData(self,input_directory):
self.cli.executeCommand('tar -C"' + input_directory + '" -cvzf - ./ | gpg -c --batch --passphrase ' + shlex.quote(self.master_password) + ' > "' + self.paths.getEncryptedMainDataFile() + '"')
def encryptMetaData(self):
self.encryptUserFile()
self.encryptGroupFiles()
self.encryptAccumulatedFile()

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

@@ -0,0 +1,43 @@
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 getUserFilesPath(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 getUserFileSuffix(self,file_type):
return '.json' + self.getFileExtension(file_type)
def getUserFilePath(self,user_id,file_type):
return self.getUserFilesPath(file_type) + user_id + self.getUserFileSuffix(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

@@ -1,42 +1,52 @@
import argparse
from classes.Encryption import Encryption
from classes.Cleanup import Cleanup
from classes.Decryption import Decryption
from classes.Decryption import Decryption, AutomaticIdentificationImpossibleException
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()
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('--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('--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('--add-user-information',type=bool, dest='add_user_information', default=False, required=False, action=argparse.BooleanOptionalAction)
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('--input-directory',type=str,dest='input_directory',required=False, help="The directory from which the data should be encrypted.")
parser.add_argument('--meta-data',type=bool, dest='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. When mode is decrypt and this flag is set the accumulated file will be decrypted.")
args = parser.parse_args()
print("Application started.")
print("To leave the appplication use the key kombination: <<Ctr>> + <<Alt>> + <<C>>")
print("Cleaning up all decrypted files.")
cleanup.cleanupFiles(Paths.TYPE_DECRYPTED)
print("Selected Mode: " + args.mode)
if args.mode == 'cleanup':
@@ -45,86 +55,102 @@ 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()
if args.master_password is None:
if args.user is None:
decrypt = Decryption(cli,paths)
if args.meta_data is True:
if args.master_password is None:
print("Enter the master password:")
master_password = getpass()
else:
master_password = args.master_password
decrypt = Decryption(cli,paths)
print("Decrypting accumulated data.")
decrypt.setUserPassword(master_password)
decrypt.decryptAccumulatedFile()
dirty_exit()
if args.user is None:
try:
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:")
decrypt.initializeUser(input())
else:
decrypt.initializeUser(args.user)
if args.user_password is None:
while True:
print("Enter the user password:")
decrypt.setUserPassword(getpass())
print("Decrypting User File...")
try:
decrypt.initializeUserDataDecryption();
break;
except Exception as error:
print("An error occured. Propably you typed in a wrong password :( The error is: " + str(error))
else:
decrypt.setUserPassword(args.user_password)
user_id = input()
decrypt.initializeUser(user_id)
else:
decrypt.initializeUser(args.user)
if args.user_password is None:
while True:
print("Enter the user password:")
decrypt.setUserPassword(getpass())
print("Decrypting User File...")
try:
decrypt.initializeUserDataDecryption();
except Exception as error:
print("An error occured. Propably you passed a wrong password :( The error is: " + str(error))
clean_exit()
print("\nContact the following persons and request their password share: \n")
for contact_id in decrypt.user_data['contacts']:
print("user_id: " + contact_id)
for label in decrypt.user_data['contacts'][contact_id]:
print(label + ": " + decrypt.user_data['contacts'][contact_id][label])
while True:
print("\nReset password shares.\n")
decrypt.resetDecrypterIds()
try:
password_shares_count = 1
while password_shares_count < decrypt.getNeededDecryptersAmount():
print(str(password_shares_count) + " password shares had been added.")
print("Password shares for the the users " + str(decrypt.getDecrypterIds()) + " been added. ")
print("You need to add " + str((decrypt.getNeededDecryptersAmount()-password_shares_count)) +" more password shares.")
print("\nType in the user id of another decrypter:")
decrypt.addDecrypterId(int(input()))
password_shares_count += 1
break
except Exception as error:
print("The following error occured <<" + str(error) + ">> :( \n Try again :)")
print("\nYour data is:\n")
print("FOR PASSWORD GROUP: " + decrypt.getDecryptersGroupName())
print("FOR USER ID: " + decrypt.getUserId())
print("PASSWORD SHARE IS: " + decrypt.getPasswordShare() + "\n")
while True:
try:
decrypt.resetPasswordShare()
co_decrypter_ids = decrypt.getCoDecrypterIds()
for co_decrypter_id in decrypt.getCoDecrypterIds():
print("Type in the password share for: \n")
print("FOR PASSWORD GROUP: " + decrypt.getDecryptersGroupName())
print("FOR USER: " + str(co_decrypter_id))
print("PASSWORD SHARE IS: ")
decrypt.addPasswordShare(co_decrypter_id, input())
print("\nTHE GROUP PASSWORD IS: " + decrypt.getGroupPassword())
print("\nDecrypting group password file.\n")
decrypt.initializeGroupDataEncryption()
print("THE MASTER PASSWORD IS: " + decrypt.getMasterPassword())
break;
except:
print("An unexpected error occured: \n" + traceback.format_exc())
dirty_exit()
print("Decrypting accumulated file...")
decrypt.setUserPassword(args.master_password)
decrypt.decryptAccumulatedFile()
clean_exit()
except Exception as error:
print("An error occured. Propably you typed in a wrong password :( The error is: " + str(error))
else:
decrypt.setUserPassword(args.user_password)
print("Decrypting User File...")
try:
decrypt.initializeUserDataDecryption();
except Exception as error:
print("An error occured. Propably you passed a wrong password :( The error is: " + str(error))
clean_exit()
print("\nContact the following persons and request their password share: \n")
for contact_id in decrypt.user_data['contacts']:
print("user_id: " + contact_id)
for label in decrypt.user_data['contacts'][contact_id]:
print(label + ": " + decrypt.user_data['contacts'][contact_id][label])
while True:
print("\nReset password shares.\n")
decrypt.resetDecrypterIds()
try:
password_shares_count = 1
while password_shares_count < decrypt.getNeededDecryptersAmount():
print(str(password_shares_count) + " password shares had been added.")
print("Password shares for the the users " + str(decrypt.getDecrypterIds()) + " been added. ")
print("You need to add " + str((decrypt.getNeededDecryptersAmount()-password_shares_count)) +" more password shares.")
print("\nType in the user id of another decrypter:")
decrypt.addDecrypterId(int(input()))
password_shares_count += 1
break
except Exception as error:
print("The following error occured <<" + str(error) + ">> :( \n Try again :)")
print("\nYour data is:\n")
print("FOR PASSWORD GROUP: " + decrypt.getDecryptersGroupName())
print("FOR USER ID: " + decrypt.getUserId())
print("PASSWORD SHARE IS: " + decrypt.getPasswordShare() + "\n")
while True:
try:
decrypt.resetPasswordShare()
co_decrypter_ids = decrypt.getCoDecrypterIds()
for co_decrypter_id in decrypt.getCoDecrypterIds():
print("Type in the password share for: \n")
print("FOR PASSWORD GROUP: " + decrypt.getDecryptersGroupName())
print("FOR USER: " + str(co_decrypter_id))
print("PASSWORD SHARE IS: ")
decrypt.addPasswordShare(co_decrypter_id, input())
print("\nTHE GROUP PASSWORD IS: " + decrypt.getGroupPassword())
print("\nDecrypting group password file.\n")
decrypt.initializeGroupDataEncryption()
print("THE MASTER PASSWORD IS: " + decrypt.getMasterPassword())
break;
except:
print("An unexpected error occured: \n" + traceback.format_exc())
print("Decrypting main data.")
decrypt.decryptMainData()
print("The data was decrypted to: " + paths.getDecryptedMainDataStandartFolder())
dirty_exit()
if args.mode == 'encrypt':
if args.master_password is None:
@@ -132,15 +158,22 @@ try:
master_password = getpass()
else:
master_password = args.master_password
encrypt = Encryption(args.amount_of_secret_holders, args.decryption_quota, master_password)
if args.add_user_information is not None:
encrypt = Encryption(cli,paths,args.amount_of_secret_holders, args.decryption_quota, master_password)
if args.add_user_information is True:
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+ ">>:" )
encrypt.addInformationToUser(user_id, label, str(input()))
encrypt.compileData()
encrypt.encrypt()
clean_exit()
if args.meta_data is True:
print('Cleaning up encrypted meta data.')
cleanup.cleanupMetaData(Paths.TYPE_ENCRYPTED)
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()
except KeyboardInterrupt:
print("Program interrupted by user.")
clean_exit()