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;
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)]
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
302pub 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 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 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 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 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 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#[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 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 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 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 #[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 #[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 #[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 #[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 #[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 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 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 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 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 pub(crate) fn rng(&mut self) -> &mut Crypto::HpkePrng {
824 &mut self.prng
825 }
826}
827
828impl HpkeKeyPair {
829 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 pub fn private_key(&self) -> &HpkePrivateKey {
840 &self.private_key
841 }
842
843 pub fn public_key(&self) -> &HpkePublicKey {
845 &self.public_key
846 }
847
848 pub fn into_keys(self) -> (HpkePrivateKey, HpkePublicKey) {
850 (self.private_key, self.public_key)
851 }
852
853 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 pub fn new(b: Vec<u8>) -> Self {
878 Self { value: b }
879 }
880
881 #[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
900impl 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 pub fn new(value: Vec<u8>) -> Self {
938 Self { value }
939 }
940
941 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#[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 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 #[doc(hidden)]
1030 pub fn key(&self) -> &[u8] {
1031 &self.key
1032 }
1033 #[doc(hidden)]
1035 pub fn nonce(&self) -> &[u8] {
1036 &self.nonce
1037 }
1038 #[doc(hidden)]
1040 pub fn exporter_secret(&self) -> &[u8] {
1041 &self.exporter_secret
1042 }
1043 #[doc(hidden)]
1045 pub fn sequence_number(&self) -> u32 {
1046 self.sequence_number
1047 }
1048 }
1049
1050 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 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 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 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}