atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
585e6b7ce08636105da83cdbed5ff24679d0db4d
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git

Blame: src/secret.rs

782069860236atagen2026-10-10 12:44 UTC1
use std::fmt::Write as _;
99524cf9f17catagen2026-10-10 10:53 UTC2
99524cf9f17catagen2026-10-10 10:53 UTC3
use hmac::{Hmac, Mac};
99524cf9f17catagen2026-10-10 10:53 UTC4
use sha2::Sha256;
99524cf9f17catagen2026-10-10 10:53 UTC5
782069860236atagen2026-10-10 12:44 UTC6
pub struct Secret(Vec<u8>);
99524cf9f17catagen2026-10-10 10:53 UTC7
99524cf9f17catagen2026-10-10 10:53 UTC8
fn hex(bytes: &[u8]) -> String {
99524cf9f17catagen2026-10-10 10:53 UTC9
    bytes.iter().fold(String::new(), |mut out, b| {
99524cf9f17catagen2026-10-10 10:53 UTC10
        let _ = write!(out, "{b:02x}");
99524cf9f17catagen2026-10-10 10:53 UTC11
        out
99524cf9f17catagen2026-10-10 10:53 UTC12
    })
99524cf9f17catagen2026-10-10 10:53 UTC13
}
99524cf9f17catagen2026-10-10 10:53 UTC14
99524cf9f17catagen2026-10-10 10:53 UTC15
fn unhex(text: &str) -> Option<Vec<u8>> {
99524cf9f17catagen2026-10-10 10:53 UTC16
    if !text.len().is_multiple_of(2) {
99524cf9f17catagen2026-10-10 10:53 UTC17
        return None;
99524cf9f17catagen2026-10-10 10:53 UTC18
    }
99524cf9f17catagen2026-10-10 10:53 UTC19
    (0..text.len())
99524cf9f17catagen2026-10-10 10:53 UTC20
        .step_by(2)
99524cf9f17catagen2026-10-10 10:53 UTC21
        .map(|i| u8::from_str_radix(text.get(i..i + 2)?, 16).ok())
99524cf9f17catagen2026-10-10 10:53 UTC22
        .collect()
99524cf9f17catagen2026-10-10 10:53 UTC23
}
99524cf9f17catagen2026-10-10 10:53 UTC24
782069860236atagen2026-10-10 12:44 UTC25
impl Secret {
782069860236atagen2026-10-10 12:44 UTC26
    pub fn new(key: Vec<u8>) -> Self {
782069860236atagen2026-10-10 12:44 UTC27
        Self(key)
782069860236atagen2026-10-10 12:44 UTC28
    }
99524cf9f17catagen2026-10-10 10:53 UTC29
782069860236atagen2026-10-10 12:44 UTC30
    pub fn random() -> Self {
782069860236atagen2026-10-10 12:44 UTC31
        Self(rand::random::<[u8; 32]>().to_vec())
782069860236atagen2026-10-10 12:44 UTC32
    }
99524cf9f17catagen2026-10-10 10:53 UTC33
782069860236atagen2026-10-10 12:44 UTC34
    fn mac(&self, message: &str) -> Hmac<Sha256> {
782069860236atagen2026-10-10 12:44 UTC35
        let mut mac = Hmac::<Sha256>::new_from_slice(&self.0).expect("hmac accepts any key length");
782069860236atagen2026-10-10 12:44 UTC36
        mac.update(message.as_bytes());
782069860236atagen2026-10-10 12:44 UTC37
        mac
782069860236atagen2026-10-10 12:44 UTC38
    }
782069860236atagen2026-10-10 12:44 UTC39
782069860236atagen2026-10-10 12:44 UTC40
    pub fn sign(&self, name: &str, value: &str) -> String {
782069860236atagen2026-10-10 12:44 UTC41
        let tag = self.mac(&format!("{name}={value}")).finalize().into_bytes();
782069860236atagen2026-10-10 12:44 UTC42
        format!("{value}.{}", hex(&tag))
782069860236atagen2026-10-10 12:44 UTC43
    }
782069860236atagen2026-10-10 12:44 UTC44
782069860236atagen2026-10-10 12:44 UTC45
    pub fn verify<'a>(&self, name: &str, signed: &'a str) -> Option<&'a str> {
782069860236atagen2026-10-10 12:44 UTC46
        let (value, tag) = signed.rsplit_once('.')?;
782069860236atagen2026-10-10 12:44 UTC47
        self.mac(&format!("{name}={value}"))
782069860236atagen2026-10-10 12:44 UTC48
            .verify_slice(&unhex(tag)?)
782069860236atagen2026-10-10 12:44 UTC49
            .ok()?;
782069860236atagen2026-10-10 12:44 UTC50
        Some(value)
782069860236atagen2026-10-10 12:44 UTC51
    }
782069860236atagen2026-10-10 12:44 UTC52
782069860236atagen2026-10-10 12:44 UTC53
    /// Mixes the secret into a seed, so a public seed and public source cannot predict rolls offline.
782069860236atagen2026-10-10 12:44 UTC54
    pub fn mix_seed(&self, seed: u64) -> u64 {
782069860236atagen2026-10-10 12:44 UTC55
        let tag = self.mac(&format!("seed={seed}")).finalize().into_bytes();
782069860236atagen2026-10-10 12:44 UTC56
        u64::from_le_bytes(tag[..8].try_into().expect("sha256 is longer than 8 bytes"))
782069860236atagen2026-10-10 12:44 UTC57
    }
99524cf9f17catagen2026-10-10 10:53 UTC58
}