From 11848ba2220390d1f00ad92b22c132820550f950 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Tue, 13 Dec 2022 15:55:01 +0100 Subject: [PATCH] Implemented escaping for passwords on bash level --- .gitignore | 2 +- Readme.md => README.md | 17 +++- scripts/classes/Decryption.py | 14 +-- scripts/classes/Encryption.py | 7 +- scripts/main.py | 157 ++++++++++++++++++---------------- 5 files changed, 110 insertions(+), 87 deletions(-) rename Readme.md => README.md (83%) diff --git a/.gitignore b/.gitignore index 7dfe6d7..d9801b8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ __pycache__ -testcases.txt \ No newline at end of file +INSTRUCTIONS.md \ No newline at end of file diff --git a/Readme.md b/README.md similarity index 83% rename from Readme.md rename to README.md index be29c90..c75b575 100644 --- a/Readme.md +++ b/README.md @@ -40,15 +40,23 @@ To delete all encrypted data execute: python scripts/main.py --mode cleanup --file-types encrypted ``` -## decrypt +## decrypt ### decrypt automatic To decrypt the data execute: ```bash -python scripts/main.py --mode decrypt +python scripts/main.py --mode decrypt-data ``` +### decrypt automatic +To decrypt the accumulated datafile execute: + +```bash +python scripts/main.py --mode decrypt --decrypt-accumulated-file +``` + + ### decrypt defined user To decrypt the data for a defined user execute: @@ -56,16 +64,17 @@ To decrypt the data for a defined user execute: python scripts/main.py --mode decrypt --user "<>" ``` +### addtional instructions +In the [INSTRUCTIONS.md](./Instruction.md) file the master encrypter can leave additional instructions. + ## encrypt ### encrypt main data - ```bash python scripts/main.py --secret-holders-amount "<>" --quota "<>" --mode encrypt --master-password "<>" --input-directory "<>" ``` ### encrypt master password - To encrypt the master-password file and to create the neccessary encrypted meta data execute: ```bash diff --git a/scripts/classes/Decryption.py b/scripts/classes/Decryption.py index 02b5d71..0b10799 100644 --- a/scripts/classes/Decryption.py +++ b/scripts/classes/Decryption.py @@ -1,6 +1,7 @@ import json import os from pathlib import Path +import shlex class AutomaticIdentificationImpossibleException(Exception): pass @@ -35,12 +36,18 @@ class Decryption(): 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.paths.getGroupFilePath(self.group_name, self.paths.TYPE_DECRYPTED) self.decryptGroupFile() 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])) @@ -70,9 +77,6 @@ class Decryption(): 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: @@ -114,7 +118,7 @@ class Decryption(): return data def decryptFile(self,password,input_file_path,output_file_path): - self.cli.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.paths.getUserFilePath(self.user_id,self.paths.TYPE_ENCRYPTED) @@ -130,4 +134,4 @@ class Decryption(): 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 --one-top-level="' + self.paths.getDecryptedMainDataStandartFolder() + '" -xvzf -') \ No newline at end of file + self.cli.executeCommand('gpg --batch --passphrase ' + shlex.quote(self.getMasterPassword()) + ' -d "' + self.paths.getEncryptedMainDataFile() + '" | tar --one-top-level="' + self.paths.getDecryptedMainDataStandartFolder() + '" -xvzf -') \ No newline at end of file diff --git a/scripts/classes/Encryption.py b/scripts/classes/Encryption.py index 0536abb..c996860 100644 --- a/scripts/classes/Encryption.py +++ b/scripts/classes/Encryption.py @@ -5,6 +5,7 @@ import numpy import re import json from .Paths import Paths +import shlex class Encryption(): @@ -104,7 +105,7 @@ class Encryption(): index += 1 def encryptStringToFile(self,text,output_file,password): - self.cli.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: @@ -125,7 +126,7 @@ class Encryption(): 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 "' + password + '" -o "' + output_file + '"') + self.cli.executeCommand('cat \'' + input_file + '\' | gpg --symmetric --armor --batch --passphrase ' + shlex.quote(password) + ' -o "' + output_file + '"') def deleteDecryptedAccumulatedFile(self): self.cli.executeCommand('rm ' + self.paths.getAccumulatedFilePath(Paths.TYPE_DECRYPTED)) @@ -144,7 +145,7 @@ class Encryption(): self.deleteDecryptedAccumulatedFile() def encryptMainData(self,input_directory): - self.cli.executeCommand('tar -C"' + input_directory + '" -cvzf - ./ | gpg -c --batch --passphrase "' + self.master_password +'" > "' + self.paths.getEncryptedMainDataFile() + '"') + 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() diff --git a/scripts/main.py b/scripts/main.py index ac0127a..80bedae 100644 --- a/scripts/main.py +++ b/scripts/main.py @@ -36,6 +36,7 @@ try: 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('--decrypt-accumulated-file',type=bool, dest='decrypt_accumulated_file', default=False , action=argparse.BooleanOptionalAction ,required=False, help="Decrypts the accumulated file.") 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('--add-user-information',type=bool, dest='add_user_information', default=False, required=False, action=argparse.BooleanOptionalAction, help="Add additional information to users.") @@ -45,6 +46,8 @@ try: print("Application started.") print("To leave the appplication use the key kombination: <> + <> + <>") + print("Cleaning up all decrypted files.") + cleanup.cleanupFiles(Paths.TYPE_DECRYPTED) print("Selected Mode: " + args.mode) if args.mode == 'cleanup': @@ -63,85 +66,91 @@ try: if args.mode == 'decrypt': decrypt = Decryption(cli,paths) - if args.master_password is None: - 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:") - user_id = input() - decrypt.initializeUser(user_id) + if args.decrypt_accumulated_file is True: + if args.master_password is None: + print("Enter the master password:") + master_password = getpass() 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) + 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:") + 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()) - print("Decrypting main data.") - decrypt.decryptMainData() - print("The data was decrypted to: " + paths.getDecryptedMainDataStandartFolder()) - dirty_exit() - print("Decrypting accumulated data.") - decrypt.setUserPassword(args.master_password) - decrypt.decryptAccumulatedFile() + 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':