aranya_daemon_api/crypto/
keys.rs1use core::{borrow::Borrow, fmt, marker::PhantomData};
2use std::iter;
3
4use anyhow::Result;
5use aranya_crypto::{
6 dangerous::spideroak_crypto::{
7 import::ImportError,
8 kem::{DecapKey as _, Kem},
9 keys::PublicKey,
10 signer::PkError,
11 },
12 id::{IdError, IdExt, Identified},
13 unwrapped, CipherSuite, Engine, Oids, Random,
14};
15use aranya_id::custom_id;
16use ciborium as cbor;
17use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
18
19custom_id! {
20 pub struct ApiKeyId;
22}
23
24pub struct ApiKey<CS: CipherSuite>(<<CS as CipherSuite>::Kem as Kem>::DecapKey);
27
28impl<CS: CipherSuite> ApiKey<CS> {
29 pub(crate) fn new<CE>(eng: &CE) -> Self
30 where
31 CE: Engine<CS = CS>,
32 {
33 Self(Random::random(eng))
34 }
35
36 #[inline]
38 pub fn id(&self) -> Result<ApiKeyId, IdError> {
39 self.public()?.id()
40 }
41
42 pub fn public(&self) -> Result<PublicApiKey<CS>, PkError> {
44 Ok(PublicApiKey(self.0.public()?))
45 }
46
47 pub(crate) fn as_inner(&self) -> &<<CS as CipherSuite>::Kem as Kem>::DecapKey {
48 &self.0
49 }
50
51 pub fn generate<CE>(eng: &CE) -> Self
53 where
54 CE: Engine<CS = CS>,
55 {
56 Self::new(eng)
57 }
58}
59
60impl<CS: CipherSuite> Clone for ApiKey<CS> {
61 #[inline]
62 fn clone(&self) -> Self {
63 Self(self.0.clone())
64 }
65}
66
67impl<CS: CipherSuite> fmt::Display for ApiKey<CS> {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 write!(f, "{}", self.id().map_err(|_| fmt::Error)?)
70 }
71}
72
73impl<CS: CipherSuite> fmt::Debug for ApiKey<CS> {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 f.debug_tuple("ApiKey")
76 .field(&self.id().map_err(|_| fmt::Error)?)
77 .finish()
78 }
79}
80
81impl<CS: CipherSuite> Identified for ApiKey<CS> {
82 type Id = ApiKeyId;
83
84 #[inline]
85 fn id(&self) -> Result<Self::Id, IdError> {
86 self.id()
87 }
88}
89
90unwrapped! {
91 name: ApiKey;
92 type: Decap;
93 into: |key: Self| { key.0 };
94 from: |key| { Self(key) };
95}
96
97pub struct PublicApiKey<CS: CipherSuite>(<<CS as CipherSuite>::Kem as Kem>::EncapKey);
99
100impl<CS: CipherSuite> PublicApiKey<CS> {
101 #[inline]
103 pub fn id(&self) -> Result<ApiKeyId, IdError> {
104 let pk = &self.0.export();
105 let id = ApiKeyId::new::<CS>(b"ApiKey", iter::once(pk.borrow()));
106 Ok(id)
107 }
108
109 pub(crate) fn as_inner(&self) -> &<<CS as CipherSuite>::Kem as Kem>::EncapKey {
110 &self.0
111 }
112
113 pub fn encode(&self) -> Result<Vec<u8>> {
115 let mut buf = Vec::new();
116 cbor::into_writer(self, &mut buf)?;
117 Ok(buf)
118 }
119
120 pub fn decode(data: &[u8]) -> Result<Self> {
122 Ok(cbor::from_reader(data)?)
123 }
124}
125
126impl<CS: CipherSuite> Clone for PublicApiKey<CS> {
127 #[inline]
128 fn clone(&self) -> Self {
129 Self(self.0.clone())
130 }
131}
132
133impl<CS: CipherSuite> AsRef<PublicApiKey<CS>> for PublicApiKey<CS> {
134 #[inline]
135 fn as_ref(&self) -> &Self {
136 self
137 }
138}
139
140impl<CS: CipherSuite> Eq for PublicApiKey<CS> {}
141impl<CS: CipherSuite> PartialEq for PublicApiKey<CS> {
142 #[inline]
143 fn eq(&self, other: &Self) -> bool {
144 match (self.id(), other.id()) {
145 (Ok(lhs), Ok(rhs)) => lhs == rhs,
146 _ => false,
147 }
148 }
149}
150
151impl<CS: CipherSuite> fmt::Display for PublicApiKey<CS> {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "{}", self.id().map_err(|_| fmt::Error)?)
154 }
155}
156
157impl<CS: CipherSuite> fmt::Debug for PublicApiKey<CS> {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 write!(
160 f,
161 concat!(stringify!(PublicApiKey), " {}"),
162 self.id().map_err(|_| fmt::Error)?
163 )
164 }
165}
166
167impl<CS: CipherSuite> Serialize for PublicApiKey<CS> {
168 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
169 where
170 S: Serializer,
171 {
172 ExportedData::<CS, _>::from_key(&self.0, ExportedDataType::PublicApiKey)
173 .serialize(serializer)
174 }
175}
176
177impl<'de, CS: CipherSuite> Deserialize<'de> for PublicApiKey<CS> {
178 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
179 where
180 D: Deserializer<'de>,
181 {
182 let data = ExportedData::<CS, SerdeOwnedKey<_>>::deserialize(deserializer)?;
183 if !data.is_type(ExportedDataType::PublicApiKey) {
184 Err(de::Error::custom(ImportError::InvalidContext))
185 } else {
186 Ok(Self(data.data.0))
187 }
188 }
189}
190
191impl<CS: CipherSuite> Identified for PublicApiKey<CS> {
192 type Id = ApiKeyId;
193
194 #[inline]
195 fn id(&self) -> Result<Self::Id, IdError> {
196 self.id()
197 }
198}
199
200#[allow(clippy::enum_variant_names)]
203#[derive(Copy, Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
204enum ExportedDataType {
205 PublicApiKey,
206}
207
208#[derive(Serialize, Deserialize)]
210#[serde(deny_unknown_fields)]
211struct ExportedData<CS, T>
212where
213 CS: CipherSuite,
214{
215 #[serde(bound = "CS: CipherSuite")]
217 oids: Oids<CS>,
218 name: ExportedDataType,
220 pub(crate) data: T,
222}
223
224impl<CS, T> ExportedData<CS, T>
225where
226 CS: CipherSuite,
227{
228 pub(crate) fn is_type(&self, name: ExportedDataType) -> bool {
229 self.name == name
230 }
231}
232
233impl<'a, CS, K: PublicKey> ExportedData<CS, SerdeBorrowedKey<'a, K>>
234where
235 CS: CipherSuite,
236{
237 pub(crate) fn from_key(pk: &'a K, name: ExportedDataType) -> Self {
238 Self {
239 oids: CS::OIDS,
240 name,
241 data: SerdeBorrowedKey(pk),
242 }
243 }
244}
245
246pub(crate) struct SerdeOwnedKey<K>(pub(crate) K);
248
249impl<'de, K: PublicKey> Deserialize<'de> for SerdeOwnedKey<K> {
250 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
251 where
252 D: Deserializer<'de>,
253 {
254 struct PkVisitor<K>(PhantomData<K>);
255
256 impl<'de, K: PublicKey> de::Visitor<'de> for PkVisitor<K> {
257 type Value = K;
258
259 fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
260 write!(f, "a public key")
261 }
262
263 fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
264 where
265 E: de::Error,
266 {
267 K::import(v).map_err(de::Error::custom)
268 }
269
270 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
271 where
272 E: de::Error,
273 {
274 K::import(v).map_err(de::Error::custom)
275 }
276 }
277 let pk = deserializer.deserialize_bytes(PkVisitor::<K>(PhantomData))?;
278 Ok(SerdeOwnedKey(pk))
279 }
280}
281
282struct SerdeBorrowedKey<'a, K>(&'a K);
284
285impl<K: PublicKey> Serialize for SerdeBorrowedKey<'_, K> {
286 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
287 where
288 S: Serializer,
289 {
290 serializer.serialize_bytes(self.0.export().borrow())
291 }
292}