1use core::{array::TryFromSliceError, borrow::Borrow, fmt, marker::PhantomData, result::Result};
4
5use crate::{
6 csprng::{Csprng, Random},
7 hpke::KemId,
8 import::{Import, ImportError},
9 kdf::{Kdf, KdfError, Prk},
10 keys::{PublicKey, RawSecretBytes, SecretKey},
11 signer::PkError,
12 zeroize::{zeroize_flat_type, ZeroizeOnDrop},
13};
14
15#[derive(Debug, Eq, PartialEq)]
17pub enum KemError {
18 InvalidDecapKeyFormat,
20 InvalidEncapKeyFormat,
22 Encap,
24 Decapsulation,
26 DhKem(DhKemError),
28 Import(ImportError),
30 PublicKey(PkError),
32}
33
34impl fmt::Display for KemError {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 Self::InvalidDecapKeyFormat => write!(f, "invalid secret key data"),
38 Self::InvalidEncapKeyFormat => write!(f, "invalid public key data"),
39 Self::Encap => write!(f, "encapsulation failed"),
40 Self::Decapsulation => write!(f, "unable to decapsulate symmetric key"),
41 Self::DhKem(err) => write!(f, "{}", err),
42 Self::Import(err) => write!(f, "{}", err),
43 Self::PublicKey(err) => write!(f, "{}", err),
44 }
45 }
46}
47
48impl core::error::Error for KemError {
49 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
50 match self {
51 Self::DhKem(err) => Some(err),
52 Self::Import(err) => Some(err),
53 _ => None,
54 }
55 }
56}
57
58impl From<DhKemError> for KemError {
59 fn from(err: DhKemError) -> Self {
60 Self::DhKem(err)
61 }
62}
63
64impl From<ImportError> for KemError {
65 fn from(err: ImportError) -> Self {
66 Self::Import(err)
67 }
68}
69
70impl From<PkError> for KemError {
71 fn from(err: PkError) -> Self {
72 Self::PublicKey(err)
73 }
74}
75
76#[allow(non_snake_case)]
84pub trait Kem {
85 type DecapKey: DecapKey<EncapKey = Self::EncapKey>;
87 type EncapKey: EncapKey;
89
90 type Secret: RawSecretBytes + ZeroizeOnDrop;
94
95 type Encap: Borrow<[u8]> + for<'a> Import<&'a [u8]>;
97
98 fn encap<R: Csprng>(
103 rng: &mut R,
104 pkR: &Self::EncapKey,
105 ) -> Result<(Self::Secret, Self::Encap), KemError>;
106
107 fn encap_deterministically(
121 pkR: &Self::EncapKey,
122 skE: Self::DecapKey,
123 ) -> Result<(Self::Secret, Self::Encap), KemError>;
124
125 fn decap(enc: &Self::Encap, skR: &Self::DecapKey) -> Result<Self::Secret, KemError>;
128
129 fn auth_encap<R: Csprng>(
138 rng: &mut R,
139 pkR: &Self::EncapKey,
140 skS: &Self::DecapKey,
141 ) -> Result<(Self::Secret, Self::Encap), KemError>;
142
143 fn auth_encap_deterministically(
162 pkR: &Self::EncapKey,
163 skS: &Self::DecapKey,
164 skE: Self::DecapKey,
165 ) -> Result<(Self::Secret, Self::Encap), KemError>;
166
167 fn auth_decap(
175 enc: &Self::Encap,
176 skR: &Self::DecapKey,
177 pkS: &Self::EncapKey,
178 ) -> Result<Self::Secret, KemError>;
179}
180
181pub trait DecapKey: SecretKey + Random {
183 type EncapKey: EncapKey;
185
186 fn public(&self) -> Result<Self::EncapKey, PkError>;
188}
189
190pub trait EncapKey: PublicKey {}
192
193#[derive(Debug, Eq, PartialEq)]
195pub enum EcdhError {
196 Other(&'static str),
198}
199
200impl fmt::Display for EcdhError {
201 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202 match self {
203 Self::Other(msg) => write!(f, "{}", msg),
204 }
205 }
206}
207
208impl core::error::Error for EcdhError {}
209
210pub trait Ecdh {
218 const SCALAR_SIZE: usize;
220
221 type PrivateKey: DecapKey<EncapKey = Self::PublicKey>;
223 type PublicKey: EncapKey;
236
237 type SharedSecret: Borrow<[u8]> + ZeroizeOnDrop;
240
241 fn ecdh(
244 local: &Self::PrivateKey,
245 remote: &Self::PublicKey,
246 ) -> Result<Self::SharedSecret, EcdhError>;
247}
248
249pub struct SharedSecret<const N: usize>([u8; N]);
251
252impl<const N: usize> SharedSecret<N> {
253 pub fn as_mut_ptr(&mut self) -> *mut u8 {
255 self.0.as_mut_ptr()
256 }
257
258 #[allow(clippy::len_without_is_empty)]
260 pub const fn len(&self) -> usize {
261 self.0.len()
262 }
263}
264
265impl<const N: usize> Default for SharedSecret<N> {
266 fn default() -> Self {
267 Self([0u8; N])
268 }
269}
270
271impl<const N: usize> Borrow<[u8]> for SharedSecret<N> {
272 fn borrow(&self) -> &[u8] {
273 &self.0
274 }
275}
276
277impl<const N: usize> TryFrom<&[u8]> for SharedSecret<N> {
278 type Error = TryFromSliceError;
279
280 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
281 Ok(Self(data.try_into()?))
282 }
283}
284
285impl<const N: usize> fmt::Debug for SharedSecret<N> {
286 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287 f.debug_tuple("SharedSecret").finish_non_exhaustive()
288 }
289}
290
291impl<const N: usize> ZeroizeOnDrop for SharedSecret<N> {}
292impl<const N: usize> Drop for SharedSecret<N> {
293 fn drop(&mut self) {
294 unsafe { zeroize_flat_type(&mut self.0) }
301 }
302}
303
304#[derive(Debug, Eq, PartialEq)]
306pub enum DhKemError {
307 Ecdh(EcdhError),
309 Kdf(KdfError),
311 Import(ImportError),
313}
314
315impl fmt::Display for DhKemError {
316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
317 match self {
318 Self::Ecdh(err) => write!(f, "{}", err),
319 Self::Kdf(err) => write!(f, "{}", err),
320 Self::Import(err) => write!(f, "{}", err),
321 }
322 }
323}
324
325impl core::error::Error for DhKemError {
326 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
327 match self {
328 Self::Ecdh(err) => Some(err),
329 Self::Kdf(err) => Some(err),
330 Self::Import(err) => Some(err),
331 }
332 }
333}
334
335pub struct DhKem<E, F> {
337 id: KemId,
338 _e: PhantomData<E>,
339 _f: PhantomData<F>,
340}
341
342#[allow(non_snake_case)]
343impl<E: Ecdh, F: Kdf> DhKem<E, F> {
344 pub fn new(id: KemId) -> Self {
346 Self {
347 id,
348 _e: PhantomData,
349 _f: PhantomData,
350 }
351 }
352
353 pub fn encap<R: Csprng>(
355 &self,
356 rng: &mut R,
357 pkR: &E::PublicKey,
358 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
359 let skE = E::PrivateKey::random(rng);
360 self.encap_deterministically(pkR, skE)
361 }
362
363 pub fn encap_deterministically(
365 &self,
366 pkR: &E::PublicKey,
367 skE: E::PrivateKey,
368 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
369 let pkE = skE.public()?;
380 let dh = (E::ecdh(&skE, pkR).map_err(DhKemError::Ecdh)?, None);
381 let enc = pkE.export();
382
383 let pkRm = pkR.export();
384
385 let shared_secret =
386 Self::extract_and_expand(&dh, &enc, &pkRm, None, self.id).map_err(DhKemError::Kdf)?;
387 Ok((shared_secret, enc))
388 }
389
390 pub fn decap(
392 &self,
393 enc: &PubKeyData<E>,
394 skR: &E::PrivateKey,
395 ) -> Result<Prk<F::PrkSize>, KemError> {
396 let pkE = E::PublicKey::import(enc.borrow())?;
406 let dh = (E::ecdh(skR, &pkE).map_err(DhKemError::Ecdh)?, None);
407
408 let pkRm = skR.public()?.export();
409
410 let shared_secret =
411 Self::extract_and_expand(&dh, enc, &pkRm, None, self.id).map_err(DhKemError::Kdf)?;
412 Ok(shared_secret)
413 }
414
415 pub fn auth_encap<R: Csprng>(
417 &self,
418 rng: &mut R,
419 pkR: &E::PublicKey,
420 skS: &E::PrivateKey,
421 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
422 let skE = E::PrivateKey::random(rng);
423 self.auth_encap_deterministically(pkR, skS, skE)
424 }
425
426 pub fn auth_encap_deterministically(
428 &self,
429 pkR: &E::PublicKey,
430 skS: &E::PrivateKey,
431 skE: E::PrivateKey,
432 ) -> Result<(Prk<F::PrkSize>, PubKeyData<E>), KemError> {
433 let pkE = skE.public()?;
445 let dh = (
446 E::ecdh(&skE, pkR).map_err(DhKemError::Ecdh)?,
447 Some(E::ecdh(skS, pkR).map_err(DhKemError::Ecdh)?),
448 );
449 let enc = pkE.export();
450
451 let pkRm = pkR.export();
452 let pkSm = skS.public()?.export();
453
454 let shared_secret = Self::extract_and_expand(&dh, &enc, &pkRm, Some(&pkSm), self.id)
455 .map_err(DhKemError::Kdf)?;
456 Ok((shared_secret, enc))
457 }
458
459 pub fn auth_decap(
461 &self,
462 enc: &PubKeyData<E>,
463 skR: &E::PrivateKey,
464 pkS: &E::PublicKey,
465 ) -> Result<Prk<F::PrkSize>, KemError> {
466 let pkE = E::PublicKey::import(enc.borrow())?;
477 let dh = (
478 E::ecdh(skR, &pkE).map_err(DhKemError::Ecdh)?,
479 Some(E::ecdh(skR, pkS).map_err(DhKemError::Ecdh)?),
480 );
481
482 let pkRm = skR.public()?.export();
483 let pkSm = pkS.export();
484
485 let shared_secret = Self::extract_and_expand(&dh, enc, &pkRm, Some(&pkSm), self.id)
486 .map_err(DhKemError::Kdf)?;
487 Ok(shared_secret)
488 }
489
490 fn extract_and_expand(
492 dh: &(E::SharedSecret, Option<E::SharedSecret>),
493 enc: &PubKeyData<E>,
494 pkRm: &PubKeyData<E>,
495 pkSm: Option<&PubKeyData<E>>,
496 id: KemId,
497 ) -> Result<Prk<F::PrkSize>, KdfError> {
498 let mut out = Prk::<F::PrkSize>::default();
509
510 let labeled_ikm: &[&[u8]] = &[
518 b"HPKE-v1",
519 b"KEM",
521 &id.to_be_bytes(),
522 b"eae_prk",
524 dh.0.borrow(),
526 dh.1.as_ref().map_or(&[], |v| v.borrow()),
527 ];
528
529 let labeled_info: &[&[u8]] = &[
532 &(F::PRK_SIZE as u16).to_be_bytes()[..],
533 b"HPKE-v1",
534 b"KEM",
536 &id.to_be_bytes(),
537 b"shared_secret",
539 enc.borrow(),
541 pkRm.borrow(),
542 pkSm.map_or(&[], |v| v.borrow()),
543 ];
544
545 F::extract_and_expand_multi(
546 out.as_bytes_mut(),
547 labeled_ikm.iter().copied(),
548 &[],
549 labeled_info.iter().copied(),
550 )?;
551 Ok(out)
552 }
553}
554
555impl<E, F> fmt::Debug for DhKem<E, F> {
556 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
557 f.debug_struct("DhKem").field("id", &self.id).finish()
558 }
559}
560
561type PubKeyData<T> = <<T as Ecdh>::PublicKey as PublicKey>::Data;
562
563#[macro_export]
586macro_rules! dhkem_impl {
587 (
588 $name:ident,
589 $doc:expr,
590 $kem_id:expr,
591 $ecdh:ty,
592 $kdf:ty,
593 $sk:ident,
594 $pk:ident
595 $(, oid = $oid:ident)?
596 $(,)?
597 ) => {
598 #[doc = concat!($doc, ".")]
599 #[derive(Debug)]
600 pub struct $name;
601
602 impl $name {
603 const KEM_ID: $crate::hpke::KemId = $kem_id;
604 }
605
606 #[allow(non_snake_case)]
607 impl $crate::kem::Kem for $name {
608 type DecapKey = $sk;
609 type EncapKey = $pk;
610 type Secret = $crate::kdf::Prk<<$kdf as $crate::kdf::Kdf>::PrkSize>;
611 type Encap = <$pk as $crate::keys::PublicKey>::Data;
612
613 fn encap<R: $crate::csprng::Csprng>(
614 rng: &mut R,
615 pkR: &Self::EncapKey,
616 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
617 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).encap(rng, pkR)
618 }
619
620 fn encap_deterministically(
621 pkR: &Self::EncapKey,
622 skE: Self::DecapKey,
623 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
624 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID)
625 .encap_deterministically(pkR, skE)
626 }
627
628 fn decap(
629 enc: &Self::Encap,
630 skR: &Self::DecapKey,
631 ) -> ::core::result::Result<Self::Secret, $crate::kem::KemError> {
632 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).decap(enc, skR)
633 }
634
635 fn auth_encap<R: $crate::csprng::Csprng>(
636 rng: &mut R,
637 pkR: &Self::EncapKey,
638 skS: &Self::DecapKey,
639 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
640 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).auth_encap(rng, pkR, skS)
641 }
642
643 fn auth_encap_deterministically(
644 pkR: &Self::EncapKey,
645 skS: &Self::DecapKey,
646 skE: Self::DecapKey,
647 ) -> ::core::result::Result<(Self::Secret, Self::Encap), $crate::kem::KemError> {
648 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID)
649 .auth_encap_deterministically(pkR, skS, skE)
650 }
651
652 fn auth_decap(
653 enc: &Self::Encap,
654 skR: &Self::DecapKey,
655 pkS: &Self::EncapKey,
656 ) -> ::core::result::Result<Self::Secret, $crate::kem::KemError> {
657 $crate::kem::DhKem::<$ecdh, $kdf>::new(Self::KEM_ID).auth_decap(enc, skR, pkS)
658 }
659 }
660
661 impl $crate::hpke::HpkeKem for $name {
662 const ID: $crate::hpke::KemId = Self::KEM_ID;
663 }
664
665 $(impl $crate::oid::Identified for $name {
666 const OID: &'static $crate::oid::Oid = $oid;
667 })?
668 };
669}
670pub(crate) use dhkem_impl;