paseto_core/paserk/
plaintext.rs

1use alloc::boxed::Box;
2use core::fmt;
3use core::marker::PhantomData;
4
5use crate::PasetoError;
6use crate::key::{HasKey, Key, KeyType};
7use crate::version::Version;
8
9/// A plaintext encoding of a key.
10///
11/// Be advised that this encoding has no extra security, so it is not safe to transport as is.
12pub struct KeyText<V: Version, K: KeyType> {
13    data: Box<[u8]>,
14    _key: PhantomData<(V, K)>,
15}
16
17impl<V: HasKey<K>, K: KeyType> Key<V, K> {
18    /// Expose the key data such that it can be serialized.
19    ///
20    /// Be advised that serializing key data can be dangerous. Make sure
21    /// they are saved on secure disks or sent on secure connections only.
22    pub fn expose_key(&self) -> KeyText<V, K> {
23        KeyText {
24            data: V::encode(&self.0),
25            _key: PhantomData,
26        }
27    }
28}
29
30impl<V: Version, K: KeyType> KeyText<V, K> {
31    /// Create a KeyText type from the raw key bytes.
32    pub fn from_raw_bytes(b: &[u8]) -> Self {
33        KeyText {
34            data: b.into(),
35            _key: PhantomData,
36        }
37    }
38
39    /// View the raw key bytes of the key.
40    pub fn as_raw_bytes(&self) -> &[u8] {
41        &self.data
42    }
43}
44
45impl<V: Version, K: KeyType> PartialEq for KeyText<V, K> {
46    fn eq(&self, other: &Self) -> bool {
47        self.data == other.data
48    }
49}
50
51impl<V: Version, K: KeyType> PartialOrd for KeyText<V, K> {
52    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
53        Some(self.cmp(other))
54    }
55}
56
57impl<V: Version, K: KeyType> Eq for KeyText<V, K> {}
58
59impl<V: Version, K: KeyType> Ord for KeyText<V, K> {
60    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
61        self.data.cmp(&other.data)
62    }
63}
64
65impl<V: Version, K: KeyType> core::hash::Hash for KeyText<V, K> {
66    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
67        self.data.hash(state);
68    }
69}
70
71impl<V: HasKey<K>, K: KeyType> TryFrom<KeyText<V, K>> for Key<V, K> {
72    type Error = PasetoError;
73    fn try_from(value: KeyText<V, K>) -> Result<Key<V, K>, PasetoError> {
74        V::decode(&value.data).map(Key)
75    }
76}
77
78impl<V: Version, K: KeyType> fmt::Display for KeyText<V, K> {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        f.write_str(V::PASERK_HEADER)?;
81        f.write_str(K::HEADER)?;
82        crate::base64::write_to_fmt(&self.data, f)
83    }
84}
85
86impl<V: Version, K: KeyType> core::str::FromStr for KeyText<V, K> {
87    type Err = PasetoError;
88
89    fn from_str(s: &str) -> Result<Self, Self::Err> {
90        let s = s
91            .strip_prefix(V::PASERK_HEADER)
92            .ok_or(PasetoError::InvalidKey)?;
93        let s = s.strip_prefix(K::HEADER).ok_or(PasetoError::InvalidKey)?;
94
95        let data = crate::base64::decode_vec(s)?.into_boxed_slice();
96
97        Ok(Self {
98            data,
99            _key: PhantomData,
100        })
101    }
102}
103
104serde_str!(
105    impl<V, K> KeyText<V, K>
106    where
107        V: Version,
108        K: KeyType,
109    {
110        fn expecting() {
111            format_args!("a {}{} PASERK key", V::PASERK_HEADER, K::HEADER)
112        }
113    }
114);