Created
February 26, 2024 15:27
-
-
Save jdmichaud/fb2abbe7395c7033d9118efe247f1bab to your computer and use it in GitHub Desktop.
TOTP client in Rust
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://rednafi.com/go/totp_client/ | |
// https://datatracker.ietf.org/doc/html/rfc6238 | |
use sha1::{Sha1}; | |
use hmac::{Hmac, Mac}; | |
use std::time::{SystemTime, UNIX_EPOCH}; | |
fn generate_totp(secret_key: &str, timestamp: u64) -> u32 { | |
// The base32 encoded secret key string is decoded to a byte slice | |
let secret_bytes = base32::decode( | |
base32::Alphabet::RFC4648 { padding: true }, | |
&secret_key.trim().to_ascii_uppercase() | |
).unwrap(); | |
// 30 seconds is the timestep as defined in rfc6238 | |
let time_bytes = (timestamp / 30).to_be(); | |
// The timestamp bytes are concatenated with the decoded secret key | |
// bytes. Then a 20-byte SHA-1 hash is calculated from the byte slice | |
let mut mac0 = <Hmac<Sha1> as Mac>::new_from_slice(&secret_bytes).unwrap(); | |
mac0.update(&time_bytes.to_ne_bytes()); | |
let result = mac0.finalize().into_bytes(); | |
// and the SHA-1 with 0x0F (15) to get a single-digit offset | |
let offset: usize = (result[result.len() - 1] & 0x0F) as usize; | |
// Truncate the SHA-1 by the offset and convert it into a 32-bit | |
// unsigned int. AND the 32-bit int with 0x7FFFFFFF (2147483647) | |
// to get a 31-bit unsigned int. | |
let truncated_hash = u32::from_ne_bytes(result[offset..offset + 4].try_into().unwrap()) & 0x7FFFFFFF; | |
// Take modulo 1_000_000 to get a 6-digit code | |
truncated_hash % 1_000_000 | |
} | |
fn main() { | |
let unix_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap(); | |
println!("{:06}", generate_totp("KRCVGVCUIVJVIRKT", unix_epoch.as_secs())); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment