web-dev-qa-db-fra.com

Générer un mot de passe fort en C #?

Je me demandais comment générer un mot de passe fort et sécurisé en C #.

J'ai googlé un peu et j'ai vu cette formule dans Wikipedia, où L est la longueur du mot de passe et N est le nombre de symboles possibles:

alt text

En outre, j'ai trouvé cette question , mais pour une raison quelconque, la méthode Membership.GeneratePassword renvoie simplement un nombre aléatoire avec 1 chiffre, qui ne contient absolument aucun mot de passe. Toutes les solutions restantes étaient très lentes (> = 0,5 s).

J'ai besoin d'aide pour mettre en œuvre cette formule (je ne sais pas par où commencer). Vous pouvez également suggérer une autre solution ou expliquer pourquoi la variable GeneratePassword ne fonctionne pas.

28
Alon Gubkin

Je viens d'essayer ce qui suit dans linqpad:

System.Web.Security.Membership.GeneratePassword(25, 10)

C'est le mot de passe que j'ai obtenu: 

System.Web.Security.Membership.GeneratePassword(128, 100)

ce qui m'a valu ce qui suit en l'exécutant trois fois:

| c ^.:? m) #q + () V;} [Z (}) /? -; $] + @! | ^/8 * _9. $ &. &! (? = ^! Wx? [@ % + & - @ b;)> N; & + * w [> $ 2 + _ $% l; + h + # zhs ^ {e? & * (} X_% |:}]]} * X [+) Er% J/- =; Q0 {: + =% c7: ^ $ 
 
 /: _) HxF + *) {2 |; (>: * N ^ +! _ & |} B . $})? [V = [+ v ({-: - @ 9-Z $ j?. [-} (@ MHx +} (} Mz_S (7 # 4} {..> @ G |! +++ {+ C = | _} = + r ^ @ & $ 0; L * | kz -; $ ++/N3 $ =}?;% &]] */^ # ^! + 
 
: * {] - x ^ $ g {|? *)) _ = B @ ^. #% L; g | +) # [nq}? y (_ (m;] S ^ I $ * q = l - [_ /?} & -! k ^ (+ [_ {Z | &: ^%! _)! = p% =) = wYd - #. UP $% s1 {* l% + [% ?! c + 7 = @ = .; {+ M)! ^} & d /] {]; (&}

cela a pris bien moins d'une seconde, d'ailleurs. Le cadre est votre ami.

Voir http://msdn.Microsoft.com/en-us/library/system.web.security.membership.generatepassword.aspx

74
Will

Pour répondre à votre question sur cette formule:

La formule dit qu'un mot de passe de longueur L tiré d'un alphabet de N symboles équivaut à un mot de passe de longueur H tiré d'un alphabet de deux symboles. Donc, si vous avez, disons, 64 symboles (par exemple abc ... xyzABC ... XYZ01 ... 89_!) Et que le mot de passe compte 10 caractères, cela vous donne une sécurité équivalente à un mot de passe 10 log2 64 = 60 caractères tiré de l'alphabet "ab". 

Un "log" est l'opération inverse de l'exponentiation. Deux au sixième pouvoir vous donne soixante-quatre, donc le "log deux" de soixante-quatre vous donne six.

9
Eric Lippert

Je ne sais pas où j'ai trouvé cela, mais voici une classe générant une entropie élevée, des chaînes véritablement aléatoires pouvant être utilisées comme mots de passe.

using System.Security.Cryptography;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class PasswordGenerator
{
    public int MinimumLengthPassword { get; private set; }
    public int MaximumLengthPassword { get; private set; }
    public int MinimumLowerCaseChars { get; private set; }
    public int MinimumUpperCaseChars { get; private set; }
    public int MinimumNumericChars { get; private set; }
    public int MinimumSpecialChars { get; private set; }

    public static string AllLowerCaseChars { get; private set; }
    public static string AllUpperCaseChars { get; private set; }
    public static string AllNumericChars { get; private set; }
    public static string AllSpecialChars { get; private set; }
    private readonly string _allAvailableChars;

    private readonly RandomSecureVersion _randomSecure = new RandomSecureVersion();
    private int _minimumNumberOfChars;

    static PasswordGenerator()
    {
        // Define characters that are valid and reject ambiguous characters such as ilo, IO and 1 or 0
        AllLowerCaseChars = GetCharRange('a', 'z', exclusiveChars: "ilo");
        AllUpperCaseChars = GetCharRange('A', 'Z', exclusiveChars: "IO");
        AllNumericChars = GetCharRange('2', '9');
        AllSpecialChars = "!@#%*()$?+-=";

    }

    public PasswordGenerator(
        int minimumLengthPassword = 15,
        int maximumLengthPassword = 20,
        int minimumLowerCaseChars = 2,
        int minimumUpperCaseChars = 2,
        int minimumNumericChars = 2,
        int minimumSpecialChars = 2)
    {
        if (minimumLengthPassword < 15)
        {
            throw new ArgumentException("The minimumlength is smaller than 15.",
                "minimumLengthPassword");
        }

        if (minimumLengthPassword > maximumLengthPassword)
        {
            throw new ArgumentException("The minimumLength is bigger than the maximum length.",
                "minimumLengthPassword");
        }

        if (minimumLowerCaseChars < 2)
        {
            throw new ArgumentException("The minimumLowerCase is smaller than 2.",
                "minimumLowerCaseChars");
        }

        if (minimumUpperCaseChars < 2)
        {
            throw new ArgumentException("The minimumUpperCase is smaller than 2.",
                "minimumUpperCaseChars");
        }

        if (minimumNumericChars < 2)
        {
            throw new ArgumentException("The minimumNumeric is smaller than 2.",
                "minimumNumericChars");
        }

        if (minimumSpecialChars < 2)
        {
            throw new ArgumentException("The minimumSpecial is smaller than 2.",
                "minimumSpecialChars");
        }

        _minimumNumberOfChars = minimumLowerCaseChars + minimumUpperCaseChars +
                                minimumNumericChars + minimumSpecialChars;

        if (minimumLengthPassword < _minimumNumberOfChars)
        {
            throw new ArgumentException(
                "The minimum length of the password is smaller than the sum " +
                "of the minimum characters of all catagories.",
                "maximumLengthPassword");
        }

        MinimumLengthPassword = minimumLengthPassword;
        MaximumLengthPassword = maximumLengthPassword;

        MinimumLowerCaseChars = minimumLowerCaseChars;
        MinimumUpperCaseChars = minimumUpperCaseChars;
        MinimumNumericChars = minimumNumericChars;
        MinimumSpecialChars = minimumSpecialChars;

        _allAvailableChars =
            OnlyIfOneCharIsRequired(minimumLowerCaseChars, AllLowerCaseChars) +
            OnlyIfOneCharIsRequired(minimumUpperCaseChars, AllUpperCaseChars) +
            OnlyIfOneCharIsRequired(minimumNumericChars, AllNumericChars) +
            OnlyIfOneCharIsRequired(minimumSpecialChars, AllSpecialChars);
    }

    private string OnlyIfOneCharIsRequired(int minimum, string allChars)
    {
        return minimum > 0 || _minimumNumberOfChars == 0 ? allChars : string.Empty;
    }

    public string Generate()
    {
        var lengthOfPassword = _randomSecure.Next(MinimumLengthPassword, MaximumLengthPassword);

        // Get the required number of characters of each catagory and 
        // add random charactes of all catagories
        var minimumChars = GetRandomString(AllLowerCaseChars, MinimumLowerCaseChars) +
                        GetRandomString(AllUpperCaseChars, MinimumUpperCaseChars) +
                        GetRandomString(AllNumericChars, MinimumNumericChars) +
                        GetRandomString(AllSpecialChars, MinimumSpecialChars);
        var rest = GetRandomString(_allAvailableChars, lengthOfPassword - minimumChars.Length);
        var unshuffeledResult = minimumChars + rest;

        // Shuffle the result so the order of the characters are unpredictable
        var result = unshuffeledResult.ShuffleTextSecure();
        return result;
    }

    private string GetRandomString(string possibleChars, int lenght)
    {
        var result = string.Empty;
        for (var position = 0; position < lenght; position++)
        {
            var index = _randomSecure.Next(possibleChars.Length);
            result += possibleChars[index];
        }
        return result;
    }

    private static string GetCharRange(char minimum, char maximum, string exclusiveChars = "")
    {
        var result = string.Empty;
        for (char value = minimum; value <= maximum; value++)
        {
            result += value;
        }
        if (!string.IsNullOrEmpty(exclusiveChars))
        {
            var inclusiveChars = result.Except(exclusiveChars).ToArray();
            result = new string(inclusiveChars);
        }
        return result;
    }
}

internal static class Extensions
{
    private static readonly Lazy<RandomSecureVersion> RandomSecure =
        new Lazy<RandomSecureVersion>(() => new RandomSecureVersion());
    public static IEnumerable<T> ShuffleSecure<T>(this IEnumerable<T> source)
    {
        var sourceArray = source.ToArray();
        for (int counter = 0; counter < sourceArray.Length; counter++)
        {
            int randomIndex = RandomSecure.Value.Next(counter, sourceArray.Length);
            yield return sourceArray[randomIndex];

            sourceArray[randomIndex] = sourceArray[counter];
        }
    }

    public static string ShuffleTextSecure(this string source)
    {
        var shuffeldChars = source.ShuffleSecure().ToArray();
        return new string(shuffeldChars);
    }
}

internal class RandomSecureVersion
{
    //Never ever ever never use Random() in the generation of anything that requires true security/randomness
    //and high entropy or I will hunt you down with a pitchfork!! Only RNGCryptoServiceProvider() is safe.
    private readonly RNGCryptoServiceProvider _rngProvider = new RNGCryptoServiceProvider();

    public int Next()
    {
        var randomBuffer = new byte[4];
        _rngProvider.GetBytes(randomBuffer);
        var result = BitConverter.ToInt32(randomBuffer, 0);
        return result;
    }

    public int Next(int maximumValue)
    {
        // Do not use Next() % maximumValue because the distribution is not OK
        return Next(0, maximumValue);
    }

    public int Next(int minimumValue, int maximumValue)
    {
        var seed = Next();

        //  Generate uniformly distributed random integers within a given range.
        return new Random(seed).Next(minimumValue, maximumValue);
    }
}

Consommez dans votre code ainsi:

var generator = new PasswordGenerator();
string password = generator.Generate();
Console.WriteLine(password);
8
Richard

Je ne sais pas si cela vous aidera, mais c'est ce que j'utilise lorsque je veux générer un mot de passe aléatoire, qui est également fort. Il est simple et rapide à mettre en œuvre/comprendre et n’est pas aussi excessif que celui proposé par le fournisseur d’adhésion ci-dessus ...

    private string Token(byte Length) {
        char[] Chars = new char[] {
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
        };
        string String = string.Empty;
        Random Random = new Random();

        for (byte a = 0; a < Length; a++) {
            String += Chars[Random.Next(0, 61)];
        };

        return (String);
    }
6
Gup3rSuR4c
4
LiamB

Pourquoi ne pas simplement remplir un tableau avec quelques caractères et en choisir un nombre au hasard. Vous pouvez les diviser en groupes pour vous assurer qu'ils incluent des lettres, des chiffres et des caractères spéciaux.

Vous devrez également choisir la longueur appropriée et la quantité de chaque groupe de caractères à inclure, et c'est tout. Je ne pense pas que vous ayez besoin de formules sophistiquées.

1
anthares

Pour les systèmes qui n'autorisent pas les mots de passe générés par l'utilisateur, rien de plus simple: tout mot de passe est aussi sécurisé que long. Sans compter, bien sûr, les personnes qui collent des post-its à des moniteurs, etc.

Vous voulez probablement maximiser le jeu de caractères à partir duquel le mot de passe est généré. Mais restreindre les mots de passe générés réduit considérablement l’espace de recherche et rend donc le mot de passe moins sécurisé. Encore une fois, cela ne s'applique que si l'utilisateur ne peut pas choisir son propre mot de passe.

Si vous traitez avec des mots de passe générés et créés par l'utilisateur, tous les paris sont évidemment désactivés. Vous voudrez alors probablement générer les mots de passe de manière à utiliser autant de caractères que possible de classes différentes, ressemblant à un mot de passe fort choisi par l'utilisateur. Idéalement, il devrait être conforme aux mêmes contraintes que le mot de passe créé par l'utilisateur doit également être transmis (le cas échéant).

1
Joey

Que diriez-vous de Guid.NewGuid().ToString();?

1
dkackman

J'utiliserais Guid moi-même :) et ferais modifier le mot de passe par l'utilisateur après la connexion

0
Ash