Comment utiliser scrypt pour générer du hash pour mot de passe et sel en Python
j'aimerais utiliser scrypt pour créer un hachage pour les mots de passe et les sels de mes utilisateurs. J'ai trouvé deux références , mais il y a des choses que je ne comprends pas à leur sujet.
ils utilisent les fonctions scrypt encrypt et decrypt. L'un crypte une chaîne aléatoire et l'autre crypte le sel (qui semble erroné puisque seul le mot de passe et non le sel est utilisé pour le décryptage). Il semble que la fonction de décryptage soit utilisé pour valider le mot de passe/sel comme effet secondaire du déchiffrement.
basé sur le peu que je comprends, ce que je veux est une fonction de dérivation de clé (KDF) plutôt que le cryptage/déchiffrement et que le KDF est probablement généré et utilisé par scrypt pour le cryptage/déchiffrement. Le véritable KDF est utilisé en coulisse et je crains que suivre aveuglément ces exemples ne conduise à une erreur. Si les fonctions scrypt encrypt / decrypt sont utilisées pour générer et vérifier mot de passe, Je ne comprends pas le rôle de la chaîne étant crypté. Son contenu ou sa longueur est-il important?
2 réponses
vous avez raison - les fonctions scrypt que ces deux liens utilisent sont l'utilitaire de chiffrement de fichier scrypt, et non le kdf sous-jacent. J'ai travaillé lentement sur la création d'un hachage de mot de passe autonome basé sur scrypt pour python, et j'ai rencontré ce problème moi-même.
l'utilitaire de fichier scrypt effectue ce qui suit: sélectionne les paramètres n/r/p de scrypt spécifiques à votre système et le paramètre" min time". Il génère alors un sel de 32 octets, puis appelle scrypt(n,r,p,salt,pwd)
pour créer une clé de 64 octets. La chaîne binaire que l'outil retourne est composée de: 1) un en-tête contenant n, r, p valeurs, et le sel encodé en binaire; 2) une somme de contrôle sha256 de l'en-tête; et 3) une copie signée hmac-sha256 de la somme de contrôle, en utilisant les 32 premiers octets de la clé. Par la suite, il utilise les 32 octets restants de la clé pour chiffrer les données d'entrée.
il y a quelques implications de ceci que je peux voir:
-
le les données d'entrée n'ont pas de sens, car elles n'affectent pas réellement le sel utilisé, et encrypt() génère un nouveau sel à chaque fois.
-
vous ne pouvez pas configurer la charge de travail n,r,p manuellement, ou de toute autre manière, sauf le paramètre embarrassant min-time. il ne s'agit pas d'insécurité, mais d'une façon plutôt maladroite de contrôler le facteur travail.
-
après que l'appel de décryptage régénère la clé et la compare avec le hmac, il sera rejeter tout ce qui est juste si votre mot de passe est erroné - mais si c'est juste, il passera à aussi décrypter le paquet de données. C'est beaucoup de travail supplémentaire, l'attaquant n'aurez pas à effectuer - ils n'ont même pas de dériver de 64 octets, seulement 32 pour vérifier la signature. Ce problème ne le rend pas incertain exactement, mais faire du travail que votre attaquant ne fait pas n'est jamais souhaitable.
-
il n'y a pas façon de configurer la clé salt, La Taille de clé dérivée, etc. les valeurs actuelles ne sont pas si mauvaises, mais quand même, ce n'est pas idéal.
-
la limitation" max time " de l'utilitaire de décryptage est incorrecte pour le hachage de mot de passe - chaque fois que le décryptage est appelé, il estime la vitesse de votre système, et fait quelques "deviner" quant à savoir si elle peut calculer la clé dans le temps max - qui est plus au-dessus de votre attaquant ne doit pas faire( voir #3), mais il signifie également decrypt pourrait commencer à rejeter les mots de passe sous une lourde charge système.
-
Je ne suis pas sûr pourquoi Colin Percival n'a pas fait le KDF & parameter-choosing code partie de l'api publique, mais il est en fait explicitement marqué "privé" à l'intérieur du code source - pas même exporté pour le lien. Cela me fait hésiter à y accéder directement sans beaucoup plus d'étude.
dans l'Ensemble, ce qui il faut un format de hachage agréable qui peut stocker scrypt, et une implémentation qui expose le kdf sous-jacent et l'algorithme de choix des paramètres. J'y travaille actuellement moi-même pour passlib , mais il n'a pas vu beaucoup d'attention : (
juste pour faire court - les instructions de ce site sont "ok", j'utiliserais juste une chaîne vide comme le contenu du fichier, et être conscient des frais généraux supplémentaires et les problèmes.
ces deux références ont complètement tort. Ne pas muck avec encrypt
et decrypt
: il suffit d'utiliser hash
le KDF n'est pas directement exposé, mais hash
est assez proche. (En fait, il me semble qu'il est encore mieux, parce qu'il mélange la garniture d'un sandwich PBKDF2.)
cet exemple de code fonctionne avec python2.7 et python3.2. Il utilise PyCrypto, passlib, et PY-scrypt, mais seulement besoins py-scrypt.
vous voudrez utiliser une fonction de comparaison de contenu-temps comme passlib.utils.consteq
pour atténuer les attaques de synchronisation.
vous voudrez également choisir les paramètres avec soin. Les valeurs par défaut logN=14, r=8,p = 1 signifient 1 "round" en utilisant 16 MiB de mémoire. Sur un serveur, vous voulez probablement quelque chose de plus comme 10,8,8 -- moins de RAM, plus de CPU. Vous devriez le chronométrer sur votre matériel sous votre charge prévue.