trussed_hkdf/
lib.rs

1// Copyright (C) Nitrokey GmbH
2// SPDX-License-Identifier: Apache-2.0 or MIT
3
4#![no_std]
5#![warn(non_ascii_idents, trivial_casts, unused, unused_qualifications)]
6#![deny(unsafe_code)]
7
8use serde::{Deserialize, Serialize};
9use trussed_core::{
10    config::MAX_MEDIUM_DATA_LENGTH,
11    serde_extensions::{Extension, ExtensionClient, ExtensionResult},
12    types::{Bytes, KeyId, Location, Message},
13    Error,
14};
15
16#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
17pub struct OkmId(pub KeyId);
18
19/// Can represent either data or a key
20#[derive(Serialize, Deserialize)]
21pub enum KeyOrData<const N: usize> {
22    Key(KeyId),
23    Data(Bytes<N>),
24}
25
26pub struct HkdfExtension;
27
28impl Extension for HkdfExtension {
29    type Request = HkdfRequest;
30    type Reply = HkdfReply;
31}
32
33#[allow(clippy::large_enum_variant)]
34#[derive(Serialize, Deserialize)]
35pub enum HkdfRequest {
36    Extract(HkdfExtractRequest),
37    Expand(HkdfExpandRequest),
38}
39#[derive(Serialize, Deserialize)]
40pub enum HkdfReply {
41    Extract(HkdfExtractReply),
42    Expand(HkdfExpandReply),
43}
44
45impl From<HkdfExpandRequest> for HkdfRequest {
46    fn from(v: HkdfExpandRequest) -> Self {
47        Self::Expand(v)
48    }
49}
50
51impl From<HkdfExtractRequest> for HkdfRequest {
52    fn from(v: HkdfExtractRequest) -> Self {
53        Self::Extract(v)
54    }
55}
56
57impl From<HkdfExpandReply> for HkdfReply {
58    fn from(v: HkdfExpandReply) -> Self {
59        Self::Expand(v)
60    }
61}
62
63impl From<HkdfExtractReply> for HkdfReply {
64    fn from(v: HkdfExtractReply) -> Self {
65        Self::Extract(v)
66    }
67}
68
69impl TryFrom<HkdfRequest> for HkdfExpandRequest {
70    type Error = Error;
71    fn try_from(v: HkdfRequest) -> Result<Self, Error> {
72        match v {
73            HkdfRequest::Expand(v) => Ok(v),
74            _ => Err(Error::InternalError),
75        }
76    }
77}
78impl TryFrom<HkdfRequest> for HkdfExtractRequest {
79    type Error = Error;
80    fn try_from(v: HkdfRequest) -> Result<Self, Error> {
81        match v {
82            HkdfRequest::Extract(v) => Ok(v),
83            _ => Err(Error::InternalError),
84        }
85    }
86}
87
88impl TryFrom<HkdfReply> for HkdfExpandReply {
89    type Error = Error;
90    fn try_from(v: HkdfReply) -> Result<Self, Error> {
91        match v {
92            HkdfReply::Expand(v) => Ok(v),
93            _ => Err(Error::InternalError),
94        }
95    }
96}
97impl TryFrom<HkdfReply> for HkdfExtractReply {
98    type Error = Error;
99    fn try_from(v: HkdfReply) -> Result<Self, Error> {
100        match v {
101            HkdfReply::Extract(v) => Ok(v),
102            _ => Err(Error::InternalError),
103        }
104    }
105}
106
107#[derive(Serialize, Deserialize)]
108pub struct HkdfExtractReply {
109    pub okm: OkmId,
110}
111
112#[derive(Serialize, Deserialize)]
113pub struct HkdfExtractRequest {
114    pub ikm: KeyOrData<MAX_MEDIUM_DATA_LENGTH>,
115    pub salt: Option<KeyOrData<MAX_MEDIUM_DATA_LENGTH>>,
116    /// Location to store the OKM
117    pub storage: Location,
118}
119
120#[derive(Serialize, Deserialize)]
121pub struct HkdfExpandReply {
122    pub key: KeyId,
123}
124
125#[derive(Serialize, Deserialize)]
126pub struct HkdfExpandRequest {
127    pub prk: OkmId,
128    pub info: Message,
129    pub len: usize,
130    pub storage: Location,
131}
132
133pub type HkdfResult<'a, R, C> = ExtensionResult<'a, HkdfExtension, R, C>;
134
135pub trait HkdfClient: ExtensionClient<HkdfExtension> {
136    fn hkdf_extract(
137        &mut self,
138        ikm: KeyOrData<MAX_MEDIUM_DATA_LENGTH>,
139        salt: Option<KeyOrData<MAX_MEDIUM_DATA_LENGTH>>,
140        storage: Location,
141    ) -> HkdfResult<'_, HkdfExtractReply, Self> {
142        self.extension(HkdfRequest::Extract(HkdfExtractRequest {
143            ikm,
144            salt,
145            storage,
146        }))
147    }
148    fn hkdf_expand(
149        &mut self,
150        prk: OkmId,
151        info: Message,
152        len: usize,
153        storage: Location,
154    ) -> HkdfResult<'_, HkdfExpandReply, Self> {
155        self.extension(HkdfRequest::Expand(HkdfExpandRequest {
156            prk,
157            info,
158            len,
159            storage,
160        }))
161    }
162}
163
164impl<C: ExtensionClient<HkdfExtension>> HkdfClient for C {}