1use core::{
7 cmp::{Eq, PartialEq},
8 fmt::{self, Debug},
9 iter::IntoIterator,
10 mem::{self, size_of},
11 ops::{BitXor, Deref, DerefMut},
12 result::Result,
13};
14
15use buggy::{Bug, BugExt};
16use generic_array::{ArrayLength, GenericArray, IntoArrayLength};
17use serde::{Deserialize, Serialize};
18use subtle::{Choice, ConstantTimeEq};
19use typenum::{
20 generic_const_mappings::Const,
21 type_operators::{IsGreaterOrEqual, IsLess},
22 Unsigned, U16, U65536,
23};
24
25#[doc(inline)]
26pub use crate::hpke::AeadId;
27use crate::{
28 csprng::{Csprng, Random},
29 kdf::{Expand, Kdf, KdfError, Prk},
30 keys::{raw_key, SecretKey, SecretKeyBytes},
31 util::const_assert,
32 zeroize::Zeroize,
33};
34
35const_assert!(size_of::<usize>() >= 4);
39
40#[derive(Copy, Clone, Debug, Eq, PartialEq)]
45pub struct BufferTooSmallError(pub Option<usize>);
46
47impl BufferTooSmallError {
48 pub const fn as_str(&self) -> &'static str {
50 "dest buffer too small"
51 }
52}
53
54impl fmt::Display for BufferTooSmallError {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 if let Some(n) = self.0 {
57 write!(f, "{} (need {})", self.as_str(), n)
58 } else {
59 write!(f, "{}", self.as_str())
60 }
61 }
62}
63
64impl core::error::Error for BufferTooSmallError {}
65
66#[derive(Copy, Clone, Debug, Eq, PartialEq)]
68pub struct InvalidNonceSize;
69
70impl InvalidNonceSize {
71 pub const fn as_str(&self) -> &'static str {
73 "nonce size is invalid"
74 }
75}
76
77impl fmt::Display for InvalidNonceSize {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 write!(f, "{}", self.as_str())
80 }
81}
82
83impl core::error::Error for InvalidNonceSize {}
84
85#[derive(Debug, Eq, PartialEq)]
87pub enum SealError {
88 Bug(Bug),
90 Other(&'static str),
92 InvalidKeySize,
94 InvalidNonceSize(InvalidNonceSize),
96 InvalidOverheadSize,
98 PlaintextTooLong,
100 AdditionalDataTooLong,
102 BufferTooSmall(BufferTooSmallError),
104 Encryption,
106}
107
108impl SealError {
109 pub fn as_str(&self) -> &'static str {
111 match self {
112 Self::Bug(err) => err.msg(),
113 Self::Other(msg) => msg,
114 Self::InvalidKeySize => "invalid key size",
115 Self::InvalidNonceSize(err) => err.as_str(),
116 Self::InvalidOverheadSize => "invalid overhead size",
117 Self::PlaintextTooLong => "plaintext too long",
118 Self::AdditionalDataTooLong => "additional data too long",
119 Self::Encryption => "encryption error",
120 Self::BufferTooSmall(err) => err.as_str(),
121 }
122 }
123}
124
125impl fmt::Display for SealError {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self {
128 Self::Bug(err) => write!(f, "{}", err),
129 Self::BufferTooSmall(err) => write!(f, "{}", err),
130 Self::InvalidNonceSize(err) => write!(f, "{}", err),
131 _ => write!(f, "{}", self.as_str()),
132 }
133 }
134}
135
136impl core::error::Error for SealError {
137 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
138 match self {
139 Self::Bug(err) => Some(err),
140 Self::BufferTooSmall(err) => Some(err),
141 Self::InvalidNonceSize(err) => Some(err),
142 _ => None,
143 }
144 }
145}
146
147impl From<BufferTooSmallError> for SealError {
148 fn from(value: BufferTooSmallError) -> Self {
149 SealError::BufferTooSmall(value)
150 }
151}
152
153impl From<Bug> for SealError {
154 fn from(value: Bug) -> Self {
155 SealError::Bug(value)
156 }
157}
158
159impl From<InvalidNonceSize> for SealError {
160 fn from(value: InvalidNonceSize) -> Self {
161 SealError::InvalidNonceSize(value)
162 }
163}
164
165#[derive(Debug, Eq, PartialEq)]
167pub enum OpenError {
168 Bug(Bug),
170 Other(&'static str),
172 InvalidKeySize,
174 InvalidNonceSize(InvalidNonceSize),
176 InvalidOverheadSize,
178 PlaintextTooLong,
180 CiphertextTooLong,
182 AdditionalDataTooLong,
184 BufferTooSmall(BufferTooSmallError),
186 Authentication,
188}
189
190impl OpenError {
191 pub fn as_str(&self) -> &'static str {
193 match self {
194 Self::Bug(err) => err.msg(),
195 Self::Other(msg) => msg,
196 Self::InvalidKeySize => "invalid key size",
197 Self::InvalidNonceSize(err) => err.as_str(),
198 Self::InvalidOverheadSize => "invalid overhead size",
199 Self::PlaintextTooLong => "plaintext too long",
200 Self::CiphertextTooLong => "ciphertext too long",
201 Self::AdditionalDataTooLong => "additional data too long",
202 Self::Authentication => "authentication error",
203 Self::BufferTooSmall(err) => err.as_str(),
204 }
205 }
206}
207
208impl fmt::Display for OpenError {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 match self {
211 Self::Bug(err) => write!(f, "{}", err),
212 Self::BufferTooSmall(err) => write!(f, "{}", err),
213 Self::InvalidNonceSize(err) => write!(f, "{}", err),
214 _ => write!(f, "{}", self.as_str()),
215 }
216 }
217}
218
219impl core::error::Error for OpenError {
220 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
221 match self {
222 Self::Bug(err) => Some(err),
223 Self::BufferTooSmall(err) => Some(err),
224 Self::InvalidNonceSize(err) => Some(err),
225 _ => None,
226 }
227 }
228}
229
230impl From<BufferTooSmallError> for OpenError {
231 fn from(value: BufferTooSmallError) -> Self {
232 OpenError::BufferTooSmall(value)
233 }
234}
235
236impl From<Bug> for OpenError {
237 fn from(value: Bug) -> Self {
238 OpenError::Bug(value)
239 }
240}
241
242impl From<InvalidNonceSize> for OpenError {
243 fn from(value: InvalidNonceSize) -> Self {
244 OpenError::InvalidNonceSize(value)
245 }
246}
247
248#[derive(Copy, Clone, Debug, Eq, PartialEq)]
269pub enum Lifetime {
270 Unlimited,
273 Messages(u64),
278 Bytes(u64),
280}
281
282impl Lifetime {
283 const fn as_u64(self) -> u64 {
284 match self {
285 Self::Unlimited => u64::MAX,
286 Self::Messages(x) => x,
287 Self::Bytes(x) => x,
288 }
289 }
290
291 #[inline]
294 #[must_use]
295 pub fn consume(self, bytes: u64) -> Option<Self> {
296 match self {
297 Self::Unlimited => Some(Self::Unlimited),
298 Self::Messages(x) => x.checked_sub(1).map(Self::Messages),
299 Self::Bytes(x) => x.checked_sub(bytes).map(Self::Bytes),
300 }
301 }
302
303 #[inline]
306 #[must_use]
307 pub fn consume_mut(&mut self, bytes: u64) -> bool {
308 self.consume(bytes).inspect(|v| *self = *v).is_some()
309 }
310}
311
312impl PartialEq<u64> for Lifetime {
313 fn eq(&self, other: &u64) -> bool {
314 self.as_u64() == *other
315 }
316}
317
318pub trait Aead {
358 const ID: AeadId;
360
361 const LIFETIME: Lifetime;
363
364 type KeySize: ArrayLength + IsGreaterOrEqual<U16> + IsLess<U65536> + 'static;
368 const KEY_SIZE: usize = Self::KeySize::USIZE;
370
371 type NonceSize: ArrayLength + IsLess<U65536> + 'static;
375 const NONCE_SIZE: usize = Self::NonceSize::USIZE;
377
378 type Overhead: ArrayLength + IsGreaterOrEqual<U16> + 'static;
387 const OVERHEAD: usize = Self::Overhead::USIZE;
389
390 const MAX_PLAINTEXT_SIZE: u64;
395 const MAX_ADDITIONAL_DATA_SIZE: u64;
400 const MAX_CIPHERTEXT_SIZE: u64 =
407 match Self::MAX_PLAINTEXT_SIZE.checked_add(Self::OVERHEAD as u64) {
408 Some(n) => n,
409 None => panic!("overflow"),
410 };
411
412 type Key: SecretKey<Size = Self::KeySize>;
414
415 fn new(key: &Self::Key) -> Self;
417
418 fn seal(
438 &self,
439 mut dst: &mut [u8],
440 nonce: &[u8],
441 plaintext: &[u8],
442 additional_data: &[u8],
443 ) -> Result<(), SealError> {
444 check_seal_params::<Self>(&mut dst, nonce, plaintext, additional_data)?;
445 dst[..plaintext.len()].copy_from_slice(plaintext);
446 let tag_idx = dst
447 .len()
448 .checked_sub(Self::OVERHEAD)
449 .assume("out length must be >= overhead")?;
450 let (dst, overhead) = dst.split_at_mut(tag_idx);
451 self.seal_in_place(nonce, dst, overhead, additional_data)
452 .inspect_err(|_| dst.zeroize())
455 }
456
457 fn seal_in_place(
475 &self,
476 nonce: &[u8],
477 data: &mut [u8],
478 overhead: &mut [u8],
479 additional_data: &[u8],
480 ) -> Result<(), SealError>;
481
482 fn open(
499 &self,
500 dst: &mut [u8],
501 nonce: &[u8],
502 ciphertext: &[u8],
503 additional_data: &[u8],
504 ) -> Result<(), OpenError> {
505 check_open_params::<Self>(dst, nonce, ciphertext, additional_data)?;
506
507 let max = ciphertext.len().checked_sub(Self::OVERHEAD).assume(
508 "`ciphertext.len() >= Self::OVERHEAD` should be enforced by `check_open_params`",
509 )?;
510 let (ciphertext, overhead) = ciphertext.split_at(max);
511 let out = &mut dst[..max];
512 out.copy_from_slice(ciphertext);
513 self.open_in_place(nonce, out, overhead, additional_data)
514 .inspect_err(|_| out.zeroize())
517 }
518
519 fn open_in_place(
532 &self,
533 nonce: &[u8],
534 data: &mut [u8],
535 overhead: &[u8],
536 additional_data: &[u8],
537 ) -> Result<(), OpenError>;
538}
539
540pub type KeyData<A> = SecretKeyBytes<<<A as Aead>::Key as SecretKey>::Size>;
543
544pub type Tag<A> = GenericArray<u8, <A as Aead>::Overhead>;
546
547const fn check_aead_params<A: Aead + ?Sized>() {
548 const {
549 assert!(A::KEY_SIZE >= 16);
550 assert!(A::OVERHEAD >= 16);
551 assert!(A::MAX_PLAINTEXT_SIZE >= u32::MAX as u64);
552 assert!(A::MAX_CIPHERTEXT_SIZE == A::MAX_PLAINTEXT_SIZE + (A::OVERHEAD as u64));
553 assert!(A::MAX_ADDITIONAL_DATA_SIZE >= u32::MAX as u64);
554 }
555}
556
557pub fn check_seal_params<A: Aead + ?Sized>(
562 dst: &mut &mut [u8],
563 nonce: &[u8],
564 plaintext: &[u8],
565 additional_data: &[u8],
566) -> Result<(), SealError> {
567 check_aead_params::<A>();
568
569 let need = match plaintext.len().checked_add(A::OVERHEAD) {
570 None => return Err(SealError::PlaintextTooLong),
572 Some(n) => n,
573 };
574 if need > dst.len() {
575 return Err(SealError::BufferTooSmall(BufferTooSmallError(Some(need))));
576 }
577 *dst = &mut mem::take(dst)[..need];
578
579 if nonce.len() != A::NONCE_SIZE {
580 return Err(SealError::InvalidNonceSize(InvalidNonceSize));
581 }
582 if plaintext.len() as u64 > A::MAX_PLAINTEXT_SIZE {
583 return Err(SealError::PlaintextTooLong);
584 }
585 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
586 return Err(SealError::AdditionalDataTooLong);
587 }
588
589 Ok(())
590}
591
592pub const fn check_seal_in_place_params<A: Aead + ?Sized>(
595 nonce: &[u8],
596 data: &[u8],
597 overhead: &[u8],
598 additional_data: &[u8],
599) -> Result<(), SealError> {
600 check_aead_params::<A>();
601
602 if nonce.len() != A::NONCE_SIZE {
603 return Err(SealError::InvalidNonceSize(InvalidNonceSize));
604 }
605 if data.len() as u64 > A::MAX_PLAINTEXT_SIZE {
606 return Err(SealError::PlaintextTooLong);
607 }
608 if overhead.len() > A::OVERHEAD {
609 return Err(SealError::InvalidOverheadSize);
610 }
611 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
612 return Err(SealError::AdditionalDataTooLong);
613 }
614 Ok(())
615}
616
617pub const fn check_open_params<A: Aead + ?Sized>(
620 dst: &[u8],
621 nonce: &[u8],
622 ciphertext: &[u8],
623 additional_data: &[u8],
624) -> Result<(), OpenError> {
625 check_aead_params::<A>();
626
627 let need = match ciphertext.len().checked_sub(A::OVERHEAD) {
628 None => return Err(OpenError::Authentication),
631 Some(n) => n,
632 };
633 if need > dst.len() {
634 return Err(OpenError::BufferTooSmall(BufferTooSmallError(Some(need))));
635 }
636 if nonce.len() != A::NONCE_SIZE {
637 return Err(OpenError::InvalidNonceSize(InvalidNonceSize));
638 }
639 if ciphertext.len() as u64 > A::MAX_CIPHERTEXT_SIZE {
642 return Err(OpenError::CiphertextTooLong);
643 }
644 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
645 return Err(OpenError::AdditionalDataTooLong);
646 }
647 Ok(())
648}
649
650pub const fn check_open_in_place_params<A: Aead + ?Sized>(
653 nonce: &[u8],
654 data: &[u8],
655 overhead: &[u8],
656 additional_data: &[u8],
657) -> Result<(), OpenError> {
658 check_aead_params::<A>();
659
660 if nonce.len() != A::NONCE_SIZE {
661 return Err(OpenError::InvalidNonceSize(InvalidNonceSize));
662 }
663 let Some(max_len) = A::MAX_PLAINTEXT_SIZE.checked_sub(A::OVERHEAD as u64) else {
664 return Err(OpenError::Other(
665 "implementation bug: `Aead::MAX_PLAINTEXT_SIZE < Aead::OVERHEAD`",
666 ));
667 };
668 if data.len() as u64 > max_len {
669 return Err(OpenError::PlaintextTooLong);
670 }
671 if overhead.len() > A::OVERHEAD {
672 return Err(OpenError::InvalidOverheadSize);
673 }
674 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
675 return Err(OpenError::AdditionalDataTooLong);
676 }
677 Ok(())
678}
679
680raw_key! {
681 pub AeadKey,
683}
684
685impl<N: ArrayLength> AeadKey<N> {
686 pub(crate) fn as_array<const U: usize>(&self) -> &[u8; U]
688 where
689 Const<U>: IntoArrayLength<ArrayLength = N>,
690 {
691 self.0.as_array()
692 }
693}
694
695#[derive(Clone, Default, Hash, Eq, PartialEq, Serialize, Deserialize)]
697#[repr(transparent)]
698#[serde(bound = "")]
699#[serde(transparent)]
700pub struct Nonce<N: ArrayLength>(GenericArray<u8, N>);
701
702impl<N: ArrayLength> Nonce<N> {
703 pub const SIZE: usize = N::USIZE;
705
706 #[inline]
708 #[allow(clippy::len_without_is_empty)]
709 pub const fn len(&self) -> usize {
710 Self::SIZE
711 }
712
713 pub(crate) const fn from_bytes(nonce: GenericArray<u8, N>) -> Self {
714 Self(nonce)
715 }
716
717 pub(crate) fn try_from_slice(data: &[u8]) -> Result<Self, InvalidNonceSize> {
718 let nonce = GenericArray::try_from_slice(data).map_err(|_| InvalidNonceSize)?;
719 Ok(Self(nonce.clone()))
720 }
721}
722
723impl<N: ArrayLength> Copy for Nonce<N> where N::ArrayType<u8>: Copy {}
724
725impl<N: ArrayLength> Debug for Nonce<N> {
726 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
727 f.debug_tuple("Nonce").field(&self.0).finish()
728 }
729}
730
731impl<N: ArrayLength> Deref for Nonce<N> {
732 type Target = [u8];
733
734 #[inline]
735 fn deref(&self) -> &Self::Target {
736 &self.0
737 }
738}
739
740impl<N: ArrayLength> DerefMut for Nonce<N> {
741 #[inline]
742 fn deref_mut(&mut self) -> &mut Self::Target {
743 &mut self.0
744 }
745}
746
747impl<N: ArrayLength> BitXor for Nonce<N> {
748 type Output = Self;
749
750 #[inline]
751 fn bitxor(mut self, rhs: Self) -> Self::Output {
752 for (x, y) in self.0.iter_mut().zip(&rhs.0) {
753 *x ^= y;
754 }
755 self
756 }
757}
758
759impl<N: ArrayLength> BitXor for &Nonce<N> {
760 type Output = Nonce<N>;
761
762 #[inline]
763 fn bitxor(self, rhs: Self) -> Self::Output {
764 let mut lhs = self.clone();
765 for (x, y) in lhs.0.iter_mut().zip(&rhs.0) {
766 *x ^= y;
767 }
768 lhs
769 }
770}
771
772impl<N: ArrayLength> ConstantTimeEq for Nonce<N> {
773 #[inline]
774 fn ct_eq(&self, other: &Self) -> Choice {
775 self.0.ct_eq(&other.0)
776 }
777}
778
779impl<N: ArrayLength> Random for Nonce<N> {
780 fn random<R: Csprng>(rng: &mut R) -> Self {
781 Self(Random::random(rng))
782 }
783}
784
785impl<N: ArrayLength> Expand for Nonce<N>
786where
787 N: IsLess<U65536>,
788{
789 type Size = N;
790
791 fn expand_multi<'a, K, I>(prk: &Prk<K::PrkSize>, info: I) -> Result<Self, KdfError>
792 where
793 K: Kdf,
794 I: IntoIterator<Item = &'a [u8]>,
795 I::IntoIter: Clone,
796 {
797 Ok(Self(Expand::expand_multi::<K, I>(prk, info)?))
798 }
799}
800
801impl<N: ArrayLength> TryFrom<&[u8]> for Nonce<N> {
802 type Error = InvalidNonceSize;
803
804 fn try_from(data: &[u8]) -> Result<Self, InvalidNonceSize> {
805 Self::try_from_slice(data)
806 }
807}
808
809pub trait IndCca2: Aead {}
812
813pub trait CommittingAead: Aead {}
815
816pub trait Cmt1Aead: CommittingAead {}
820
821pub trait Cmt3Aead: Cmt1Aead {}
826
827pub trait Cmt4Aead: Cmt3Aead {}
832
833#[cfg(feature = "committing-aead")]
834mod committing {
835 use core::{fmt, marker::PhantomData, num::NonZeroU64, result::Result};
836
837 use buggy::{Bug, BugExt};
838 use generic_array::{ArrayLength, GenericArray};
839 use typenum::{
840 type_operators::{IsGreaterOrEqual, IsLess},
841 Unsigned, U16, U65536,
842 };
843
844 use super::{Aead, KeyData, Nonce, OpenError, SealError};
845 use crate::import::{ExportError, ImportError};
846
847 #[doc(hidden)]
849 pub trait BlockCipher {
850 type BlockSize: ArrayLength + IsGreaterOrEqual<U16> + IsLess<U65536> + 'static;
852 const BLOCK_SIZE: usize = Self::BlockSize::USIZE;
854 type Key;
856
857 fn new(key: &Self::Key) -> Self;
859 fn encrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>);
861 }
862
863 #[doc(hidden)]
868 pub struct CtrThenXorPrf<A, C> {
869 _aead: PhantomData<A>,
870 _cipher: PhantomData<C>,
871 }
872
873 impl<A, C> CtrThenXorPrf<A, C>
874 where
875 A: Aead,
876 C: BlockCipher<Key = A::Key>,
877 A::NonceSize: IsLess<C::BlockSize>,
880 GenericArray<u8, C::BlockSize>: Clone,
881 {
882 #[inline]
885 #[allow(clippy::type_complexity)] pub fn commit(
887 key: &A::Key,
888 nonce: &Nonce<A::NonceSize>,
889 ) -> Result<(GenericArray<u8, C::BlockSize>, KeyData<A>), Bug> {
890 let mut cx = Default::default();
891 let key = Self::commit_into(&mut cx, key, nonce)?;
892 Ok((cx, key))
893 }
894
895 pub fn commit_into(
898 cx: &mut GenericArray<u8, C::BlockSize>,
899 key: &A::Key,
900 nonce: &Nonce<A::NonceSize>,
901 ) -> Result<KeyData<A>, Bug> {
902 #[inline(always)]
909 fn pad<C: BlockCipher>(
910 m: &[u8],
911 i: NonZeroU64,
912 ) -> Result<GenericArray<u8, C::BlockSize>, Bug> {
913 debug_assert!(m.len() < C::BlockSize::USIZE);
916
917 let mut b = GenericArray::<u8, C::BlockSize>::default();
918 b[..m.len()].copy_from_slice(m);
919 let x = i.get().to_le_bytes();
920 let n = usize::checked_sub(b.len(), m.len())
921 .assume("nonce size <= block size")?
922 .min(x.len());
923 b[m.len()..].copy_from_slice(&x[..n]);
924 Ok(b)
925 }
926
927 let mut i = NonZeroU64::MIN;
928 let cipher = C::new(key);
929 let nonce = nonce.as_ref();
930
931 let v_1 = {
932 let x_1 = pad::<C>(nonce, i)?;
934
935 let mut v_1 = {
937 let mut tmp = x_1.clone();
940 cipher.encrypt_block(&mut tmp);
941 tmp
942 };
943
944 for (v, x) in v_1.iter_mut().zip(x_1.iter()) {
946 *v ^= x;
947 }
948 v_1
949 };
950 cx.copy_from_slice(&v_1);
951
952 let mut key = KeyData::<A>::default();
953 for chunk in key.as_bytes_mut().chunks_mut(C::BLOCK_SIZE) {
954 i = i
955 .checked_add(1)
956 .assume("should be impossible to overflow")?;
960
961 let v_i = {
963 let mut x_i = pad::<C>(nonce, i)?;
965 cipher.encrypt_block(&mut x_i);
966 x_i
967 };
968 chunk.copy_from_slice(&v_i[..chunk.len()]);
969 }
970 Ok(key)
971 }
972 }
973
974 #[derive(Debug, Eq, PartialEq)]
976 pub enum UtcError {
977 Bug(Bug),
979 Import(ImportError),
981 }
982
983 impl UtcError {
984 const fn as_str(&self) -> &'static str {
985 match self {
986 Self::Bug(_) => "bug",
987 Self::Import(_) => "unable to import HtE transformed key",
988 }
989 }
990 }
991
992 impl fmt::Display for UtcError {
993 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
994 match self {
995 Self::Bug(err) => write!(f, "{}: {err}", self.as_str()),
996 Self::Import(err) => write!(f, "{}: {err}", self.as_str()),
997 }
998 }
999 }
1000
1001 impl core::error::Error for UtcError {
1002 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1003 match self {
1004 Self::Bug(err) => Some(err),
1005 Self::Import(err) => Some(err),
1006 }
1007 }
1008 }
1009
1010 impl From<Bug> for UtcError {
1011 fn from(err: Bug) -> Self {
1012 Self::Bug(err)
1013 }
1014 }
1015
1016 impl From<ImportError> for UtcError {
1017 fn from(err: ImportError) -> Self {
1018 Self::Import(err)
1019 }
1020 }
1021
1022 impl From<UtcError> for SealError {
1023 fn from(err: UtcError) -> SealError {
1024 SealError::Other(err.as_str())
1025 }
1026 }
1027
1028 impl From<UtcError> for OpenError {
1029 fn from(err: UtcError) -> OpenError {
1030 OpenError::Other(err.as_str())
1031 }
1032 }
1033
1034 #[cfg_attr(feature = "committing-aead", macro_export)]
1058 #[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
1059 macro_rules! utc_aead {
1060 ($name:ident, $inner:ty, $cipher:ty, $doc:expr) => {
1061 #[doc = $doc]
1062 pub struct $name {
1063 key: <$inner as $crate::aead::Aead>::Key,
1064 }
1065
1066 impl $name {
1067 const COMMITMENT_SIZE: usize = <<$cipher as $crate::aead::BlockCipher>::BlockSize as
1068 $crate::typenum::Unsigned>::USIZE;
1069 }
1070
1071 impl $crate::aead::CommittingAead for $name {}
1072
1073 impl $crate::aead::Cmt1Aead for $name {}
1074
1075 impl $crate::aead::Aead for $name {
1076 const ID: $crate::aead::AeadId = $crate::aead::AeadId::$name;
1077 const LIFETIME: $crate::aead::Lifetime = <$inner as $crate::aead::Aead>::LIFETIME;
1078
1079 type KeySize = <$inner as $crate::aead::Aead>::KeySize;
1080 type NonceSize = <$inner as $crate::aead::Aead>::NonceSize;
1081 type Overhead = $crate::typenum::Sum<
1082 <$inner as $crate::aead::Aead>::Overhead,
1083 <$cipher as $crate::aead::BlockCipher>::BlockSize,
1085 >;
1086
1087 const MAX_PLAINTEXT_SIZE: u64 = <$inner as $crate::aead::Aead>::MAX_PLAINTEXT_SIZE;
1088 const MAX_ADDITIONAL_DATA_SIZE: u64 =
1089 <$inner as $crate::aead::Aead>::MAX_ADDITIONAL_DATA_SIZE;
1090
1091 type Key = <$inner as $crate::aead::Aead>::Key;
1092
1093 #[inline]
1094 fn new(key: &Self::Key) -> Self {
1095 Self { key: key.clone() }
1096 }
1097
1098 fn seal(
1099 &self,
1100 mut dst: &mut [u8],
1101 nonce: &[u8],
1102 plaintext: &[u8],
1103 additional_data: &[u8],
1104 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1105 $crate::aead::check_seal_params::<Self>(
1106 &mut dst,
1107 nonce,
1108 plaintext,
1109 additional_data,
1110 )?;
1111
1112 let (dst, cx) = $crate::buggy::BugExt::assume(
1113 dst.split_last_chunk_mut::<{Self::COMMITMENT_SIZE}>(),
1114 "`COMMITMENT_SIZE` fits in `out`",
1115 )?;
1116 let key_bytes = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit_into(
1117 cx.into(),
1118 &self.key,
1119 &nonce.try_into()?,
1120 )?;
1121 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1122 .map_err($crate::aead::UtcError::Import)?;
1123 <$inner as $crate::aead::Aead>::new(&key).seal(
1124 dst,
1125 nonce,
1126 plaintext,
1127 additional_data,
1128 )
1129 }
1130
1131 fn seal_in_place(
1132 &self,
1133 nonce: &[u8],
1134 data: &mut [u8],
1135 overhead: &mut [u8],
1136 additional_data: &[u8],
1137 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1138 $crate::aead::check_seal_in_place_params::<Self>(
1139 nonce,
1140 data,
1141 overhead,
1142 additional_data,
1143 )?;
1144
1145 let (tag, cx) = $crate::buggy::BugExt::assume(
1146 overhead.split_last_chunk_mut::<{Self::COMMITMENT_SIZE}>(),
1147 "`COMMITMENT_SIZE` fits in `overhead`",
1148 )?;
1149 let key_bytes = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit_into(
1150 cx.into(),
1151 &self.key,
1152 &nonce.try_into()?,
1153 )?;
1154 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1155 .map_err($crate::aead::UtcError::Import)?;
1156 <$inner as $crate::aead::Aead>::new(&key).seal_in_place(
1157 nonce,
1158 data,
1159 tag,
1160 additional_data,
1161 )
1162 }
1163
1164 fn open(
1165 &self,
1166 dst: &mut [u8],
1167 nonce: &[u8],
1168 ciphertext: &[u8],
1169 additional_data: &[u8],
1170 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1171 $crate::aead::check_open_params::<Self>(
1172 dst,
1173 nonce,
1174 ciphertext,
1175 additional_data,
1176 )?;
1177
1178 let (ciphertext, got_cx) = $crate::buggy::BugExt::assume(
1179 ciphertext.split_last_chunk::<{Self::COMMITMENT_SIZE}>(),
1180 "`COMMITMENT_SIZE` fits in `ciphertext`",
1181 )?;
1182 let (want_cx, key_bytes) = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit(
1183 &self.key,
1184 &nonce.try_into()?,
1185 )?;
1186 if !bool::from($crate::subtle::ConstantTimeEq::ct_eq(
1187 want_cx.as_slice(),
1188 got_cx,
1189 )) {
1190 Err($crate::aead::OpenError::Authentication)
1191 } else {
1192 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1193 .map_err($crate::aead::UtcError::Import)?;
1194 <$inner as $crate::aead::Aead>::new(&key).open(
1195 dst,
1196 nonce,
1197 ciphertext,
1198 additional_data,
1199 )
1200 }
1201 }
1202
1203 fn open_in_place(
1204 &self,
1205 nonce: &[u8],
1206 data: &mut [u8],
1207 overhead: &[u8],
1208 additional_data: &[u8],
1209 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1210 $crate::aead::check_open_in_place_params::<Self>(
1211 nonce,
1212 data,
1213 overhead,
1214 additional_data,
1215 )?;
1216
1217 let (overhead, got_cx) = $crate::buggy::BugExt::assume(
1218 overhead.split_last_chunk::<{Self::COMMITMENT_SIZE}>(),
1219 "`COMMITMENT_SIZE` fits in `overhead`",
1220 )?;
1221 let (want_cx, key_bytes) = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit(
1222 &self.key,
1223 &nonce.try_into()?,
1224 )?;
1225 if !bool::from($crate::subtle::ConstantTimeEq::ct_eq(
1226 want_cx.as_slice(),
1227 got_cx,
1228 )) {
1229 Err($crate::aead::OpenError::Authentication)
1230 } else {
1231 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1232 .map_err($crate::aead::UtcError::Import)?;
1233 <$inner as $crate::aead::Aead>::new(&key).open_in_place(
1234 nonce,
1235 data,
1236 overhead,
1237 additional_data,
1238 )
1239 }
1240 }
1241 }
1242 };
1243 }
1244 pub(crate) use utc_aead;
1245
1246 #[derive(Debug, Eq, PartialEq)]
1248 pub enum HteError {
1249 Export(ExportError),
1251 Import(ImportError),
1253 }
1254
1255 impl HteError {
1256 const fn as_str(&self) -> &'static str {
1257 match self {
1258 Self::Export(_) => "unable to export inner secret key",
1259 Self::Import(_) => "unable to import HtE transformed key",
1260 }
1261 }
1262 }
1263
1264 impl fmt::Display for HteError {
1265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1266 match self {
1267 Self::Export(err) => write!(f, "{}: {err}", self.as_str()),
1268 Self::Import(err) => write!(f, "{}: {err}", self.as_str()),
1269 }
1270 }
1271 }
1272
1273 impl core::error::Error for HteError {
1274 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1275 match self {
1276 Self::Export(err) => Some(err),
1277 Self::Import(err) => Some(err),
1278 }
1279 }
1280 }
1281
1282 impl From<ExportError> for HteError {
1283 fn from(err: ExportError) -> Self {
1284 Self::Export(err)
1285 }
1286 }
1287
1288 impl From<ImportError> for HteError {
1289 fn from(err: ImportError) -> Self {
1290 Self::Import(err)
1291 }
1292 }
1293
1294 impl From<HteError> for SealError {
1295 fn from(err: HteError) -> SealError {
1296 SealError::Other(err.as_str())
1297 }
1298 }
1299
1300 impl From<HteError> for OpenError {
1301 fn from(err: HteError) -> OpenError {
1302 OpenError::Other(err.as_str())
1303 }
1304 }
1305
1306 #[cfg_attr(feature = "committing-aead", macro_export)]
1330 #[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
1331 macro_rules! hte_aead {
1332 ($name:ident, $inner:ty, $hash:ty, $doc:expr) => {
1333 #[doc = $doc]
1334 pub struct $name {
1335 key: <$inner as $crate::aead::Aead>::Key,
1336 }
1337
1338 impl $name {
1339 fn hash(
1340 &self,
1341 nonce: &[u8],
1342 ad: &[u8],
1343 ) -> ::core::result::Result<
1344 <$inner as $crate::aead::Aead>::Key,
1345 $crate::aead::HteError,
1346 > {
1347 let tag = {
1350 let key = $crate::keys::SecretKey::try_export_secret(&self.key)?;
1351 let mut hmac = $crate::hmac::Hmac::<$hash>::new(key.as_bytes());
1352 hmac.update(nonce);
1353 hmac.update(ad);
1354 hmac.tag()
1355 };
1356 let mut key_bytes = $crate::generic_array::GenericArray::<
1357 u8,
1358 <<$inner as $crate::aead::Aead>::Key as $crate::keys::SecretKey>::Size,
1359 >::default();
1360 let k = ::core::cmp::min(tag.len(), key_bytes.as_slice().len());
1361 key_bytes
1362 .as_mut_slice()
1363 .copy_from_slice(&tag.as_bytes()[..k]);
1364 let key =
1365 <<$inner as $crate::aead::Aead>::Key as $crate::import::Import<_>>::import(
1366 key_bytes.as_slice(),
1367 )?;
1368 Ok(key)
1369 }
1370 }
1371
1372 impl $crate::aead::CommittingAead for $name where $inner: $crate::aead::Cmt1Aead {}
1375
1376 impl $crate::aead::Cmt1Aead for $name {}
1377
1378 impl $crate::aead::Cmt3Aead for $name {}
1379
1380 impl $crate::aead::Cmt4Aead for $name where $inner: $crate::aead::Cmt1Aead {}
1381
1382 impl $crate::aead::Aead for $name {
1383 const ID: $crate::aead::AeadId = $crate::aead::AeadId::$name;
1384 const LIFETIME: $crate::aead::Lifetime = <$inner as $crate::aead::Aead>::LIFETIME;
1385
1386 type KeySize = <$inner as $crate::aead::Aead>::KeySize;
1387 type NonceSize = <$inner as $crate::aead::Aead>::NonceSize;
1388 type Overhead = <$inner as $crate::aead::Aead>::Overhead;
1390
1391 const MAX_PLAINTEXT_SIZE: u64 = <$inner as $crate::aead::Aead>::MAX_PLAINTEXT_SIZE;
1392 const MAX_ADDITIONAL_DATA_SIZE: u64 =
1393 <$inner as $crate::aead::Aead>::MAX_ADDITIONAL_DATA_SIZE;
1394
1395 type Key = <$inner as $crate::aead::Aead>::Key;
1396
1397 #[inline]
1398 fn new(key: &Self::Key) -> Self {
1399 Self { key: key.clone() }
1400 }
1401
1402 fn seal(
1403 &self,
1404 mut dst: &mut [u8],
1405 nonce: &[u8],
1406 plaintext: &[u8],
1407 additional_data: &[u8],
1408 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1409 $crate::aead::check_seal_params::<Self>(
1410 &mut dst,
1411 nonce,
1412 plaintext,
1413 additional_data,
1414 )?;
1415
1416 let key = self.hash(nonce, additional_data)?;
1417 <$inner as $crate::aead::Aead>::new(&key).seal(
1418 dst,
1419 nonce,
1420 plaintext,
1421 additional_data,
1422 )
1423 }
1424
1425 fn seal_in_place(
1426 &self,
1427 nonce: &[u8],
1428 data: &mut [u8],
1429 overhead: &mut [u8],
1430 additional_data: &[u8],
1431 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1432 $crate::aead::check_seal_in_place_params::<Self>(
1433 nonce,
1434 data,
1435 overhead,
1436 additional_data,
1437 )?;
1438
1439 let key = self.hash(nonce, additional_data)?;
1440 <$inner as $crate::aead::Aead>::new(&key).seal_in_place(
1441 nonce,
1442 data,
1443 overhead,
1444 additional_data,
1445 )
1446 }
1447
1448 fn open(
1449 &self,
1450 dst: &mut [u8],
1451 nonce: &[u8],
1452 ciphertext: &[u8],
1453 additional_data: &[u8],
1454 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1455 $crate::aead::check_open_params::<Self>(
1456 dst,
1457 nonce,
1458 ciphertext,
1459 additional_data,
1460 )?;
1461
1462 let key = self.hash(nonce, additional_data)?;
1463 <$inner as $crate::aead::Aead>::new(&key).open(
1464 dst,
1465 nonce,
1466 ciphertext,
1467 additional_data,
1468 )
1469 }
1470
1471 fn open_in_place(
1472 &self,
1473 nonce: &[u8],
1474 data: &mut [u8],
1475 overhead: &[u8],
1476 additional_data: &[u8],
1477 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1478 $crate::aead::check_open_in_place_params::<Self>(
1479 nonce,
1480 data,
1481 overhead,
1482 additional_data,
1483 )?;
1484
1485 let key = self.hash(nonce, additional_data)?;
1486 <$inner as $crate::aead::Aead>::new(&key).open_in_place(
1487 nonce,
1488 data,
1489 overhead,
1490 additional_data,
1491 )
1492 }
1493 }
1494 };
1495 }
1496 pub(crate) use hte_aead;
1497}
1498#[cfg(feature = "committing-aead")]
1499#[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
1500pub use committing::*;