Search code examples
mysqlone-time-password

Implementing parts of rfc4226 (HOTP) in mysql


Like the title says, I'm trying to implement the programmatic parts of RFC4226 "HOTP: An HMAC-Based One-Time Password Algorithm" in SQL. I think I've got a version that works (in that for a small test sample, it produces the same result as the Java version in the code), but it contains a nested pair of hex(unhex()) calls, which I feel can be done better. I am constrained by a) needing to do this algorithm, and b) needing to do it in mysql, otherwise I'm happy to look at other ways of doing this.

What I've got so far:

  -- From the inside out...

  -- Concatinate the users secret, and the number of time its been used
  -- find the SHA1 hash of that string
  -- Turn a 40 byte hex encoding into a 20 byte binary string
  -- keep the first 4 bytes
  -- turn those back into a hex represnetation
  -- convert that into an integer
  -- Throw away the most-significant bit (solves signed/unsigned problems)
  -- Truncate to 6 digits
  -- store into otp
  -- from the otpsecrets table

  select (conv(hex(substr(unhex(sha1(concat(secret, uses))), 1, 4)), 16, 10) & 0x7fffffff) % 1000000
    into otp
    from otpsecrets;

Is there a better (more efficient) way of doing this?


Solution

  • I haven't read the spec, but I think you don't need to convert back and forth between hex and binary, so this might be a little more efficient:

    SELECT (conv(substr(sha1(concat(secret, uses)), 1, 8), 16, 10) & 0x7fffffff) % 1000000
    INTO otp
    FROM otpsecrets;
    

    This seems to give the same result as your query for a few examples I tested.