Skip to main content

embedded_cal/
lib.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2// SPDX-FileCopyrightText: Inria-AIO, Cryspen, and Christian Amsüss
3//! embedded-cal is a family of interface traits around cryptography, primarily [`Cal`].
4//!
5//! *Users of the trait* can implement their high-level cryptographic protocol implementation
6//! libraries or applications on top of the trait, and leverage hardware acceleration available on
7//! some platforms, without being tied to a particular implementation of the algorithms or a
8//! aprticular acceleration module.
9//!
10//! *Providers of the trait* can be software implementations, specific hardware platforms, or
11//! embedded operating systems that provide whichever acceleration or algorithms are configured for
12//! a givens build.
13//!
14//! Neither the users or nor the providers are generally implemented in this crate; however, being
15//! the centerpiece of the embedded-cal ecosystem, this documentation points to some noteworthy
16//! implementations outside the crate.
17//!
18//! ## How to use this crate
19//!
20//! ### … as a user
21//!
22//! When a library you use requires you to pass in an implementation of [`Cal`], their functions
23//! are generic over implementations of [`Cal`].
24//!
25//! Depending on the system you use the library on, you can obtain a suitable instance to pass in
26//! from:
27//!
28//! * Your operating system.
29//!   * On embedded systems, this can be provided explicitly by the RTOS (e.g. work in progress in
30//!     Ariel OS and RIOT OS).
31//!   * On `std` systems, you can use software based implementations, which (while fundamentally
32//!     composable) generally offer a feature for ready-to-use construction (e.g.
33//!     [`embedded_cal_libcrux::Standalone::standalone()`](https://docs.rs/embedded-cal-libcrux/latest/embedded_cal_libcrux/type.Standalone.html#method.standalone)
34//!     or
35//!     [`embedded_cal_rustcrypto::Standalone::standalone()`](https://docs.rs/embedded-cal-rustcrypto/latest/embedded_cal_rustcrypto/type.Standalone.html#method.standalone).
36//! * When developing on bare metal, an implementation such as
37//!   [`embedded-cal-nrf54l15`](https://docs.rs/embedded-cal-nrf54l15/latest/embedded_cal_nrf54l15/struct.Nrf54l15Cal.html)
38//!   can be constructed from the underlying hardware registers, and later augmented with software
39//!   layers.
40//!
41//! Examples of these are in
42//! [`embedded-cal-examples/src/bin/demo.rs`](https://github.com/lake-rs/embedded-cal/blob/main/embedded-cal-examples/src/bin/demo.rs)
43//! -- depending on the components selected by features, the `Cal` instance is constructed through
44//! a standalone constructor or by composition.
45//!
46//! ### … as a high-level library author
47//!
48//! When writing a library, be generic over `Cal` implementations.
49//!
50//! Where possible, it is recommended to take short-lived references to a `Cal`, because this
51//! enables users to go with a lock-free exclusive version where that is an advantage.
52//!
53//! An example of this is in
54//! [`embedded-cal-examples/src/lib.rs`](https://github.com/lake-rs/embedded-cal/blob/main/embedded-cal-examples/src/lib.rs):
55//! Some of the operations work from a selection of algorithms for agility,
56//! some pick fixed algorithm (and fail if it is unsupported; with future Rust versions this can
57//! [become a build time failure](https://github.com/lake-rs/embedded-cal/issues/144)),
58//!
59//! ### … when wrapping hardware
60//!
61//! Most parts of the [`Cal`] trait are optional to implement, in the sense that supporting no
62//! algorithms is easy. (This is the reason why rather than having a single trait, there is an
63//! [`Cal::AeadProvider`] iand [`.aead()`][Cal::aead()] accessor: If your hardware can not do it,
64//! just don't provide it.
65//!
66//! In particular, for many aspects (list growing), there are "plumbing" traits you can implement
67//! instead. For example, for SHA2, implement
68//! [`plumbing::hash::Sha2Short`] and set [`SUPPORTED =
69//! true`][plumbing::hash::Sha2Short::SUPPORTED]. While this does not
70//! immediately give the users access to the algorithms, a higher-up wrapper can pick up the parts
71//! and fill in the gaps. This way, edge-case prone buffer handling can be done by more carefully
72//! vetted components rather than being repetitively implemented.
73//!
74//! ### … as an embedded RTOS maintainer
75//!
76//! Provide an easy single type implementing [`Cal`]. Configuration should happen outside of the
77//! RTOS, typically in system-wide build configuration. By default, it is recommended to build from
78//! whichever accelerated type is available for the hardware, and use
79//! [`embedded-cal-libcrux`](https://docs.rs/embedded-cal-nrf54l15/latest/embedded_cal_nrf54l15/struct.Nrf54l15Cal.html)
80//! to fill gaps.
81//!
82//! On many systems, that type needs to be a singleton and can not be shared (e.g. because it needs
83//! exclusive access to some registers).
84//!
85//! On systems where mutex-style access is widespread, provide a mutex based implementation that
86//! can be shared / cloned easily, so that libraries that can not do everything in short-lived
87//! operations can be given something to work with. This API can be enabled conditionally based on
88//! whether any user in the current build requests it.
89//!
90//! It is recommended to also have an accessor for short-time access available unconditionally. If
91//! the mutex based API is requested, this merely hands out another copy of the shared instance;
92//! otherwise, it can use a simpler run-time (or even build-time) check.
93//!
94//! ## Distinguishing properties and related work
95//!
96//! The interfaces of this crate are geared towards *cryptographic agility*: An application should
97//! not need to be changed in order to support a larger set of hash functions or elliptic curves.
98//! This is aligned with how higher-level cryptographic systems such as COSE or TLS work:
99//! algorithms are negotiated rather than built into the protocol. In this, embedded-cal is
100//! distinct from many rustcrypto traits such as [`aead`](https://docs.rs/aead/latest/aead/) or
101//! [`digest`](https://docs.rs/digest/latest/digest/), through which generic application code gets
102//! monomorphized onto a concrete algorithm.
103//!
104//! The crates focus on the *Embedded Rust ecosystem*, which includes bare metal and RTOS
105//! applications. It is `no_std`, and does not use dynamic allocation in general. In this,
106//! embedded-cal is distinct from the otherwise similar [PSA Crypto
107//! API](https://arm-software.github.io/psa-api/crypto/) (which uses C embedded idioms).
108//!
109//! Implementations of embedded-cal are *composable*: Rather than having to select a single
110//! provider of cryptographic tools, it allows picking suitable parts. For example, a software
111//! implementation can be composed from the OS's source of randomness and the [libcrux software
112//! implementation](https://crates.io/crates/embedded-cal-libcrux); on embedded hardware, there is
113//! typically one layer of what the hardware can do, augmented by a software layer that fills gaps
114//! (e.g. when the hardware accelerates elliptic curves primitives, and the software then make a
115//! full DH key establishment out of it). Also, different algorithms can be served by different
116//! components.
117//!
118//! The library is designed *with resident secrets in mind* (event though currently, no
119//! implementations provide that): Keys are never required to be visible to the user, by virtue of
120//! using associated types in many places. This way, implementations based on secure elements can
121//! use either encapsulated keys or key slot handles.
122#![no_std]
123
124pub mod empty;
125pub mod util;
126
127mod aead;
128mod dh;
129mod error;
130mod hash;
131mod hkdf;
132mod hmac;
133// FIXME: Once we start API stability, this should be a dedicated crate.
134pub mod plumbing;
135
136pub use aead::{AadGenerator, AeadAlgorithm, AeadProvider, DecryptionFailed};
137pub use dh::{
138    DhAlgorithm, DhProvider, IncompatibleKeys, test_dh_algorithm_ecdh_p256, test_dh_selftest,
139};
140pub use error::ImportError;
141pub use hash::{HashAlgorithm, HashProvider, test_hash_algorithm_sha256};
142pub use hkdf::{HkdfError, HkdfProvider};
143pub use hmac::{HmacAlgorithm, HmacProvider, test_hmac_algorithm_hmacsha256};
144
145#[allow(
146    type_alias_bounds,
147    reason = "makes the intention clearer, and no danger of later incompatibility because the type expansion explicitly requires that C is a Cal"
148)]
149/// Accessors to the deep associated types of a [`Cal`].
150///
151/// As associated types often need explicit naming of the trait (even when the trait is in scope),
152/// and due to the various Provider traits being associated types, accessing eg. a Cal's AEAD
153/// algorithm type is relatively cumbersome.
154///
155/// This module provides easy `{Interface}{Type}Of` style type aliases for various values of
156/// `Interface` and `Type`.
157///
158/// For example, [`AeadAlgorithmOf<C>`][accessor::AeadAlgorithmOf] is a shorthand way of writing
159/// `<<C as Cal>::AeadProvider as AeadProvider>::Algorithm`, which would often be required because
160/// associated type trait requirements are not automatically made available.
161pub mod accessor {
162    use super::*;
163
164    pub type AeadProviderOf<C: Cal> = <C as Cal>::AeadProvider;
165    pub type AeadAlgorithmOf<C: Cal> = <<C as Cal>::AeadProvider as AeadProvider>::Algorithm;
166    pub type AeadKeyOf<C: Cal> = <<C as Cal>::AeadProvider as AeadProvider>::Key;
167    pub type AeadTagOf<C: Cal> = <<C as Cal>::AeadProvider as AeadProvider>::Tag;
168
169    pub type DhProviderOf<C: Cal> = <C as Cal>::DhProvider;
170    pub type DhAlgorithmOf<C: Cal> = <<C as Cal>::DhProvider as DhProvider>::Algorithm;
171    pub type DhVisibleSecretKeyOf<C: Cal> =
172        <<C as Cal>::DhProvider as DhProvider>::VisibleSecretKey;
173    pub type DhSecretKeyOf<C: Cal> = <<C as Cal>::DhProvider as DhProvider>::SecretKey;
174    pub type DhPublicKeyOf<C: Cal> = <<C as Cal>::DhProvider as DhProvider>::PublicKey;
175    pub type DhSharedSecretOf<C: Cal> = <<C as Cal>::DhProvider as DhProvider>::SharedSecret;
176
177    pub type HashProviderOf<C: Cal> = <C as Cal>::HashProvider;
178    pub type HashAlgorithmOf<C: Cal> = <<C as Cal>::HashProvider as HashProvider>::Algorithm;
179    pub type HashStateOf<C: Cal> = <<C as Cal>::HashProvider as HashProvider>::State;
180    pub type HashOutputOf<C: Cal> = <<C as Cal>::HashProvider as HashProvider>::Output;
181
182    pub type HmacProviderOf<C: Cal> = <C as Cal>::HmacProvider;
183    pub type HmacAlgorithmOf<C: Cal> = <<C as Cal>::HmacProvider as HmacProvider>::Algorithm;
184    pub type HmacKeyOf<C: Cal> = <<C as Cal>::HmacProvider as HmacProvider>::Key;
185    pub type HmacStateOf<C: Cal> = <<C as Cal>::HmacProvider as HmacProvider>::State;
186    pub type HmacOutputOf<C: Cal> = <<C as Cal>::HmacProvider as HmacProvider>::Output;
187}
188
189/// Cryptographic abstraction provider that encompasses all features abstracted by the
190/// embedded-cal.
191///
192/// To ease implementation and give better access to its aspects, this does not have a list of
193/// supertraits, but rather various associated types and acccessors to them.
194///
195/// These allow passing on full portions of the feature set between implementations. Common choices
196/// for the associated type and the corresponding accessor implementation are:
197///
198/// * `type XxxProvider = Self` / `self`, when an object does provide that functionality.
199/// * `type XxxProvider = Self::Base` / `self.base.xxx()`, when an extender does not touch that
200///   functionality at all and merely forwards it to whatever is being extended.
201/// * `type XxxProvider = embedded_cal::empty::EmptyCal` / `&mut self.empty`, when a non-extender
202///   (typically a hardware module) does not implement something at all.
203///
204///   Note that to keep the types reasonably simple, the accessors are `fn(&mut Self) -> &mut
205///   Self::XxxProvider`, which requires an existing (albeit zero-sized) [`EmptyCal`][empty::EmptyCal],
206///   which is most easily provided by adding one as a field to the `Self` struct. (The alternative
207///   would be to go through `AsMut` indirections or use lifetime-generic associated types like
208///   `type XxxProvider<'t> = &mut Self` / `= Empty`, and that is not only unergonomic, it also
209///   hinders restraining them in `where` clauses).
210pub trait Cal {
211    /// The non-supertrait responsible for key establishment.
212    type DhProvider: DhProvider;
213    type AeadProvider: AeadProvider;
214    type HashProvider: HashProvider;
215    type HmacProvider: HmacProvider;
216
217    fn dh(&mut self) -> &mut Self::DhProvider;
218    fn aead(&mut self) -> &mut Self::AeadProvider;
219    fn hash(&mut self) -> &mut Self::HashProvider;
220    fn hmac(&mut self) -> &mut Self::HmacProvider;
221}