hpke_rs/
lib.rs

1#![doc = include_str!("../Readme.md")]
2//! # Examples
3//!
4//! Oneshot HPKE encryption.
5//!
6//! ```
7//! use hpke_rs::{*, hpke_types::*};
8//! use hpke_rs_libcrux::HpkeLibcrux;
9//! use hpke_rs_crypto::{HpkeCrypto, RngCore};
10//!
11//! // Set up hpke mode.
12//! let mut hpke = Hpke::<HpkeLibcrux>::new(Mode::Base, KemAlgorithm::DhKem25519,
13//!    KdfAlgorithm::HkdfSha256, AeadAlgorithm::ChaCha20Poly1305);
14//!
15//! // Generate keys. The other parties public key must be received in some way.
16//! let (sk_r, pk_r) = hpke.generate_key_pair().unwrap().into_keys();
17//! let (sk_s, pk_s) = hpke.generate_key_pair().unwrap().into_keys();
18//!
19//! // Set the input. Only `plain_text` is required
20//! let info = b"HPKE demo info";
21//! let aad = b"HPKE demo aad";
22//! let plaintext = b"HPKE demo plain text";
23//! let exporter_context = b"HPKE demo exporter context";
24//!
25//! // We don't use authentication or PSKs here.
26//! let psk = None;
27//! let psk_id = None;
28//! let sk_s = None;
29//! let pk_s = None;
30//!
31//! // Encrypt the `plaintext` to the receiver.
32//! let (enc, ctxt) = hpke
33//!     .seal(&pk_r, info, aad, plaintext, psk, psk_id, sk_s)
34//!     .unwrap();
35//!
36//! // Decrypt the ciphertext on the receiver.
37//! let ptxt = hpke
38//!     .open(&enc, &sk_r, info, aad, &ctxt, psk, psk_id, pk_s)
39//!     .unwrap();
40//!
41//! assert_eq!(ptxt, plaintext);
42//! ```
43//!
44//! Encryption context.
45//!
46//! ```
47//! use hpke_rs::{*, hpke_types::*};
48//! use hpke_rs_libcrux::HpkeLibcrux;
49//! use hpke_rs_crypto::{HpkeCrypto, RngCore};
50//!
51//! // Set up hpke mode.
52//! let mut hpke = Hpke::<HpkeLibcrux>::new(Mode::Base, KemAlgorithm::DhKem25519,
53//!    KdfAlgorithm::HkdfSha256, AeadAlgorithm::ChaCha20Poly1305);
54//!
55//! // Generate keys. The other parties public key must be received in some way.
56//! let (sk_r, pk_r) = hpke.generate_key_pair().unwrap().into_keys();
57//! let (sk_s, pk_s) = hpke.generate_key_pair().unwrap().into_keys();
58//!
59//! // Set the input. Only `plain_text` is required
60//! let info = b"HPKE demo info";
61//! let aad = b"HPKE demo aad";
62//! let plaintext = b"HPKE demo plain text";
63//! let exporter_context = b"HPKE demo exporter context";
64//!
65//! // We don't use authentication or PSKs here.
66//! let psk = None;
67//! let psk_id = None;
68//! let sk_s = None;
69//! let pk_s = None;
70//!
71//! // Set up the context on both sides.
72//! let (enc, mut sender_context) = hpke
73//!     .setup_sender(&pk_r, info, psk, psk_id, sk_s)
74//!     .unwrap();
75//!
76//! // Share `enc` with the receiver.
77//! let mut receiver_context = hpke
78//!     .setup_receiver(&enc, &sk_r, info, psk, psk_id, pk_s)
79//!     .unwrap();
80//!
81//! // Encrypt the plaintext to the receiver, using the context.
82//! let ctxt = sender_context.seal(aad, plaintext).unwrap();
83//!
84//! // Decrypt the ciphertext on the receiver, using the context.
85//! let ptxt = receiver_context.open(aad, &ctxt).unwrap();
86//!
87//! assert_eq!(ptxt, plaintext);
88//! ```
89
90#![forbid(unsafe_code, unused_must_use, unstable_features)]
91#![deny(
92    trivial_casts,
93    trivial_numeric_casts,
94    missing_docs,
95    unused_import_braces,
96    unused_extern_crates,
97    unused_qualifications
98)]
99#![cfg_attr(not(test), no_std)]
100
101extern crate alloc;
102#[cfg(feature = "std")]
103extern crate std;
104
105use alloc::{
106    format,
107    string::{String, ToString},
108    vec,
109    vec::Vec,
110};
111
112#[cfg(feature = "hpke-test-prng")]
113use hpke_rs_crypto::HpkeTestRng;
114use hpke_rs_crypto::{
115    types::{AeadAlgorithm, KdfAlgorithm, KemAlgorithm},
116    HpkeCrypto,
117};
118use prelude::kdf::{labeled_expand, labeled_extract};
119
120/// Re-export of the HPKE types from the [`hpke_rs_crypto`] crate.
121pub use hpke_rs_crypto::types as hpke_types;
122
123/// Re-export of the RustCrypto crate.
124#[cfg(feature = "rustcrypto")]
125pub use hpke_rs_rust_crypto as rustcrypto;
126
127/// Re-export of the libcrux crate.
128#[cfg(feature = "libcrux")]
129pub use hpke_rs_libcrux as libcrux;
130
131#[cfg(not(feature = "hpke-test-prng"))]
132use rand_core::TryRngCore;
133
134#[cfg(feature = "serialization")]
135pub(crate) use serde::{Deserialize, Serialize};
136use zeroize::Zeroize;
137
138mod dh_kem;
139pub(crate) mod kdf;
140mod kem;
141pub mod prelude;
142
143mod util;
144
145#[cfg(test)]
146mod test_aead;
147#[cfg(test)]
148mod test_kdf;
149
150#[deprecated(
151    since = "0.0.7",
152    note = "Please use HpkeError instead. This alias will be removed with the first stable  0.1 release."
153)]
154#[allow(dead_code)]
155#[allow(clippy::upper_case_acronyms)]
156type HPKEError = HpkeError;
157
158/// HPKE Error types.
159#[derive(Debug, Clone, PartialEq)]
160pub enum HpkeError {
161    /// Error opening an HPKE ciphertext.
162    OpenError,
163
164    /// Invalid configuration or arguments.
165    InvalidConfig,
166
167    /// Invalid input.
168    InvalidInput,
169
170    /// Unknown HPKE mode.
171    UnknownMode,
172
173    /// Inconsistent PSK input.
174    InconsistentPsk,
175
176    /// PSK input is required but missing.
177    MissingPsk,
178
179    /// PSK input is provided but not needed.
180    UnnecessaryPsk,
181
182    /// PSK input is too short (needs to be at least 32 bytes).
183    InsecurePsk,
184
185    /// An error in the crypto library occurred.
186    CryptoError(String),
187
188    /// The message limit for this AEAD, key, and nonce.
189    MessageLimitReached,
190
191    /// Unable to collect enough randomness.
192    InsufficientRandomness,
193}
194
195#[cfg(feature = "std")]
196impl std::error::Error for HpkeError {}
197
198impl core::fmt::Display for HpkeError {
199    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
200        write!(f, "HPKE Error: {:?}", self)
201    }
202}
203
204#[deprecated(
205    since = "0.0.7",
206    note = "Please use HpkePublicKey instead. This alias will be removed with the first stable  0.1 release."
207)]
208#[allow(clippy::upper_case_acronyms)]
209#[allow(missing_docs)]
210pub type HPKEPublicKey = HpkePublicKey;
211
212/// An HPKE public key is a byte vector.
213#[derive(Debug, PartialEq, Clone, Default)]
214#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
215pub struct HpkePublicKey {
216    value: Vec<u8>,
217}
218
219#[deprecated(
220    since = "0.0.7",
221    note = "Please use HpkePrivateKey instead. This alias will be removed with the first stable  0.1 release."
222)]
223#[allow(clippy::upper_case_acronyms)]
224#[allow(missing_docs)]
225pub type HPKEPrivateKey = HpkePrivateKey;
226
227/// An HPKE private key is a byte vector.
228#[derive(Default, Zeroize)]
229#[zeroize(drop)] // XXX: Change to `ZeroizeOnDrop` when moving to 1.5
230#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
231#[cfg_attr(feature = "hazmat", derive(Clone))]
232pub struct HpkePrivateKey {
233    value: Vec<u8>,
234}
235
236#[deprecated(
237    since = "0.0.7",
238    note = "Please use HpkeKeyPair instead. This alias will be removed with the first stable  0.1 release."
239)]
240#[allow(clippy::upper_case_acronyms)]
241#[allow(missing_docs)]
242pub type HPKEKeyPair = HpkeKeyPair;
243
244/// An HPKE key pair has an HPKE private and public key.
245#[derive(Debug, Default)]
246#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
247#[cfg_attr(feature = "hazmat", derive(Clone))]
248pub struct HpkeKeyPair {
249    private_key: HpkePrivateKey,
250    public_key: HpkePublicKey,
251}
252
253/// HPKE supports four modes.
254#[derive(PartialEq, Copy, Clone, Debug)]
255#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
256#[repr(u8)]
257pub enum Mode {
258    /// HPKE Base mode.
259    Base = 0x00,
260
261    /// HPKE with PSK.
262    Psk = 0x01,
263
264    /// Authenticated HPKE.
265    Auth = 0x02,
266
267    /// Authenticated HPKE with PSK.
268    AuthPsk = 0x03,
269}
270
271impl core::fmt::Display for Mode {
272    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
273        write!(f, "{:?}", self)
274    }
275}
276
277impl TryFrom<u8> for Mode {
278    type Error = HpkeError;
279    fn try_from(x: u8) -> Result<Mode, HpkeError> {
280        match x {
281            0x00 => Ok(Mode::Base),
282            0x01 => Ok(Mode::Psk),
283            0x02 => Ok(Mode::Auth),
284            0x03 => Ok(Mode::AuthPsk),
285            _ => Err(HpkeError::UnknownMode),
286        }
287    }
288}
289
290/// Type alias for encapsulated secrets.
291/// A byte vector.
292type EncapsulatedSecret = Vec<u8>;
293
294/// Type alias for ciphertexts.
295/// A byte vector.
296type Ciphertext = Vec<u8>;
297
298/// Type alias for plain text.
299/// A byte vector.
300type Plaintext = Vec<u8>;
301
302/// The HPKE context.
303/// Note that the RFC currently doesn't define this.
304/// Also see <https://github.com/cfrg/draft-irtf-cfrg-hpke/issues/161>.
305pub struct Context<Crypto: 'static + HpkeCrypto> {
306    key: Vec<u8>,
307    nonce: Vec<u8>,
308    exporter_secret: Vec<u8>,
309    sequence_number: u32,
310    hpke: Hpke<Crypto>,
311}
312
313#[cfg(feature = "hazmat")]
314impl<Crypto: HpkeCrypto> core::fmt::Debug for Context<Crypto> {
315    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
316        write!(
317            f,
318            "Context {{\n  key: {:?}\n  nonce: {:?}\n exporter_secret: {:?}\n seq no: {:?}\n}}",
319            self.key, self.nonce, self.exporter_secret, self.sequence_number
320        )
321    }
322}
323
324#[cfg(not(feature = "hazmat"))]
325impl<Crypto: HpkeCrypto> core::fmt::Debug for Context<Crypto> {
326    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
327        write!(
328            f,
329            "Context {{\n  key: {:?}\n  nonce: {:?}\n exporter_secret: {:?}\n seq no: {:?}\n}}",
330            &"***", &"***", &"***", &"***"
331        )
332    }
333}
334
335impl<Crypto: HpkeCrypto> Context<Crypto> {
336    /// 5.2. Encryption and Decryption
337    ///
338    /// Takes the associated data and the plain text as byte slices and returns
339    /// the ciphertext or an error.
340    ///
341    /// ```text
342    /// def Context.Seal(aad, pt):
343    ///   ct = Seal(self.key, self.ComputeNonce(self.seq), aad, pt)
344    ///   self.IncrementSeq()
345    ///   return ct
346    /// ```
347    pub fn seal(&mut self, aad: &[u8], plain_txt: &[u8]) -> Result<Ciphertext, HpkeError> {
348        let ctxt = Crypto::aead_seal(
349            self.hpke.aead_id,
350            &self.key,
351            &self.compute_nonce(),
352            aad,
353            plain_txt,
354        )?;
355        self.increment_seq()?;
356        Ok(ctxt)
357    }
358
359    /// 5.2. Encryption and Decryption
360    ///
361    /// Takes the associated data and the ciphertext as byte slices and returns
362    /// the plain text or an error.
363    ///
364    /// ```text
365    /// def Context.Open(aad, ct):
366    ///   pt = Open(self.key, self.ComputeNonce(self.seq), aad, ct)
367    ///   if pt == OpenError:
368    ///     raise OpenError
369    ///   self.IncrementSeq()
370    ///   return pt
371    /// ```
372    pub fn open(&mut self, aad: &[u8], cipher_txt: &[u8]) -> Result<Plaintext, HpkeError> {
373        let ptxt = Crypto::aead_open(
374            self.hpke.aead_id,
375            &self.key,
376            &self.compute_nonce(),
377            aad,
378            cipher_txt,
379        )?;
380        self.increment_seq()?;
381        Ok(ptxt)
382    }
383
384    /// 5.3. Secret Export
385    ///
386    /// Takes a serialised exporter context as byte slice and a length for the
387    /// output secret and returns an exporter secret as byte vector.
388    ///
389    /// ```text
390    /// def Context.Export(exporter_context, L):
391    ///  return LabeledExpand(self.exporter_secret, "sec", exporter_context, L)
392    ///```
393    pub fn export(&self, exporter_context: &[u8], length: usize) -> Result<Vec<u8>, HpkeError> {
394        labeled_expand::<Crypto>(
395            self.hpke.kdf_id,
396            &self.exporter_secret,
397            &self.hpke.ciphersuite(),
398            "sec",
399            exporter_context,
400            length,
401        )
402        .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))
403    }
404
405    /// def Context<ROLE>.ComputeNonce(seq):
406    ///     seq_bytes = I2OSP(seq, Nn)
407    ///     return xor(self.base_nonce, seq_bytes)
408    fn compute_nonce(&self) -> Vec<u8> {
409        let seq = self.sequence_number.to_be_bytes();
410        let mut enc_seq = vec![0u8; self.nonce.len() - seq.len()];
411        enc_seq.extend_from_slice(&seq);
412        util::xor_bytes(&enc_seq, &self.nonce)
413    }
414
415    /// def Context<ROLE>.IncrementSeq():
416    ///     if self.seq >= (1 << (8*Nn)) - 1:
417    ///       raise MessageLimitReached
418    ///     self.seq += 1
419    fn increment_seq(&mut self) -> Result<(), HpkeError> {
420        if u128::from(self.sequence_number)
421            >= ((1u128 << (8 * Crypto::aead_nonce_length(self.hpke.aead_id))) - 1)
422        {
423            return Err(HpkeError::MessageLimitReached);
424        }
425        self.sequence_number += 1;
426        Ok(())
427    }
428}
429
430/// The HPKE configuration struct.
431/// This holds the configuration for HPKE but no state.
432/// To use HPKE first instantiate the configuration with
433/// `let hpke = Hpke::new(mode, kem_mode, kdf_mode, aead_mode)`.
434/// Now one can use the `hpke` configuration.
435///
436/// Note that cloning does NOT clone the PRNG state.
437#[derive(Debug)]
438pub struct Hpke<Crypto: 'static + HpkeCrypto> {
439    mode: Mode,
440    kem_id: KemAlgorithm,
441    kdf_id: KdfAlgorithm,
442    aead_id: AeadAlgorithm,
443    prng: Crypto::HpkePrng,
444}
445
446impl<Crypto: 'static + HpkeCrypto> Clone for Hpke<Crypto> {
447    fn clone(&self) -> Self {
448        Self {
449            mode: self.mode,
450            kem_id: self.kem_id,
451            kdf_id: self.kdf_id,
452            aead_id: self.aead_id,
453            prng: Crypto::prng(),
454        }
455    }
456}
457
458impl<Crypto: HpkeCrypto> core::fmt::Display for Hpke<Crypto> {
459    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
460        write!(
461            f,
462            "{}_{}_{}_{}",
463            self.mode.to_string().to_lowercase(),
464            self.kem_id.to_string().to_lowercase(),
465            self.kdf_id.to_string().to_lowercase(),
466            self.aead_id.to_string().to_lowercase()
467        )
468    }
469}
470
471impl<Crypto: HpkeCrypto> Hpke<Crypto> {
472    /// Set up the configuration for HPKE.
473    pub fn new(
474        mode: Mode,
475        kem_id: KemAlgorithm,
476        kdf_id: KdfAlgorithm,
477        aead_id: AeadAlgorithm,
478    ) -> Self {
479        Self {
480            mode,
481            kem_id,
482            kdf_id,
483            aead_id,
484            prng: Crypto::prng(),
485        }
486    }
487
488    /// Set up an HPKE sender.
489    ///
490    /// For the base and PSK modes this encapsulates the public key `pk_r`
491    /// of the receiver.
492    /// For the Auth and AuthPSK modes this encapsulates and authenticates
493    /// the public key `pk_r` of the receiver with the senders secret key `sk_s`.
494    ///
495    /// **Note** that this API expects the public key to be encoded.
496    /// This differs from the RFC.
497    /// But the public keys will be present in encoded form rather than raw form
498    /// such that it doesn't make sense to deserialize before passing it in.
499    ///
500    /// The encapsulated secret is returned together with the context.
501    /// If the secret key is missing in an authenticated mode, an error is returned.
502    pub fn setup_sender(
503        &mut self,
504        pk_r: &HpkePublicKey,
505        info: &[u8],
506        psk: Option<&[u8]>,
507        psk_id: Option<&[u8]>,
508        sk_s: Option<&HpkePrivateKey>,
509    ) -> Result<(EncapsulatedSecret, Context<Crypto>), HpkeError> {
510        let (zz, enc) = match self.mode {
511            Mode::Base | Mode::Psk => kem::encaps::<Crypto>(self, pk_r.value.as_slice())?,
512            Mode::Auth | Mode::AuthPsk => {
513                let sk_s = match sk_s {
514                    Some(s) => &s.value,
515                    None => return Err(HpkeError::InvalidInput),
516                };
517                kem::auth_encaps::<Crypto>(self, pk_r.value.as_slice(), sk_s)?
518            }
519        };
520        Ok((
521            enc,
522            self.clone().key_schedule(
523                &zz,
524                info,
525                psk.unwrap_or_default(),
526                psk_id.unwrap_or_default(),
527            )?,
528        ))
529    }
530
531    /// Set up an HPKE receiver.
532    ///
533    /// For the base and PSK modes this decapsulates `enc` with the secret key
534    /// `sk_r` of the receiver.
535    /// For the Auth and AuthPSK modes this decapsulates and authenticates `enc`
536    /// with the secret key `sk_r` of the receiver and the senders public key `pk_s`.
537    ///
538    /// **Note** that this API expects the public key to be encoded.
539    /// This differs from the RFC.
540    /// But the public keys will be present in encoded form rather than raw form
541    /// such that it doesn't make sense to deserialize before passing it in.
542    ///
543    /// The context based on the decapsulated values and, if present, the PSK is
544    /// returned.
545    /// If the secret key is missing in an authenticated mode, an error is returned.
546    pub fn setup_receiver(
547        &self,
548        enc: &[u8],
549        sk_r: &HpkePrivateKey,
550        info: &[u8],
551        psk: Option<&[u8]>,
552        psk_id: Option<&[u8]>,
553        pk_s: Option<&HpkePublicKey>,
554    ) -> Result<Context<Crypto>, HpkeError> {
555        let zz = match self.mode {
556            Mode::Base | Mode::Psk => kem::decaps::<Crypto>(self.kem_id, enc, &sk_r.value)?,
557            Mode::Auth | Mode::AuthPsk => {
558                let pk_s = match pk_s {
559                    Some(s) => s.value.as_slice(),
560                    None => return Err(HpkeError::InvalidInput),
561                };
562                kem::auth_decaps::<Crypto>(self.kem_id, enc, &sk_r.value, pk_s)?
563            }
564        };
565        self.clone().key_schedule(
566            &zz,
567            info,
568            psk.unwrap_or_default(),
569            psk_id.unwrap_or_default(),
570        )
571    }
572
573    /// 6. Single-Shot APIs
574    /// 6.1. Encryption and Decryption
575    ///
576    /// Single shot API to encrypt the bytes in `plain_text` to the public key
577    /// `pk_r`.
578    ///
579    /// **Note** that this API expects the public key to be encoded.
580    /// This differs from the RFC.
581    /// But the public keys will be present in encoded form rather than raw form
582    /// such that it doesn't make sense to deserialize before passing it in.
583    ///
584    /// Returns the encapsulated secret and the ciphertext, or an error.
585    #[allow(clippy::too_many_arguments)]
586    pub fn seal(
587        &mut self,
588        pk_r: &HpkePublicKey,
589        info: &[u8],
590        aad: &[u8],
591        plain_txt: &[u8],
592        psk: Option<&[u8]>,
593        psk_id: Option<&[u8]>,
594        sk_s: Option<&HpkePrivateKey>,
595    ) -> Result<(EncapsulatedSecret, Ciphertext), HpkeError> {
596        let (enc, mut context) = self.setup_sender(pk_r, info, psk, psk_id, sk_s)?;
597        let ctxt = context.seal(aad, plain_txt)?;
598        Ok((enc, ctxt))
599    }
600
601    /// 6. Single-Shot APIs
602    /// 6.1. Encryption and Decryption
603    ///
604    /// Single shot API to decrypt the bytes in `ct` with the private key `sk_r`.
605    ///
606    /// **Note** that this API expects the public key to be encoded.
607    /// This differs from the RFC.
608    /// But the public keys will be present in encoded form rather than raw form
609    /// such that it doesn't make sense to deserialize before passing it in.
610    ///
611    /// Returns the decrypted plain text, or an error.
612    #[allow(clippy::too_many_arguments)]
613    pub fn open(
614        &self,
615        enc: &[u8],
616        sk_r: &HpkePrivateKey,
617        info: &[u8],
618        aad: &[u8],
619        ct: &[u8],
620        psk: Option<&[u8]>,
621        psk_id: Option<&[u8]>,
622        pk_s: Option<&HpkePublicKey>,
623    ) -> Result<Plaintext, HpkeError> {
624        let mut context = self.setup_receiver(enc, sk_r, info, psk, psk_id, pk_s)?;
625        context.open(aad, ct)
626    }
627
628    /// 6. Single-Shot APIs
629    /// 6.2. Secret Export
630    ///
631    /// Single shot API to derive an exporter secret for receiver with public key
632    /// `pk_r`.
633    ///
634    /// **Note** that this API expects the public key to be encoded.
635    /// This differs from the RFC.
636    /// But the public keys will be present in encoded form rather than raw form
637    /// such that it doesn't make sense to deserialize before passing it in.
638    ///
639    /// Returns the encapsulated secret and the exporter secret for the given
640    /// exporter context and length.
641    #[allow(clippy::too_many_arguments)]
642    pub fn send_export(
643        &mut self,
644        pk_r: &HpkePublicKey,
645        info: &[u8],
646        psk: Option<&[u8]>,
647        psk_id: Option<&[u8]>,
648        sk_s: Option<&HpkePrivateKey>,
649        exporter_context: &[u8],
650        length: usize,
651    ) -> Result<(EncapsulatedSecret, Vec<u8>), HpkeError> {
652        let (enc, context) = self.setup_sender(pk_r, info, psk, psk_id, sk_s)?;
653        Ok((enc, context.export(exporter_context, length)?))
654    }
655
656    /// 6. Single-Shot APIs
657    /// 6.2. Secret Export
658    ///
659    /// Single shot API to derive an exporter secret for receiver with private key
660    /// `sk_r`.
661    ///
662    /// **Note** that this API expects the public key to be encoded.
663    /// This differs from the RFC.
664    /// But the public keys will be present in encoded form rather than raw form
665    /// such that it doesn't make sense to deserialize before passing it in.
666    ///
667    /// Returns the exporter secret for the given exporter context and length.
668    #[allow(clippy::too_many_arguments)]
669    pub fn receiver_export(
670        &self,
671        enc: &[u8],
672        sk_r: &HpkePrivateKey,
673        info: &[u8],
674        psk: Option<&[u8]>,
675        psk_id: Option<&[u8]>,
676        pk_s: Option<&HpkePublicKey>,
677        exporter_context: &[u8],
678        length: usize,
679    ) -> Result<Vec<u8>, HpkeError> {
680        let context = self.setup_receiver(enc, sk_r, info, psk, psk_id, pk_s)?;
681        context.export(exporter_context, length)
682    }
683
684    /// Verify PSKs.
685    #[inline(always)]
686    fn verify_psk_inputs(&self, psk: &[u8], psk_id: &[u8]) -> Result<(), HpkeError> {
687        let got_psk = !psk.is_empty();
688        let got_psk_id = !psk_id.is_empty();
689        if (got_psk && !got_psk_id) || (!got_psk && got_psk_id) {
690            return Err(HpkeError::InconsistentPsk);
691        }
692
693        if got_psk && (self.mode == Mode::Base || self.mode == Mode::Auth) {
694            return Err(HpkeError::UnnecessaryPsk);
695        }
696        if !got_psk && (self.mode == Mode::Psk || self.mode == Mode::AuthPsk) {
697            return Err(HpkeError::MissingPsk);
698        }
699
700        // The PSK MUST have at least 32 bytes of entropy and SHOULD be of length Nh bytes or longer.
701        if (self.mode == Mode::Psk || self.mode == Mode::AuthPsk) && psk.len() < 32 {
702            return Err(HpkeError::InsecurePsk);
703        }
704
705        Ok(())
706    }
707
708    #[inline]
709    fn ciphersuite(&self) -> Vec<u8> {
710        util::concat(&[
711            b"HPKE",
712            &(self.kem_id as u16).to_be_bytes(),
713            &(self.kdf_id as u16).to_be_bytes(),
714            &(self.aead_id as u16).to_be_bytes(),
715        ])
716    }
717
718    #[inline]
719    fn key_schedule_context(
720        &self,
721        info: &[u8],
722        psk_id: &[u8],
723        suite_id: &[u8],
724    ) -> Result<Vec<u8>, HpkeError> {
725        let psk_id_hash =
726            labeled_extract::<Crypto>(self.kdf_id, &[0], suite_id, "psk_id_hash", psk_id)?;
727        let info_hash = labeled_extract::<Crypto>(self.kdf_id, &[0], suite_id, "info_hash", info)?;
728        Ok(util::concat(&[
729            &[self.mode as u8],
730            &psk_id_hash,
731            &info_hash,
732        ]))
733    }
734
735    /// Creating the Encryption Context
736    /// Generate the HPKE context from the given input.
737    pub fn key_schedule(
738        &self,
739        shared_secret: &[u8],
740        info: &[u8],
741        psk: &[u8],
742        psk_id: &[u8],
743    ) -> Result<Context<Crypto>, HpkeError> {
744        self.verify_psk_inputs(psk, psk_id)?;
745        let suite_id = self.ciphersuite();
746        let key_schedule_context = self.key_schedule_context(info, psk_id, &suite_id)?;
747        let secret =
748            labeled_extract::<Crypto>(self.kdf_id, shared_secret, &suite_id, "secret", psk)
749                .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
750
751        let key = labeled_expand::<Crypto>(
752            self.kdf_id,
753            &secret,
754            &suite_id,
755            "key",
756            &key_schedule_context,
757            Crypto::aead_key_length(self.aead_id),
758        )
759        .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
760        let base_nonce = labeled_expand::<Crypto>(
761            self.kdf_id,
762            &secret,
763            &suite_id,
764            "base_nonce",
765            &key_schedule_context,
766            Crypto::aead_nonce_length(self.aead_id),
767        )
768        .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
769        let exporter_secret = labeled_expand::<Crypto>(
770            self.kdf_id,
771            &secret,
772            &suite_id,
773            "exp",
774            &key_schedule_context,
775            Crypto::kdf_digest_length(self.kdf_id),
776        )
777        .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
778
779        Ok(Context {
780            key,
781            nonce: base_nonce,
782            exporter_secret,
783            sequence_number: 0,
784            hpke: self.clone(),
785        })
786    }
787
788    /// 4. Cryptographic Dependencies
789    /// Randomized algorithm to generate a key pair `(skX, pkX)` for the KEM.
790    /// This is equivalent to `derive_key_pair(random_vector(sk.len()))`
791    ///
792    /// Returns an `HpkeKeyPair`.
793    pub fn generate_key_pair(&mut self) -> Result<HpkeKeyPair, HpkeError> {
794        let (sk, pk) = kem::key_gen::<Crypto>(self.kem_id, &mut self.prng)?;
795        Ok(HpkeKeyPair::new(sk, pk))
796    }
797
798    /// 7.1.2. DeriveKeyPair
799    /// Derive a key pair for the used KEM with the given input key material.
800    ///
801    /// Returns an `HpkeKeyPair` result or an `HpkeError` if key derivation fails.
802    pub fn derive_key_pair(&self, ikm: &[u8]) -> Result<HpkeKeyPair, HpkeError> {
803        let (pk, sk) = kem::derive_key_pair::<Crypto>(self.kem_id, ikm)?;
804        Ok(HpkeKeyPair::new(sk, pk))
805    }
806
807    #[inline]
808    pub(crate) fn random(&mut self, len: usize) -> Result<Vec<u8>, HpkeError> {
809        let prng = &mut self.prng;
810        let mut out = vec![0u8; len];
811
812        #[cfg(feature = "hpke-test-prng")]
813        prng.try_fill_test_bytes(&mut out)
814            .map_err(|_| HpkeError::InsufficientRandomness)?;
815        #[cfg(not(feature = "hpke-test-prng"))]
816        prng.try_fill_bytes(&mut out)
817            .map_err(|_| HpkeError::InsufficientRandomness)?;
818
819        Ok(out)
820    }
821
822    /// Get the rng.
823    pub(crate) fn rng(&mut self) -> &mut Crypto::HpkePrng {
824        &mut self.prng
825    }
826}
827
828impl HpkeKeyPair {
829    /// Create a new HPKE key pair.
830    /// Consumes the private and public key bytes.
831    pub fn new(sk: Vec<u8>, pk: Vec<u8>) -> Self {
832        Self {
833            private_key: HpkePrivateKey::new(sk),
834            public_key: HpkePublicKey::new(pk),
835        }
836    }
837
838    /// Get a reference to the HPKE private key of this key pair.
839    pub fn private_key(&self) -> &HpkePrivateKey {
840        &self.private_key
841    }
842
843    /// Get a reference to the HPKE public key of this key pair.
844    pub fn public_key(&self) -> &HpkePublicKey {
845        &self.public_key
846    }
847
848    /// Split the key pair into the two keys
849    pub fn into_keys(self) -> (HpkePrivateKey, HpkePublicKey) {
850        (self.private_key, self.public_key)
851    }
852
853    /// Build a key pair from two keys
854    pub fn from_keys(private_key: HpkePrivateKey, public_key: HpkePublicKey) -> Self {
855        Self {
856            private_key,
857            public_key,
858        }
859    }
860}
861
862impl From<(Vec<u8>, Vec<u8>)> for HpkeKeyPair {
863    fn from((sk, pk): (Vec<u8>, Vec<u8>)) -> Self {
864        Self::new(sk, pk)
865    }
866}
867
868impl From<(&[u8], &[u8])> for HpkeKeyPair {
869    fn from((sk, pk): (&[u8], &[u8])) -> Self {
870        Self::new(sk.to_vec(), pk.to_vec())
871    }
872}
873
874impl HpkePrivateKey {
875    /// Create a new HPKE private key.
876    /// Consumes the private key bytes.
877    pub fn new(b: Vec<u8>) -> Self {
878        Self { value: b }
879    }
880
881    /// Get the raw key as byte slice.
882    #[cfg(feature = "hazmat")]
883    pub fn as_slice(&self) -> &[u8] {
884        &self.value
885    }
886}
887
888impl From<Vec<u8>> for HpkePrivateKey {
889    fn from(b: Vec<u8>) -> Self {
890        Self::new(b)
891    }
892}
893
894impl From<&[u8]> for HpkePrivateKey {
895    fn from(b: &[u8]) -> Self {
896        Self::new(b.to_vec())
897    }
898}
899
900/// Hopefully constant time comparison of the two values as long as they have the
901/// same length.
902impl PartialEq for HpkePrivateKey {
903    fn eq(&self, other: &Self) -> bool {
904        if self.value.len() != other.value.len() {
905            return false;
906        }
907
908        let mut different_bits = 0u8;
909        for (&byte_a, &byte_b) in self.value.iter().zip(other.value.iter()) {
910            different_bits |= byte_a ^ byte_b;
911        }
912        (1u8 & ((different_bits.wrapping_sub(1)).wrapping_shr(8)).wrapping_sub(1)) == 0
913    }
914}
915
916#[cfg(not(feature = "hazmat"))]
917impl core::fmt::Debug for HpkePrivateKey {
918    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
919        f.debug_struct("HpkePrivateKey")
920            .field("value", &"***")
921            .finish()
922    }
923}
924
925#[cfg(feature = "hazmat")]
926impl core::fmt::Debug for HpkePrivateKey {
927    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
928        f.debug_struct("HpkePrivateKey")
929            .field("value", &self.value)
930            .finish()
931    }
932}
933
934impl HpkePublicKey {
935    /// Create a new HPKE public key.
936    /// Consumes the public key bytes.
937    pub fn new(value: Vec<u8>) -> Self {
938        Self { value }
939    }
940
941    /// Get the raw key as byte slice.
942    pub fn as_slice(&self) -> &[u8] {
943        self.value.as_slice()
944    }
945}
946
947impl From<Vec<u8>> for HpkePublicKey {
948    fn from(b: Vec<u8>) -> Self {
949        Self::new(b)
950    }
951}
952
953impl From<&[u8]> for HpkePublicKey {
954    fn from(b: &[u8]) -> Self {
955        Self::new(b.to_vec())
956    }
957}
958
959#[cfg(feature = "serialization")]
960impl tls_codec::Size for HpkePublicKey {
961    #[inline(always)]
962    fn tls_serialized_len(&self) -> usize {
963        tls_codec::VLByteSlice(self.as_slice()).tls_serialized_len()
964    }
965}
966
967#[cfg(feature = "serialization")]
968impl tls_codec::Serialize for HpkePublicKey {
969    #[inline(always)]
970    fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
971        tls_codec::VLByteSlice(self.as_slice()).tls_serialize(writer)
972    }
973}
974
975#[cfg(feature = "serialization")]
976impl tls_codec::Size for &HpkePublicKey {
977    #[inline(always)]
978    fn tls_serialized_len(&self) -> usize {
979        tls_codec::VLByteSlice(self.as_slice()).tls_serialized_len()
980    }
981}
982
983#[cfg(feature = "serialization")]
984impl tls_codec::Serialize for &HpkePublicKey {
985    #[inline(always)]
986    fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
987        tls_codec::VLByteSlice(self.as_slice()).tls_serialize(writer)
988    }
989}
990
991#[cfg(feature = "serialization")]
992impl tls_codec::Deserialize for HpkePublicKey {
993    #[inline(always)]
994    fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, tls_codec::Error> {
995        Ok(Self {
996            value: tls_codec::VLBytes::tls_deserialize(bytes)?.into(),
997        })
998    }
999}
1000
1001#[cfg(feature = "serialization")]
1002impl tls_codec::Deserialize for &HpkePublicKey {
1003    #[inline(always)]
1004    fn tls_deserialize<R: std::io::Read>(_: &mut R) -> Result<Self, tls_codec::Error> {
1005        Err(tls_codec::Error::DecodingError(
1006            "Error trying to deserialize a reference.".to_string(),
1007        ))
1008    }
1009}
1010
1011/// Test util module. Should be moved really.
1012#[cfg(feature = "hpke-test")]
1013pub mod test_util {
1014    use alloc::{format, string::String, vec, vec::Vec};
1015
1016    use crate::HpkeError;
1017    use hpke_rs_crypto::{HpkeCrypto, HpkeTestRng};
1018
1019    impl<Crypto: HpkeCrypto> super::Hpke<Crypto> {
1020        /// Set PRNG state for testing.
1021        pub fn seed(&mut self, seed: &[u8]) -> Result<(), HpkeError> {
1022            self.prng.seed(seed);
1023            Ok(())
1024        }
1025    }
1026
1027    impl<Crypto: HpkeCrypto> super::Context<Crypto> {
1028        /// Get a reference to the key in the context.
1029        #[doc(hidden)]
1030        pub fn key(&self) -> &[u8] {
1031            &self.key
1032        }
1033        /// Get a reference to the nonce in the context.
1034        #[doc(hidden)]
1035        pub fn nonce(&self) -> &[u8] {
1036            &self.nonce
1037        }
1038        /// Get a reference to the exporter secret in the context.
1039        #[doc(hidden)]
1040        pub fn exporter_secret(&self) -> &[u8] {
1041            &self.exporter_secret
1042        }
1043        /// Get a reference to the sequence number in the context.
1044        #[doc(hidden)]
1045        pub fn sequence_number(&self) -> u32 {
1046            self.sequence_number
1047        }
1048    }
1049
1050    /// Convert `bytes` to a hex string.
1051    pub fn bytes_to_hex(bytes: &[u8]) -> String {
1052        let mut hex = String::new();
1053        for &b in bytes {
1054            hex += &format!("{:02X}", b);
1055        }
1056        hex
1057    }
1058
1059    /// Convert a hex string to a byte vector.
1060    pub fn hex_to_bytes(hex: &str) -> Vec<u8> {
1061        assert!(hex.len() % 2 == 0);
1062        let mut bytes = Vec::new();
1063        for i in 0..(hex.len() / 2) {
1064            bytes.push(u8::from_str_radix(&hex[2 * i..2 * i + 2], 16).unwrap());
1065        }
1066        bytes
1067    }
1068
1069    /// Convert a hex string to a byte vector.
1070    /// If the input is `None`, this returns an empty vector.
1071    pub fn hex_to_bytes_option(hex: Option<String>) -> Vec<u8> {
1072        match hex {
1073            Some(s) => hex_to_bytes(&s),
1074            None => vec![],
1075        }
1076    }
1077
1078    /// Convert a byte slice into byte slice option.
1079    /// Returns `Nonce` if the byte slice is empty and `Some(v)` otherwise.
1080    pub fn vec_to_option_slice(v: &[u8]) -> Option<&[u8]> {
1081        if v.is_empty() {
1082            None
1083        } else {
1084            Some(v)
1085        }
1086    }
1087}
1088
1089impl From<hpke_rs_crypto::error::Error> for HpkeError {
1090    fn from(e: hpke_rs_crypto::error::Error) -> Self {
1091        match e {
1092            hpke_rs_crypto::error::Error::AeadOpenError => HpkeError::OpenError,
1093            hpke_rs_crypto::error::Error::AeadInvalidNonce
1094            | hpke_rs_crypto::error::Error::AeadInvalidCiphertext => HpkeError::InvalidInput,
1095            hpke_rs_crypto::error::Error::UnknownAeadAlgorithm => HpkeError::UnknownMode,
1096            hpke_rs_crypto::error::Error::CryptoLibraryError(s) => HpkeError::CryptoError(s),
1097            hpke_rs_crypto::error::Error::HpkeInvalidOutputLength => {
1098                HpkeError::CryptoError("Invalid HPKE output length".to_string())
1099            }
1100            hpke_rs_crypto::error::Error::UnknownKdfAlgorithm => {
1101                HpkeError::CryptoError("Unknown KDF algorithm.".to_string())
1102            }
1103            hpke_rs_crypto::error::Error::KemInvalidSecretKey => {
1104                HpkeError::CryptoError("Invalid KEM secret key".to_string())
1105            }
1106            hpke_rs_crypto::error::Error::KemInvalidPublicKey => {
1107                HpkeError::CryptoError("Invalid KEM public key".to_string())
1108            }
1109            hpke_rs_crypto::error::Error::UnknownKemAlgorithm => {
1110                HpkeError::CryptoError("Unknown KEM algorithm".to_string())
1111            }
1112            hpke_rs_crypto::error::Error::InsufficientRandomness => {
1113                HpkeError::InsufficientRandomness
1114            }
1115            hpke_rs_crypto::error::Error::UnsupportedKemOperation => HpkeError::InvalidConfig,
1116            hpke_rs_crypto::error::Error::KemInvalidCiphertext => HpkeError::InvalidInput,
1117        }
1118    }
1119}