trussed_hpke/
lib.rs

1// Copyright (C) Nitrokey GmbH
2// SPDX-License-Identifier: Apache-2.0 or MIT
3
4//! Trussed Extension providing DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, ChaCha20Poly1305
5//! For more details, see <https://www.rfc-editor.org/rfc/rfc9180.html#name-dhkemx25519-hkdf-sha256-hkdf>
6
7#![no_std]
8#![warn(non_ascii_idents, trivial_casts, unused, unused_qualifications)]
9#![deny(unsafe_code)]
10
11use serde::{Deserialize, Serialize};
12use serde_byte_array::ByteArray;
13
14use trussed_core::serde_extensions::{Extension, ExtensionClient, ExtensionResult};
15use trussed_core::types::{KeyId, Location, Message, PathBuf, ShortData};
16use trussed_core::Error;
17
18#[derive(Deserialize, Serialize)]
19pub enum HpkeRequest {
20    Seal(HpkeSealRequest),
21    SealKey(HpkeSealKeyRequest),
22    SealKeyToFile(HpkeSealKeyToFileRequest),
23    Open(HpkeOpenRequest),
24    OpenKey(HpkeOpenKeyRequest),
25    OpenKeyFromFile(HpkeOpenKeyFromFileRequest),
26}
27
28impl From<HpkeSealRequest> for HpkeRequest {
29    fn from(value: HpkeSealRequest) -> Self {
30        Self::Seal(value)
31    }
32}
33impl From<HpkeSealKeyRequest> for HpkeRequest {
34    fn from(value: HpkeSealKeyRequest) -> Self {
35        Self::SealKey(value)
36    }
37}
38impl From<HpkeSealKeyToFileRequest> for HpkeRequest {
39    fn from(value: HpkeSealKeyToFileRequest) -> Self {
40        Self::SealKeyToFile(value)
41    }
42}
43impl From<HpkeOpenRequest> for HpkeRequest {
44    fn from(value: HpkeOpenRequest) -> Self {
45        Self::Open(value)
46    }
47}
48impl From<HpkeOpenKeyRequest> for HpkeRequest {
49    fn from(value: HpkeOpenKeyRequest) -> Self {
50        Self::OpenKey(value)
51    }
52}
53impl From<HpkeOpenKeyFromFileRequest> for HpkeRequest {
54    fn from(value: HpkeOpenKeyFromFileRequest) -> Self {
55        Self::OpenKeyFromFile(value)
56    }
57}
58impl TryFrom<HpkeRequest> for HpkeSealRequest {
59    type Error = Error;
60    fn try_from(value: HpkeRequest) -> Result<Self, Self::Error> {
61        match value {
62            HpkeRequest::Seal(this) => Ok(this),
63            _ => Err(Error::InternalError),
64        }
65    }
66}
67
68impl TryFrom<HpkeRequest> for HpkeSealKeyRequest {
69    type Error = Error;
70    fn try_from(value: HpkeRequest) -> Result<Self, Self::Error> {
71        match value {
72            HpkeRequest::SealKey(this) => Ok(this),
73            _ => Err(Error::InternalError),
74        }
75    }
76}
77
78impl TryFrom<HpkeRequest> for HpkeSealKeyToFileRequest {
79    type Error = Error;
80    fn try_from(value: HpkeRequest) -> Result<Self, Self::Error> {
81        match value {
82            HpkeRequest::SealKeyToFile(this) => Ok(this),
83            _ => Err(Error::InternalError),
84        }
85    }
86}
87
88impl TryFrom<HpkeRequest> for HpkeOpenRequest {
89    type Error = Error;
90    fn try_from(value: HpkeRequest) -> Result<Self, Self::Error> {
91        match value {
92            HpkeRequest::Open(this) => Ok(this),
93            _ => Err(Error::InternalError),
94        }
95    }
96}
97
98impl TryFrom<HpkeRequest> for HpkeOpenKeyRequest {
99    type Error = Error;
100    fn try_from(value: HpkeRequest) -> Result<Self, Self::Error> {
101        match value {
102            HpkeRequest::OpenKey(this) => Ok(this),
103            _ => Err(Error::InternalError),
104        }
105    }
106}
107
108impl TryFrom<HpkeRequest> for HpkeOpenKeyFromFileRequest {
109    type Error = Error;
110    fn try_from(value: HpkeRequest) -> Result<Self, Self::Error> {
111        match value {
112            HpkeRequest::OpenKeyFromFile(this) => Ok(this),
113            _ => Err(Error::InternalError),
114        }
115    }
116}
117
118/// Seal to a public key
119///
120/// As described in 6.1 with mode "base"
121#[derive(Deserialize, Serialize)]
122pub struct HpkeSealRequest {
123    pub key: KeyId,
124    pub plaintext: Message,
125    pub aad: ShortData,
126    pub info: ShortData,
127    /// The location of the stored "enc" key
128    pub enc_location: Location,
129}
130
131/// Seal to a public key
132///
133/// As described in 6.1 with mode "base"
134#[derive(Deserialize, Serialize)]
135pub struct HpkeSealKeyRequest {
136    pub public_key: KeyId,
137    pub key_to_seal: KeyId,
138    pub aad: ShortData,
139    pub info: ShortData,
140}
141
142/// Seal to a public key
143///
144/// As described in 6.1 with mode "base"
145#[derive(Deserialize, Serialize)]
146pub struct HpkeSealKeyToFileRequest {
147    pub public_key: KeyId,
148    pub key_to_seal: KeyId,
149    pub aad: ShortData,
150    pub info: ShortData,
151    pub file: PathBuf,
152    pub location: Location,
153}
154
155/// Open with a private key
156///
157/// As described in 6.1 with mode "base"
158#[derive(Deserialize, Serialize)]
159pub struct HpkeOpenRequest {
160    pub key: KeyId,
161    pub enc_key: KeyId,
162    pub ciphertext: Message,
163    pub tag: ByteArray<16>,
164    pub aad: ShortData,
165    pub info: ShortData,
166}
167
168/// Open with a private key
169///
170/// As described in 6.1 with mode "base"
171#[derive(Deserialize, Serialize)]
172pub struct HpkeOpenKeyRequest {
173    pub key: KeyId,
174    pub sealed_key: Message,
175    pub aad: ShortData,
176    pub info: ShortData,
177    pub location: Location,
178}
179
180/// Open with a private key
181///
182/// As described in 6.1 with mode "base"
183#[derive(Deserialize, Serialize)]
184pub struct HpkeOpenKeyFromFileRequest {
185    pub key: KeyId,
186    pub sealed_key: PathBuf,
187    pub sealed_location: Location,
188    pub unsealed_location: Location,
189    pub aad: ShortData,
190    pub info: ShortData,
191}
192
193/// Seal to a public key
194///
195/// As described in 6.1 with mode "base"
196#[derive(Deserialize, Serialize)]
197pub struct HpkeSealReply {
198    pub enc: KeyId,
199    pub ciphertext: Message,
200    pub tag: ByteArray<16>,
201}
202/// Seal a key to a public key
203#[derive(Deserialize, Serialize)]
204pub struct HpkeSealKeyReply {
205    pub data: Message,
206}
207
208/// Seal a key to a public key
209#[derive(Deserialize, Serialize)]
210pub struct HpkeSealKeyToFileReply {}
211
212#[derive(Deserialize, Serialize)]
213pub enum HpkeReply {
214    Seal(HpkeSealReply),
215    SealKey(HpkeSealKeyReply),
216    SealKeyToFile(HpkeSealKeyToFileReply),
217    Open(HpkeOpenReply),
218    OpenKey(HpkeOpenKeyReply),
219    OpenKeyFromFile(HpkeOpenKeyFromFileReply),
220}
221
222impl From<HpkeSealReply> for HpkeReply {
223    fn from(value: HpkeSealReply) -> Self {
224        Self::Seal(value)
225    }
226}
227impl From<HpkeSealKeyReply> for HpkeReply {
228    fn from(value: HpkeSealKeyReply) -> Self {
229        Self::SealKey(value)
230    }
231}
232impl From<HpkeSealKeyToFileReply> for HpkeReply {
233    fn from(value: HpkeSealKeyToFileReply) -> Self {
234        Self::SealKeyToFile(value)
235    }
236}
237impl From<HpkeOpenReply> for HpkeReply {
238    fn from(value: HpkeOpenReply) -> Self {
239        Self::Open(value)
240    }
241}
242impl From<HpkeOpenKeyReply> for HpkeReply {
243    fn from(value: HpkeOpenKeyReply) -> Self {
244        Self::OpenKey(value)
245    }
246}
247impl From<HpkeOpenKeyFromFileReply> for HpkeReply {
248    fn from(value: HpkeOpenKeyFromFileReply) -> Self {
249        Self::OpenKeyFromFile(value)
250    }
251}
252impl TryFrom<HpkeReply> for HpkeSealReply {
253    type Error = Error;
254    fn try_from(value: HpkeReply) -> Result<Self, Self::Error> {
255        match value {
256            HpkeReply::Seal(this) => Ok(this),
257            _ => Err(Error::InternalError),
258        }
259    }
260}
261
262impl TryFrom<HpkeReply> for HpkeSealKeyReply {
263    type Error = Error;
264    fn try_from(value: HpkeReply) -> Result<Self, Self::Error> {
265        match value {
266            HpkeReply::SealKey(this) => Ok(this),
267            _ => Err(Error::InternalError),
268        }
269    }
270}
271
272impl TryFrom<HpkeReply> for HpkeSealKeyToFileReply {
273    type Error = Error;
274    fn try_from(value: HpkeReply) -> Result<Self, Self::Error> {
275        match value {
276            HpkeReply::SealKeyToFile(this) => Ok(this),
277            _ => Err(Error::InternalError),
278        }
279    }
280}
281
282impl TryFrom<HpkeReply> for HpkeOpenReply {
283    type Error = Error;
284    fn try_from(value: HpkeReply) -> Result<Self, Self::Error> {
285        match value {
286            HpkeReply::Open(this) => Ok(this),
287            _ => Err(Error::InternalError),
288        }
289    }
290}
291
292impl TryFrom<HpkeReply> for HpkeOpenKeyReply {
293    type Error = Error;
294    fn try_from(value: HpkeReply) -> Result<Self, Self::Error> {
295        match value {
296            HpkeReply::OpenKey(this) => Ok(this),
297            _ => Err(Error::InternalError),
298        }
299    }
300}
301
302impl TryFrom<HpkeReply> for HpkeOpenKeyFromFileReply {
303    type Error = Error;
304    fn try_from(value: HpkeReply) -> Result<Self, Self::Error> {
305        match value {
306            HpkeReply::OpenKeyFromFile(this) => Ok(this),
307            _ => Err(Error::InternalError),
308        }
309    }
310}
311
312/// Open with a private key
313///
314/// As described in 6.1 with mode "base"
315#[derive(Deserialize, Serialize)]
316pub struct HpkeOpenReply {
317    pub plaintext: Message,
318}
319
320/// Open with a private key
321///
322/// As described in 6.1 with mode "base"
323#[derive(Deserialize, Serialize)]
324pub struct HpkeOpenKeyReply {
325    pub key: KeyId,
326}
327
328/// Open with a private key
329///
330/// As described in 6.1 with mode "base"
331#[derive(Deserialize, Serialize)]
332pub struct HpkeOpenKeyFromFileReply {
333    pub key: KeyId,
334}
335
336pub type HpkeResult<'a, R, C> = ExtensionResult<'a, HpkeExtension, R, C>;
337
338pub struct HpkeExtension;
339
340impl Extension for HpkeExtension {
341    type Request = HpkeRequest;
342    type Reply = HpkeReply;
343}
344
345pub trait HpkeClient: ExtensionClient<HpkeExtension> {
346    fn hpke_seal(
347        &mut self,
348        key: KeyId,
349        plaintext: Message,
350        aad: ShortData,
351        info: ShortData,
352        enc_location: Location,
353    ) -> HpkeResult<'_, HpkeSealReply, Self> {
354        self.extension(HpkeRequest::Seal(HpkeSealRequest {
355            key,
356            plaintext,
357            aad,
358            info,
359            enc_location,
360        }))
361    }
362
363    fn hpke_seal_key(
364        &mut self,
365        public_key: KeyId,
366        key_to_seal: KeyId,
367        aad: ShortData,
368        info: ShortData,
369    ) -> HpkeResult<'_, HpkeSealKeyReply, Self> {
370        self.extension(HpkeRequest::SealKey(HpkeSealKeyRequest {
371            public_key,
372            key_to_seal,
373            aad,
374            info,
375        }))
376    }
377
378    fn hpke_seal_key_to_file(
379        &mut self,
380        file: PathBuf,
381        location: Location,
382        public_key: KeyId,
383        key_to_seal: KeyId,
384        aad: ShortData,
385        info: ShortData,
386    ) -> HpkeResult<'_, HpkeSealKeyToFileReply, Self> {
387        self.extension(HpkeRequest::SealKeyToFile(HpkeSealKeyToFileRequest {
388            file,
389            public_key,
390            key_to_seal,
391            aad,
392            info,
393            location,
394        }))
395    }
396
397    fn hpke_open(
398        &mut self,
399        key: KeyId,
400        enc_key: KeyId,
401        ciphertext: Message,
402        tag: ByteArray<16>,
403        aad: ShortData,
404        info: ShortData,
405    ) -> HpkeResult<'_, HpkeOpenReply, Self> {
406        self.extension(HpkeRequest::Open(HpkeOpenRequest {
407            key,
408            tag,
409            enc_key,
410            ciphertext,
411            aad,
412            info,
413        }))
414    }
415    fn hpke_open_key(
416        &mut self,
417        key: KeyId,
418        sealed_key: Message,
419        aad: ShortData,
420        info: ShortData,
421        location: Location,
422    ) -> HpkeResult<'_, HpkeOpenKeyReply, Self> {
423        self.extension(HpkeRequest::OpenKey(HpkeOpenKeyRequest {
424            key,
425            sealed_key,
426            aad,
427            info,
428            location,
429        }))
430    }
431    fn hpke_open_key_from_file(
432        &mut self,
433        key: KeyId,
434        sealed_key: PathBuf,
435        sealed_location: Location,
436        unsealed_location: Location,
437        aad: ShortData,
438        info: ShortData,
439    ) -> HpkeResult<'_, HpkeOpenKeyFromFileReply, Self> {
440        self.extension(HpkeRequest::OpenKeyFromFile(HpkeOpenKeyFromFileRequest {
441            key,
442            aad,
443            info,
444            sealed_key,
445            sealed_location,
446            unsealed_location,
447        }))
448    }
449}
450
451impl<T: ExtensionClient<HpkeExtension>> HpkeClient for T {}