simple-steam-totp 0.1.0

Generate Steam TOTP auth codes from Rust
Documentation
use std::time::{SystemTime};

use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha1::Sha1;

const INTERVAL : u64 = 30;
const ALPHABET : &str = "23456789BCDFGHJKMNPQRTVWXY";

/// Generate a Steam Authenticator code for the given shared secret (expected as a base64 encoded string).
/// 
/// You can find the shared secret within your Steam Desktop Authenticator maFile.
/// 
/// # Example
/// ```
/// use simple_steam_totp::{generate};
/// 
/// println!("{}", generate("V59i4SUqNiuYDrssYyMz62RSI9k=").unwrap());
/// ```
pub fn generate(shared_secret: &str) -> Result<String, &'static str> {
    let counter : u64 = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs() / INTERVAL;
    let decoded_shared_secret = match base64::decode(shared_secret) {
        Ok(decoded) => decoded,
        Err(_) => return Err("Error decoding base64 shared secret"),
    };

    let mut hmac = Hmac::new(Sha1::new(), decoded_shared_secret.as_slice());
    hmac.input(counter.to_be_bytes().as_slice());
    let code = hmac.result().code().to_vec();
    let start = (code[19] & 0xf) as usize;
    let mut fullcode = (((code[start] & 0x7f) as u32) << 24) |
                  ((code[start + 1] as u32) << 16) |
                  ((code[start + 2] as u32) << 8) |
                  (code[start + 3] as u32);

    let mut otp : [u8; 5] = [0; 5];
    for i in 0..5 {
        otp[i] = ALPHABET.as_bytes()[fullcode as usize % ALPHABET.len()];
        fullcode /= ALPHABET.len() as u32;
    }

    Ok(String::from_utf8(otp.to_vec()).unwrap())
}