Skip to content

TOTP / HOTP does not match other implementations? #6

@djc

Description

@djc

In testing this crate's TOTP implementation against Yubico Authenticator, I found that the (default, so 6-digit SHA-1) TOTP codes generated by Yubico Authenticator were not accepted by TOTP::is_valid(). I tested another implementation that I wrote many years ago in Python, whose codes did match Yubico Authenticator. I then came up with a Rust implementation that matches Yubico Authenticator and my older Python code:

fn totp_valid(secret: &[u8], code: &str, tolerance: u64) -> bool {
    assert!(tolerance < 7);
    let testing = u32::from_str(code).unwrap();
    let anchor = SystemTime::now()
        .duration_since(time::UNIX_EPOCH)
        .unwrap()
        .as_secs()
        / 30;
    let key = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, secret);
    let mut tested = [false; 16];

    for i in (7u64 - tolerance)..(8 + tolerance) {
        let current = (anchor + i) - 8;
        let tag = hmac::sign(&key, &current.to_be_bytes()[..]);
        let offset = (tag.as_ref()[19] & 15) as usize;
        let p = u32::from_be_bytes(tag.as_ref()[offset..offset + 4].try_into().unwrap());
        tested[i as usize] = dbg!((p & 0x7fff_ffff) % 1_000_000) == testing;
    }

    tested.iter().fold(false, |acc, p| acc | p)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions