6
votes

Mot de passe One HMAC-Basé en C # (RFC 4226 - Hotp)

Je tente d'envelopper mon cerveau autour de générer un mot de passe ponctuel expirant à 6 chiffres / caractères non sensibles.

Ma source est https://www.rfc-editor.org/rfc/rfc4226#ssection-5

première définition des paramètres xxx

puis nous avons l'algorithme pour générer le hotp xxx

alors, nous avons tronqué défini comme xxx

puis un exemple est proposé pour un hotp à 6 chiffres xxx

Je suis plutôt à une perte de tentative de convertir en utiles C # Code pour générer des mots de passe d'une fois. J'ai déjà du code pour créer un HMAC expirant comme suit: xxx

Je ne sais pas comment aller de cela, à 6 chiffres comme proposé dans les algorithmes ci-dessus. < / p>


3 commentaires

Je crois que C est un timbre DateTime et K est la clé secrète que j'ai déjà affectée au compte de chaque utilisateur. Sur quoi je les hass correctement, puis tronquent jusqu'à 6 chiffres, c'est où je suis confus.


L'annexe C fournit une implémentation de référence en Java qui devrait être facilement traduisée à C #.


C'est, mais cela ne génère qu'un hotp numérique. J'aimerais vraiment un hotp alphanumérique.


3 Réponses :


3
votes

Vous avez deux problèmes ici:

  1. Si vous générez alpha-numérique, vous ne vous conformez pas à la RFC - à ce stade, vous pouvez simplement prendre tous les octets et les transformer en une chaîne hexagonale et être alpha-numérique. Ou, Convertissez-les en Base 36 si vous voulez AZ et 0-9. La section 5.4 de la RFC vous donne la standard Hotp Calc pour un paramètre SET DIGIT (AVIS que chiffre est un paramètre avec C , < code> k et t ). Si vous choisissez d'ignorer cette section, vous n'avez pas besoin de convertir le code - utilisez simplement ce que vous voulez.

  2. Votre tableau d'octets "résultat" a le temps d'expiration simplement bourré des 8 premiers octets après hachage. Si votre troncature alphanumérique à 6 chiffres ne les collecte pas avec des parties du hachage, il peut ainsi de ne pas être calculé du tout. Il est également très facile de "faire semblant" ou de replay - hachage le secret une fois, puis mettez toutes les tiques que vous voulez devant elle - pas vraiment un mot de passe unique. Notez que le paramètre C dans le RFC est conçu pour remplir la fenêtre expirante et doit être ajouté à l'entrée avant calculer le code de hachage.


1 commentaires

Après avoir creusé dessus, je devais laisser tomber l'idée d'un OTP expirant tout en un. L'algorithme utilise un compteur - c'est-à-dire qu'il a été conçu pour fonctionner de manière autonome sur un périphérique matériel (comme un dongle / téléphone cellulaire) et sur un serveur de validation. De cette façon, si le comptoir est identique, le même OTP est toujours généré - car il n'ya aucun moyen de retirer les données, car il y avait dans mon HMAC expirant. Mais vous avez raison sur les deux chefs d'accusation. Pour que cela expire, je dois faire plus que cet algorithme est mis en place, et si je veux avoir une OTP alphanumérique, j'ai besoin d'un algorithme différent.



2
votes

Pour toute personne intéressée, j'ai trouvé un moyen de créer une expiration dans mon mot de passe unique. L'approche consiste à utiliser le temps créé jusqu'à la minute (ignorer des secondes, millisecondes, etc.). Une fois que vous avez cette valeur, utilisez les ticks de la dateTime comme compteur ou variable C.

otplifespan code> est ma vie hotp en minutes. P>

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

    return alg.ComputeHash(text);
}


0 commentaires

2
votes

Cet extrait devrait 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();
    }
}


1 commentaires

Cela semble bon. Mais Chars [] caractères = nouveau char [A.Length]; donne une erreur car les caractères ont déjà été définis dans la portée déjà.