HMAC-based one time password in C# (RFC 4226 - HOTP)

前端 未结 3 1608
猫巷女王i
猫巷女王i 2021-02-01 10:59

I am attempting to wrap my brain around generating a 6 digit/character non case sensitive expiring one-time password.

My source is http://tools.ietf.org/html/rfc4226#sec

3条回答
  •  迷失自我
    2021-02-01 11:50

    For anyone interested, I did figure out a way to build expiration into my one time password. The approach is to use the created time down to the minute (ignoring seconds, milliseconds, etc). Once you have that value, use the ticks of the DateTime as your counter, or variable C.

    otpLifespan is my HOTP lifespan in 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
    

    My expiring HOTP extends from my numeric HOTP which has a static validation method that checks the length, ensures it is numeric, validates the checksum if it is used, and finally compares the hotp passed in with a generated one.

    The only downside to this is that each time you validate an expiring hotp, your worse case scenario is to check n + 1 HOTP values where n is the lifespan in minutes.

    The java code example in the document outlining RFC 4226 was a very straightforward move into C#. The only piece I really had to put any effort into rewriting was the hashing method.

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

    I hope this helps anyone else attempting to generate one time passwords.

提交回复
热议问题