Non ci sono evidenti punti deboli di sicurezza con i tuoi schemi. Quello originale (a parte il non memorizzare un numero di versione con gli hash in modo da poter aggiornare il tuo schema a più giri o un nuovo pepe, se necessario), o il nuovo a strati con bcrypt. Bcrypt può prendere 72 byte di input quindi non ci sono problemi nell'usare sha256 come hash.
Sarei attento se codificherai l'output del tuo shash6shsh rafforzato dalle chiavi prima di inviarlo a bcrypt. In linea di principio, probabilmente è meglio tenerlo in forma binaria - se si stesse usando sha512, sarebbe possibile utilizzare tutti i byte (come 72 byte = 576 bit). Garantito con sha-256, non importa finché lo fai correttamente. Un hash sha256 è lungo 32 byte (in binario con lettere non stampabili), lungo 44 byte dopo la codifica base64, lungo 64 byte (in esadecimale), ma 88 byte se si codifica in base64 l'hash con codifica esadecimale (che sarebbe parzialmente sicurezza troncata e leggermente indebolita - ad esempio, anziché 256 bit di sicurezza intrinseca hai 72/88 * 256 ~ 209 bit).
Nota, se un utente ha una password di entropia estremamente alta (ad esempio, 400 bit di entropia) che in linea di principio richiederebbe ~ 2 ^ 400 di tempo per craccare, usando sha256 come fase intermedia ci vorrà solo del tempo ~ 2 ^ 256 prima che sia probabile trovare una password che funzioni. Concesso 2 ^ 256 è completamente sicuro in questi giorni (come qualcosa di significativamente più di ~ 2 ^ 80, quindi questa differenza non ha rilevanza pratica).
Diventa più complicato e potenzialmente più fastidioso da mantenere (garantito che si potrebbe sostenere che questa è una buona cosa - se il database è mai stato trapelato sarebbe più difficile per un utente malintenzionato fare in modo che una GPU la forza bruta). Se aggiorni il tuo sistema e le cose non funzionano perfettamente, ci sono molti più punti in cui le cose potrebbero andare storte. Se qualcuno nuovo sviluppatore arriva e vede gli hash in forma come bcrypt, può presumere che siano solo bcrypt e cambi qualcosa che infrange il sistema.
Un'alternativa sarebbe quella di mantenere entrambi i sistemi sul posto e di aggiornare con garbo gli utenti a bcrypt sul loro prossimo login riuscito.
def login(username, password):
user = get_user(username)
if user.uses_old_hash():
calculated_old_hash = sha256_1000_round(password, salt=user.salt)
if constant_time_string_compare(user.hash, calculated_old_hash):
calculated_new_hash = bcrypt.hashpw(password, salt=bcrypt.gensalt(12))
user.hash = calculated_new_hash
print "Login Successful"
return True
else:
print "Login Failed"
return False
else:
hash = user.hash
calculated_new_hash = bcrypt.hashpw(password, salt=hash)
if constant_time_string_compare(hash, calculated_new_hash):
print "Login Successful"
return True
else:
print "Login Failed"
return False