Ronjinson981 / blindfaith.app

2 stars 0 forks source link

New one #5

Open Ronjinson981 opened 3 months ago

Ronjinson981 commented 3 months ago

© 2024 Nicholas Lienner Wardle. All rights reserved.

Unauthorized copying of this file, via any medium, is strictly prohibited.

Proprietary and confidential.

Trademarks and brands are the property of their respective owners.

NOTICE TO USER:

This software is the confidential and proprietary information of Nicholas Lienner Wardle ("Confidential Information").

You shall not disclose such Confidential Information and shall use it only in accordance with the terms of the license agreement

you entered into with Nicholas Lienner Wardle.

#

Nicholas Lienner Wardle retains all ownership rights to this software.

By using this software, you agree to the terms and conditions outlined in the accompanying license agreement.

import os import logging import re import configparser from cryptography.hazmat.primitives.kdf.argon2 import Argon2, Type from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import padding from cryptography.hazmat.backends import default_backend from getpass import getpass # For secure password input from shutil import rmtree

Constants

CONFIG_FILE = 'config.ini' SALT_FILE_TEMPLATE = '{}_salt.bin' DERIVED_KEY_FILE_TEMPLATE = '{}_derived_key.bin' ENCRYPTED_DATA_FILE = 'encrypted_data.bin' BLOCK_SIZE = 128 # AES block size in bits

Set up logging

logging.basicConfig(level=logging.INFO) logger = logging.getLogger(name)

Load configurations

config = configparser.ConfigParser() config.read(CONFIG_FILE)

MEMORY_COST = config.getint('Argon2', 'MemoryCost', fallback=102400) # 100 MB memory cost TIME_COST = config.getint('Argon2', 'TimeCost', fallback=2) # 2 iterations PARALLELISM = config.getint('Argon2', 'Parallelism', fallback=8) # 8 parallel threads KEY_LENGTH = config.getint('Argon2', 'KeyLength', fallback=32) # 32 bytes derived key length

def save_to_file(data, filename): """Save binary data to a file.""" with open(filename, 'wb') as f: f.write(data) logger.info(f"Saved data to {filename}")

def load_from_file(filename): """Load binary data from a file.""" with open(filename, 'rb') as f: return f.read()

def derive_key(password, salt): """Derive a key using Argon2 KDF.""" argon2_kdf = Argon2( memory_cost=MEMORY_COST, time_cost=TIME_COST, parallelism=PARALLELISM, length=KEY_LENGTH, salt=salt, type=Type.I # Argon2i is better for password hashing ) return argon2_kdf.derive(password)

def verify_key(password, derived_key, salt): """Verify the derived key using Argon2 KDF.""" argon2_kdf = Argon2( memory_cost=MEMORY_COST, time_cost=TIME_COST, parallelism=PARALLELISM, length=KEY_LENGTH, salt=salt, type=Type.I ) try: argon2_kdf.verify(password, derived_key) return True except Exception as e: logger.error(f"Password verification failed: {e}") return False

def generate_or_load_salt(user): """Generate or load the salt for a specific user.""" salt_file = SALT_FILE_TEMPLATE.format(user) if not os.path.exists(salt_file): salt = os.urandom(16) # Generate a random 16-byte salt save_to_file(salt, salt_file) else: salt = load_from_file(salt_file) return salt

def encrypt_data(key, data): """Encrypt data using AES.""" iv = os.urandom(16) # Generate a random initialization vector cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) encryptor = cipher.encryptor() padder = padding.PKCS7(BLOCK_SIZE).padder() padded_data = padder.update(data) + padder.finalize() encrypted_data = encryptor.update(padded_data) + encryptor.finalize() return iv + encrypted_data

def decrypt_data(key, encrypted_data): """Decrypt data using AES.""" iv = encrypted_data[:16] cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) decryptor = cipher.decryptor() padded_data = decryptor.update(encrypted_data[16:]) + decryptor.finalize() unpadder = padding.PKCS7(BLOCK_SIZE).unpadder() data = unpadder.update(padded_data) + unpadder.finalize() return data

def validate_password(password): """Validate the password against complexity requirements.""" if len(password) < 8: logger.error("Password must be at least 8 characters long") return False if not re.search(r'[A-Z]', password): logger.error("Password must contain at least one uppercase letter") return False if not re.search(r'[a-z]', password): logger.error("Password must contain at least one lowercase letter") return False if not re.search(r'[0-9]', password): logger.error("Password must contain at least one digit") return False if not re.search(r'[!@#\$%\^&*]', password): logger.error("Password must contain at least one special character (!@#$%^&*)") return False return True

def secure_delete(file_path): """Securely delete a file by overwriting it before deletion.""" if os.path.exists(file_path): with open(file_path, 'ba+', buffering=0) as f: length = f.tell() f.seek(0) f.write(os.urandom(length)) os.remove(file_path) logger.info(f"Securely deleted file: {file_path}")

def register_user(): """Register a new user by creating a salt and derived key.""" user = input("Enter your username: ") while True: password = getpass("Enter your password: ") if validate_password(password): password = password.encode() break else:

# Generate salt and derive key
salt = os.urandom(16)
derived_key = derive_key(password, salt)

# Save salt and derived key to files
save_to_file(salt, SALT_FILE_TEMPLATE.format(user))
save_to_file(derived_key, DERIVED_KEY_FILE_TEMPLATE.format(user))

logger.info(f"User {user} registered successfully")

def encrypt_file(user): """Encrypt a file for a specific user.""" password = getpass("Enter your password: ").encode()

# Load salt and derive key
salt = load_from_file(SALT_FILE_TEMPLATE.format(user))
derived_key = derive_key(password, salt)

# Verify the derived key
stored_derived_key = load_from_file(DERIVED_KEY_FILE_TEMPLATE.format(user))
if not verify_key(password, stored_derived_key, salt):
    logger.error("Password verification failed")
    return

# Get file to encrypt
file_path = input("Enter the file path to encrypt: ")
with open(file_path, 'rb') as f:
    file_data = f.read()

# Encrypt and save the encrypted file
encrypted_data = encrypt_data(derived_key, file_data)
save_to_file(encrypted_data, ENCRYPTED_DATA_FILE)
logger.info(f"File {file_path} encrypted successfully")

# Securely delete the original file
secure_delete(file_path)

def decrypt_file(user): """Decrypt a file for a specific user.""" password = getpass("Enter your password: ").encode()

# Load salt and derive key
salt = load_from_file(SALT_FILE_TEMPLATE.format(user))
derived_key = derive_key(password, salt)

# Verify the derived key
stored_derived_key = load_from_file(DERIVED_KEY_FILE_TEMPLATE.format(user))
if not verify_key(password, stored_derived_key, salt):
    logger.error("Password verification failed")
    return

# Load and decrypt the file
encrypted_data = load_from_file(ENCRYPTED_DATA_FILE)
decrypted_data = decrypt_data(derived_key, encrypted_data)

# Save the decrypted file
output_file = input("Enter the output file path for the decrypted data: ")
save_to_file(decrypted_data, output_file)
logger.info(f"File decrypted and saved to {output_file}")

def main(): while True: print("1. Register User") print("2. Encrypt File") print("3. Decrypt File") print("4. Exit") choice = input("Enter your choice: ")

    if choice == '1':
        register_user()
    elif choice == '2':
        user = input("Enter your username: ")
        encrypt_file(user)
    elif choice == '3':
        user = input("Enter your username: ")
        decrypt_file(user)
    elif choice == '4':
        break        else:
        print("Invalid choice. Please try again.")

if name == "main":

Ensure the configuration file exists

if not os.path.exists(CONFIG_FILE):
    config['Argon2'] = {
        'MemoryCost': '102400',
        'TimeCost': '2',
        'Parallelism': '8',
        'KeyLength': '32'
    }
    with open(CONFIG_FILE, 'w') as configfile:
        config.write(configfile)
    logger.info(f"Configuration file {CONFIG_FILE} created with default values.")

main()