web-dev-qa-db-fra.com

Mot de passe de hachage en C #? Bcrypt/PBKDF2

J'ai cherché MSDN et d'autres ressources sur la façon de procéder, mais je n'ai trouvé aucune solution claire. C'est le meilleur que j'ai trouvé http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generating-a-key-from-a-password.aspx?Redirected=true

J'aimerais hacher les mots de passe en C # en utilisant bcrypt ou PBKDF2 (qui semble être lié à bcrypt). J'aime expérimenter le nombre de tours nécessaires à mon ordinateur pour hacher un mot de passe. Cependant, tout semble concerner le cryptage alors que tout le monde parle de hachage. Je ne peux pas comprendre. Comment puis-je hacher un mot de passe? Cela ressemble plus à PBKDF2 (Rfc2898?) Est un générateur de nombres aléatoires et j'utilise GetBytes (quantité) pour choisir la taille de ma taille de hachage.

Je suis confus. Comment puis-je hacher un mot de passe avec bcrypt/PBKDF?

33
user34537

PBKDF2

Tu étais vraiment proche en fait. Le lien que vous avez indiqué vous montre comment appeler la fonction Rfc2898DeriveBytes pour obtenir les résultats du hachage PBKDF2. Cependant, vous avez été contrarié par le fait que l'exemple utilisait la clé dérivée à des fins de chiffrement (la motivation première de PBKDF1 et 2 était de créer des fonctions de dérivation "clé" adaptées à une utilisation en tant que clés de chiffrement). Bien sûr, nous ne souhaitons pas utiliser la sortie pour le chiffrement mais comme un hachage.

Vous pouvez essayer la bibliothèque SimpleCrypto.Net écrite exactement à cette fin si vous voulez PBKDF2. Si vous regardez l'implémentation , vous pouvez voir que c'est en fait une mince enveloppe (vous l'avez deviné) Rfc2898DeriveBytes .

BCrypt

Vous pouvez essayer l’implémentation C # nommée (quoi d’autre) BCrypt.NET si vous souhaitez expérimenter avec cette variante.

Déni de responsabilité: Je n'ai utilisé ni testé aucune des librairies auxquelles je me suis connecté ... YMMV

32
paracycle

Cela m'a pris (éternel } _ (jours il a fallu des jours) à trouver quoi coder pour obtenir des mots de passe hachés au travail !! donc je le mets ici pour plus de commodité. 

Vous devez lire les documentation et théorie1théorie2 , puis vous pourriez être ouvert aux échappatoires en matière de sécurité. La sécurité est un très gros sujet! Attention aux acheteurs!

Ajoutez le package NuGet BCrypt.Net à la solution

const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor); 

Vous devez ajuster le WorkFactor à ce qui est approprié, voir discussions . C'est un fonction log2

"Le numéro est log2, donc chaque fois que les ordinateurs doublent en vitesse, ajoutez 1 au numéro par défaut."

Ensuite, vous stockez le mot de passe haché dans votre base de données sous la forme passwordFromLocalDB et testez une password entrante comme ceci: 

if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)

Bonne chance!

8
JPK

Plus tôt cette année, je cherchais la même chose pour la création de hachages pour notre projet ASP.NET Web Forms. Je souhaitais le faire de la même manière que les projets MVC le font immédiatement.

Je suis tombé sur cette question => Mot de passe Hasher par défaut pour l’identité ASP.NET, comment cela fonctionne-t-il et est-il sécurisé? Puis j'ai trouvé la source avec la méthode ByteArraysEqual ici => http://www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm -140327/Version/Par défaut/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core/Crypto.cs? ImageName = Microsoft.AspNet.Identity.Core

2
Luke T O'Brien

PBKDF2 utilise HMACSHA1. Si vous souhaitez une solution plus moderne et personnalisable, vous devez consulter cette API utilisant HMACSHA256 ou 512 avec une extension de clé identique à PBKDF2.

https://sourceforge.net/projects/pwdtknet/

Un exemple d’interface graphique inclus dans le code source a montré comment obtenir un hachage à partir d’un mot de passe, y compris la création de crypto random salt ..... enjoy :) 

1
thashiznets

Pour PBKDF2, vous pourrez peut-être utiliser System.Security.Cryptography.Rfc2898DeriveBytes.

Voir MSDN ici: http://msdn.Microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

1
Jay S

j'étais intéressé par une réponse qui n'impliquait aucune bibliothèque.

J'ai lu cet article https://crackstation.net/hashing-security.htm qui relie une implémentation dans différentes langues C # parmi lesquelles je lierai ici

https://github.com/defuse/password-hashing/blob/master/PasswordStorage.cs

fait intéressant, il utilise Rfc2898DeriveBytes comme mentionné à quelques reprises ici.

private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes){
    using (var pbkdf2 = new Rfc2898DeriveBytes(password, salt)) {
        pbkdf2.IterationCount = iterations;
        return pbkdf2.GetBytes(outputBytes);
    }
}
0
CyberFox

PBKDF2

Dans l'exemple de http://msdn.Microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx , lorsque vous arrivez à la ligne "Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes (pwd1) , myIterations); ", k1 est le hachage. L'exemple du cryptage s'explique par le fait que Rfc2898DeriveBytes a été conçu à l'origine pour créer des clés de cryptage.

Si vous ne fournissez pas de sel, Rfc2898DeriveBytes créera le sien, mais je ne sais pas si RNGCryptoServiceProvider réussit mieux à être cryptographiquement aléatoire.

Selon OWASP ( https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2 ), l’utilisation sous-jacente de SHA1 par Rfc2898DeriveBytes signifie qu’elle n’est valable que pour des haches jusqu’à 160 bits. Si vous créez un hachage plus long, un attaquant ne doit plus se soucier que des 160 premiers bits, mais vous avez rendu le hachage/authentification de mot de passe plus coûteux pour vous, sans gain.

Voici un exemple de code pour le hachage du mot de passe Rfc2898DeriveBytes (stockez le hachage, le sel et les itérations dans la base de données):

public class Rfc2898PasswordEncoder
{
    private int _byteLength = 160 / 8; // 160 bit hash length

    public class EncodedPassword
    {
        public byte[] Hash { get; set; }
        public byte[] Salt { get; set; }
        public int Iterations { get; set; }
    }

    public EncodedPassword EncodePassword(string password, int iterations)
    {
        var populatedPassword = new EncodedPassword
        {
            Salt = CreateSalt(),
            Iterations = iterations
        };

        // Add Hash
        populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);

        return populatedPassword;
    }

    public bool ValidatePassword(string password, EncodedPassword encodedPassword)
    {
        // Create Hash
        var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);

        return testHash == encodedPassword.Hash;
    }

    public byte[] CreateSalt()
    {
        var salt = new byte[_byteLength]; // Salt should be same length as hash

        using (var saltGenerator = new RNGCryptoServiceProvider())
        {
            saltGenerator.GetBytes(salt);
        }

        return salt;
    }

    private byte[] CreateHash(string password, byte[] salt, long iterations)
    {
        byte[] hash;
        using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
        {
            hash = hashGenerator.GetBytes(_byteLength);
        }

        return hash;
    }
} 
0
Phil