br-crypto 0.4.8

This is an crypto
Documentation
use std::time::{SystemTime, UNIX_EPOCH};
use base32::Alphabet;
use byteorder::{BigEndian, ByteOrder};
use urlencoding::encode;
use hmac::{Hmac, Mac};
use rand::RngCore;
use sha1::Sha1;
type HmacSha1 = Hmac<Sha1>;

/// 一次性密码认证
pub struct Totp {}
impl Totp {
    /// 创建绑定二维码
    /// * issuer 发行方
    /// * username 账号
    /// * secret_base32 密钥
    pub fn create_bind_qrcode(issuer: &str, username: &str, secret: &str) -> String {
        let issuer = encode(issuer).to_string();
        format!("otpauth://totp/{issuer}:{username}?secret={secret}&issuer={issuer}")
    }
    /// 获取密钥
    /// * length 密钥长度
    pub fn generate_secret_base32(length: usize) -> String {
        let mut bytes = vec![0u8; length];
        rand::rng().fill_bytes(&mut bytes);
        base32::encode(Alphabet::Rfc4648 { padding: false }, &bytes)
    }
    /// 获取当前验证码
    /// * secret_base32 密钥
    /// * step 间隔
    pub fn get_code(secret_base32: &str, step: i64) -> String {
        let t = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64 % 30;
        let time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64 + step - t;
        // Step 1: decode Base32 secret
        let key = base32::decode(Alphabet::Rfc4648 { padding: false }, secret_base32).unwrap();
        // Step 2: compute counter (T = time / step)
        let counter = time / 30;
        let mut counter_bytes = [0u8; 8];
        BigEndian::write_u64(&mut counter_bytes, counter as u64);
        // Step 3: HMAC-SHA1
        let mut mac = HmacSha1::new_from_slice(&key).unwrap();
        mac.update(&counter_bytes);
        let hmac_result = mac.finalize().into_bytes();
        // Step 4: Dynamic Truncation
        let offset = (hmac_result[19] & 0x0f) as usize;
        let bin_code = (((hmac_result[offset] & 0x7f) as u32) << 24) | ((hmac_result[offset + 1] as u32) << 16) | ((hmac_result[offset + 2] as u32) << 8) | (hmac_result[offset + 3] as u32);
        // Step 5: truncate to digits
        let res = bin_code % 10u32.pow(6);
        format!("{res:06}")
    }
}