extrapaytr-crypto 0.1.0

Digest, HMAC, constant-time comparison and at-rest sealing helpers for ExtraPayTR
Documentation
use base64::Engine as _;
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;

pub fn base64_encode(input: impl AsRef<[u8]>) -> String {
    BASE64_STANDARD.encode(input)
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
#[error("invalid base64 input")]
pub struct Base64DecodeError;

pub fn base64_decode(input: impl AsRef<[u8]>) -> Result<Vec<u8>, Base64DecodeError> {
    BASE64_STANDARD.decode(input).map_err(|_| Base64DecodeError)
}

pub fn hex_lower(input: impl AsRef<[u8]>) -> String {
    hex::encode(input)
}

pub fn hex_upper(input: impl AsRef<[u8]>) -> String {
    hex::encode_upper(input)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn base64_round_trips() {
        let original = b"apiKey:abc&randomKey:123&signature:deadbeef";
        let encoded = base64_encode(original);
        let decoded = base64_decode(&encoded).unwrap();
        assert_eq!(decoded, original);
    }

    #[test]
    fn base64_decode_rejects_garbage() {
        assert!(base64_decode("not valid base64!!").is_err());
    }

    #[test]
    fn hex_case_variants() {
        let bytes = [0xdeu8, 0xad, 0xbe, 0xef];
        assert_eq!(hex_lower(bytes), "deadbeef");
        assert_eq!(hex_upper(bytes), "DEADBEEF");
    }
}