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