1use core::{array::TryFromSliceError, borrow::Borrow, fmt, marker::PhantomData, result::Result};
4
5use zeroize::ZeroizeOnDrop;
6
7use crate::{
8 csprng::{Csprng, Random},
9 hpke::KemId,
10 import::{Import, ImportError},
11 kdf::{Kdf, KdfError, Prk},
12 keys::{PublicKey, RawSecretBytes, SecretKey},
13 signer::PkError,
14};
15
16#[derive(Debug, Eq, PartialEq)]
18pub enum KemError {
19 InvalidDecapKeyFormat,
21 InvalidEncapKeyFormat,
23 Encap,
25 Decapsulation,
27 DhKem(DhKemError),
29 Import(ImportError),
31 PublicKey(PkError),
33}
34
35impl fmt::Display for KemError {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 Self::InvalidDecapKeyFormat => write!(f, "invalid secret key data"),
39 Self::InvalidEncapKeyFormat => write!(f, "invalid public key data"),
40 Self::Encap => write!(f, "encapsulation failed"),
41 Self::Decapsulation => write!(f, "unable to decapsulate symmetric key"),
42 Self::DhKem(err) => write!(f, "{}", err),
43 Self::Import(err) => write!(f, "{}", err),
44 Self::PublicKey(err) => write!(f, "{}", err),
45 }
46 }
47}
48
49impl core::error::Error for KemError {
50 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
51 match self {
52 Self::DhKem(err) => Some(err),
53 Self::Import(err) => Some(err),
54 _ => None,
55 }
56 }
57}
58
59impl From<DhKemError> for KemError {
60 fn from(err: DhKemError) -> Self {
61 Self::DhKem(err)
62 }
63}
64
65impl From<ImportError> for KemError {
66 fn from(err: ImportError) -> Self {
67 Self::Import(err)
68 }
69}
70
71impl From<PkError> for KemError {
72 fn from(err: PkError) -> Self {
73 Self::PublicKey(err)
74 }
75}
76
77#[allow(non_snake_case)]
85pub trait Kem {
86 type DecapKey: DecapKey<EncapKey = Self::EncapKey>;
88 type EncapKey: EncapKey;
90
91 type Secret: RawSecretBytes + ZeroizeOnDrop;
95
96 type Encap: Borrow<[u8]> + for<'a> Import<&'a [u8]>;
98
99 fn encap<R: Csprng>(
104 rng: R,
105 pkR: &Self::EncapKey,
106 ) -> Result<(Self::Secret, Self::Encap), KemError>;
107
108 fn encap_deterministically(
122 pkR: &Self::EncapKey,
123 skE: Self::DecapKey,
124 ) -> Result<(Self::Secret, Self::Encap), KemError>;
125
126 fn decap(enc: &Self::Encap, skR: &Self::DecapKey) -> Result<Self::Secret, KemError>;
129
130 fn auth_encap<R: Csprng>(
139 rng: R,
140 pkR: &Self::EncapKey,
141 skS: &Self::DecapKey,
142 ) -> Result<(Self::Secret, Self::Encap), KemError>;
143
144 fn auth_encap_deterministically(
163 pkR: &Self::EncapKey,
164 skS: &Self::DecapKey,
165 skE: Self::DecapKey,
166 ) -> Result<(Self::Secret, Self::Encap), KemError>;
167
168 fn auth_decap(
176 enc: &Self::Encap,
177 skR: &Self::DecapKey,
178 pkS: &Self::EncapKey,
179 ) -> Result<Self::Secret, KemError>;
180}
181
182pub trait DecapKey: SecretKey + Random {
184 type EncapKey: EncapKey;
186
187 fn public(&self) -> Result<Self::EncapKey, PkError>;
189}
190
191pub trait EncapKey: PublicKey {}
193
194#[derive(Debug, Eq, PartialEq)]
196pub enum EcdhError {
197 Other(&'static str),
199}
200
201impl fmt::Display for EcdhError {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 match self {
204 Self::Other(msg) => write!(f, "{}", msg),
205 }
206 }
207}
208
209impl core::error::Error for EcdhError {}
210
211pub trait Ecdh {
219 const SCALAR_SIZE: usize;
221
222 type PrivateKey: DecapKey<EncapKey = Self::PublicKey>;
224 type PublicKey: EncapKey;
237
238 type SharedSecret: Borrow<[u8]> + ZeroizeOnDrop;
241
242 fn ecdh(
245 local: &Self::PrivateKey,
246 remote: &Self::PublicKey,
247 ) -> Result<Self::SharedSecret, EcdhError>;
248}
249
250#[derive(ZeroizeOnDrop)]
252pub struct SharedSecret<const N: usize>([u8; N]);
253
254impl<const N: usize> SharedSecret<N> {
255 pub fn as_mut_ptr(&mut self) -> *mut u8 {
257 self.0.as_mut_ptr()
258 }
259
260 #[allow(clippy::len_without_is_empty)]
262 pub const fn len(&self) -> usize {
263 self.0.len()
264 }
265}
266
267impl<const N: usize> Default for SharedSecret<N> {
268 fn default() -> Self {
269 Self([0u8; N])
270 }
271}
272
273impl<const N: usize> Borrow<[u8]> for SharedSecret<N> {
274 fn borrow(&self) -> &[u8] {
275 &self.0
276 }
277}
278
279impl<const N: usize> TryFrom<&[u8]> for SharedSecret<N> {
280 type Error = TryFromSliceError;
281
282 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
283 Ok(Self(data.try_into()?))
284 }
285}
286
287impl<const N: usize> fmt::Debug for SharedSecret<N> {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 f.debug_tuple("SharedSecret").finish_non_exhaustive()
290 }
291}
292
293#[derive(Debug, Eq, PartialEq)]
295pub enum DhKemError {
296 Ecdh(EcdhError),
298 Kdf(KdfError),
300 Import(ImportError),
302}
303
304impl fmt::Display for DhKemError {
305 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306 match self {
307 Self::Ecdh(err) => write!(f, "{}", err),
308 Self::Kdf(err) => write!(f, "{}", err),
309 Self::Import(err) => write!(f, "{}", err),
310 }
311 }
312}
313
314impl core::error::Error for DhKemError {
315 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
316 match self {
317 Self::Ecdh(err) => Some(err),
318 Self::Kdf(err) => Some(err),
319 Self::Import(err) => Some(err),
320 }
321 }
322}
323
324pub struct DhKem<E, F> {
326 id: KemId,
327 _e: PhantomData<E>,
328 _f: PhantomData<F>,
329}
330
331#[allow(non_snake_case)]
332impl<E: Ecdh, F: Kdf> DhKem<E, F> {
333 pub fn new(id: KemId) -> Self {
335 Self {
336 id,
337 _e: PhantomData,
338 _f: PhantomData,
339 }
340 }
341
342 pub fn encap<R: Csprng>(
344 &self,
345 rng: R,
346 pkR: &E::PublicKey,
347 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
348 let skE = E::PrivateKey::random(rng);
349 self.encap_deterministically(pkR, skE)
350 }
351
352 pub fn encap_deterministically(
354 &self,
355 pkR: &E::PublicKey,
356 skE: E::PrivateKey,
357 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
358 let pkE = skE.public()?;
369 let dh = (E::ecdh(&skE, pkR).map_err(DhKemError::Ecdh)?, None);
370 let enc = pkE.export();
371
372 let pkRm = pkR.export();
373
374 let shared_secret =
375 Self::extract_and_expand(&dh, &enc, &pkRm, None, self.id).map_err(DhKemError::Kdf)?;
376 Ok((shared_secret, enc))
377 }
378
379 pub fn decap(
381 &self,
382 enc: &PubKeyData<E>,
383 skR: &E::PrivateKey,
384 ) -> Result<Prk<F::PrkSize>, KemError> {
385 let pkE = E::PublicKey::import(enc.borrow())?;
395 let dh = (E::ecdh(skR, &pkE).map_err(DhKemError::Ecdh)?, None);
396
397 let pkRm = skR.public()?.export();
398
399 let shared_secret =
400 Self::extract_and_expand(&dh, enc, &pkRm, None, self.id).map_err(DhKemError::Kdf)?;
401 Ok(shared_secret)
402 }
403
404 pub fn auth_encap<R: Csprng>(
406 &self,
407 rng: R,
408 pkR: &E::PublicKey,
409 skS: &E::PrivateKey,
410 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
411 let skE = E::PrivateKey::random(rng);
412 self.auth_encap_deterministically(pkR, skS, skE)
413 }
414
415 pub fn auth_encap_deterministically(
417 &self,
418 pkR: &E::PublicKey,
419 skS: &E::PrivateKey,
420 skE: E::PrivateKey,
421 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
422 let pkE = skE.public()?;
434 let dh = (
435 E::ecdh(&skE, pkR).map_err(DhKemError::Ecdh)?,
436 Some(E::ecdh(skS, pkR).map_err(DhKemError::Ecdh)?),
437 );
438 let enc = pkE.export();
439
440 let pkRm = pkR.export();
441 let pkSm = skS.public()?.export();
442
443 let shared_secret = Self::extract_and_expand(&dh, &enc, &pkRm, Some(&pkSm), self.id)
444 .map_err(DhKemError::Kdf)?;
445 Ok((shared_secret, enc))
446 }
447
448 pub fn auth_decap(
450 &self,
451 enc: &PubKeyData<E>,
452 skR: &E::PrivateKey,
453 pkS: &E::PublicKey,
454 ) -> Result<Prk<F::PrkSize>, KemError> {
455 let pkE = E::PublicKey::import(enc.borrow())?;
466 let dh = (
467 E::ecdh(skR, &pkE).map_err(DhKemError::Ecdh)?,
468 Some(E::ecdh(skR, pkS).map_err(DhKemError::Ecdh)?),
469 );
470
471 let pkRm = skR.public()?.export();
472 let pkSm = pkS.export();
473
474 let shared_secret = Self::extract_and_expand(&dh, enc, &pkRm, Some(&pkSm), self.id)
475 .map_err(DhKemError::Kdf)?;
476 Ok(shared_secret)
477 }
478
479 fn extract_and_expand(
481 dh: &(E::SharedSecret, Option<E::SharedSecret>),
482 enc: &PubKeyData<E>,
483 pkRm: &PubKeyData<E>,
484 pkSm: Option<&PubKeyData<E>>,
485 id: KemId,
486 ) -> Result<Prk<F::PrkSize>, KdfError> {
487 let mut out = Prk::<F::PrkSize>::default();
498
499 let labeled_ikm: &[&[u8]] = &[
507 b"HPKE-v1",
508 b"KEM",
510 &id.to_be_bytes(),
511 b"eae_prk",
513 dh.0.borrow(),
515 dh.1.as_ref().map_or(&[], |v| v.borrow()),
516 ];
517
518 let labeled_info: &[&[u8]] = &[
521 &(F::PRK_SIZE as u16).to_be_bytes()[..],
522 b"HPKE-v1",
523 b"KEM",
525 &id.to_be_bytes(),
526 b"shared_secret",
528 enc.borrow(),
530 pkRm.borrow(),
531 pkSm.map_or(&[], |v| v.borrow()),
532 ];
533
534 F::extract_and_expand_multi(
535 out.as_bytes_mut(),
536 labeled_ikm.iter().copied(),
537 &[],
538 labeled_info.iter().copied(),
539 )?;
540 Ok(out)
541 }
542}
543
544impl<E, F> fmt::Debug for DhKem<E, F> {
545 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546 f.debug_struct("DhKem").field("id", &self.id).finish()
547 }
548}
549
550type PubKeyData<T> = <<T as Ecdh>::PublicKey as PublicKey>::Data;
551
552#[macro_export]
575macro_rules! dhkem_impl {
576 (
577 $name:ident,
578 $doc:expr,
579 $kem_id:expr,
580 $ecdh:ty,
581 $kdf:ty,
582 $sk:ident,
583 $pk:ident
584 $(, oid = $oid:ident)?
585 $(,)?
586 ) => {
587 #[doc = concat!($doc, ".")]
588 #[derive(Debug)]
589 pub struct $name;
590
591 impl $name {
592 const KEM_ID: $crate::hpke::KemId = $kem_id;
593 }
594
595 #[allow(non_snake_case)]
596 impl $crate::kem::Kem for $name {
597 type DecapKey = $sk;
598 type EncapKey = $pk;
599 type Secret = $crate::kdf::Prk<<$kdf as $crate::kdf::Kdf>::PrkSize>;
600 type Encap = <$pk as $crate::keys::PublicKey>::Data;
601
602 fn encap<R: $crate::csprng::Csprng>(
603 rng: R,
604 pkR: &Self::EncapKey,
605 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
606 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).encap(rng, pkR)
607 }
608
609 fn encap_deterministically(
610 pkR: &Self::EncapKey,
611 skE: Self::DecapKey,
612 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
613 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID)
614 .encap_deterministically(pkR, skE)
615 }
616
617 fn decap(
618 enc: &Self::Encap,
619 skR: &Self::DecapKey,
620 ) -> ::core::result::Result<Self::Secret, $crate::kem::KemError> {
621 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).decap(enc, skR)
622 }
623
624 fn auth_encap<R: $crate::csprng::Csprng>(
625 rng: R,
626 pkR: &Self::EncapKey,
627 skS: &Self::DecapKey,
628 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
629 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).auth_encap(rng, pkR, skS)
630 }
631
632 fn auth_encap_deterministically(
633 pkR: &Self::EncapKey,
634 skS: &Self::DecapKey,
635 skE: Self::DecapKey,
636 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
637 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID)
638 .auth_encap_deterministically(pkR, skS, skE)
639 }
640
641 fn auth_decap(
642 enc: &Self::Encap,
643 skR: &Self::DecapKey,
644 pkS: &Self::EncapKey,
645 ) -> ::core::result::Result<Self::Secret, $crate::kem::KemError> {
646 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).auth_decap(enc, skR, pkS)
647 }
648 }
649
650 impl $crate::hpke::HpkeKem for $name {
651 const ID: $crate::hpke::KemId = Self::KEM_ID;
652 }
653
654 $(impl $crate::oid::Identified for $name {
655 const OID: &'static $crate::oid::Oid = $oid;
656 })?
657 };
658}
659pub(crate) use dhkem_impl;