1use core::fmt;
2use std::hash::Hash;
3use std::marker::PhantomData;
4
5use base64ct::Encoding;
6
7use crate::PasetoError;
8use crate::version::{self, Marker};
9
10pub trait Key: Clone {
12 type Version: version::Version;
13 type KeyType: Marker;
14
15 fn encode(&self) -> Box<[u8]>;
16 fn decode(bytes: &[u8]) -> Result<Self, PasetoError>;
17}
18
19pub trait SealingKey<Purpose>: Key {
23 type UnsealingKey: UnsealingKey<Purpose, Version = Self::Version>;
25
26 fn unsealing_key(&self) -> Self::UnsealingKey;
28
29 fn random() -> Result<Self, PasetoError>;
31
32 fn nonce() -> Result<Vec<u8>, PasetoError>;
34
35 fn dangerous_seal_with_nonce(
37 &self,
38 encoding: &'static str,
39 nonce: Vec<u8>,
40 footer: &[u8],
41 aad: &[u8],
42 ) -> Result<Vec<u8>, PasetoError>;
43}
44
45pub trait UnsealingKey<Purpose>: Key {
49 fn unseal<'a>(
50 &self,
51 encoding: &'static str,
52 payload: &'a mut [u8],
53 footer: &[u8],
54 aad: &[u8],
55 ) -> Result<&'a [u8], PasetoError>;
56}
57
58pub struct KeyId<K: Key> {
60 id: [u8; 33],
61 _key: PhantomData<K>,
62}
63
64impl<K: Key> PartialEq for KeyId<K> {
65 fn eq(&self, other: &Self) -> bool {
66 self.id == other.id
67 }
68}
69
70impl<K: Key> PartialOrd for KeyId<K> {
71 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
72 Some(self.cmp(other))
73 }
74}
75
76impl<K: Key> Eq for KeyId<K> {}
77
78impl<K: Key> Ord for KeyId<K> {
79 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
80 self.id.cmp(&other.id)
81 }
82}
83
84impl<K: Key> Hash for KeyId<K> {
85 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
86 self.id.hash(state);
87 }
88}
89
90impl<K: Key> From<&KeyText<K>> for KeyId<K> {
91 fn from(value: &KeyText<K>) -> Self {
92 Self {
93 id: <K::Version as version::Version>::hash_key(
94 <K::KeyType as Marker>::ID_HEADER,
95 value.to_string().as_bytes(),
96 ),
97 _key: value._key,
98 }
99 }
100}
101
102pub struct KeyText<K: Key> {
106 data: Box<[u8]>,
107 _key: PhantomData<K>,
108}
109
110impl<K: Key> PartialEq for KeyText<K> {
111 fn eq(&self, other: &Self) -> bool {
112 self.data == other.data
113 }
114}
115
116impl<K: Key> PartialOrd for KeyText<K> {
117 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
118 Some(self.cmp(other))
119 }
120}
121
122impl<K: Key> Eq for KeyText<K> {}
123
124impl<K: Key> Ord for KeyText<K> {
125 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
126 self.data.cmp(&other.data)
127 }
128}
129
130impl<K: Key> Hash for KeyText<K> {
131 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
132 self.data.hash(state);
133 }
134}
135
136impl<K: Key> KeyText<K> {
137 pub fn decode(&self) -> Result<K, PasetoError> {
138 K::decode(&self.data)
139 }
140}
141
142impl<K: Key> From<&K> for KeyText<K> {
143 fn from(value: &K) -> Self {
144 Self {
145 data: value.encode(),
146 _key: PhantomData,
147 }
148 }
149}
150
151impl<K: Key> fmt::Display for KeyId<K> {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 f.write_str(<K::Version as version::Version>::PASERK_HEADER)?;
154 f.write_str(<K::KeyType as Marker>::ID_HEADER)?;
155
156 let mut id = [0u8; 44];
157 let id = &<base64ct::Base64UrlUnpadded as Encoding>::encode(&self.id, &mut id)
158 .map_err(|_| fmt::Error)?;
159 f.write_str(id)
160 }
161}
162
163impl<K: Key> std::str::FromStr for KeyId<K> {
164 type Err = PasetoError;
165
166 fn from_str(s: &str) -> Result<Self, Self::Err> {
167 let s = s
168 .strip_prefix(<K::Version as version::Version>::PASERK_HEADER)
169 .ok_or(PasetoError::InvalidKey)?;
170 let s = s
171 .strip_prefix(<K::KeyType as Marker>::ID_HEADER)
172 .ok_or(PasetoError::InvalidKey)?;
173
174 let mut id = [0u8; 33];
175 let len = <base64ct::Base64UrlUnpadded as Encoding>::decode(s, &mut id)
176 .map_err(|_| PasetoError::Base64DecodeError)?
177 .len();
178
179 if len != 33 {
180 return Err(PasetoError::InvalidKey);
181 }
182
183 Ok(Self {
184 id,
185 _key: PhantomData,
186 })
187 }
188}
189
190impl<K: Key> fmt::Display for KeyText<K> {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 f.write_str(<K::Version as version::Version>::PASERK_HEADER)?;
193 f.write_str(<K::KeyType as Marker>::HEADER)?;
194 f.write_str(&base64ct::Base64UrlUnpadded::encode_string(&self.data))
195 }
196}
197
198impl<K: Key> std::str::FromStr for KeyText<K> {
199 type Err = PasetoError;
200
201 fn from_str(s: &str) -> Result<Self, Self::Err> {
202 let s = s
203 .strip_prefix(<K::Version as version::Version>::PASERK_HEADER)
204 .ok_or(PasetoError::InvalidKey)?;
205 let s = s
206 .strip_prefix(<K::KeyType as Marker>::HEADER)
207 .ok_or(PasetoError::InvalidKey)?;
208
209 let data = base64ct::Base64UrlUnpadded::decode_vec(s)
210 .map_err(|_| PasetoError::Base64DecodeError)?
211 .into_boxed_slice();
212
213 Ok(Self {
214 data,
215 _key: PhantomData,
216 })
217 }
218}