Fixed some grammatical errors
Fixed empty input handling Removed old functions. Edited help section Edited README
This commit is contained in:
@@ -14,81 +14,6 @@ if_verbose = False
|
|||||||
def verbose(string):
|
def verbose(string):
|
||||||
if if_verbose: print(string)
|
if if_verbose: print(string)
|
||||||
|
|
||||||
# Encrypting data
|
|
||||||
def encrypt_data():
|
|
||||||
|
|
||||||
# Pesterish file asker
|
|
||||||
while True:
|
|
||||||
file_name = input("\nEnter the name of a zip file, without the extension that is in the same directory as this script. \nE.g. for encrypt.zip you would type \"encrypt\". Name > ") + ".zip"
|
|
||||||
if Path(file_name).is_file():
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("This zip file does not exist!")
|
|
||||||
|
|
||||||
file_chosen_name = input("\nMake a name for your encrypted file, e.g. encrypted (press enter for default)\nName > ")
|
|
||||||
if file_chosen_name == "":
|
|
||||||
file_chosen_name = "encrypted"
|
|
||||||
|
|
||||||
keyfile = input("\nDo you want enable keyfile encryption?\nIf enabled, decryption is only possible with the file.[y]/[N] ")
|
|
||||||
if keyfile == "y" or keyfile == "Y":
|
|
||||||
print("Keyfile enabled.")
|
|
||||||
enable_keyfile = True
|
|
||||||
else:
|
|
||||||
print("Keyfile disabled.")
|
|
||||||
enable_keyfile = False
|
|
||||||
|
|
||||||
# Pestering password asker until you confirm it
|
|
||||||
while True:
|
|
||||||
password = getpass.getpass("\nCreating password > ")
|
|
||||||
confirm = input(f"Did you type the correct password, and remember it? [Y]/[n] ")
|
|
||||||
if confirm == "Y" or confirm == "y" or confirm == "":
|
|
||||||
password = password.encode()
|
|
||||||
break
|
|
||||||
|
|
||||||
# 1. Setup Salt
|
|
||||||
salt = os.urandom(16)
|
|
||||||
|
|
||||||
# 2. Derive Key
|
|
||||||
kdf = PBKDF2HMAC(
|
|
||||||
algorithm=hashes.SHA256(),
|
|
||||||
length=32,
|
|
||||||
salt=salt,
|
|
||||||
iterations=480000,
|
|
||||||
)
|
|
||||||
key = base64.urlsafe_b64encode(kdf.derive(password))
|
|
||||||
f = Fernet(key)
|
|
||||||
|
|
||||||
print("Encrypting...", end = " ")
|
|
||||||
try:
|
|
||||||
# 3. Encrypt and save SALT + DATA together
|
|
||||||
with open(file_name, 'rb') as file:
|
|
||||||
original_data = file.read()
|
|
||||||
|
|
||||||
encrypted_data = f.encrypt(original_data)
|
|
||||||
|
|
||||||
if not enable_keyfile:
|
|
||||||
with open(f"{file_chosen_name}.p7c_enc", 'wb') as file:
|
|
||||||
# Write the 16-byte salt first, then the encrypted data
|
|
||||||
file.write(salt)
|
|
||||||
file.write(encrypted_data)
|
|
||||||
|
|
||||||
elif enable_keyfile:
|
|
||||||
with open(f"key.p7c_key", 'wb') as key:
|
|
||||||
key.write(salt)
|
|
||||||
|
|
||||||
with open(f"{file_chosen_name}.p7c_enc", 'wb') as file:
|
|
||||||
file.write(encrypted_data)
|
|
||||||
else:
|
|
||||||
print("What the f** did you do something to enable_keyfile?")
|
|
||||||
|
|
||||||
print("Encrypted! ")
|
|
||||||
delete_original = input("Delete the original zip file for security? [Y]/[n] ")
|
|
||||||
if delete_original == "Y" or delete_original == "y" or delete_original == "":
|
|
||||||
os.remove(f"{file_name}")
|
|
||||||
print("Original file removed.")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error! {e}")
|
|
||||||
|
|
||||||
# Encrypting data
|
# Encrypting data
|
||||||
def encrypt_data_neo(unencrypted_name, password, encrypted_name=None, use_key=None, keyfile_name=None, delete_original=None):
|
def encrypt_data_neo(unencrypted_name, password, encrypted_name=None, use_key=None, keyfile_name=None, delete_original=None):
|
||||||
|
|
||||||
@@ -172,77 +97,6 @@ def encrypt_data_neo(unencrypted_name, password, encrypted_name=None, use_key=No
|
|||||||
verbose("🔥🔥🔥 THIS IS AN ERROR 🔥🔥🔥")
|
verbose("🔥🔥🔥 THIS IS AN ERROR 🔥🔥🔥")
|
||||||
print(f"\nAn error has occured.\n {e}\n")
|
print(f"\nAn error has occured.\n {e}\n")
|
||||||
|
|
||||||
# Decrypting data
|
|
||||||
def decrypt_data():
|
|
||||||
# 1. Get the password from the user
|
|
||||||
while True:
|
|
||||||
choose_file = input("\nName of the p7c_enc file without extension, e.g. \"encrypted\"\nName > ") + ".p7c_enc"
|
|
||||||
if Path(choose_file).is_file():
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("This p7c_enc file does not exist!")
|
|
||||||
|
|
||||||
key_exists = input("Do you have a p7c_key keyfile? [y]/[N] ")
|
|
||||||
if key_exists == "y" or key_exists == "Y":
|
|
||||||
while True:
|
|
||||||
input("Double check if your key is in the same direcory as this code and your encrypted file.\nIt must be named key.p7c_key. Press ENTER to check.")
|
|
||||||
if Path("key.p7c_key").is_file():
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("Does not exist!")
|
|
||||||
there_is_a_key = True
|
|
||||||
else:
|
|
||||||
there_is_a_key = False
|
|
||||||
|
|
||||||
password = getpass.getpass("Password > ").encode()
|
|
||||||
|
|
||||||
# 2. Open the encrypted file and extract the salt + data
|
|
||||||
if there_is_a_key:
|
|
||||||
with open("key.p7c_key", 'rb') as file:
|
|
||||||
file_salt = file.read(16)
|
|
||||||
with open(choose_file, 'rb') as file:
|
|
||||||
encrypted_data = file.read()
|
|
||||||
|
|
||||||
elif not there_is_a_key:
|
|
||||||
with open(choose_file, 'rb') as file:
|
|
||||||
# Read exactly 16 bytes for the salt
|
|
||||||
file_salt = file.read(16)
|
|
||||||
# Read everything else as the encrypted data
|
|
||||||
encrypted_data = file.read()
|
|
||||||
else:
|
|
||||||
print("WHAT DID YOU DO TO THERE_IS_A_KEY?!")
|
|
||||||
|
|
||||||
# 3. Re-derive the EXACT same key using that salt
|
|
||||||
kdf = PBKDF2HMAC(
|
|
||||||
algorithm=hashes.SHA256(),
|
|
||||||
length=32,
|
|
||||||
salt=file_salt,
|
|
||||||
iterations=480000,
|
|
||||||
)
|
|
||||||
key = base64.urlsafe_b64encode(kdf.derive(password))
|
|
||||||
f = Fernet(key)
|
|
||||||
|
|
||||||
# 4. Decrypt and save the original file
|
|
||||||
print("Decrypting...", end = " ")
|
|
||||||
try:
|
|
||||||
decrypted_data = f.decrypt(encrypted_data)
|
|
||||||
|
|
||||||
with open('unencrypted.zip', 'wb') as file:
|
|
||||||
file.write(decrypted_data)
|
|
||||||
print("Success.")
|
|
||||||
delete_encrypted = input("\nDelete the encrypted file (and key, if exists)? [Y]/[n] ")
|
|
||||||
if delete_encrypted == "Y" or delete_encrypted == "y" or delete_encrypted == "":
|
|
||||||
os.remove(choose_file)
|
|
||||||
if there_is_a_key:
|
|
||||||
os.remove("key.p7c_key")
|
|
||||||
print("Key removed.")
|
|
||||||
print("Encrypted file removed.")
|
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Could not decrypt!.\nThis might be due to a wrong file or corrupted data?\nDetailed info:\n{e}.")
|
|
||||||
|
|
||||||
# Decrypting data
|
|
||||||
def decrypt_data_neo(encrypted_name, password, unencrypted_name=None, use_key=None, keyfile_name=None, delete_original=None):
|
def decrypt_data_neo(encrypted_name, password, unencrypted_name=None, use_key=None, keyfile_name=None, delete_original=None):
|
||||||
|
|
||||||
choose_file = encrypted_name
|
choose_file = encrypted_name
|
||||||
@@ -290,11 +144,11 @@ def decrypt_data_neo(encrypted_name, password, unencrypted_name=None, use_key=No
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
decrypted_data = f.decrypt(encrypted_data)
|
decrypted_data = f.decrypt(encrypted_data)
|
||||||
verbose("data unencrypted.")
|
verbose("data decrypted.")
|
||||||
|
|
||||||
with open(f'{unencrypted_name}', 'wb') as file:
|
with open(f'{unencrypted_name}', 'wb') as file:
|
||||||
file.write(decrypted_data)
|
file.write(decrypted_data)
|
||||||
verbose("unencrypted data written to disk.")
|
verbose("decrypted data written to disk.")
|
||||||
if delete_original:
|
if delete_original:
|
||||||
os.remove(encrypted_name)
|
os.remove(encrypted_name)
|
||||||
verbose("Encrypted file removed.")
|
verbose("Encrypted file removed.")
|
||||||
@@ -305,25 +159,13 @@ def decrypt_data_neo(encrypted_name, password, unencrypted_name=None, use_key=No
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\nError. Could not decrypt. It is likely that your password is wrong.\nError: {e}.\n")
|
print(f"\nError. Could not decrypt. It is likely that your password is wrong.\nError: {e}.\n")
|
||||||
|
|
||||||
# Main function
|
|
||||||
def old_main():
|
|
||||||
while True:
|
|
||||||
print("\nPCS - P7MJ's enCryption System | V A-2-i Dividend | P7MJ")
|
|
||||||
choice = input("[1] Encrypt [2] Decrypt [x] Exit > ")
|
|
||||||
if choice == "1":
|
|
||||||
encrypt_data()
|
|
||||||
elif choice == "2":
|
|
||||||
decrypt_data()
|
|
||||||
elif choice == "x":
|
|
||||||
sys.exit(0)
|
|
||||||
else:
|
|
||||||
print("Not an option!!!")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
while True:
|
while True:
|
||||||
inputs = input("[PCS] ")
|
inputs = input("[PCS] ")
|
||||||
list_inputs = inputs.split()
|
list_inputs = inputs.split()
|
||||||
|
verbose(inputs)
|
||||||
|
verbose(list_inputs)
|
||||||
|
|
||||||
if not list_inputs:
|
if not list_inputs:
|
||||||
continue
|
continue
|
||||||
@@ -335,15 +177,27 @@ if __name__ == "__main__":
|
|||||||
list_inputs[i] = True
|
list_inputs[i] = True
|
||||||
|
|
||||||
if list_inputs[0] == "help":
|
if list_inputs[0] == "help":
|
||||||
print("encrypt unencrypted_name encrypted_name=None password use_key=None keyfile_name=None delete_original=None")
|
print("Encrypt:")
|
||||||
# 1 2 3 4 5 6
|
print(" encrypt unencrypted_name [encrypted_name] password [use_key] [keyfile_name] [delete_original]")
|
||||||
print("decrypt encrypted_name unencrypted_name=None password use_key=None keyfile_name=None delete_original=None")
|
print()
|
||||||
# 1 2 3 4 5 6
|
print("Decrypt:")
|
||||||
print("\nDue to this program being able to encrypt absolutely ANYTHING, It is recommended to name your encrypted archives after your original file.")
|
print(" decrypt encrypted_name [unencrypted_name] password [use_key] [keyfile_name] [delete_original]")
|
||||||
print("E.g. archive.zip should be named archive.zip.p7c_enc.")
|
print()
|
||||||
print("This ensures that you remember the extension.")
|
print("Credits:")
|
||||||
print("\nFor compatibility with PCS A-2-i Dividend, the keyfile must be named key.p7c_key. Additionally, append .p7c_enc to all encrypted archive names.")
|
print(" credits")
|
||||||
print("For compatability with PCS A-1-i Proto, follow A-2-i standards, but do not use any form of keyfile.")
|
print()
|
||||||
|
print("Exit:")
|
||||||
|
print(" exit")
|
||||||
|
print()
|
||||||
|
print("Notes:")
|
||||||
|
print(" [Optional]: optional parameter")
|
||||||
|
print("\nThis program is able to encrypt absolutely ANYTHING.\nIt is recommended to name your encrypted archives after your original file.")
|
||||||
|
print(" E.g. archive.zip should be named archive.zip.p7c_enc.")
|
||||||
|
print(" This ensures that you remember the extension and don't end up decrypting into the wrong format.")
|
||||||
|
print()
|
||||||
|
print("Compatibility Notices")
|
||||||
|
print(" For compatibility with PCS A-2-i Dividend, the keyfile must be named key.p7c_key.\n Additionally, append .p7c_enc to all encrypted archive names.")
|
||||||
|
print(" For compatability with PCS A-1-i Proto, follow A-2-i standards, but do not use any form of keyfile.")
|
||||||
|
|
||||||
elif list_inputs[0] == "credits":
|
elif list_inputs[0] == "credits":
|
||||||
print("PCS A-3-i Terminal by P7MJ.")
|
print("PCS A-3-i Terminal by P7MJ.")
|
||||||
@@ -368,6 +222,8 @@ if __name__ == "__main__":
|
|||||||
print("Invalid use of decrypt: length of parameters incorrect.")
|
print("Invalid use of decrypt: length of parameters incorrect.")
|
||||||
print('If you wish to leave a parameter empty, type "None", "0", "No", "no", or "False".')
|
print('If you wish to leave a parameter empty, type "None", "0", "No", "no", or "False".')
|
||||||
print('Type "help" for more information.')
|
print('Type "help" for more information.')
|
||||||
|
else:
|
||||||
|
print("Command not found.")
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
79
README.md
79
README.md
@@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
PCS is a secure and lightweight Python utility designed to encrypt and decrypt any type of file that can be read in binary. Virtually every file can be encrypted and decrypted, including archives, pictures, movies, code, and programs.
|
PCS is a secure and lightweight Python utility designed to encrypt and decrypt any type of file that can be read in binary. Virtually every file can be encrypted and decrypted, including archives, pictures, movies, code, and programs.
|
||||||
|
|
||||||
It is the standard encryption program for [BUGPy-mOS](https://git.wholeworldcoding.com/wholeworldcoding/BUGPy-mOS) (implemented as the FDEA launcher and encryption "ant"). An implementation derived from the older A-2-i is included as part of the core script.
|
It is the standard encryption program for [BUGPy-mOS](https://git.wholeworldcoding.com/wholeworldcoding/BUGPy-mOS) (implemented as the FDEA launcher and encryption "ant"). An implementation derived from the older A-2-i is included in BUGPy as an utility.
|
||||||
|
|
||||||
This version features total extension freedom. You can now not only encrypt `.zip` files, but any type of file readable in binary. Additionally, there are no longer any limits regarding the names and extensions of the archives and the keyfiles generated.
|
This version features total extension freedom. You can now not only encrypt `.zip` files, but any type of file readable in binary. Additionally, there are no longer any limits regarding the names and extensions of the archives and the keyfiles generated.
|
||||||
|
|
||||||
A-3-i, is compatible both ways with A-2-i, provided that you follow A-2-i's strict filename extension protocols. A-3-i and A-2-i are compatible with A-1-i if you do not use keyfiles while encrypting.
|
A-3-i, is compatible both ways with A-2-i, provided that you follow A-2-i's strict filename extension protocols. A-3-i and A-2-i are compatible with A-1-i if you do not use keyfiles while encrypting.
|
||||||
|
|
||||||
PCS is tested on **Debian Trixie** only. It should work on other Linux distributions, Windows, and Mac, but it is not tested.
|
PCS is tested on **Debian Trixie** only. It should work on other Linux distributions, Windows, and Mac, but it is not tested or guaranteed.
|
||||||
|
|
||||||
## 🧩 Features
|
## 🧩 Features
|
||||||
|
|
||||||
@@ -22,10 +22,10 @@ PCS is tested on **Debian Trixie** only. It should work on other Linux distribut
|
|||||||
|
|
||||||
- Fernet ensures that if the file is corrupted, tampered with, or an attempt to decrypt it has a wrong password, the program will refuse to decrypt rather than producing corrupt data.
|
- Fernet ensures that if the file is corrupted, tampered with, or an attempt to decrypt it has a wrong password, the program will refuse to decrypt rather than producing corrupt data.
|
||||||
|
|
||||||
- Shredding of original files, including keyfiles, is supported after encryption or decryption.
|
- Removal of original files, including keyfiles, is supported after encryption or decryption.
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> The security of the archive depends on your password! Since there is no limit to your password length, or complexity, ensure your password has >8 chars and includes symbols and numbers.
|
> The security of the archive depends on your password! Since there is no limit to your password length, or complexity, ensure your password has >9 chars and includes symbols and numbers. This makes it impractical for attackers to brute-force your password in time.
|
||||||
|
|
||||||
## 🛠️ Installation and Dependencies
|
## 🛠️ Installation and Dependencies
|
||||||
|
|
||||||
@@ -45,8 +45,77 @@ Navigate to the folder and run:
|
|||||||
python3 PCS-A-3-i\ Terminal.py
|
python3 PCS-A-3-i\ Terminal.py
|
||||||
```
|
```
|
||||||
|
|
||||||
After you are inside, type `help` for built-in help.
|
You will be greeted by a prompt:
|
||||||
|
|
||||||
|
```
|
||||||
|
[PCS]
|
||||||
|
```
|
||||||
|
|
||||||
|
Command Usage:
|
||||||
|
|
||||||
|
`encrypt unencrypted_name [encrypted_name] password [use_key] [keyfile_name] [delete_original]`
|
||||||
|
|
||||||
|
`decrypt encrypted_name [unencrypted_name] password [use_key] [keyfile_name] [delete_original]`
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
`encrypt README.md README.md.p7c_enc hello!26 0 0 0`
|
||||||
|
|
||||||
|
- Encrypts `README.md` into `README.md.p7c_enc` using password `hello!26` without using keyfiles or deleting original files
|
||||||
|
|
||||||
|
`decrypt README.md.p7c_enc README.md hello!26 0 0 0`
|
||||||
|
|
||||||
|
- Decrypts `README.md.p7c_enc` into `README.md` using password `hello!26` without using keyfiles or deleting original files
|
||||||
|
|
||||||
|
`encrypt archive.zip archive.zip.p7c_enc hello!na 1 archive_key.p7c_key 1`
|
||||||
|
|
||||||
|
- Encrypts `archive.zip` into `archive.zip.p7c_enc` with password `hello!na` and creating keyfile `archive_key.p7c_key`. Deletes the original file (`archive.zip`) after encryption.
|
||||||
|
|
||||||
|
`decrypt archive.zip.p7c_enc archive.zip hello!na 1 archive_key.p7c_key ``
|
||||||
|
|
||||||
|
- Decrypts `archive.zip.p7c_enc` into `archive.zip` with password `hello!na` and using `archive_key.p7c_key` as the keyfile. Deletes `archive_zip.p7c_enc` and `archive_key.p7c_key` after decryption.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
All parameters in square brackets (`[` `]`) are optional, but you must put something in there.
|
||||||
|
|
||||||
|
If you wish to leave them blank, please type one of:
|
||||||
|
- `None`
|
||||||
|
- `0`
|
||||||
|
- `no`
|
||||||
|
- `No`
|
||||||
|
- `False`
|
||||||
|
in their place.
|
||||||
|
|
||||||
|
If you wish to set use_key or delete_original to True, please type one of:
|
||||||
|
- `True`
|
||||||
|
- `1`
|
||||||
|
- `yes`
|
||||||
|
- `Yes`
|
||||||
|
- `exists`
|
||||||
|
- `Exists`
|
||||||
|
in their place.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Typing `help` lists all commands and their usage!
|
||||||
|
|
||||||
|
## ⁉️ FAQ
|
||||||
|
|
||||||
|
### It says file not found!
|
||||||
|
|
||||||
|
- Make sure your file is in the same directory as the script, and that you run the script from the folder it is in.
|
||||||
|
|
||||||
|
### It's so hard to use compared to the A-2-i!
|
||||||
|
|
||||||
|
- I wanted to get rid of the ambiguous prompts that were very unstandardized. If you are OK with lack of total extension and filename freedom and are ok with the quirks, go use A-2-i.
|
||||||
|
|
||||||
|
### Will you make a GUI?
|
||||||
|
|
||||||
|
- No. I might make one someday but the chances are very, very low, since I don't see the point in it. However, if you are interested and have the skills (or know how to vibe code), you can absolutely clone this and make one yourself.
|
||||||
|
|
||||||
## 🏅 Credits
|
## 🏅 Credits
|
||||||
|
|
||||||
P7MJ Original.
|
P7MJ Original.
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> Feel free to contribute! This project is FOSS.
|
||||||
|
|||||||
Reference in New Issue
Block a user