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 subtle::{Choice, ConstantTimeEq};
18use typenum::{
19 generic_const_mappings::Const,
20 type_operators::{IsGreaterOrEqual, IsLess},
21 Unsigned, U16, U65536,
22};
23
24use crate::{
25 csprng::{Csprng, Random},
26 kdf::{Expand, Kdf, KdfError, Prk},
27 keys::{raw_key, SecretKey, SecretKeyBytes},
28 util::const_assert,
29 zeroize::Zeroize,
30};
31
32const_assert!(size_of::<usize>() >= 4);
36
37#[derive(Copy, Clone, Debug, Eq, PartialEq)]
42pub struct BufferTooSmallError(pub Option<usize>);
43
44impl BufferTooSmallError {
45 pub const fn as_str(&self) -> &'static str {
47 "dest buffer too small"
48 }
49}
50
51impl fmt::Display for BufferTooSmallError {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 if let Some(n) = self.0 {
54 write!(f, "{} (need {})", self.as_str(), n)
55 } else {
56 write!(f, "{}", self.as_str())
57 }
58 }
59}
60
61impl core::error::Error for BufferTooSmallError {}
62
63#[derive(Copy, Clone, Debug, Eq, PartialEq)]
65pub struct InvalidNonceSize;
66
67impl InvalidNonceSize {
68 pub const fn as_str(&self) -> &'static str {
70 "nonce size is invalid"
71 }
72}
73
74impl fmt::Display for InvalidNonceSize {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 write!(f, "{}", self.as_str())
77 }
78}
79
80impl core::error::Error for InvalidNonceSize {}
81
82#[derive(Debug, Eq, PartialEq)]
84pub enum SealError {
85 Bug(Bug),
87 Other(&'static str),
89 InvalidKeySize,
91 InvalidNonceSize(InvalidNonceSize),
93 InvalidOverheadSize,
95 PlaintextTooLong,
97 AdditionalDataTooLong,
99 BufferTooSmall(BufferTooSmallError),
101 Encryption,
103}
104
105impl SealError {
106 pub fn as_str(&self) -> &'static str {
108 match self {
109 Self::Bug(err) => err.msg(),
110 Self::Other(msg) => msg,
111 Self::InvalidKeySize => "invalid key size",
112 Self::InvalidNonceSize(err) => err.as_str(),
113 Self::InvalidOverheadSize => "invalid overhead size",
114 Self::PlaintextTooLong => "plaintext too long",
115 Self::AdditionalDataTooLong => "additional data too long",
116 Self::Encryption => "encryption error",
117 Self::BufferTooSmall(err) => err.as_str(),
118 }
119 }
120}
121
122impl fmt::Display for SealError {
123 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
124 match self {
125 Self::Bug(err) => write!(f, "{}", err),
126 Self::BufferTooSmall(err) => write!(f, "{}", err),
127 Self::InvalidNonceSize(err) => write!(f, "{}", err),
128 _ => write!(f, "{}", self.as_str()),
129 }
130 }
131}
132
133impl core::error::Error for SealError {
134 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
135 match self {
136 Self::Bug(err) => Some(err),
137 Self::BufferTooSmall(err) => Some(err),
138 Self::InvalidNonceSize(err) => Some(err),
139 _ => None,
140 }
141 }
142}
143
144impl From<BufferTooSmallError> for SealError {
145 fn from(value: BufferTooSmallError) -> Self {
146 SealError::BufferTooSmall(value)
147 }
148}
149
150impl From<Bug> for SealError {
151 fn from(value: Bug) -> Self {
152 SealError::Bug(value)
153 }
154}
155
156impl From<InvalidNonceSize> for SealError {
157 fn from(value: InvalidNonceSize) -> Self {
158 SealError::InvalidNonceSize(value)
159 }
160}
161
162#[derive(Debug, Eq, PartialEq)]
164pub enum OpenError {
165 Bug(Bug),
167 Other(&'static str),
169 InvalidKeySize,
171 InvalidNonceSize(InvalidNonceSize),
173 InvalidOverheadSize,
175 PlaintextTooLong,
177 CiphertextTooLong,
179 AdditionalDataTooLong,
181 BufferTooSmall(BufferTooSmallError),
183 Authentication,
185}
186
187impl OpenError {
188 pub fn as_str(&self) -> &'static str {
190 match self {
191 Self::Bug(err) => err.msg(),
192 Self::Other(msg) => msg,
193 Self::InvalidKeySize => "invalid key size",
194 Self::InvalidNonceSize(err) => err.as_str(),
195 Self::InvalidOverheadSize => "invalid overhead size",
196 Self::PlaintextTooLong => "plaintext too long",
197 Self::CiphertextTooLong => "ciphertext too long",
198 Self::AdditionalDataTooLong => "additional data too long",
199 Self::Authentication => "authentication error",
200 Self::BufferTooSmall(err) => err.as_str(),
201 }
202 }
203}
204
205impl fmt::Display for OpenError {
206 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207 match self {
208 Self::Bug(err) => write!(f, "{}", err),
209 Self::BufferTooSmall(err) => write!(f, "{}", err),
210 Self::InvalidNonceSize(err) => write!(f, "{}", err),
211 _ => write!(f, "{}", self.as_str()),
212 }
213 }
214}
215
216impl core::error::Error for OpenError {
217 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
218 match self {
219 Self::Bug(err) => Some(err),
220 Self::BufferTooSmall(err) => Some(err),
221 Self::InvalidNonceSize(err) => Some(err),
222 _ => None,
223 }
224 }
225}
226
227impl From<BufferTooSmallError> for OpenError {
228 fn from(value: BufferTooSmallError) -> Self {
229 OpenError::BufferTooSmall(value)
230 }
231}
232
233impl From<Bug> for OpenError {
234 fn from(value: Bug) -> Self {
235 OpenError::Bug(value)
236 }
237}
238
239impl From<InvalidNonceSize> for OpenError {
240 fn from(value: InvalidNonceSize) -> Self {
241 OpenError::InvalidNonceSize(value)
242 }
243}
244
245#[derive(Copy, Clone, Debug, Eq, PartialEq)]
266pub enum Lifetime {
267 Unlimited,
270 Messages(u64),
275 Bytes(u64),
277}
278
279impl Lifetime {
280 const fn as_u64(self) -> u64 {
281 match self {
282 Self::Unlimited => u64::MAX,
283 Self::Messages(x) => x,
284 Self::Bytes(x) => x,
285 }
286 }
287
288 #[inline]
291 #[must_use]
292 pub fn consume(self, bytes: u64) -> Option<Self> {
293 match self {
294 Self::Unlimited => Some(Self::Unlimited),
295 Self::Messages(x) => x.checked_sub(1).map(Self::Messages),
296 Self::Bytes(x) => x.checked_sub(bytes).map(Self::Bytes),
297 }
298 }
299
300 #[inline]
303 #[must_use]
304 pub fn consume_mut(&mut self, bytes: u64) -> bool {
305 self.consume(bytes).inspect(|v| *self = *v).is_some()
306 }
307}
308
309impl PartialEq<u64> for Lifetime {
310 fn eq(&self, other: &u64) -> bool {
311 self.as_u64() == *other
312 }
313}
314
315pub trait Aead {
355 const LIFETIME: Lifetime;
357
358 type KeySize: ArrayLength + IsGreaterOrEqual<U16> + IsLess<U65536> + 'static;
362 const KEY_SIZE: usize = Self::KeySize::USIZE;
364
365 type NonceSize: ArrayLength + IsLess<U65536> + 'static;
369 const NONCE_SIZE: usize = Self::NonceSize::USIZE;
371
372 type Overhead: ArrayLength + IsGreaterOrEqual<U16> + 'static;
381 const OVERHEAD: usize = Self::Overhead::USIZE;
383
384 const MAX_PLAINTEXT_SIZE: u64;
389 const MAX_ADDITIONAL_DATA_SIZE: u64;
394 const MAX_CIPHERTEXT_SIZE: u64 =
401 match Self::MAX_PLAINTEXT_SIZE.checked_add(Self::OVERHEAD as u64) {
402 Some(n) => n,
403 None => panic!("overflow"),
404 };
405
406 type Key: SecretKey<Size = Self::KeySize>;
408
409 fn new(key: &Self::Key) -> Self;
411
412 fn seal(
432 &self,
433 mut dst: &mut [u8],
434 nonce: &[u8],
435 plaintext: &[u8],
436 additional_data: &[u8],
437 ) -> Result<(), SealError> {
438 check_seal_params::<Self>(&mut dst, nonce, plaintext, additional_data)?;
439 dst[..plaintext.len()].copy_from_slice(plaintext);
440 let tag_idx = dst
441 .len()
442 .checked_sub(Self::OVERHEAD)
443 .assume("out length must be >= overhead")?;
444 let (dst, overhead) = dst.split_at_mut(tag_idx);
445 self.seal_in_place(nonce, dst, overhead, additional_data)
446 .inspect_err(|_| dst.zeroize())
449 }
450
451 fn seal_in_place(
469 &self,
470 nonce: &[u8],
471 data: &mut [u8],
472 overhead: &mut [u8],
473 additional_data: &[u8],
474 ) -> Result<(), SealError>;
475
476 fn open(
493 &self,
494 dst: &mut [u8],
495 nonce: &[u8],
496 ciphertext: &[u8],
497 additional_data: &[u8],
498 ) -> Result<(), OpenError> {
499 check_open_params::<Self>(dst, nonce, ciphertext, additional_data)?;
500
501 let max = ciphertext.len().checked_sub(Self::OVERHEAD).assume(
502 "`ciphertext.len() >= Self::OVERHEAD` should be enforced by `check_open_params`",
503 )?;
504 let (ciphertext, overhead) = ciphertext.split_at(max);
505 let out = &mut dst[..max];
506 out.copy_from_slice(ciphertext);
507 self.open_in_place(nonce, out, overhead, additional_data)
508 .inspect_err(|_| out.zeroize())
511 }
512
513 fn open_in_place(
526 &self,
527 nonce: &[u8],
528 data: &mut [u8],
529 overhead: &[u8],
530 additional_data: &[u8],
531 ) -> Result<(), OpenError>;
532}
533
534pub type KeyData<A> = SecretKeyBytes<<<A as Aead>::Key as SecretKey>::Size>;
537
538pub type Tag<A> = GenericArray<u8, <A as Aead>::Overhead>;
540
541const fn check_aead_params<A: Aead + ?Sized>() {
542 const {
543 assert!(A::KEY_SIZE >= 16);
544 assert!(A::OVERHEAD >= 16);
545 assert!(A::MAX_PLAINTEXT_SIZE >= u32::MAX as u64);
546 assert!(A::MAX_CIPHERTEXT_SIZE == A::MAX_PLAINTEXT_SIZE + (A::OVERHEAD as u64));
547 assert!(A::MAX_ADDITIONAL_DATA_SIZE >= u32::MAX as u64);
548 }
549}
550
551pub fn check_seal_params<A: Aead + ?Sized>(
556 dst: &mut &mut [u8],
557 nonce: &[u8],
558 plaintext: &[u8],
559 additional_data: &[u8],
560) -> Result<(), SealError> {
561 check_aead_params::<A>();
562
563 let need = match plaintext.len().checked_add(A::OVERHEAD) {
564 None => return Err(SealError::PlaintextTooLong),
566 Some(n) => n,
567 };
568 if need > dst.len() {
569 return Err(SealError::BufferTooSmall(BufferTooSmallError(Some(need))));
570 }
571 *dst = &mut mem::take(dst)[..need];
572
573 if nonce.len() != A::NONCE_SIZE {
574 return Err(SealError::InvalidNonceSize(InvalidNonceSize));
575 }
576 if plaintext.len() as u64 > A::MAX_PLAINTEXT_SIZE {
577 return Err(SealError::PlaintextTooLong);
578 }
579 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
580 return Err(SealError::AdditionalDataTooLong);
581 }
582
583 Ok(())
584}
585
586pub const fn check_seal_in_place_params<A: Aead + ?Sized>(
589 nonce: &[u8],
590 data: &[u8],
591 overhead: &[u8],
592 additional_data: &[u8],
593) -> Result<(), SealError> {
594 check_aead_params::<A>();
595
596 if nonce.len() != A::NONCE_SIZE {
597 return Err(SealError::InvalidNonceSize(InvalidNonceSize));
598 }
599 if data.len() as u64 > A::MAX_PLAINTEXT_SIZE {
600 return Err(SealError::PlaintextTooLong);
601 }
602 if overhead.len() > A::OVERHEAD {
603 return Err(SealError::InvalidOverheadSize);
604 }
605 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
606 return Err(SealError::AdditionalDataTooLong);
607 }
608 Ok(())
609}
610
611pub const fn check_open_params<A: Aead + ?Sized>(
614 dst: &[u8],
615 nonce: &[u8],
616 ciphertext: &[u8],
617 additional_data: &[u8],
618) -> Result<(), OpenError> {
619 check_aead_params::<A>();
620
621 let need = match ciphertext.len().checked_sub(A::OVERHEAD) {
622 None => return Err(OpenError::Authentication),
625 Some(n) => n,
626 };
627 if need > dst.len() {
628 return Err(OpenError::BufferTooSmall(BufferTooSmallError(Some(need))));
629 }
630 if nonce.len() != A::NONCE_SIZE {
631 return Err(OpenError::InvalidNonceSize(InvalidNonceSize));
632 }
633 if ciphertext.len() as u64 > A::MAX_CIPHERTEXT_SIZE {
636 return Err(OpenError::CiphertextTooLong);
637 }
638 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
639 return Err(OpenError::AdditionalDataTooLong);
640 }
641 Ok(())
642}
643
644pub const fn check_open_in_place_params<A: Aead + ?Sized>(
647 nonce: &[u8],
648 data: &[u8],
649 overhead: &[u8],
650 additional_data: &[u8],
651) -> Result<(), OpenError> {
652 check_aead_params::<A>();
653
654 if nonce.len() != A::NONCE_SIZE {
655 return Err(OpenError::InvalidNonceSize(InvalidNonceSize));
656 }
657 let Some(max_len) = A::MAX_PLAINTEXT_SIZE.checked_sub(A::OVERHEAD as u64) else {
658 return Err(OpenError::Other(
659 "implementation bug: `Aead::MAX_PLAINTEXT_SIZE < Aead::OVERHEAD`",
660 ));
661 };
662 if data.len() as u64 > max_len {
663 return Err(OpenError::PlaintextTooLong);
664 }
665 if overhead.len() > A::OVERHEAD {
666 return Err(OpenError::InvalidOverheadSize);
667 }
668 if additional_data.len() as u64 > A::MAX_ADDITIONAL_DATA_SIZE {
669 return Err(OpenError::AdditionalDataTooLong);
670 }
671 Ok(())
672}
673
674raw_key! {
675 pub AeadKey,
677}
678
679impl<N: ArrayLength> AeadKey<N> {
680 pub(crate) fn as_array<const U: usize>(&self) -> &[u8; U]
682 where
683 Const<U>: IntoArrayLength<ArrayLength = N>,
684 {
685 self.0.as_array()
686 }
687}
688
689#[derive(Clone, Default, Hash, Eq, PartialEq)]
691#[repr(transparent)]
692pub struct Nonce<N: ArrayLength>(GenericArray<u8, N>);
693
694impl<N: ArrayLength> Nonce<N> {
695 pub const SIZE: usize = N::USIZE;
697
698 #[inline]
700 #[allow(clippy::len_without_is_empty)]
701 pub const fn len(&self) -> usize {
702 Self::SIZE
703 }
704
705 #[doc(hidden)]
707 pub fn into_inner(self) -> GenericArray<u8, N> {
708 self.0
709 }
710
711 pub(crate) const fn from_bytes(nonce: GenericArray<u8, N>) -> Self {
712 Self(nonce)
713 }
714
715 pub(crate) fn try_from_slice(data: &[u8]) -> Result<Self, InvalidNonceSize> {
716 let nonce = GenericArray::try_from_slice(data).map_err(|_| InvalidNonceSize)?;
717 Ok(Self(nonce.clone()))
718 }
719}
720
721impl<N: ArrayLength> Copy for Nonce<N> where N::ArrayType<u8>: Copy {}
722
723impl<N: ArrayLength> Debug for Nonce<N> {
724 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725 f.debug_tuple("Nonce").field(&self.0).finish()
726 }
727}
728
729impl<N: ArrayLength> Deref for Nonce<N> {
730 type Target = [u8];
731
732 #[inline]
733 fn deref(&self) -> &Self::Target {
734 &self.0
735 }
736}
737
738impl<N: ArrayLength> DerefMut for Nonce<N> {
739 #[inline]
740 fn deref_mut(&mut self) -> &mut Self::Target {
741 &mut self.0
742 }
743}
744
745impl<N: ArrayLength> BitXor for Nonce<N> {
746 type Output = Self;
747
748 #[inline]
749 fn bitxor(mut self, rhs: Self) -> Self::Output {
750 for (x, y) in self.0.iter_mut().zip(&rhs.0) {
751 *x ^= y;
752 }
753 self
754 }
755}
756
757impl<N: ArrayLength> BitXor for &Nonce<N> {
758 type Output = Nonce<N>;
759
760 #[inline]
761 fn bitxor(self, rhs: Self) -> Self::Output {
762 let mut lhs = self.clone();
763 for (x, y) in lhs.0.iter_mut().zip(&rhs.0) {
764 *x ^= y;
765 }
766 lhs
767 }
768}
769
770impl<N: ArrayLength> ConstantTimeEq for Nonce<N> {
771 #[inline]
772 fn ct_eq(&self, other: &Self) -> Choice {
773 self.0.ct_eq(&other.0)
774 }
775}
776
777impl<N: ArrayLength> Random for Nonce<N> {
778 fn random<R: Csprng>(rng: &mut R) -> Self {
779 Self(Random::random(rng))
780 }
781}
782
783impl<N: ArrayLength> Expand for Nonce<N>
784where
785 N: IsLess<U65536>,
786{
787 type Size = N;
788
789 fn expand_multi<'a, K, I>(prk: &Prk<K::PrkSize>, info: I) -> Result<Self, KdfError>
790 where
791 K: Kdf,
792 I: IntoIterator<Item = &'a [u8]>,
793 I::IntoIter: Clone,
794 {
795 Ok(Self(Expand::expand_multi::<K, I>(prk, info)?))
796 }
797}
798
799impl<N: ArrayLength> TryFrom<&[u8]> for Nonce<N> {
800 type Error = InvalidNonceSize;
801
802 fn try_from(data: &[u8]) -> Result<Self, InvalidNonceSize> {
803 Self::try_from_slice(data)
804 }
805}
806
807pub trait IndCca2: Aead {}
810
811pub trait CommittingAead: Aead {}
813
814pub trait Cmt1Aead: CommittingAead {}
818
819pub trait Cmt3Aead: Cmt1Aead {}
824
825pub trait Cmt4Aead: Cmt3Aead {}
830
831#[cfg(feature = "committing-aead")]
832mod committing {
833 use core::{fmt, marker::PhantomData, num::NonZeroU64, result::Result};
834
835 use buggy::{Bug, BugExt};
836 use generic_array::{ArrayLength, GenericArray};
837 use typenum::{
838 type_operators::{IsGreaterOrEqual, IsLess},
839 Unsigned, U16, U65536,
840 };
841
842 use super::{Aead, KeyData, Nonce, OpenError, SealError};
843 use crate::import::{ExportError, ImportError};
844
845 #[doc(hidden)]
847 pub trait BlockCipher {
848 type BlockSize: ArrayLength + IsGreaterOrEqual<U16> + IsLess<U65536> + 'static;
850 const BLOCK_SIZE: usize = Self::BlockSize::USIZE;
852 type Key;
854
855 fn new(key: &Self::Key) -> Self;
857 fn encrypt_block(&self, block: &mut GenericArray<u8, Self::BlockSize>);
859 }
860
861 #[doc(hidden)]
866 pub struct CtrThenXorPrf<A, C> {
867 _aead: PhantomData<fn() -> A>,
868 _cipher: PhantomData<fn() -> C>,
869 }
870
871 impl<A, C> CtrThenXorPrf<A, C>
872 where
873 A: Aead,
874 C: BlockCipher<Key = A::Key>,
875 A::NonceSize: IsLess<C::BlockSize>,
878 GenericArray<u8, C::BlockSize>: Clone,
879 {
880 #[inline]
883 #[allow(clippy::type_complexity)] pub fn commit(
885 key: &A::Key,
886 nonce: &Nonce<A::NonceSize>,
887 ) -> Result<(GenericArray<u8, C::BlockSize>, KeyData<A>), Bug> {
888 let mut cx = Default::default();
889 let key = Self::commit_into(&mut cx, key, nonce)?;
890 Ok((cx, key))
891 }
892
893 pub fn commit_into(
896 cx: &mut GenericArray<u8, C::BlockSize>,
897 key: &A::Key,
898 nonce: &Nonce<A::NonceSize>,
899 ) -> Result<KeyData<A>, Bug> {
900 #[inline(always)]
907 fn pad<C: BlockCipher>(
908 m: &[u8],
909 i: NonZeroU64,
910 ) -> Result<GenericArray<u8, C::BlockSize>, Bug> {
911 debug_assert!(m.len() < C::BlockSize::USIZE);
914
915 let mut b = GenericArray::<u8, C::BlockSize>::default();
916 b[..m.len()].copy_from_slice(m);
917 let x = i.get().to_le_bytes();
918 let n = usize::checked_sub(b.len(), m.len())
919 .assume("nonce size <= block size")?
920 .min(x.len());
921 b[m.len()..].copy_from_slice(&x[..n]);
922 Ok(b)
923 }
924
925 let mut i = NonZeroU64::MIN;
926 let cipher = C::new(key);
927 let nonce = nonce.as_ref();
928
929 let v_1 = {
930 let x_1 = pad::<C>(nonce, i)?;
932
933 let mut v_1 = {
935 let mut tmp = x_1.clone();
938 cipher.encrypt_block(&mut tmp);
939 tmp
940 };
941
942 for (v, x) in v_1.iter_mut().zip(x_1.iter()) {
944 *v ^= x;
945 }
946 v_1
947 };
948 cx.copy_from_slice(&v_1);
949
950 let mut key = KeyData::<A>::default();
951 for chunk in key.as_bytes_mut().chunks_mut(C::BLOCK_SIZE) {
952 i = i
953 .checked_add(1)
954 .assume("should be impossible to overflow")?;
958
959 let v_i = {
961 let mut x_i = pad::<C>(nonce, i)?;
963 cipher.encrypt_block(&mut x_i);
964 x_i
965 };
966 chunk.copy_from_slice(&v_i[..chunk.len()]);
967 }
968 Ok(key)
969 }
970 }
971
972 impl<A, C> fmt::Debug for CtrThenXorPrf<A, C> {
973 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
974 f.debug_struct("CtrThenXorPrf").finish_non_exhaustive()
975 }
976 }
977
978 #[derive(Debug, Eq, PartialEq)]
980 pub enum UtcError {
981 Bug(Bug),
983 Import(ImportError),
985 }
986
987 impl UtcError {
988 const fn as_str(&self) -> &'static str {
989 match self {
990 Self::Bug(_) => "bug",
991 Self::Import(_) => "unable to import HtE transformed key",
992 }
993 }
994 }
995
996 impl fmt::Display for UtcError {
997 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
998 match self {
999 Self::Bug(err) => write!(f, "{}: {err}", self.as_str()),
1000 Self::Import(err) => write!(f, "{}: {err}", self.as_str()),
1001 }
1002 }
1003 }
1004
1005 impl core::error::Error for UtcError {
1006 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1007 match self {
1008 Self::Bug(err) => Some(err),
1009 Self::Import(err) => Some(err),
1010 }
1011 }
1012 }
1013
1014 impl From<Bug> for UtcError {
1015 fn from(err: Bug) -> Self {
1016 Self::Bug(err)
1017 }
1018 }
1019
1020 impl From<ImportError> for UtcError {
1021 fn from(err: ImportError) -> Self {
1022 Self::Import(err)
1023 }
1024 }
1025
1026 impl From<UtcError> for SealError {
1027 fn from(err: UtcError) -> SealError {
1028 SealError::Other(err.as_str())
1029 }
1030 }
1031
1032 impl From<UtcError> for OpenError {
1033 fn from(err: UtcError) -> OpenError {
1034 OpenError::Other(err.as_str())
1035 }
1036 }
1037
1038 #[cfg_attr(feature = "committing-aead", macro_export)]
1062 #[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
1063 macro_rules! utc_aead {
1064 ($name:ident, $inner:ty, $cipher:ty, $doc:expr $(, $oid:expr)? $(,)?) => {
1065 #[doc = $doc]
1066 #[derive(Debug)]
1067 pub struct $name {
1068 key: <$inner as $crate::aead::Aead>::Key,
1069 }
1070
1071 impl $name {
1072 const COMMITMENT_SIZE: usize = <<$cipher as $crate::aead::BlockCipher>::BlockSize as
1073 $crate::typenum::Unsigned>::USIZE;
1074 }
1075
1076 impl $crate::aead::CommittingAead for $name {}
1077
1078 impl $crate::aead::Cmt1Aead for $name {}
1079
1080 impl $crate::aead::Aead for $name {
1081 const LIFETIME: $crate::aead::Lifetime = <$inner as $crate::aead::Aead>::LIFETIME;
1082
1083 type KeySize = <$inner as $crate::aead::Aead>::KeySize;
1084 type NonceSize = <$inner as $crate::aead::Aead>::NonceSize;
1085 type Overhead = $crate::typenum::Sum<
1086 <$inner as $crate::aead::Aead>::Overhead,
1087 <$cipher as $crate::aead::BlockCipher>::BlockSize,
1089 >;
1090
1091 const MAX_PLAINTEXT_SIZE: u64 = <$inner as $crate::aead::Aead>::MAX_PLAINTEXT_SIZE;
1092 const MAX_ADDITIONAL_DATA_SIZE: u64 =
1093 <$inner as $crate::aead::Aead>::MAX_ADDITIONAL_DATA_SIZE;
1094
1095 type Key = <$inner as $crate::aead::Aead>::Key;
1096
1097 #[inline]
1098 fn new(key: &Self::Key) -> Self {
1099 Self { key: key.clone() }
1100 }
1101
1102 fn seal(
1103 &self,
1104 mut dst: &mut [u8],
1105 nonce: &[u8],
1106 plaintext: &[u8],
1107 additional_data: &[u8],
1108 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1109 $crate::aead::check_seal_params::<Self>(
1110 &mut dst,
1111 nonce,
1112 plaintext,
1113 additional_data,
1114 )?;
1115
1116 let (dst, cx) = $crate::buggy::BugExt::assume(
1117 dst.split_last_chunk_mut::<{Self::COMMITMENT_SIZE}>(),
1118 "`COMMITMENT_SIZE` fits in `out`",
1119 )?;
1120 let key_bytes = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit_into(
1121 cx.into(),
1122 &self.key,
1123 &nonce.try_into()?,
1124 )?;
1125 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1126 .map_err($crate::aead::UtcError::Import)?;
1127 <$inner as $crate::aead::Aead>::new(&key).seal(
1128 dst,
1129 nonce,
1130 plaintext,
1131 additional_data,
1132 )
1133 }
1134
1135 fn seal_in_place(
1136 &self,
1137 nonce: &[u8],
1138 data: &mut [u8],
1139 overhead: &mut [u8],
1140 additional_data: &[u8],
1141 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1142 $crate::aead::check_seal_in_place_params::<Self>(
1143 nonce,
1144 data,
1145 overhead,
1146 additional_data,
1147 )?;
1148
1149 let (tag, cx) = $crate::buggy::BugExt::assume(
1150 overhead.split_last_chunk_mut::<{Self::COMMITMENT_SIZE}>(),
1151 "`COMMITMENT_SIZE` fits in `overhead`",
1152 )?;
1153 let key_bytes = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit_into(
1154 cx.into(),
1155 &self.key,
1156 &nonce.try_into()?,
1157 )?;
1158 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1159 .map_err($crate::aead::UtcError::Import)?;
1160 <$inner as $crate::aead::Aead>::new(&key).seal_in_place(
1161 nonce,
1162 data,
1163 tag,
1164 additional_data,
1165 )
1166 }
1167
1168 fn open(
1169 &self,
1170 dst: &mut [u8],
1171 nonce: &[u8],
1172 ciphertext: &[u8],
1173 additional_data: &[u8],
1174 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1175 $crate::aead::check_open_params::<Self>(
1176 dst,
1177 nonce,
1178 ciphertext,
1179 additional_data,
1180 )?;
1181
1182 let (ciphertext, got_cx) = $crate::buggy::BugExt::assume(
1183 ciphertext.split_last_chunk::<{Self::COMMITMENT_SIZE}>(),
1184 "`COMMITMENT_SIZE` fits in `ciphertext`",
1185 )?;
1186 let (want_cx, key_bytes) = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit(
1187 &self.key,
1188 &nonce.try_into()?,
1189 )?;
1190 if !bool::from($crate::subtle::ConstantTimeEq::ct_eq(
1191 want_cx.as_slice(),
1192 got_cx,
1193 )) {
1194 Err($crate::aead::OpenError::Authentication)
1195 } else {
1196 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1197 .map_err($crate::aead::UtcError::Import)?;
1198 <$inner as $crate::aead::Aead>::new(&key).open(
1199 dst,
1200 nonce,
1201 ciphertext,
1202 additional_data,
1203 )
1204 }
1205 }
1206
1207 fn open_in_place(
1208 &self,
1209 nonce: &[u8],
1210 data: &mut [u8],
1211 overhead: &[u8],
1212 additional_data: &[u8],
1213 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1214 $crate::aead::check_open_in_place_params::<Self>(
1215 nonce,
1216 data,
1217 overhead,
1218 additional_data,
1219 )?;
1220
1221 let (overhead, got_cx) = $crate::buggy::BugExt::assume(
1222 overhead.split_last_chunk::<{Self::COMMITMENT_SIZE}>(),
1223 "`COMMITMENT_SIZE` fits in `overhead`",
1224 )?;
1225 let (want_cx, key_bytes) = $crate::aead::CtrThenXorPrf::<$inner, $cipher>::commit(
1226 &self.key,
1227 &nonce.try_into()?,
1228 )?;
1229 if !bool::from($crate::subtle::ConstantTimeEq::ct_eq(
1230 want_cx.as_slice(),
1231 got_cx,
1232 )) {
1233 Err($crate::aead::OpenError::Authentication)
1234 } else {
1235 let key = $crate::import::Import::<_>::import(key_bytes.as_bytes())
1236 .map_err($crate::aead::UtcError::Import)?;
1237 <$inner as $crate::aead::Aead>::new(&key).open_in_place(
1238 nonce,
1239 data,
1240 overhead,
1241 additional_data,
1242 )
1243 }
1244 }
1245 }
1246
1247 $(impl $crate::oid::Identified for $name {
1248 const OID: &$crate::oid::Oid = $oid;
1249 })?
1250 };
1251 }
1252 pub(crate) use utc_aead;
1253
1254 #[derive(Debug, Eq, PartialEq)]
1256 pub enum HteError {
1257 Export(ExportError),
1259 Import(ImportError),
1261 }
1262
1263 impl HteError {
1264 const fn as_str(&self) -> &'static str {
1265 match self {
1266 Self::Export(_) => "unable to export inner secret key",
1267 Self::Import(_) => "unable to import HtE transformed key",
1268 }
1269 }
1270 }
1271
1272 impl fmt::Display for HteError {
1273 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1274 match self {
1275 Self::Export(err) => write!(f, "{}: {err}", self.as_str()),
1276 Self::Import(err) => write!(f, "{}: {err}", self.as_str()),
1277 }
1278 }
1279 }
1280
1281 impl core::error::Error for HteError {
1282 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
1283 match self {
1284 Self::Export(err) => Some(err),
1285 Self::Import(err) => Some(err),
1286 }
1287 }
1288 }
1289
1290 impl From<ExportError> for HteError {
1291 fn from(err: ExportError) -> Self {
1292 Self::Export(err)
1293 }
1294 }
1295
1296 impl From<ImportError> for HteError {
1297 fn from(err: ImportError) -> Self {
1298 Self::Import(err)
1299 }
1300 }
1301
1302 impl From<HteError> for SealError {
1303 fn from(err: HteError) -> SealError {
1304 SealError::Other(err.as_str())
1305 }
1306 }
1307
1308 impl From<HteError> for OpenError {
1309 fn from(err: HteError) -> OpenError {
1310 OpenError::Other(err.as_str())
1311 }
1312 }
1313
1314 #[cfg_attr(feature = "committing-aead", macro_export)]
1338 #[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
1339 macro_rules! hte_aead {
1340 ($name:ident, $inner:ty, $hash:ty, $doc:expr $(, $oid:expr)? $(,)?) => {
1341 #[doc = $doc]
1342 #[derive(Debug)]
1343 pub struct $name {
1344 key: <$inner as $crate::aead::Aead>::Key,
1345 }
1346
1347 impl $name {
1348 fn hash(
1349 &self,
1350 nonce: &[u8],
1351 ad: &[u8],
1352 ) -> ::core::result::Result<
1353 <$inner as $crate::aead::Aead>::Key,
1354 $crate::aead::HteError,
1355 > {
1356 let tag = {
1359 let bytes = $crate::keys::SecretKey::try_export_secret(&self.key)?;
1360 let key = $crate::hmac::HmacKey::<$hash>::new(
1361 $crate::keys::RawSecretBytes::raw_secret_bytes(&bytes),
1362 );
1363 let mut hmac = $crate::hmac::Hmac::<$hash>::new(&key);
1364 hmac.update(nonce);
1365 hmac.update(ad);
1366 hmac.tag()
1367 };
1368 let mut key_bytes = $crate::generic_array::GenericArray::<
1369 u8,
1370 <<$inner as $crate::aead::Aead>::Key as $crate::keys::SecretKey>::Size,
1371 >::default();
1372 let k = ::core::cmp::min(tag.len(), key_bytes.as_slice().len());
1373 key_bytes
1374 .as_mut_slice()
1375 .copy_from_slice(&tag.as_bytes()[..k]);
1376 let key =
1377 <<$inner as $crate::aead::Aead>::Key as $crate::import::Import<_>>::import(
1378 key_bytes.as_slice(),
1379 )?;
1380 Ok(key)
1381 }
1382 }
1383
1384 impl $crate::aead::CommittingAead for $name where $inner: $crate::aead::Cmt1Aead {}
1387
1388 impl $crate::aead::Cmt1Aead for $name {}
1389
1390 impl $crate::aead::Cmt3Aead for $name {}
1391
1392 impl $crate::aead::Cmt4Aead for $name where $inner: $crate::aead::Cmt1Aead {}
1393
1394 impl $crate::aead::Aead for $name {
1395 const LIFETIME: $crate::aead::Lifetime = <$inner as $crate::aead::Aead>::LIFETIME;
1396
1397 type KeySize = <$inner as $crate::aead::Aead>::KeySize;
1398 type NonceSize = <$inner as $crate::aead::Aead>::NonceSize;
1399 type Overhead = <$inner as $crate::aead::Aead>::Overhead;
1401
1402 const MAX_PLAINTEXT_SIZE: u64 = <$inner as $crate::aead::Aead>::MAX_PLAINTEXT_SIZE;
1403 const MAX_ADDITIONAL_DATA_SIZE: u64 =
1404 <$inner as $crate::aead::Aead>::MAX_ADDITIONAL_DATA_SIZE;
1405
1406 type Key = <$inner as $crate::aead::Aead>::Key;
1407
1408 #[inline]
1409 fn new(key: &Self::Key) -> Self {
1410 Self { key: key.clone() }
1411 }
1412
1413 fn seal(
1414 &self,
1415 mut dst: &mut [u8],
1416 nonce: &[u8],
1417 plaintext: &[u8],
1418 additional_data: &[u8],
1419 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1420 $crate::aead::check_seal_params::<Self>(
1421 &mut dst,
1422 nonce,
1423 plaintext,
1424 additional_data,
1425 )?;
1426
1427 let key = self.hash(nonce, additional_data)?;
1428 <$inner as $crate::aead::Aead>::new(&key).seal(
1429 dst,
1430 nonce,
1431 plaintext,
1432 additional_data,
1433 )
1434 }
1435
1436 fn seal_in_place(
1437 &self,
1438 nonce: &[u8],
1439 data: &mut [u8],
1440 overhead: &mut [u8],
1441 additional_data: &[u8],
1442 ) -> ::core::result::Result<(), $crate::aead::SealError> {
1443 $crate::aead::check_seal_in_place_params::<Self>(
1444 nonce,
1445 data,
1446 overhead,
1447 additional_data,
1448 )?;
1449
1450 let key = self.hash(nonce, additional_data)?;
1451 <$inner as $crate::aead::Aead>::new(&key).seal_in_place(
1452 nonce,
1453 data,
1454 overhead,
1455 additional_data,
1456 )
1457 }
1458
1459 fn open(
1460 &self,
1461 dst: &mut [u8],
1462 nonce: &[u8],
1463 ciphertext: &[u8],
1464 additional_data: &[u8],
1465 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1466 $crate::aead::check_open_params::<Self>(
1467 dst,
1468 nonce,
1469 ciphertext,
1470 additional_data,
1471 )?;
1472
1473 let key = self.hash(nonce, additional_data)?;
1474 <$inner as $crate::aead::Aead>::new(&key).open(
1475 dst,
1476 nonce,
1477 ciphertext,
1478 additional_data,
1479 )
1480 }
1481
1482 fn open_in_place(
1483 &self,
1484 nonce: &[u8],
1485 data: &mut [u8],
1486 overhead: &[u8],
1487 additional_data: &[u8],
1488 ) -> ::core::result::Result<(), $crate::aead::OpenError> {
1489 $crate::aead::check_open_in_place_params::<Self>(
1490 nonce,
1491 data,
1492 overhead,
1493 additional_data,
1494 )?;
1495
1496 let key = self.hash(nonce, additional_data)?;
1497 <$inner as $crate::aead::Aead>::new(&key).open_in_place(
1498 nonce,
1499 data,
1500 overhead,
1501 additional_data,
1502 )
1503 }
1504 }
1505
1506 $(impl $crate::oid::Identified for $name {
1507 const OID: &$crate::oid::Oid = $oid;
1508 })?
1509 };
1510 }
1511 pub(crate) use hte_aead;
1512}
1513#[cfg(feature = "committing-aead")]
1514#[cfg_attr(docsrs, doc(cfg(feature = "committing-aead")))]
1515pub use committing::*;