Actualmente estoy escribiendo mi propio pequeño administrador de contraseñas
Ese es tu primer error. Algo en este complejo tiene muchas trampas sutiles en las que incluso los expertos a veces caen, sin mucha experiencia en esta área, no tienes la oportunidad de hacer algo que esté cerca de asegurar.
almacena la clave en un hash SHA256
Uh oh ...
Esto no necesariamente indica que estás haciendo algo mal, pero tengo muchas dudas de que lo harás bien. ¿Supongo que estás hablando de una contraseña maestra que está siendo bloqueada aquí? La contraseña maestra se debe convertir en una clave usando un KDF como PBKDF2, bcrypt o Argon2, luego esta tecla se usa para cifrar las contraseñas almacenadas.
Si desea tener una forma de verificar que la contraseña sea correcta, debe guardar un hash de la clave, pero NO DEBE almacenar la clave en sí ... si guarda la ¡La clave de cualquier persona que tenga acceso a su almacenamiento tiene todo lo que necesita para descifrar todas las contraseñas!
Si no está hablando de hashear una contraseña maestra y quiere decir una clave real generada al azar, no tengo idea de lo que está intentando lograr aquí, pero no debería usar un KDF lento con una gran cantidad de número de iteraciones.
Alternativamente, podría estar usando la contraseña maestra dos veces, una vez para almacenar como un hash para verificar más tarde que la contraseña que ingresa el usuario es correcta, y nuevamente para usarla como clave para el cifrado. Dependiendo de cómo se haga esto, podría ir desde una falla de diseño hasta entregar la clave por completo.
Editar: Después de ver el código completo, parece ser una cuarta opción: almacena un hash de la contraseña para verificar más tarde si la contraseña ingresada es correcta, luego hash este hash para usar como la clave, que es casi tan mala como almacenar la clave en sí misma.
Yo creo el hash haciendo lo siguiente:
def sha256_rounds(raw, rounds=100001):
obj = hashlib.sha256()
for _ in xrange(rounds):
obj.update(raw)
raw = obj.digest()
return obj.digest()
Realmente no está claro qué raw
está aquí, pero asumo que es la contraseña. Lo que estás haciendo es un hash sin sal usando SHA256. ¡No intentes crear tu propio KDF!
Una vez creado, se almacena con lo siguiente:
key = base64.urlsafe_b64encode(provided_key)
length = len(key)
with open(key_file, "a+") as key_:
front_salt, back_salt = os.urandom(16), os.urandom(16)
key_.write("{}{}{}:{}".format(front_salt, key, back_salt, length))
Entonces, ¿está creando la clave con la clave de hash, luego agregando un salt aleatorio al frente y atrás? No solo concatenar 2 sales diferentes al frente y atrás no es estándar, ¡no está logrando nada aquí porque se hace después de que el KDF ya ha terminado! Solo estás agregando algunos valores aleatorios para tenerlos allí.
Para mostrar qué tan malo es esto (a partir de commit 609fdb5ce976c7e5aa1832670505da60012b73bc), todo lo que se necesita para volcar todas las contraseñas almacenadas sin requiere una contraseña maestra es esto:
from encryption.aes_encryption import AESCipher
from lib.settings import store_key, MAIN_DIR, DATABASE_FILE, display_formatted_list_output
from sql.sql import create_connection, select_all_data
conn, cursor = create_connection(DATABASE_FILE)
display_formatted_list_output(select_all_data(cursor, "encrypted_data"), store_key(MAIN_DIR))
Si bien puede ser una buena experiencia de aprendizaje intentar crear un administrador de contraseñas, por favor por favor nunca lo uses para nada a distancia. importante. Como sugiere @Xenos, no parece que tenga la suficiente experiencia de que crear su propio administrador de contraseñas realmente sería beneficioso de todos modos, probablemente sería una mejor oportunidad de aprendizaje para echar un vistazo a un administrador de contraseñas de código abierto existente.