Skip to main content

armour_core/
enc.rs

1use std::fmt::Debug;
2
3#[cfg(feature = "cipher")]
4use blowfish_rs::Blowfish;
5#[cfg(feature = "cipher")]
6use const_decoder::Decoder;
7
8use crate::error::ArmourError;
9use crate::zbase::ZBASE32;
10use crate::{IdStr, Result};
11
12#[inline(always)]
13pub fn encode(id: &[u8; 8]) -> IdStr {
14    let mut buf = IdStr::zero_filled();
15    ZBASE32.encode_mut(id, unsafe { buf.as_bytes_mut() });
16    buf
17}
18
19#[inline(always)]
20pub fn decode(id: &str) -> Result<[u8; 8]> {
21    let mut buf = [0u8; 8];
22    ZBASE32
23        .decode_mut(id.as_bytes(), &mut buf)
24        .map_err(|_| ArmourError::ZBaseDecodeError)?;
25    Ok(buf)
26}
27
28#[cfg(feature = "cipher")]
29#[derive(Debug)]
30pub struct Cipher(Blowfish);
31
32#[cfg(not(feature = "cipher"))]
33#[derive(Debug)]
34pub struct Cipher;
35
36#[cfg(feature = "cipher")]
37impl Cipher {
38    /// key should be Base64Url decoded 56 bytes long (~ 75 chars)
39    pub const fn new(key: &str) -> Self {
40        let bytes: [u8; 56] = Decoder::Base64Url.decode(key.as_bytes());
41        Self(Blowfish::new(&bytes))
42    }
43
44    pub const fn raw(blowfish: Blowfish) -> Self {
45        Self(blowfish)
46    }
47}
48
49#[cfg(not(feature = "cipher"))]
50impl Cipher {
51    pub const fn new(_key: &str) -> Self {
52        Self
53    }
54}
55
56/// key should be Base64Url decoded 56 bytes long (~ 75 chars)
57pub trait IdHasher: Copy + Ord + Eq + Sized + Send + Sync + Debug {
58    const HASHER: Cipher;
59
60    #[inline]
61    fn encrypt(id: u64) -> u64 {
62        #[cfg(feature = "cipher")]
63        {
64            Self::HASHER.0.encrypt_u64(id)
65        }
66        #[cfg(not(feature = "cipher"))]
67        {
68            id
69        }
70    }
71
72    #[inline]
73    fn decrypt(id: u64) -> u64 {
74        #[cfg(feature = "cipher")]
75        {
76            Self::HASHER.0.decrypt_u64(id)
77        }
78        #[cfg(not(feature = "cipher"))]
79        {
80            id
81        }
82    }
83
84    #[cfg(feature = "std")]
85    #[inline]
86    fn ser(id: u64) -> IdStr {
87        #[cfg(feature = "cipher")]
88        let id = Self::HASHER.0.encrypt_u64(id);
89        encode(&id.to_le_bytes())
90    }
91
92    #[cfg(feature = "std")]
93    #[inline]
94    fn deser(id: &str) -> Result<u64> {
95        if id.len() != 13 {
96            return Err(ArmourError::ZBaseDecodeError);
97        }
98        let buf = decode(id)?;
99        let de = u64::from_le_bytes(buf);
100        #[cfg(feature = "cipher")]
101        let de = Self::HASHER.0.decrypt_u64(de);
102        Ok(de)
103    }
104}