Untitled

 avatar
unknown
python
2 months ago
3.9 kB
6
Indexable
#!/usr/bin/env python3
import os
import json
import base64
import argparse
from getpass import getpass
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.fernet import Fernet

SALT_FILE = 'salt.bin'
DATA_FILE = 'passwords.json.enc'
ITERATIONS = 100000

def get_salt():
    if os.path.exists(SALT_FILE):
        with open(SALT_FILE, 'rb') as f:
            return f.read()
    else:
        salt = os.urandom(16)
        with open(SALT_FILE, 'wb') as f:
            f.write(salt)
        return salt

def derive_key(master_password, salt):
    kdf = PBKDF2HMAC(
        algorithm=hashes.SHA256(),
        length=32,
        salt=salt,
        iterations=ITERATIONS,
    )
    return base64.urlsafe_b64encode(kdf.derive(master_password.encode()))

def load_data(fernet):
    if os.path.exists(DATA_FILE):
        with open(DATA_FILE, 'rb') as f:
            encrypted = f.read()
        try:
            decrypted = fernet.decrypt(encrypted)
            return json.loads(decrypted.decode())
        except Exception:
            print("Error al descifrar el archivo. ¿Contraseña maestra incorrecta?")
            exit(1)
    else:
        return {}

def save_data(fernet, data):
    encrypted = fernet.encrypt(json.dumps(data).encode())
    with open(DATA_FILE, 'wb') as f:
        f.write(encrypted)

def main():
    parser = argparse.ArgumentParser(description="Gestor de contraseñas básico")
    subparsers = parser.add_subparsers(dest='command', help='Comandos disponibles')

    parser_add = subparsers.add_parser('add', help='Añadir datos de un servicio')
    parser_add.add_argument('service', help='Nombre del servicio')

    parser_get = subparsers.add_parser('get', help='Obtener datos de un servicio')
    parser_get.add_argument('service', help='Nombre del servicio')

    parser_list = subparsers.add_parser('list', help='Listar servicios')

    parser_delete = subparsers.add_parser('delete', help='Eliminar un servicio')
    parser_delete.add_argument('service', help='Nombre del servicio')

    args = parser.parse_args()

    master = getpass("Contraseña maestra: ")
    salt = get_salt()
    key = derive_key(master, salt)
    fernet = Fernet(key)
    data = load_data(fernet)

    if args.command == 'add':
        print("Introduce los datos para el servicio.")
        print("Escribe el nombre del campo y su valor.")
        print("Cuando quieras introducir la contraseña, escribe 'pass' como nombre del campo.")
        fields = {}
        while True:
            field = input("Campo (o 'pass' para contraseña): ").strip()
            if field.lower() == 'pass':
                fields['password'] = getpass("Contraseña del servicio: ")
                break
            else:
                value = input(f"Valor para {field}: ")
                fields[field] = value
        data[args.service] = fields
        save_data(fernet, data)
        print(f"Datos para '{args.service}' guardados.")
    elif args.command == 'get':
        service_data = data.get(args.service)
        if service_data:
            print(f"Datos para {args.service}:")
            for k, v in service_data.items():
                print(f"{k}: {v}")
        else:
            print("Servicio no encontrado.")
    elif args.command == 'list':
        if data:
            print("Servicios almacenados:")
            for s in data.keys():
                print(f" - {s}")
        else:
            print("No hay servicios almacenados.")
    elif args.command == 'delete':
        if args.service in data:
            del data[args.service]
            save_data(fernet, data)
            print(f"Servicio '{args.service}' eliminado.")
        else:
            print("Servicio no encontrado.")
    else:
        parser.print_help()

if __name__ == '__main__':
    main()
Editor is loading...
Leave a Comment