1#![doc = include_str!("../Readme.md")]
2#![forbid(unsafe_code, unused_must_use, unstable_features)]
3#![deny(
4 trivial_casts,
5 trivial_numeric_casts,
6 missing_docs,
7 unused_import_braces,
8 unused_extern_crates,
9 unused_qualifications
10)]
11#![cfg_attr(not(test), no_std)]
12
13extern crate alloc;
14#[cfg(feature = "std")]
15extern crate std;
16
17use alloc::{
18 format,
19 string::{String, ToString},
20 vec,
21 vec::Vec,
22};
23
24#[cfg(feature = "hpke-test-prng")]
25use hpke_rs_crypto::HpkeTestRng;
26use hpke_rs_crypto::{
27 types::{AeadAlgorithm, KdfAlgorithm, KemAlgorithm},
28 HpkeCrypto,
29};
30use prelude::kdf::{labeled_expand, labeled_extract};
31
32pub use hpke_rs_crypto::types as hpke_types;
34
35#[cfg(feature = "rustcrypto")]
37pub use hpke_rs_rust_crypto as rustcrypto;
38
39#[cfg(feature = "libcrux")]
41pub use hpke_rs_libcrux as libcrux;
42
43#[cfg(not(feature = "hpke-test-prng"))]
44use rand_core::TryRngCore;
45
46#[cfg(feature = "serialization")]
47pub(crate) use serde::{Deserialize, Serialize};
48use zeroize::Zeroize;
49
50mod dh_kem;
51pub(crate) mod kdf;
52mod kem;
53pub mod prelude;
54
55mod util;
56
57#[cfg(test)]
58mod test_aead;
59#[cfg(test)]
60mod test_kdf;
61
62#[deprecated(
63 since = "0.0.7",
64 note = "Please use HpkeError instead. This alias will be removed with the first stable 0.1 release."
65)]
66#[allow(dead_code)]
67#[allow(clippy::upper_case_acronyms)]
68type HPKEError = HpkeError;
69
70#[derive(Debug, Clone, PartialEq)]
72pub enum HpkeError {
73 OpenError,
75
76 InvalidConfig,
78
79 InvalidInput,
81
82 UnknownMode,
84
85 InconsistentPsk,
87
88 MissingPsk,
90
91 UnnecessaryPsk,
93
94 InsecurePsk,
96
97 CryptoError(String),
99
100 MessageLimitReached,
102
103 InsufficientRandomness,
105}
106
107#[cfg(feature = "std")]
108impl std::error::Error for HpkeError {}
109
110impl core::fmt::Display for HpkeError {
111 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112 write!(f, "HPKE Error: {:?}", self)
113 }
114}
115
116#[deprecated(
117 since = "0.0.7",
118 note = "Please use HpkePublicKey instead. This alias will be removed with the first stable 0.1 release."
119)]
120#[allow(clippy::upper_case_acronyms)]
121#[allow(missing_docs)]
122pub type HPKEPublicKey = HpkePublicKey;
123
124#[derive(Debug, PartialEq, Clone, Default)]
126#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
127pub struct HpkePublicKey {
128 value: Vec<u8>,
129}
130
131#[deprecated(
132 since = "0.0.7",
133 note = "Please use HpkePrivateKey instead. This alias will be removed with the first stable 0.1 release."
134)]
135#[allow(clippy::upper_case_acronyms)]
136#[allow(missing_docs)]
137pub type HPKEPrivateKey = HpkePrivateKey;
138
139#[derive(Default, Zeroize)]
141#[zeroize(drop)] #[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
143#[cfg_attr(feature = "hazmat", derive(Clone))]
144pub struct HpkePrivateKey {
145 value: Vec<u8>,
146}
147
148#[deprecated(
149 since = "0.0.7",
150 note = "Please use HpkeKeyPair instead. This alias will be removed with the first stable 0.1 release."
151)]
152#[allow(clippy::upper_case_acronyms)]
153#[allow(missing_docs)]
154pub type HPKEKeyPair = HpkeKeyPair;
155
156#[derive(Debug, Default)]
158#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
159#[cfg_attr(feature = "hazmat", derive(Clone))]
160pub struct HpkeKeyPair {
161 private_key: HpkePrivateKey,
162 public_key: HpkePublicKey,
163}
164
165#[derive(PartialEq, Copy, Clone, Debug)]
167#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
168#[repr(u8)]
169pub enum Mode {
170 Base = 0x00,
172
173 Psk = 0x01,
175
176 Auth = 0x02,
178
179 AuthPsk = 0x03,
181}
182
183impl core::fmt::Display for Mode {
184 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
185 write!(f, "{:?}", self)
186 }
187}
188
189impl TryFrom<u8> for Mode {
190 type Error = HpkeError;
191 fn try_from(x: u8) -> Result<Mode, HpkeError> {
192 match x {
193 0x00 => Ok(Mode::Base),
194 0x01 => Ok(Mode::Psk),
195 0x02 => Ok(Mode::Auth),
196 0x03 => Ok(Mode::AuthPsk),
197 _ => Err(HpkeError::UnknownMode),
198 }
199 }
200}
201
202type EncapsulatedSecret = Vec<u8>;
205
206type Ciphertext = Vec<u8>;
209
210type Plaintext = Vec<u8>;
213
214pub struct Context<Crypto: 'static + HpkeCrypto> {
218 key: Vec<u8>,
219 nonce: Vec<u8>,
220 exporter_secret: Vec<u8>,
221 sequence_number: u32,
222 hpke: Hpke<Crypto>,
223}
224
225#[cfg(feature = "hazmat")]
226impl<Crypto: HpkeCrypto> core::fmt::Debug for Context<Crypto> {
227 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
228 write!(
229 f,
230 "Context {{\n key: {:?}\n nonce: {:?}\n exporter_secret: {:?}\n seq no: {:?}\n}}",
231 self.key, self.nonce, self.exporter_secret, self.sequence_number
232 )
233 }
234}
235
236#[cfg(not(feature = "hazmat"))]
237impl<Crypto: HpkeCrypto> core::fmt::Debug for Context<Crypto> {
238 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
239 write!(
240 f,
241 "Context {{\n key: {:?}\n nonce: {:?}\n exporter_secret: {:?}\n seq no: {:?}\n}}",
242 &"***", &"***", &"***", &"***"
243 )
244 }
245}
246
247impl<Crypto: HpkeCrypto> Context<Crypto> {
248 pub fn seal(&mut self, aad: &[u8], plain_txt: &[u8]) -> Result<Ciphertext, HpkeError> {
260 let ctxt = Crypto::aead_seal(
261 self.hpke.aead_id,
262 &self.key,
263 &self.compute_nonce(),
264 aad,
265 plain_txt,
266 )?;
267 self.increment_seq()?;
268 Ok(ctxt)
269 }
270
271 pub fn open(&mut self, aad: &[u8], cipher_txt: &[u8]) -> Result<Plaintext, HpkeError> {
285 let ptxt = Crypto::aead_open(
286 self.hpke.aead_id,
287 &self.key,
288 &self.compute_nonce(),
289 aad,
290 cipher_txt,
291 )?;
292 self.increment_seq()?;
293 Ok(ptxt)
294 }
295
296 pub fn export(&self, exporter_context: &[u8], length: usize) -> Result<Vec<u8>, HpkeError> {
306 labeled_expand::<Crypto>(
307 self.hpke.kdf_id,
308 &self.exporter_secret,
309 &self.hpke.ciphersuite(),
310 "sec",
311 exporter_context,
312 length,
313 )
314 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))
315 }
316
317 fn compute_nonce(&self) -> Vec<u8> {
321 let seq = self.sequence_number.to_be_bytes();
322 let mut enc_seq = vec![0u8; self.nonce.len() - seq.len()];
323 enc_seq.extend_from_slice(&seq);
324 util::xor_bytes(&enc_seq, &self.nonce)
325 }
326
327 fn increment_seq(&mut self) -> Result<(), HpkeError> {
332 if u128::from(self.sequence_number)
333 >= ((1u128 << (8 * Crypto::aead_nonce_length(self.hpke.aead_id))) - 1)
334 {
335 return Err(HpkeError::MessageLimitReached);
336 }
337 self.sequence_number += 1;
338 Ok(())
339 }
340}
341
342#[derive(Debug)]
350pub struct Hpke<Crypto: 'static + HpkeCrypto> {
351 mode: Mode,
352 kem_id: KemAlgorithm,
353 kdf_id: KdfAlgorithm,
354 aead_id: AeadAlgorithm,
355 prng: Crypto::HpkePrng,
356}
357
358impl<Crypto: 'static + HpkeCrypto> Clone for Hpke<Crypto> {
359 fn clone(&self) -> Self {
360 Self {
361 mode: self.mode,
362 kem_id: self.kem_id,
363 kdf_id: self.kdf_id,
364 aead_id: self.aead_id,
365 prng: Crypto::prng(),
366 }
367 }
368}
369
370impl<Crypto: HpkeCrypto> core::fmt::Display for Hpke<Crypto> {
371 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
372 write!(
373 f,
374 "{}_{}_{}_{}",
375 self.mode.to_string().to_lowercase(),
376 self.kem_id.to_string().to_lowercase(),
377 self.kdf_id.to_string().to_lowercase(),
378 self.aead_id.to_string().to_lowercase()
379 )
380 }
381}
382
383impl<Crypto: HpkeCrypto> Hpke<Crypto> {
384 pub fn new(
386 mode: Mode,
387 kem_id: KemAlgorithm,
388 kdf_id: KdfAlgorithm,
389 aead_id: AeadAlgorithm,
390 ) -> Self {
391 Self {
392 mode,
393 kem_id,
394 kdf_id,
395 aead_id,
396 prng: Crypto::prng(),
397 }
398 }
399
400 pub fn setup_sender(
415 &mut self,
416 pk_r: &HpkePublicKey,
417 info: &[u8],
418 psk: Option<&[u8]>,
419 psk_id: Option<&[u8]>,
420 sk_s: Option<&HpkePrivateKey>,
421 ) -> Result<(EncapsulatedSecret, Context<Crypto>), HpkeError> {
422 let (zz, enc) = match self.mode {
423 Mode::Base | Mode::Psk => kem::encaps::<Crypto>(self, pk_r.value.as_slice())?,
424 Mode::Auth | Mode::AuthPsk => {
425 let sk_s = match sk_s {
426 Some(s) => &s.value,
427 None => return Err(HpkeError::InvalidInput),
428 };
429 kem::auth_encaps::<Crypto>(self, pk_r.value.as_slice(), sk_s)?
430 }
431 };
432 Ok((
433 enc,
434 self.clone().key_schedule(
435 &zz,
436 info,
437 psk.unwrap_or_default(),
438 psk_id.unwrap_or_default(),
439 )?,
440 ))
441 }
442
443 pub fn setup_receiver(
459 &self,
460 enc: &[u8],
461 sk_r: &HpkePrivateKey,
462 info: &[u8],
463 psk: Option<&[u8]>,
464 psk_id: Option<&[u8]>,
465 pk_s: Option<&HpkePublicKey>,
466 ) -> Result<Context<Crypto>, HpkeError> {
467 let zz = match self.mode {
468 Mode::Base | Mode::Psk => kem::decaps::<Crypto>(self.kem_id, enc, &sk_r.value)?,
469 Mode::Auth | Mode::AuthPsk => {
470 let pk_s = match pk_s {
471 Some(s) => s.value.as_slice(),
472 None => return Err(HpkeError::InvalidInput),
473 };
474 kem::auth_decaps::<Crypto>(self.kem_id, enc, &sk_r.value, pk_s)?
475 }
476 };
477 self.clone().key_schedule(
478 &zz,
479 info,
480 psk.unwrap_or_default(),
481 psk_id.unwrap_or_default(),
482 )
483 }
484
485 #[allow(clippy::too_many_arguments)]
498 pub fn seal(
499 &mut self,
500 pk_r: &HpkePublicKey,
501 info: &[u8],
502 aad: &[u8],
503 plain_txt: &[u8],
504 psk: Option<&[u8]>,
505 psk_id: Option<&[u8]>,
506 sk_s: Option<&HpkePrivateKey>,
507 ) -> Result<(EncapsulatedSecret, Ciphertext), HpkeError> {
508 let (enc, mut context) = self.setup_sender(pk_r, info, psk, psk_id, sk_s)?;
509 let ctxt = context.seal(aad, plain_txt)?;
510 Ok((enc, ctxt))
511 }
512
513 #[allow(clippy::too_many_arguments)]
525 pub fn open(
526 &self,
527 enc: &[u8],
528 sk_r: &HpkePrivateKey,
529 info: &[u8],
530 aad: &[u8],
531 ct: &[u8],
532 psk: Option<&[u8]>,
533 psk_id: Option<&[u8]>,
534 pk_s: Option<&HpkePublicKey>,
535 ) -> Result<Plaintext, HpkeError> {
536 let mut context = self.setup_receiver(enc, sk_r, info, psk, psk_id, pk_s)?;
537 context.open(aad, ct)
538 }
539
540 #[allow(clippy::too_many_arguments)]
554 pub fn send_export(
555 &mut self,
556 pk_r: &HpkePublicKey,
557 info: &[u8],
558 psk: Option<&[u8]>,
559 psk_id: Option<&[u8]>,
560 sk_s: Option<&HpkePrivateKey>,
561 exporter_context: &[u8],
562 length: usize,
563 ) -> Result<(EncapsulatedSecret, Vec<u8>), HpkeError> {
564 let (enc, context) = self.setup_sender(pk_r, info, psk, psk_id, sk_s)?;
565 Ok((enc, context.export(exporter_context, length)?))
566 }
567
568 #[allow(clippy::too_many_arguments)]
581 pub fn receiver_export(
582 &self,
583 enc: &[u8],
584 sk_r: &HpkePrivateKey,
585 info: &[u8],
586 psk: Option<&[u8]>,
587 psk_id: Option<&[u8]>,
588 pk_s: Option<&HpkePublicKey>,
589 exporter_context: &[u8],
590 length: usize,
591 ) -> Result<Vec<u8>, HpkeError> {
592 let context = self.setup_receiver(enc, sk_r, info, psk, psk_id, pk_s)?;
593 context.export(exporter_context, length)
594 }
595
596 #[inline(always)]
598 fn verify_psk_inputs(&self, psk: &[u8], psk_id: &[u8]) -> Result<(), HpkeError> {
599 let got_psk = !psk.is_empty();
600 let got_psk_id = !psk_id.is_empty();
601 if (got_psk && !got_psk_id) || (!got_psk && got_psk_id) {
602 return Err(HpkeError::InconsistentPsk);
603 }
604
605 if got_psk && (self.mode == Mode::Base || self.mode == Mode::Auth) {
606 return Err(HpkeError::UnnecessaryPsk);
607 }
608 if !got_psk && (self.mode == Mode::Psk || self.mode == Mode::AuthPsk) {
609 return Err(HpkeError::MissingPsk);
610 }
611
612 if (self.mode == Mode::Psk || self.mode == Mode::AuthPsk) && psk.len() < 32 {
614 return Err(HpkeError::InsecurePsk);
615 }
616
617 Ok(())
618 }
619
620 #[inline]
621 fn ciphersuite(&self) -> Vec<u8> {
622 util::concat(&[
623 b"HPKE",
624 &(self.kem_id as u16).to_be_bytes(),
625 &(self.kdf_id as u16).to_be_bytes(),
626 &(self.aead_id as u16).to_be_bytes(),
627 ])
628 }
629
630 #[inline]
631 fn key_schedule_context(
632 &self,
633 info: &[u8],
634 psk_id: &[u8],
635 suite_id: &[u8],
636 ) -> Result<Vec<u8>, HpkeError> {
637 let psk_id_hash =
638 labeled_extract::<Crypto>(self.kdf_id, &[0], suite_id, "psk_id_hash", psk_id)?;
639 let info_hash = labeled_extract::<Crypto>(self.kdf_id, &[0], suite_id, "info_hash", info)?;
640 Ok(util::concat(&[
641 &[self.mode as u8],
642 &psk_id_hash,
643 &info_hash,
644 ]))
645 }
646
647 pub fn key_schedule(
650 &self,
651 shared_secret: &[u8],
652 info: &[u8],
653 psk: &[u8],
654 psk_id: &[u8],
655 ) -> Result<Context<Crypto>, HpkeError> {
656 self.verify_psk_inputs(psk, psk_id)?;
657 let suite_id = self.ciphersuite();
658 let key_schedule_context = self.key_schedule_context(info, psk_id, &suite_id)?;
659 let secret =
660 labeled_extract::<Crypto>(self.kdf_id, shared_secret, &suite_id, "secret", psk)
661 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
662
663 let key = labeled_expand::<Crypto>(
664 self.kdf_id,
665 &secret,
666 &suite_id,
667 "key",
668 &key_schedule_context,
669 Crypto::aead_key_length(self.aead_id),
670 )
671 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
672 let base_nonce = labeled_expand::<Crypto>(
673 self.kdf_id,
674 &secret,
675 &suite_id,
676 "base_nonce",
677 &key_schedule_context,
678 Crypto::aead_nonce_length(self.aead_id),
679 )
680 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
681 let exporter_secret = labeled_expand::<Crypto>(
682 self.kdf_id,
683 &secret,
684 &suite_id,
685 "exp",
686 &key_schedule_context,
687 Crypto::kdf_digest_length(self.kdf_id),
688 )
689 .map_err(|e| HpkeError::CryptoError(format!("Crypto error: {}", e)))?;
690
691 Ok(Context {
692 key,
693 nonce: base_nonce,
694 exporter_secret,
695 sequence_number: 0,
696 hpke: self.clone(),
697 })
698 }
699
700 pub fn generate_key_pair(&mut self) -> Result<HpkeKeyPair, HpkeError> {
706 let (sk, pk) = kem::key_gen::<Crypto>(self.kem_id, &mut self.prng)?;
707 Ok(HpkeKeyPair::new(sk, pk))
708 }
709
710 pub fn derive_key_pair(&self, ikm: &[u8]) -> Result<HpkeKeyPair, HpkeError> {
715 let (pk, sk) = kem::derive_key_pair::<Crypto>(self.kem_id, ikm)?;
716 Ok(HpkeKeyPair::new(sk, pk))
717 }
718
719 #[inline]
720 pub(crate) fn random(&mut self, len: usize) -> Result<Vec<u8>, HpkeError> {
721 let prng = &mut self.prng;
722 let mut out = vec![0u8; len];
723
724 #[cfg(feature = "hpke-test-prng")]
725 prng.try_fill_test_bytes(&mut out)
726 .map_err(|_| HpkeError::InsufficientRandomness)?;
727 #[cfg(not(feature = "hpke-test-prng"))]
728 prng.try_fill_bytes(&mut out)
729 .map_err(|_| HpkeError::InsufficientRandomness)?;
730
731 Ok(out)
732 }
733
734 pub(crate) fn rng(&mut self) -> &mut Crypto::HpkePrng {
736 &mut self.prng
737 }
738}
739
740impl HpkeKeyPair {
741 pub fn new(sk: Vec<u8>, pk: Vec<u8>) -> Self {
744 Self {
745 private_key: HpkePrivateKey::new(sk),
746 public_key: HpkePublicKey::new(pk),
747 }
748 }
749
750 pub fn private_key(&self) -> &HpkePrivateKey {
752 &self.private_key
753 }
754
755 pub fn public_key(&self) -> &HpkePublicKey {
757 &self.public_key
758 }
759
760 pub fn into_keys(self) -> (HpkePrivateKey, HpkePublicKey) {
762 (self.private_key, self.public_key)
763 }
764
765 pub fn from_keys(private_key: HpkePrivateKey, public_key: HpkePublicKey) -> Self {
767 Self {
768 private_key,
769 public_key,
770 }
771 }
772}
773
774impl From<(Vec<u8>, Vec<u8>)> for HpkeKeyPair {
775 fn from((sk, pk): (Vec<u8>, Vec<u8>)) -> Self {
776 Self::new(sk, pk)
777 }
778}
779
780impl From<(&[u8], &[u8])> for HpkeKeyPair {
781 fn from((sk, pk): (&[u8], &[u8])) -> Self {
782 Self::new(sk.to_vec(), pk.to_vec())
783 }
784}
785
786impl HpkePrivateKey {
787 pub fn new(b: Vec<u8>) -> Self {
790 Self { value: b }
791 }
792
793 #[cfg(feature = "hazmat")]
795 pub fn as_slice(&self) -> &[u8] {
796 &self.value
797 }
798}
799
800impl From<Vec<u8>> for HpkePrivateKey {
801 fn from(b: Vec<u8>) -> Self {
802 Self::new(b)
803 }
804}
805
806impl From<&[u8]> for HpkePrivateKey {
807 fn from(b: &[u8]) -> Self {
808 Self::new(b.to_vec())
809 }
810}
811
812impl PartialEq for HpkePrivateKey {
815 fn eq(&self, other: &Self) -> bool {
816 if self.value.len() != other.value.len() {
817 return false;
818 }
819
820 let mut different_bits = 0u8;
821 for (&byte_a, &byte_b) in self.value.iter().zip(other.value.iter()) {
822 different_bits |= byte_a ^ byte_b;
823 }
824 (1u8 & ((different_bits.wrapping_sub(1)).wrapping_shr(8)).wrapping_sub(1)) == 0
825 }
826}
827
828#[cfg(not(feature = "hazmat"))]
829impl core::fmt::Debug for HpkePrivateKey {
830 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
831 f.debug_struct("HpkePrivateKey")
832 .field("value", &"***")
833 .finish()
834 }
835}
836
837#[cfg(feature = "hazmat")]
838impl core::fmt::Debug for HpkePrivateKey {
839 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
840 f.debug_struct("HpkePrivateKey")
841 .field("value", &self.value)
842 .finish()
843 }
844}
845
846impl HpkePublicKey {
847 pub fn new(value: Vec<u8>) -> Self {
850 Self { value }
851 }
852
853 pub fn as_slice(&self) -> &[u8] {
855 self.value.as_slice()
856 }
857}
858
859impl From<Vec<u8>> for HpkePublicKey {
860 fn from(b: Vec<u8>) -> Self {
861 Self::new(b)
862 }
863}
864
865impl From<&[u8]> for HpkePublicKey {
866 fn from(b: &[u8]) -> Self {
867 Self::new(b.to_vec())
868 }
869}
870
871#[cfg(feature = "serialization")]
872impl tls_codec::Size for HpkePublicKey {
873 #[inline(always)]
874 fn tls_serialized_len(&self) -> usize {
875 tls_codec::VLByteSlice(self.as_slice()).tls_serialized_len()
876 }
877}
878
879#[cfg(feature = "serialization")]
880impl tls_codec::Serialize for HpkePublicKey {
881 #[inline(always)]
882 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
883 tls_codec::VLByteSlice(self.as_slice()).tls_serialize(writer)
884 }
885}
886
887#[cfg(feature = "serialization")]
888impl tls_codec::Size for &HpkePublicKey {
889 #[inline(always)]
890 fn tls_serialized_len(&self) -> usize {
891 tls_codec::VLByteSlice(self.as_slice()).tls_serialized_len()
892 }
893}
894
895#[cfg(feature = "serialization")]
896impl tls_codec::Serialize for &HpkePublicKey {
897 #[inline(always)]
898 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
899 tls_codec::VLByteSlice(self.as_slice()).tls_serialize(writer)
900 }
901}
902
903#[cfg(feature = "serialization")]
904impl tls_codec::Deserialize for HpkePublicKey {
905 #[inline(always)]
906 fn tls_deserialize<R: std::io::Read>(bytes: &mut R) -> Result<Self, tls_codec::Error> {
907 Ok(Self {
908 value: tls_codec::VLBytes::tls_deserialize(bytes)?.into(),
909 })
910 }
911}
912
913#[cfg(feature = "serialization")]
914impl tls_codec::Deserialize for &HpkePublicKey {
915 #[inline(always)]
916 fn tls_deserialize<R: std::io::Read>(_: &mut R) -> Result<Self, tls_codec::Error> {
917 Err(tls_codec::Error::DecodingError(
918 "Error trying to deserialize a reference.".to_string(),
919 ))
920 }
921}
922
923#[cfg(feature = "hpke-test")]
925pub mod test_util {
926 use alloc::{format, string::String, vec, vec::Vec};
927
928 use crate::HpkeError;
929 use hpke_rs_crypto::{HpkeCrypto, HpkeTestRng};
930
931 impl<Crypto: HpkeCrypto> super::Hpke<Crypto> {
932 pub fn seed(&mut self, seed: &[u8]) -> Result<(), HpkeError> {
934 self.prng.seed(seed);
935 Ok(())
936 }
937 }
938
939 impl<Crypto: HpkeCrypto> super::Context<Crypto> {
940 #[doc(hidden)]
942 pub fn key(&self) -> &[u8] {
943 &self.key
944 }
945 #[doc(hidden)]
947 pub fn nonce(&self) -> &[u8] {
948 &self.nonce
949 }
950 #[doc(hidden)]
952 pub fn exporter_secret(&self) -> &[u8] {
953 &self.exporter_secret
954 }
955 #[doc(hidden)]
957 pub fn sequence_number(&self) -> u32 {
958 self.sequence_number
959 }
960 }
961
962 pub fn bytes_to_hex(bytes: &[u8]) -> String {
964 let mut hex = String::new();
965 for &b in bytes {
966 hex += &format!("{:02X}", b);
967 }
968 hex
969 }
970
971 pub fn hex_to_bytes(hex: &str) -> Vec<u8> {
973 assert!(hex.len() % 2 == 0);
974 let mut bytes = Vec::new();
975 for i in 0..(hex.len() / 2) {
976 bytes.push(u8::from_str_radix(&hex[2 * i..2 * i + 2], 16).unwrap());
977 }
978 bytes
979 }
980
981 pub fn hex_to_bytes_option(hex: Option<String>) -> Vec<u8> {
984 match hex {
985 Some(s) => hex_to_bytes(&s),
986 None => vec![],
987 }
988 }
989
990 pub fn vec_to_option_slice(v: &[u8]) -> Option<&[u8]> {
993 if v.is_empty() {
994 None
995 } else {
996 Some(v)
997 }
998 }
999}
1000
1001impl From<hpke_rs_crypto::error::Error> for HpkeError {
1002 fn from(e: hpke_rs_crypto::error::Error) -> Self {
1003 match e {
1004 hpke_rs_crypto::error::Error::AeadOpenError => HpkeError::OpenError,
1005 hpke_rs_crypto::error::Error::AeadInvalidNonce
1006 | hpke_rs_crypto::error::Error::AeadInvalidCiphertext => HpkeError::InvalidInput,
1007 hpke_rs_crypto::error::Error::UnknownAeadAlgorithm => HpkeError::UnknownMode,
1008 hpke_rs_crypto::error::Error::CryptoLibraryError(s) => HpkeError::CryptoError(s),
1009 hpke_rs_crypto::error::Error::HpkeInvalidOutputLength => {
1010 HpkeError::CryptoError("Invalid HPKE output length".to_string())
1011 }
1012 hpke_rs_crypto::error::Error::UnknownKdfAlgorithm => {
1013 HpkeError::CryptoError("Unknown KDF algorithm.".to_string())
1014 }
1015 hpke_rs_crypto::error::Error::KemInvalidSecretKey => {
1016 HpkeError::CryptoError("Invalid KEM secret key".to_string())
1017 }
1018 hpke_rs_crypto::error::Error::KemInvalidPublicKey => {
1019 HpkeError::CryptoError("Invalid KEM public key".to_string())
1020 }
1021 hpke_rs_crypto::error::Error::UnknownKemAlgorithm => {
1022 HpkeError::CryptoError("Unknown KEM algorithm".to_string())
1023 }
1024 hpke_rs_crypto::error::Error::InsufficientRandomness => {
1025 HpkeError::InsufficientRandomness
1026 }
1027 hpke_rs_crypto::error::Error::UnsupportedKemOperation => HpkeError::InvalidConfig,
1028 hpke_rs_crypto::error::Error::KemInvalidCiphertext => HpkeError::InvalidInput,
1029 }
1030 }
1031}