J'utilise une bibliothèque Java scrypt pour le stockage des mots de passe. Il appelle une valeur N
, r
et p
lorsque je crypte des choses, que sa documentation appelle "coût CPU", "coût mémoire" et "coût de parallélisation". paramètres. Le seul problème est que je ne sais pas vraiment ce qu'ils signifient spécifiquement ou quelles seraient les bonnes valeurs pour eux; peut-être qu'ils correspondent en quelque sorte aux commutateurs -t, -m et -M sur l'application d'origine de Colin Percival ?
Quelqu'un a-t-il des suggestions à ce sujet? La bibliothèque elle-même répertorie N = 16384, r = 8 et p = 1, mais je ne sais pas si c'est fort ou faible ou quoi.
Pour commencer:
cpercival mentionné dans ses diapositives de 2009 quelque chose autour
Ces valeurs s'avèrent être assez bonnes pour une utilisation générale (password-db pour certaines WebApp) même aujourd'hui (2012-09). Bien sûr, les détails dépendent de l'application.
De plus, ces valeurs signifient (principalement):
N
: facteur de travail général, nombre d'itérations.r
: taille de bloc utilisée pour le hachage sous-jacent; affine le coût relatif de la mémoire.p
: facteur de parallélisation; affine le coût relatif du processeur.r
et p
sont destinés à répondre au problème potentiel selon lequel la vitesse du processeur, la taille de la mémoire et la bande passante n'augmentent pas comme prévu. Si les performances du processeur augmentent plus rapidement, vous augmentez p
, si au contraire une percée dans la technologie de la mémoire fournit une amélioration de l'ordre de grandeur, vous augmentez r
. Et N
est là pour suivre le doublement général des performances par période de temps .
Important: Toutes les valeurs modifient le résultat. (Mis à jour :) C'est la raison pour laquelle tous les paramètres scrypt sont stockés dans la chaîne de résultat.
La mémoire requise pour que scrypt fonctionne est calculée comme suit:
128 octets ×
N_cost
×r_blockSizeFactor
pour les paramètres que vous citez (N=16384
, r=8
, p=1
)
128 × 16384 × 8 = 16 777 216 octets = 16 Mo
Vous devez en tenir compte lors du choix des paramètres.
Bcrypt est "plus faible" que Scrypt (bien qu'encore trois ordres de grandeur plus fort que PBKDF2 ) car il ne nécessite que 4 Ko de mémoire. Vous voulez rendre difficile la parallélisation de la fissuration dans le matériel. Par exemple, si une carte vidéo possède 1,5 Go de mémoire intégrée et que vous avez réglé scrypt pour consommer 1 Go de mémoire:
128 × 16384 × 512 = 1 073 741 824 octets = 1 Go
alors un attaquant n'a pas pu le paralléliser sur sa carte vidéo. Mais alors votre application/téléphone/serveur devrait utiliser 1 Go de RAM chaque fois qu'ils calculent un mot de passe).
Cela m'aide à considérer les paramètres de cryptage comme un rectangle. Où:
cost
( [~ # ~] n [~ # ~] ) augmente la mémoire utilisation et itérations .blockSizeFactor
( r ) augmente l'utilisation de la mémoire .Le paramètre restant parallelization
( p ) signifie que vous devez faire la chose en entier 2, 3 ou plusieurs fois:
Si vous aviez plus de mémoire que CPU, vous pourriez calculer les trois chemins séparés en parallèle - nécessitant le triple de la mémoire:
Mais dans toutes les implémentations du monde réel, il est calculé en série, triplant les calculs nécessaires:
En réalité, personne n'a jamais choisi un facteur p
autre que p=1
.
Quels sont les facteurs idéaux?
Version graphique de ce qui précède:
Remarques:
r=8
courbeEt zoomé dans la version ci-dessus sur la zone raisonnable:
Je ne veux pas marcher sur les excellentes réponses fournies ci-dessus, mais personne ne parle vraiment de la raison pour laquelle "r" a la valeur qu'il a. La réponse de bas niveau fournie par le papier Scrypt de Colin Percival est qu'elle se rapporte au "produit de latence de mémoire-bande passante". Mais qu'est-ce que cela veut vraiment dire?
Si vous faites bien Scrypt, vous devriez avoir un grand bloc de mémoire qui se trouve principalement dans la mémoire principale. La mémoire principale prend du temps à extraire. Lorsqu'une itération de la boucle de saut de bloc sélectionne pour la première fois un élément du grand bloc à mélanger dans le tampon de travail, il doit attendre de l'ordre de 100 ns pour que le premier bloc de données arrive. Ensuite, il doit en demander un autre et attendre qu'il arrive.
Pour r = 1, vous feriez 4 itérations Salsa20/8 et 2n lectures imprégnées de latence à partir de la mémoire principale.
Ce n'est pas bon, car cela signifie qu'un attaquant pourrait obtenir un avantage sur vous en créant un système avec une latence réduite sur la mémoire principale.
Mais si vous augmentez r et diminuez proportionnellement N, vous pouvez atteindre les mêmes besoins en mémoire et effectuer le même nombre de calculs qu'auparavant - sauf que vous avez troqué certains accès aléatoires pour des accès séquentiels. L'extension de l'accès séquentiel permet à l'UC ou à la bibliothèque de pré-extraire efficacement les prochains blocs de données requis. Alors que la latence initiale est toujours là, la latence réduite ou éliminée pour les blocs ultérieurs fait la moyenne de la latence initiale à un niveau minimal. Ainsi, un attaquant gagnerait peu à améliorer sa technologie de mémoire par rapport à la vôtre.
Cependant, il y a un point de rendements décroissants avec l'augmentation de r, et cela est lié au "produit de latence de bande passante mémoire" mentionné précédemment. Ce que ce produit indique, c'est combien d'octets de données peuvent être en transit de la mémoire principale au processeur à un moment donné. C'est la même idée qu'une autoroute - s'il faut 10 minutes pour voyager du point A au point B (latence), et que la route livre 10 voitures/minute au point B à partir du point A (bande passante), la route entre les points A et B contient 100 voitures. Ainsi, le r optimal se rapporte au nombre de blocs de données de 64 octets que vous pouvez demander à la fois, afin de couvrir la latence de cette demande initiale.
Cela améliore la vitesse de l'algorithme, vous permettant soit d'augmenter N pour plus de mémoire et de calculs, soit d'augmenter p pour plus de calculs, comme vous le souhaitez.
Il y a d'autres problèmes avec l'augmentation trop importante de "r", dont je n'ai pas beaucoup discuté:
Pour résumer toutes les recommandations:
Une référence de ma propre implémentation de Scrypt sur une Surface Pro 3 avec un i5-4300 (2 cœurs, 4 threads), en utilisant une constante 128Nr = 16 Mo et p = 230; l'axe gauche est en secondes, l'axe inférieur est la valeur r, les barres d'erreur sont +/- 1 écart-type: