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