Question

Je cherche à envelopper mon cerveau autour de générer un sensible à 6 chiffres / caractère non cas expirant le mot de passe unique.

Ma source est http://tools.ietf.org/html/rfc4226#section -5

D'abord la définition des paramètres

C       8-byte counter value, the moving factor.  This counter
       MUST be synchronized between the HOTP generator (client)
       and the HOTP validator (server).

K       shared secret between client and server; each HOTP
       generator has a different and unique secret K.

T       throttling parameter: the server will refuse connections
       from a user after T unsuccessful authentication attempts.

Ensuite, nous avons l'algorithme pour générer le HOTP

As the output of the HMAC-SHA-1 calculation is 160 bits, we must
   truncate this value to something that can be easily entered by a
   user.

                   HOTP(K,C) = Truncate(HMAC-SHA-1(K,C))

Ensuite, nous avons troncation défini comme

String = String[0]...String[19]
 Let OffsetBits be the low-order 4 bits of String[19]
 Offset = StToNum(OffsetBits) // 0 <= OffSet <= 15
 Let P = String[OffSet]...String[OffSet+3]
 Return the Last 31 bits of P

Et un exemple est offert pour un 6 chiffres HOTP

The following code example describes the extraction of a dynamic
binary code given that hmac_result is a byte array with the HMAC-
SHA-1 result:

    int offset   =  hmac_result[19] & 0xf ;
    int bin_code = (hmac_result[offset]  & 0x7f) << 24
       | (hmac_result[offset+1] & 0xff) << 16
       | (hmac_result[offset+2] & 0xff) <<  8
       | (hmac_result[offset+3] & 0xff) ;

Je suis plutôt à une perte pour tenter de convertir en code utile C # pour générer un mot de passe de temps. J'ai déjà du code pour créer une échéance HMAC comme suit:

byte[] hashBytes = alg.ComputeHash(Encoding.UTF8.GetBytes(input));
byte[] result = new byte[8 + hashBytes.Length];

hashBytes.CopyTo(result, 8);
BitConverter.GetBytes(expireDate.Ticks).CopyTo(result, 0);

Je ne suis pas sûr de savoir comment aller de cela, à 6 chiffres tel que proposé dans les algorithmes ci-dessus.

Était-ce utile?

La solution

Vous avez deux questions ici:

  1. Si vous générez alpha-numérique, vous n'êtes pas conforme au RFC - à ce stade, vous pouvez simplement prendre les N octets et les transformer en une chaîne hexagonale et obtenir alpha-numérique. Ou, les convertir à la base 36 si vous voulez az et 0-9. L'article 5.4 de la RFC vous donne la calc standard HOTP pour un jeu de paramètres de Digit (notez que Digit est un paramètre avec C, K et T). Si vous choisissez d'ignorer cette section, vous n'avez pas besoin de convertir le code -. Il suffit d'utiliser ce que vous voulez

  2. Votre tableau d'octets « résultat » a le temps d'expiration simplement en peluche dans les 8 premiers octets après hachage. Si votre troncature à 6 chiffres alphanumériques ne sauvegardons pas ces ainsi que des parties du hachage, il peut aussi bien ne pas être calculé du tout. Il est également très facile à « faux » ou rejouer - hachage le secret une fois, puis mettez ce que vous voulez les tiques devant elle - pas vraiment un mot de passe de temps. Notez que le paramètre C dans le RFC est destiné à remplir la fenêtre expiration et doit être ajoutée à l'entrée avant calcul du code de hachage.

Autres conseils

Pour toute personne intéressée, je l'ai fait de trouver un moyen d'expiration de construction dans mon un mot de passe de temps. L'approche consiste à utiliser le temps créé à la minute (en ignorant secondes, millisecondes, etc.). Une fois que vous avez cette valeur, utilisez les tiques du DateTime comme votre compteur, ou variable C.

otpLifespan est ma durée de vie de HOTP en quelques minutes.

DateTime current = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 
    DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, 0);

for (int x = 0; x <= otpLifespan; x++)
{
    var result = NumericHOTP.Validate(hotp, key, 
        current.AddMinutes(-1 * x).Ticks);

    //return valid state if validation succeeded

    //return invalid state if the passed in value is invalid 
    //  (length, non-numeric, checksum invalid)
}

//return expired state

Mon HOTP expirant va de mon HOTP numérique qui a une méthode de validation statique qui vérifie la longueur, assure qu'il est numérique, valide la somme de contrôle si elle est utilisée, et compare enfin le HOTP passé avec un produit.

Le seul inconvénient est que chaque fois que vous validez un HOTP venant à échéance, votre pire scénario est de vérifier n + 1 valeurs HOTP où n est la durée de vie en quelques minutes.

L'exemple de code Java dans le document décrivant la RFC 4226 était un mouvement très simple en C #. La seule pièce que j'avais vraiment mis tout effort dans la réécriture était la méthode de hachage.

private static byte[] HashHMACSHA1(byte[] keyBytes, byte[] text)
{
    HMAC alg = new HMACSHA1(keyBytes);

    return alg.ComputeHash(text);
}

J'espère que cela aide quelqu'un d'autre à essayer de générer un mot de passe de temps.

Cet extrait doit faire ce que vous demandez:

  public class UniqueId
{
    public static string GetUniqueKey()
    {
        int maxSize = 6; // whatever length you want
        char[] chars = new char[62];
        string a;
        a = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
           char[] chars = new char[a.Length];
        chars = a.ToCharArray();
        int size = maxSize;
        byte[] data = new byte[1];
        RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
        crypto.GetNonZeroBytes(data);
        size = maxSize;
        data = new byte[size];
        crypto.GetNonZeroBytes(data);
        StringBuilder result = new StringBuilder(size);
        foreach (byte b in data)
        { result.Append(chars[b % (chars.Length - 1)]); }
        return result.ToString();
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top