1#![doc = include_str!("../Readme.md")]
2#![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
120pub use hpke_rs_crypto::types as hpke_types;
122
123#[cfg(feature = "rustcrypto")]
125pub use hpke_rs_rust_crypto as rustcrypto;
126
127#[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, ZeroizeOnDrop};
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#[derive(Debug, Clone, PartialEq)]
160pub enum HpkeError {
161 OpenError,
163
164 InvalidConfig,
166
167 InvalidInput,
169
170 UnknownMode,
172
173 InconsistentPsk,
175
176 MissingPsk,
178
179 UnnecessaryPsk,
181
182 InsecurePsk,
184
185 CryptoError(String),
187
188 MessageLimitReached,
190
191 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#[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#[derive(Default, Zeroize)]
229#[zeroize(drop)] #[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#[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#[derive(PartialEq, Copy, Clone, Debug, Zeroize)]
255#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
256#[repr(u8)]
257pub enum Mode {
258 Base = 0x00,
260
261 Psk = 0x01,
263
264 Auth = 0x02,
266
267 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
290type EncapsulatedSecret = Vec<u8>;
293
294type Ciphertext = Vec<u8>;
297
298type Plaintext = Vec<u8>;
301
302#[derive(Zeroize, ZeroizeOnDrop)]
306pub struct Context<Crypto: 'static + HpkeCrypto> {
307 key: Vec<u8>,
308 nonce: Vec<u8>,
309 exporter_secret: Vec<u8>,
310 sequence_number: u64,
311 hpke: Hpke<Crypto>,
312}
313
314#[cfg(feature = "hazmat")]
315impl<Crypto: HpkeCrypto> core::fmt::Debug for Context<Crypto> {
316 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
317 write!(
318 f,
319 "Context {{\n key: {:?}\n nonce: {:?}\n exporter_secret: {:?}\n seq no: {:?}\n}}",
320 self.key, self.nonce, self.exporter_secret, self.sequence_number
321 )
322 }
323}
324
325#[cfg(not(feature = "hazmat"))]
326impl<Crypto: HpkeCrypto> core::fmt::Debug for Context<Crypto> {
327 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
328 write!(
329 f,
330 "Context {{\n key: {:?}\n nonce: {:?}\n exporter_secret: {:?}\n seq no: {:?}\n}}",
331 &"***", &"***", &"***", &"***"
332 )
333 }
334}
335
336impl<Crypto: HpkeCrypto> Context<Crypto> {
337 pub fn seal(&mut self, aad: &[u8], plain_txt: &[u8]) -> Result<Ciphertext, HpkeError> {
353 if self.hpke.aead_id == AeadAlgorithm::HpkeExport {
354 return Err(HpkeError::InvalidConfig);
355 }
356
357 let ctxt = Crypto::aead_seal(
358 self.hpke.aead_id,
359 &self.key,
360 &self.compute_nonce(),
361 aad,
362 plain_txt,
363 )?;
364 self.increment_seq()?;
365 Ok(ctxt)
366 }
367
368 pub fn open(&mut self, aad: &[u8], cipher_txt: &[u8]) -> Result<Plaintext, HpkeError> {
386 if self.hpke.aead_id == AeadAlgorithm::HpkeExport {
387 return Err(HpkeError::InvalidConfig);
388 }
389
390 let ptxt = Crypto::aead_open(
391 self.hpke.aead_id,
392 &self.key,
393 &self.compute_nonce(),
394 aad,
395 cipher_txt,
396 )?;
397 self.increment_seq()?;
398 Ok(ptxt)
399 }
400
401 pub fn export(&self, exporter_context: &[u8], length: usize) -> Result<Vec<u8>, HpkeError> {
411 labeled_expand::<Crypto>(
412 self.hpke.kdf_id,
413 &self.exporter_secret,
414 &self.hpke.ciphersuite(),
415 "sec",
416 exporter_context,
417 length,
418 )
419 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))
420 }
421
422 fn compute_nonce(&self) -> Vec<u8> {
426 let seq = self.sequence_number.to_be_bytes();
427 let mut enc_seq = vec![0u8; self.nonce.len() - seq.len()];
428 enc_seq.extend_from_slice(&seq);
429 util::xor_bytes(&enc_seq, &self.nonce)
430 }
431
432 fn increment_seq(&mut self) -> Result<(), HpkeError> {
437 if u128::from(self.sequence_number)
438 >= ((1u128 << (8 * Crypto::aead_nonce_length(self.hpke.aead_id))) - 1)
439 {
440 return Err(HpkeError::MessageLimitReached);
443 }
444 self.sequence_number = self
445 .sequence_number
446 .checked_add(1)
448 .ok_or(HpkeError::MessageLimitReached)?;
449 Ok(())
450 }
451}
452
453#[derive(Debug, Zeroize)]
461pub struct Hpke<Crypto: 'static + HpkeCrypto> {
462 mode: Mode,
463 kem_id: KemAlgorithm,
464 kdf_id: KdfAlgorithm,
465 aead_id: AeadAlgorithm,
466 prng: Crypto::HpkePrng,
467}
468
469impl<Crypto: 'static + HpkeCrypto> Clone for Hpke<Crypto> {
470 fn clone(&self) -> Self {
471 Self {
472 mode: self.mode,
473 kem_id: self.kem_id,
474 kdf_id: self.kdf_id,
475 aead_id: self.aead_id,
476 prng: Crypto::prng(),
477 }
478 }
479}
480
481impl<Crypto: HpkeCrypto> core::fmt::Display for Hpke<Crypto> {
482 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
483 write!(
484 f,
485 "{}_{}_{}_{}",
486 self.mode.to_string().to_lowercase(),
487 self.kem_id.to_string().to_lowercase(),
488 self.kdf_id.to_string().to_lowercase(),
489 self.aead_id.to_string().to_lowercase()
490 )
491 }
492}
493
494impl<Crypto: HpkeCrypto> Hpke<Crypto> {
495 pub fn new(
497 mode: Mode,
498 kem_id: KemAlgorithm,
499 kdf_id: KdfAlgorithm,
500 aead_id: AeadAlgorithm,
501 ) -> Self {
502 Self {
503 mode,
504 kem_id,
505 kdf_id,
506 aead_id,
507 prng: Crypto::prng(),
508 }
509 }
510
511 pub fn setup_sender(
526 &mut self,
527 pk_r: &HpkePublicKey,
528 info: &[u8],
529 psk: Option<&[u8]>,
530 psk_id: Option<&[u8]>,
531 sk_s: Option<&HpkePrivateKey>,
532 ) -> Result<(EncapsulatedSecret, Context<Crypto>), HpkeError> {
533 let (zz, enc) = match self.mode {
534 Mode::Base | Mode::Psk => kem::encaps::<Crypto>(self, pk_r.value.as_slice())?,
535 Mode::Auth | Mode::AuthPsk => {
536 let sk_s = match sk_s {
537 Some(s) => &s.value,
538 None => return Err(HpkeError::InvalidInput),
539 };
540 kem::auth_encaps::<Crypto>(self, pk_r.value.as_slice(), sk_s)?
541 }
542 };
543 Ok((
544 enc,
545 self.clone().key_schedule(
546 &zz,
547 info,
548 psk.unwrap_or_default(),
549 psk_id.unwrap_or_default(),
550 )?,
551 ))
552 }
553
554 pub fn setup_receiver(
570 &self,
571 enc: &[u8],
572 sk_r: &HpkePrivateKey,
573 info: &[u8],
574 psk: Option<&[u8]>,
575 psk_id: Option<&[u8]>,
576 pk_s: Option<&HpkePublicKey>,
577 ) -> Result<Context<Crypto>, HpkeError> {
578 let zz = match self.mode {
579 Mode::Base | Mode::Psk => kem::decaps::<Crypto>(self.kem_id, enc, &sk_r.value)?,
580 Mode::Auth | Mode::AuthPsk => {
581 let pk_s = match pk_s {
582 Some(s) => s.value.as_slice(),
583 None => return Err(HpkeError::InvalidInput),
584 };
585 kem::auth_decaps::<Crypto>(self.kem_id, enc, &sk_r.value, pk_s)?
586 }
587 };
588 self.clone().key_schedule(
589 &zz,
590 info,
591 psk.unwrap_or_default(),
592 psk_id.unwrap_or_default(),
593 )
594 }
595
596 #[allow(clippy::too_many_arguments)]
610 pub fn seal(
611 &mut self,
612 pk_r: &HpkePublicKey,
613 info: &[u8],
614 aad: &[u8],
615 plain_txt: &[u8],
616 psk: Option<&[u8]>,
617 psk_id: Option<&[u8]>,
618 sk_s: Option<&HpkePrivateKey>,
619 ) -> Result<(EncapsulatedSecret, Ciphertext), HpkeError> {
620 let (enc, mut context) = self.setup_sender(pk_r, info, psk, psk_id, sk_s)?;
621 let ctxt = context.seal(aad, plain_txt)?;
622 Ok((enc, ctxt))
623 }
624
625 #[allow(clippy::too_many_arguments)]
638 pub fn open(
639 &self,
640 enc: &[u8],
641 sk_r: &HpkePrivateKey,
642 info: &[u8],
643 aad: &[u8],
644 ct: &[u8],
645 psk: Option<&[u8]>,
646 psk_id: Option<&[u8]>,
647 pk_s: Option<&HpkePublicKey>,
648 ) -> Result<Plaintext, HpkeError> {
649 let mut context = self.setup_receiver(enc, sk_r, info, psk, psk_id, pk_s)?;
650 context.open(aad, ct)
651 }
652
653 #[allow(clippy::too_many_arguments)]
668 pub fn send_export(
669 &mut self,
670 pk_r: &HpkePublicKey,
671 info: &[u8],
672 psk: Option<&[u8]>,
673 psk_id: Option<&[u8]>,
674 sk_s: Option<&HpkePrivateKey>,
675 exporter_context: &[u8],
676 length: usize,
677 ) -> Result<(EncapsulatedSecret, Vec<u8>), HpkeError> {
678 let (enc, context) = self.setup_sender(pk_r, info, psk, psk_id, sk_s)?;
679 Ok((enc, context.export(exporter_context, length)?))
680 }
681
682 #[allow(clippy::too_many_arguments)]
696 pub fn receiver_export(
697 &self,
698 enc: &[u8],
699 sk_r: &HpkePrivateKey,
700 info: &[u8],
701 psk: Option<&[u8]>,
702 psk_id: Option<&[u8]>,
703 pk_s: Option<&HpkePublicKey>,
704 exporter_context: &[u8],
705 length: usize,
706 ) -> Result<Vec<u8>, HpkeError> {
707 let context = self.setup_receiver(enc, sk_r, info, psk, psk_id, pk_s)?;
708 context.export(exporter_context, length)
709 }
710
711 #[inline(always)]
713 fn verify_psk_inputs(&self, psk: &[u8], psk_id: &[u8]) -> Result<(), HpkeError> {
714 let got_psk = !psk.is_empty();
715 let got_psk_id = !psk_id.is_empty();
716 if (got_psk && !got_psk_id) || (!got_psk && got_psk_id) {
717 return Err(HpkeError::InconsistentPsk);
718 }
719
720 if got_psk && (self.mode == Mode::Base || self.mode == Mode::Auth) {
721 return Err(HpkeError::UnnecessaryPsk);
722 }
723 if !got_psk && (self.mode == Mode::Psk || self.mode == Mode::AuthPsk) {
724 return Err(HpkeError::MissingPsk);
725 }
726
727 if (self.mode == Mode::Psk || self.mode == Mode::AuthPsk) && psk.len() < 32 {
729 return Err(HpkeError::InsecurePsk);
730 }
731
732 Ok(())
733 }
734
735 #[inline]
736 fn ciphersuite(&self) -> Vec<u8> {
737 util::concat(&[
738 b"HPKE",
739 &(self.kem_id as u16).to_be_bytes(),
740 &(self.kdf_id as u16).to_be_bytes(),
741 &(self.aead_id as u16).to_be_bytes(),
742 ])
743 }
744
745 #[inline]
746 fn key_schedule_context(
747 &self,
748 info: &[u8],
749 psk_id: &[u8],
750 suite_id: &[u8],
751 ) -> Result<Vec<u8>, HpkeError> {
752 let psk_id_hash =
753 labeled_extract::<Crypto>(self.kdf_id, &[0], suite_id, "psk_id_hash", psk_id)?;
754 let info_hash = labeled_extract::<Crypto>(self.kdf_id, &[0], suite_id, "info_hash", info)?;
755 Ok(util::concat(&[
756 &[self.mode as u8],
757 &psk_id_hash,
758 &info_hash,
759 ]))
760 }
761
762 pub fn key_schedule(
765 &self,
766 shared_secret: &[u8],
767 info: &[u8],
768 psk: &[u8],
769 psk_id: &[u8],
770 ) -> Result<Context<Crypto>, HpkeError> {
771 self.verify_psk_inputs(psk, psk_id)?;
772 let suite_id = self.ciphersuite();
773 let key_schedule_context = self.key_schedule_context(info, psk_id, &suite_id)?;
774 let secret =
775 labeled_extract::<Crypto>(self.kdf_id, shared_secret, &suite_id, "secret", psk)
776 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
777
778 let key = labeled_expand::<Crypto>(
779 self.kdf_id,
780 &secret,
781 &suite_id,
782 "key",
783 &key_schedule_context,
784 Crypto::aead_key_length(self.aead_id),
785 )
786 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
787 let base_nonce = labeled_expand::<Crypto>(
788 self.kdf_id,
789 &secret,
790 &suite_id,
791 "base_nonce",
792 &key_schedule_context,
793 Crypto::aead_nonce_length(self.aead_id),
794 )
795 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
796 let exporter_secret = labeled_expand::<Crypto>(
797 self.kdf_id,
798 &secret,
799 &suite_id,
800 "exp",
801 &key_schedule_context,
802 Crypto::kdf_digest_length(self.kdf_id),
803 )
804 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
805
806 Ok(Context {
807 key,
808 nonce: base_nonce,
809 exporter_secret,
810 sequence_number: 0,
811 hpke: self.clone(),
812 })
813 }
814
815 pub fn generate_key_pair(&mut self) -> Result<HpkeKeyPair, HpkeError> {
822 let (sk, pk) = kem::key_gen::<Crypto>(self.kem_id, &mut self.prng)?;
823 Ok(HpkeKeyPair::new(sk.0.clone(), pk))
824 }
825
826 pub fn derive_key_pair(&self, ikm: &[u8]) -> Result<HpkeKeyPair, HpkeError> {
831 let (pk, sk) = kem::derive_key_pair::<Crypto>(self.kem_id, ikm)?;
832 Ok(HpkeKeyPair::new(sk.0.clone(), pk))
833 }
834
835 #[inline]
836 pub(crate) fn random(&mut self, len: usize) -> Result<Vec<u8>, HpkeError> {
837 let prng = &mut self.prng;
838 let mut out = vec![0u8; len];
839
840 #[cfg(feature = "hpke-test-prng")]
841 prng.try_fill_test_bytes(&mut out)
842 .map_err(|_| HpkeError::InsufficientRandomness)?;
843 #[cfg(not(feature = "hpke-test-prng"))]
844 prng.try_fill_bytes(&mut out)
845 .map_err(|_| HpkeError::InsufficientRandomness)?;
846
847 Ok(out)
848 }
849
850 pub(crate) fn rng(&mut self) -> &mut Crypto::HpkePrng {
852 &mut self.prng
853 }
854}
855
856impl HpkeKeyPair {
857 pub fn new(sk: Vec<u8>, pk: Vec<u8>) -> Self {
860 Self {
861 private_key: HpkePrivateKey::new(sk),
862 public_key: HpkePublicKey::new(pk),
863 }
864 }
865
866 pub fn private_key(&self) -> &HpkePrivateKey {
868 &self.private_key
869 }
870
871 pub fn public_key(&self) -> &HpkePublicKey {
873 &self.public_key
874 }
875
876 pub fn into_keys(self) -> (HpkePrivateKey, HpkePublicKey) {
878 (self.private_key, self.public_key)
879 }
880
881 pub fn from_keys(private_key: HpkePrivateKey, public_key: HpkePublicKey) -> Self {
883 Self {
884 private_key,
885 public_key,
886 }
887 }
888}
889
890impl From<(Vec<u8>, Vec<u8>)> for HpkeKeyPair {
891 fn from((sk, pk): (Vec<u8>, Vec<u8>)) -> Self {
892 Self::new(sk, pk)
893 }
894}
895
896impl From<(&[u8], &[u8])> for HpkeKeyPair {
897 fn from((sk, pk): (&[u8], &[u8])) -> Self {
898 Self::new(sk.to_vec(), pk.to_vec())
899 }
900}
901
902impl HpkePrivateKey {
903 pub fn new(b: Vec<u8>) -> Self {
906 Self { value: b }
907 }
908
909 #[cfg(feature = "hazmat")]
911 pub fn as_slice(&self) -> &[u8] {
912 &self.value
913 }
914}
915
916impl From<Vec<u8>> for HpkePrivateKey {
917 fn from(b: Vec<u8>) -> Self {
918 Self::new(b)
919 }
920}
921
922impl From<&[u8]> for HpkePrivateKey {
923 fn from(b: &[u8]) -> Self {
924 Self::new(b.to_vec())
925 }
926}
927
928impl PartialEq for HpkePrivateKey {
930 fn eq(&self, other: &Self) -> bool {
931 use subtle::ConstantTimeEq;
932 self.value.ct_eq(&other.value).into()
933 }
934}
935
936#[cfg(not(feature = "hazmat"))]
937impl core::fmt::Debug for HpkePrivateKey {
938 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
939 f.debug_struct("HpkePrivateKey")
940 .field("value", &"***")
941 .finish()
942 }
943}
944
945#[cfg(feature = "hazmat")]
946impl core::fmt::Debug for HpkePrivateKey {
947 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
948 f.debug_struct("HpkePrivateKey")
949 .field("value", &self.value)
950 .finish()
951 }
952}
953
954impl HpkePublicKey {
955 pub fn new(value: Vec<u8>) -> Self {
958 Self { value }
959 }
960
961 pub fn as_slice(&self) -> &[u8] {
963 self.value.as_slice()
964 }
965}
966
967impl From<Vec<u8>> for HpkePublicKey {
968 fn from(b: Vec<u8>) -> Self {
969 Self::new(b)
970 }
971}
972
973impl From<&[u8]> for HpkePublicKey {
974 fn from(b: &[u8]) -> Self {
975 Self::new(b.to_vec())
976 }
977}
978
979#[cfg(feature = "serialization")]
980impl tls_codec::Size for HpkePublicKey {
981 #[inline(always)]
982 fn tls_serialized_len(&self) -> usize {
983 tls_codec::VLByteSlice(self.as_slice()).tls_serialized_len()
984 }
985}
986
987#[cfg(feature = "serialization")]
988impl tls_codec::Serialize for HpkePublicKey {
989 #[inline(always)]
990 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
991 tls_codec::VLByteSlice(self.as_slice()).tls_serialize(writer)
992 }
993}
994
995#[cfg(feature = "serialization")]
996impl tls_codec::Size for &HpkePublicKey {
997 #[inline(always)]
998 fn tls_serialized_len(&self) -> usize {
999 tls_codec::VLByteSlice(self.as_slice()).tls_serialized_len()
1000 }
1001}
1002
1003#[cfg(feature = "serialization")]
1004impl tls_codec::Serialize for &HpkePublicKey {
1005 #[inline(always)]
1006 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
1007 tls_codec::VLByteSlice(self.as_slice()).tls_serialize(writer)
1008 }
1009}
1010
1011#[cfg(feature = "serialization")]
1012impl tls_codec::Deserialize for HpkePublicKey {
1013 #[inline(always)]
1014 fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, tls_codec::Error> {
1015 Ok(Self {
1016 value: tls_codec::VLBytes::tls_deserialize(bytes)?.into(),
1017 })
1018 }
1019}
1020
1021#[cfg(feature = "serialization")]
1022impl tls_codec::Deserialize for &HpkePublicKey {
1023 #[inline(always)]
1024 fn tls_deserialize<R: std::io::Read>(_: &mut R) -> Result<Self, tls_codec::Error> {
1025 Err(tls_codec::Error::DecodingError(
1026 "Error trying to deserialize a reference.".to_string(),
1027 ))
1028 }
1029}
1030
1031#[cfg(feature = "hpke-test")]
1033pub mod test_util {
1034 use alloc::{format, string::String, vec, vec::Vec};
1035
1036 use crate::HpkeError;
1037 use hpke_rs_crypto::{HpkeCrypto, HpkeTestRng};
1038
1039 impl<Crypto: HpkeCrypto> super::Hpke<Crypto> {
1040 pub fn seed(&mut self, seed: &[u8]) -> Result<(), HpkeError> {
1042 self.prng.seed(seed);
1043 Ok(())
1044 }
1045 }
1046
1047 impl<Crypto: HpkeCrypto> super::Context<Crypto> {
1048 #[doc(hidden)]
1050 pub fn key(&self) -> &[u8] {
1051 &self.key
1052 }
1053 #[doc(hidden)]
1055 pub fn nonce(&self) -> &[u8] {
1056 &self.nonce
1057 }
1058 #[doc(hidden)]
1060 pub fn exporter_secret(&self) -> &[u8] {
1061 &self.exporter_secret
1062 }
1063 #[doc(hidden)]
1065 pub fn sequence_number(&self) -> u64 {
1066 self.sequence_number
1067 }
1068 }
1069
1070 pub fn bytes_to_hex(bytes: &[u8]) -> String {
1072 let mut hex = String::new();
1073 for &b in bytes {
1074 hex += &format!("{:02X}", b);
1075 }
1076 hex
1077 }
1078
1079 pub fn hex_to_bytes(hex: &str) -> Vec<u8> {
1081 assert!(hex.len() % 2 == 0);
1082 let mut bytes = Vec::new();
1083 for i in 0..(hex.len() / 2) {
1084 bytes.push(u8::from_str_radix(&hex[2 * i..2 * i + 2], 16).unwrap());
1085 }
1086 bytes
1087 }
1088
1089 pub fn hex_to_bytes_option(hex: Option<String>) -> Vec<u8> {
1092 match hex {
1093 Some(s) => hex_to_bytes(&s),
1094 None => vec![],
1095 }
1096 }
1097
1098 pub fn vec_to_option_slice(v: &[u8]) -> Option<&[u8]> {
1101 if v.is_empty() {
1102 None
1103 } else {
1104 Some(v)
1105 }
1106 }
1107}
1108
1109impl From<hpke_rs_crypto::error::Error> for HpkeError {
1110 fn from(e: hpke_rs_crypto::error::Error) -> Self {
1111 match e {
1112 hpke_rs_crypto::error::Error::AeadOpenError => HpkeError::OpenError,
1113 hpke_rs_crypto::error::Error::AeadInvalidNonce
1114 | hpke_rs_crypto::error::Error::AeadInvalidCiphertext => HpkeError::InvalidInput,
1115 hpke_rs_crypto::error::Error::UnknownAeadAlgorithm => HpkeError::UnknownMode,
1116 hpke_rs_crypto::error::Error::CryptoLibraryError(s) => HpkeError::CryptoError(s),
1117 hpke_rs_crypto::error::Error::HpkeInvalidOutputLength => {
1118 HpkeError::CryptoError("Invalid HPKE output length".to_string())
1119 }
1120 hpke_rs_crypto::error::Error::UnknownKdfAlgorithm => {
1121 HpkeError::CryptoError("Unknown KDF algorithm.".to_string())
1122 }
1123 hpke_rs_crypto::error::Error::KemInvalidSecretKey => {
1124 HpkeError::CryptoError("Invalid KEM secret key".to_string())
1125 }
1126 hpke_rs_crypto::error::Error::KemInvalidPublicKey => {
1127 HpkeError::CryptoError("Invalid KEM public key".to_string())
1128 }
1129 hpke_rs_crypto::error::Error::UnknownKemAlgorithm => {
1130 HpkeError::CryptoError("Unknown KEM algorithm".to_string())
1131 }
1132 hpke_rs_crypto::error::Error::InsufficientRandomness => {
1133 HpkeError::InsufficientRandomness
1134 }
1135 hpke_rs_crypto::error::Error::UnsupportedKemOperation => HpkeError::InvalidConfig,
1136 hpke_rs_crypto::error::Error::KemInvalidCiphertext => HpkeError::InvalidInput,
1137 }
1138 }
1139}