paseto_core/
key.rs

1//! Core traits and types for PASETO keys.
2
3use alloc::boxed::Box;
4use core::fmt;
5
6use crate::paserk::{IdVersion, KeyId, KeyText};
7use crate::sealed::Sealed;
8use crate::version::{Local, PkePublic, PkeSecret, Public, SealingVersion, Secret, Version};
9use crate::{LocalKey, PasetoError, PublicKey, SecretKey};
10
11pub(crate) type KeyInner<V, K> = <V as HasKey<K>>::Key;
12
13/// Generic key type.
14pub struct Key<V: HasKey<K>, K: KeyType>(pub(crate) KeyInner<V, K>);
15
16impl<V: HasKey<K>, K: KeyType> Clone for Key<V, K>
17where
18    KeyInner<V, K>: Clone,
19{
20    fn clone(&self) -> Self {
21        Self(self.0.clone())
22    }
23}
24
25impl<V: SealingVersion<Public>> SecretKey<V> {
26    /// Generate a random secret key
27    pub fn random() -> Result<Self, PasetoError> {
28        V::random().map(Self)
29    }
30
31    /// Derive the associated public key
32    pub fn public_key(&self) -> PublicKey<V> {
33        Key(V::unsealing_key(&self.0))
34    }
35}
36
37impl<V: SealingVersion<Local>> LocalKey<V> {
38    /// Generate a random local key
39    pub fn random() -> Result<Self, PasetoError> {
40        V::random().map(Self)
41    }
42}
43
44impl<V: SealingVersion<Local>> From<[u8; 32]> for LocalKey<V> {
45    fn from(value: [u8; 32]) -> Self {
46        Self(V::decode(&value[..]).expect("all 32 bytes should be valid local keys"))
47    }
48}
49
50impl<V: HasKey<Public>> fmt::Display for PublicKey<V> {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        self.expose_key().fmt(f)
53    }
54}
55
56impl<V: HasKey<K>, K: KeyType> core::str::FromStr for Key<V, K> {
57    type Err = PasetoError;
58    fn from_str(s: &str) -> Result<Self, Self::Err> {
59        KeyText::<V, K>::from_str(s).and_then(|k| k.try_into())
60    }
61}
62
63impl<V: IdVersion + HasKey<K>, K: KeyType> Key<V, K> {
64    /// Generate the ID of this key
65    pub fn id(&self) -> KeyId<V, K> {
66        KeyId::from(&self.expose_key())
67    }
68}
69
70/// Declares that this PASETO implementation supports the given key type,
71/// as well as how to encode/decode the key.
72pub trait HasKey<K>: Version {
73    type Key;
74
75    /// Encode the key into bytes.
76    fn encode(key: &Self::Key) -> Box<[u8]>;
77
78    /// Decode the key from bytes.
79    fn decode(bytes: &[u8]) -> Result<Self::Key, PasetoError>;
80}
81
82/// A marker for [`Secret`], [`Public`], and [`Local`]
83pub trait KeyType: Send + Sync + Sealed + Sized + 'static {
84    /// ".local." or ".public." or ".secret."
85    const HEADER: &'static str;
86    /// ".lid." or ".pid." or ".sid."
87    const ID_HEADER: &'static str;
88}
89
90/// A marker for [`Secret`] and [`Local`] keys, used for signing and encrypting tokens.
91pub trait SealingKey: KeyType {
92    const PIE_WRAP_HEADER: &'static str;
93    const PW_WRAP_HEADER: &'static str;
94}
95
96impl KeyType for Secret {
97    const HEADER: &'static str = ".secret.";
98    const ID_HEADER: &'static str = ".sid.";
99}
100
101impl SealingKey for Secret {
102    const PIE_WRAP_HEADER: &'static str = ".secret-wrap.pie.";
103    const PW_WRAP_HEADER: &'static str = ".secret-pw.";
104}
105
106impl KeyType for Public {
107    const HEADER: &'static str = ".public.";
108    const ID_HEADER: &'static str = ".pid.";
109}
110
111impl KeyType for Local {
112    const HEADER: &'static str = ".local.";
113    const ID_HEADER: &'static str = ".lid.";
114}
115
116impl SealingKey for Local {
117    const PIE_WRAP_HEADER: &'static str = ".local-wrap.pie.";
118    const PW_WRAP_HEADER: &'static str = ".local-pw.";
119}
120
121impl KeyType for PkeSecret {
122    const HEADER: &'static str = ".secret.";
123    const ID_HEADER: &'static str = ".sid.";
124}
125
126impl KeyType for PkePublic {
127    const HEADER: &'static str = ".public.";
128    const ID_HEADER: &'static str = ".pid.";
129}