1use std::sync::Arc;
2
3use subtle::ConstantTimeEq;
4use zeroize::{Zeroize, Zeroizing};
5
6use crate::backends::{AeadKey, ProviderRng};
7use crate::{
8 AEAD_IV_LENGTH, AEAD_MAX_SEGMENTS, AEAD_TAG_LENGTH, ENCODED_PARAMETERS_LENGTH, Error,
9 FLOE_IV_LENGTH, HEADER_LENGTH, HEADER_TAG_LENGTH, Key, LengthRequirement, Parameters, Provider,
10 Result, SEGMENT_OVERHEAD, SEGMENT_PAYLOAD_OFFSET, SEGMENT_PREFIX_LENGTH, SegmentBuffer,
11 SegmentFraming, SegmentKind, SegmentLayout, length_u32_to_usize, length_usize_to_u64,
12};
13
14const HEADER_TAG_PURPOSE: &[u8] = b"HEADER_TAG:";
15const MESSAGE_KEY_PURPOSE: &[u8] = b"MESSAGE_KEY:";
16const SEGMENT_KEY_PURPOSE: &[u8] = b"DEK:";
17const NONCE_BATCH_SIZE: usize = 256;
18const NONCE_BATCH_LENGTH: usize = AEAD_IV_LENGTH * NONCE_BATCH_SIZE;
19const SEGMENT_AAD_LENGTH: usize = 9;
20
21#[inline]
22fn segment_aad(position: u64, kind: SegmentKind) -> [u8; SEGMENT_AAD_LENGTH] {
23 let mut aad = [0u8; SEGMENT_AAD_LENGTH];
24 aad[..8].copy_from_slice(&position.to_be_bytes());
25 aad[8] = kind.indicator();
26 aad
27}
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
34pub struct Header([u8; HEADER_LENGTH]);
35
36impl Header {
37 pub const LEN: usize = HEADER_LENGTH;
39
40 const FLOE_IV_OFFSET: usize = ENCODED_PARAMETERS_LENGTH;
41 const TAG_OFFSET: usize = Self::FLOE_IV_OFFSET + FLOE_IV_LENGTH;
42
43 #[must_use]
45 pub const fn as_bytes(&self) -> &[u8; HEADER_LENGTH] {
46 &self.0
47 }
48
49 pub fn unverified_parameters(&self) -> Result<Parameters> {
60 Parameters::decode(*self.encoded_parameters())
61 }
62
63 fn from_fields(
64 encoded: &[u8; ENCODED_PARAMETERS_LENGTH],
65 floe_iv: &[u8; FLOE_IV_LENGTH],
66 tag: &[u8; HEADER_TAG_LENGTH],
67 ) -> Self {
68 let mut bytes = [0u8; HEADER_LENGTH];
69 bytes[..Self::FLOE_IV_OFFSET].copy_from_slice(encoded);
70 bytes[Self::FLOE_IV_OFFSET..Self::TAG_OFFSET].copy_from_slice(floe_iv);
71 bytes[Self::TAG_OFFSET..].copy_from_slice(tag);
72 Self(bytes)
73 }
74
75 fn encoded_parameters(&self) -> &[u8; ENCODED_PARAMETERS_LENGTH] {
76 self.0[..Self::FLOE_IV_OFFSET]
77 .try_into()
78 .expect("header field offsets are compile-time constants")
79 }
80
81 fn floe_iv(&self) -> &[u8; FLOE_IV_LENGTH] {
82 self.0[Self::FLOE_IV_OFFSET..Self::TAG_OFFSET]
83 .try_into()
84 .expect("header field offsets are compile-time constants")
85 }
86
87 fn tag(&self) -> &[u8; HEADER_TAG_LENGTH] {
88 self.0[Self::TAG_OFFSET..]
89 .try_into()
90 .expect("header field offsets are compile-time constants")
91 }
92}
93
94impl AsRef<[u8]> for Header {
95 fn as_ref(&self) -> &[u8] {
96 &self.0
97 }
98}
99
100impl From<[u8; HEADER_LENGTH]> for Header {
101 fn from(bytes: [u8; HEADER_LENGTH]) -> Self {
102 Self(bytes)
103 }
104}
105
106impl From<Header> for [u8; HEADER_LENGTH] {
107 fn from(header: Header) -> Self {
108 header.0
109 }
110}
111
112impl TryFrom<&[u8]> for Header {
113 type Error = Error;
114
115 fn try_from(bytes: &[u8]) -> Result<Self> {
116 let bytes: [u8; HEADER_LENGTH] =
117 bytes.try_into().map_err(|_| Error::InvalidHeaderLength {
118 actual: bytes.len(),
119 })?;
120 Ok(Self(bytes))
121 }
122}
123
124struct SecretBytes<const N: usize>([u8; N]);
125
126impl<const N: usize> SecretBytes<N> {
127 fn expose_bytes(&self) -> &[u8] {
128 &self.0
129 }
130}
131
132impl<const N: usize> Drop for SecretBytes<N> {
133 fn drop(&mut self) {
134 self.0.zeroize();
135 }
136}
137
138struct CachedKey {
139 masked_position: u64,
140 key: AeadKey,
141}
142
143impl CachedKey {
144 fn derive(context: &MessageContext, masked_position: u64) -> Result<Self> {
145 Ok(Self {
146 masked_position,
147 key: derive_segment_key(
148 context.provider,
149 context.parameters,
150 &context.message_key,
151 &context.floe_iv,
152 &context.aad,
153 masked_position,
154 )?,
155 })
156 }
157}
158
159struct MessageContext {
160 provider: Provider,
161 parameters: Parameters,
162 message_key: SecretBytes<48>,
163 floe_iv: [u8; FLOE_IV_LENGTH],
164 aad: Box<[u8]>,
165}
166
167impl core::fmt::Debug for MessageContext {
168 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
169 f.debug_struct("MessageContext")
170 .field("provider", &self.provider)
171 .field("parameters", &self.parameters)
172 .field("floe_iv", &self.floe_iv)
173 .field("aad_length", &self.aad.len())
174 .finish_non_exhaustive()
175 }
176}
177
178impl MessageContext {
179 #[inline]
180 fn new(
181 provider: Provider,
182 parameters: Parameters,
183 message_key: SecretBytes<48>,
184 floe_iv: [u8; FLOE_IV_LENGTH],
185 aad: &[u8],
186 ) -> Self {
187 Self {
188 provider,
189 parameters,
190 message_key,
191 floe_iv,
192 aad: aad.into(),
193 }
194 }
195}
196
197struct KeyCache {
198 cached_key: Option<CachedKey>,
199}
200
201impl core::fmt::Debug for KeyCache {
202 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
203 f.debug_struct("KeyCache")
204 .field(
205 "masked_position",
206 &self
207 .cached_key
208 .as_ref()
209 .map(|cached| cached.masked_position),
210 )
211 .finish_non_exhaustive()
212 }
213}
214
215impl KeyCache {
216 #[inline]
217 fn new(context: &MessageContext) -> Result<Self> {
218 Ok(Self {
219 cached_key: Some(CachedKey::derive(context, 0)?),
220 })
221 }
222
223 #[inline]
224 const fn empty() -> Self {
225 Self { cached_key: None }
226 }
227
228 #[inline]
229 fn key_for_position(&mut self, context: &MessageContext, position: u64) -> Result<&AeadKey> {
230 if position >= AEAD_MAX_SEGMENTS {
231 return Err(Error::SegmentLimit);
232 }
233
234 let masked_position = context.parameters.masked_position(position);
235 if self
236 .cached_key
237 .as_ref()
238 .is_none_or(|cached| cached.masked_position != masked_position)
239 {
240 self.cached_key = Some(CachedKey::derive(context, masked_position)?);
241 }
242 let cached = self
243 .cached_key
244 .as_ref()
245 .expect("populated by the branch above");
246 Ok(&cached.key)
247 }
248}
249
250struct NonceGenerator {
251 rng: ProviderRng,
252 bytes: [u8; NONCE_BATCH_LENGTH],
253 next: usize,
254}
255
256impl core::fmt::Debug for NonceGenerator {
257 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
258 let remaining = (NONCE_BATCH_LENGTH - self.next) / AEAD_IV_LENGTH;
259 f.debug_struct("NonceGenerator")
260 .field("remaining", &remaining)
261 .finish_non_exhaustive()
262 }
263}
264
265impl NonceGenerator {
266 #[inline]
267 fn new(rng: ProviderRng) -> Self {
268 Self {
269 rng,
270 bytes: [0; NONCE_BATCH_LENGTH],
271 next: NONCE_BATCH_LENGTH,
272 }
273 }
274
275 #[inline]
276 fn next(&mut self) -> Result<[u8; AEAD_IV_LENGTH]> {
277 if self.next == NONCE_BATCH_LENGTH {
278 self.rng.fill(&mut self.bytes)?;
279 self.next = 0;
280 }
281 let mut nonce = [0; AEAD_IV_LENGTH];
282 nonce.copy_from_slice(&self.bytes[self.next..self.next + AEAD_IV_LENGTH]);
283 self.next += AEAD_IV_LENGTH;
284 Ok(nonce)
285 }
286}
287
288#[inline]
289fn ciphertext_segment_size(
290 context: &MessageContext,
291 plaintext_length: usize,
292 kind: SegmentKind,
293) -> Result<usize> {
294 let maximum = context.parameters.plaintext_segment_length();
295 match kind {
296 SegmentKind::Final if plaintext_length <= maximum => SEGMENT_OVERHEAD
297 .checked_add(plaintext_length)
298 .ok_or(Error::LengthOverflow),
299 SegmentKind::Final => Err(Error::InvalidPlaintextLength {
300 actual: plaintext_length,
301 required: LengthRequirement::AtMost(maximum),
302 }),
303 SegmentKind::NonFinal if plaintext_length == maximum => {
304 Ok(context.parameters.ciphertext_segment_length())
305 }
306 SegmentKind::NonFinal => Err(Error::InvalidPlaintextLength {
307 actual: plaintext_length,
308 required: LengthRequirement::Exactly(maximum),
309 }),
310 }
311}
312
313#[inline]
317fn begin_segment_encryption<'a>(
318 context: &MessageContext,
319 keys: &'a mut KeyCache,
320 nonces: &mut NonceGenerator,
321 output: &mut [u8],
322 plaintext_length: usize,
323 position: u64,
324 kind: SegmentKind,
325) -> Result<(
326 usize,
327 [u8; AEAD_IV_LENGTH],
328 &'a AeadKey,
329 [u8; SEGMENT_AAD_LENGTH],
330)> {
331 let required = ciphertext_segment_size(context, plaintext_length, kind)?;
332 if output.len() < required {
333 return Err(Error::OutputTooSmall {
334 actual: output.len(),
335 required,
336 });
337 }
338 let nonce = write_segment_framing(nonces, output, kind, required)?;
339 let key = keys.key_for_position(context, position)?;
340 Ok((required, nonce, key, segment_aad(position, kind)))
341}
342
343#[inline]
344fn encrypt_segment_into_inner(
345 context: &MessageContext,
346 keys: &mut KeyCache,
347 nonces: &mut NonceGenerator,
348 plaintext: &[u8],
349 position: u64,
350 kind: SegmentKind,
351 output: &mut [u8],
352) -> Result<usize> {
353 let (required, nonce, key, segment_aad) = begin_segment_encryption(
354 context,
355 keys,
356 nonces,
357 output,
358 plaintext.len(),
359 position,
360 kind,
361 )?;
362 key.seal_into(
363 &nonce,
364 &segment_aad,
365 plaintext,
366 &mut output[SEGMENT_PAYLOAD_OFFSET..required],
367 )?;
368 Ok(required)
369}
370
371#[inline]
372fn encrypt_segment_in_place_inner(
373 context: &MessageContext,
374 keys: &mut KeyCache,
375 nonces: &mut NonceGenerator,
376 buffer: &mut [u8],
377 plaintext_length: usize,
378 position: u64,
379 kind: SegmentKind,
380) -> Result<usize> {
381 let (required, nonce, key, segment_aad) = begin_segment_encryption(
382 context,
383 keys,
384 nonces,
385 buffer,
386 plaintext_length,
387 position,
388 kind,
389 )?;
390 let tag_start = SEGMENT_PAYLOAD_OFFSET + plaintext_length;
391 let mut tag = [0u8; AEAD_TAG_LENGTH];
392 key.seal(
393 &nonce,
394 &segment_aad,
395 &mut buffer[SEGMENT_PAYLOAD_OFFSET..tag_start],
396 &mut tag,
397 )?;
398 buffer[tag_start..required].copy_from_slice(&tag);
399 Ok(required)
400}
401
402#[inline]
405fn write_segment_framing(
406 nonces: &mut NonceGenerator,
407 output: &mut [u8],
408 kind: SegmentKind,
409 required: usize,
410) -> Result<[u8; AEAD_IV_LENGTH]> {
411 let prefix = match kind {
412 SegmentKind::NonFinal => u32::MAX,
413 SegmentKind::Final => u32::try_from(required).map_err(|_| Error::LengthOverflow)?,
414 };
415 output[..SEGMENT_PREFIX_LENGTH].copy_from_slice(&prefix.to_be_bytes());
416 let nonce = nonces.next()?;
417 output[SEGMENT_PREFIX_LENGTH..SEGMENT_PAYLOAD_OFFSET].copy_from_slice(&nonce);
418 Ok(nonce)
419}
420
421#[inline]
422fn validate_segment(
423 context: &MessageContext,
424 ciphertext_segment: &[u8],
425 kind: SegmentKind,
426) -> Result<usize> {
427 let maximum = context.parameters.ciphertext_segment_length();
428 match kind {
429 SegmentKind::Final => {
430 context
431 .parameters
432 .validate_ciphertext_segment_length(ciphertext_segment.len())?;
433 }
434 SegmentKind::NonFinal if ciphertext_segment.len() != maximum => {
435 return Err(Error::InvalidCiphertextLength {
436 actual: ciphertext_segment.len(),
437 required: LengthRequirement::Exactly(maximum),
438 });
439 }
440 SegmentKind::NonFinal => {}
441 }
442
443 let prefix = u32::from_be_bytes(
444 ciphertext_segment[..SEGMENT_PREFIX_LENGTH]
445 .try_into()
446 .map_err(|_| Error::InvalidSegmentPrefix)?,
447 );
448
449 match kind {
450 SegmentKind::Final
453 if u64::from(prefix) != length_usize_to_u64(ciphertext_segment.len()) =>
454 {
455 return Err(Error::InvalidCiphertextLength {
456 actual: ciphertext_segment.len(),
457 required: LengthRequirement::Exactly(length_u32_to_usize(prefix)),
458 });
459 }
460 SegmentKind::NonFinal if prefix != u32::MAX => {
461 return Err(Error::InvalidSegmentPrefix);
462 }
463 SegmentKind::Final | SegmentKind::NonFinal => {}
464 }
465
466 Ok(ciphertext_segment.len() - SEGMENT_OVERHEAD)
467}
468
469#[inline]
470fn decrypt_segment_into_inner(
471 context: &MessageContext,
472 keys: &mut KeyCache,
473 ciphertext_segment: &[u8],
474 position: u64,
475 kind: SegmentKind,
476 plaintext_length: usize,
477 output: &mut [u8],
478) -> Result<usize> {
479 if output.len() < plaintext_length {
480 return Err(Error::OutputTooSmall {
481 actual: output.len(),
482 required: plaintext_length,
483 });
484 }
485
486 let key = keys.key_for_position(context, position)?;
487 let tag_start = ciphertext_segment.len() - AEAD_TAG_LENGTH;
488 let segment_aad = segment_aad(position, kind);
489 let nonce: &[u8; AEAD_IV_LENGTH] = ciphertext_segment
490 [SEGMENT_PREFIX_LENGTH..SEGMENT_PAYLOAD_OFFSET]
491 .try_into()
492 .map_err(|_| Error::CryptoFailure)?;
493 let tag: &[u8; AEAD_TAG_LENGTH] = ciphertext_segment[tag_start..]
494 .try_into()
495 .map_err(|_| Error::CryptoFailure)?;
496
497 key.open(
498 nonce,
499 &segment_aad,
500 &ciphertext_segment[SEGMENT_PAYLOAD_OFFSET..tag_start],
501 tag,
502 &mut output[..plaintext_length],
503 )?;
504 Ok(plaintext_length)
505}
506
507#[inline]
508fn decrypt_segment_in_place_inner<'a>(
509 context: &MessageContext,
510 keys: &mut KeyCache,
511 ciphertext_segment: &'a mut [u8],
512 position: u64,
513 kind: SegmentKind,
514) -> Result<&'a mut [u8]> {
515 let plaintext_length = validate_segment(context, ciphertext_segment, kind)?;
516 open_segment_in_place(
517 context,
518 keys,
519 ciphertext_segment,
520 position,
521 kind,
522 plaintext_length,
523 )
524}
525
526#[inline]
529fn open_segment_in_place<'a>(
530 context: &MessageContext,
531 keys: &mut KeyCache,
532 ciphertext_segment: &'a mut [u8],
533 position: u64,
534 kind: SegmentKind,
535 plaintext_length: usize,
536) -> Result<&'a mut [u8]> {
537 let key = keys.key_for_position(context, position)?;
538 let (framing, ciphertext_and_tag) = ciphertext_segment.split_at_mut(SEGMENT_PAYLOAD_OFFSET);
539 let nonce: &[u8; AEAD_IV_LENGTH] = framing[SEGMENT_PREFIX_LENGTH..]
540 .try_into()
541 .map_err(|_| Error::CryptoFailure)?;
542 let (ciphertext, tag_bytes) = ciphertext_and_tag.split_at_mut(plaintext_length);
543 let tag: &[u8; AEAD_TAG_LENGTH] = (&*tag_bytes).try_into().map_err(|_| Error::CryptoFailure)?;
544
545 let segment_aad = segment_aad(position, kind);
546 key.open_in_place(nonce, &segment_aad, tag, ciphertext)?;
547 Ok(ciphertext)
548}
549
550fn finish_in_place_decrypt(buffer: &mut SegmentBuffer, result: Result<usize>) -> Result<&mut [u8]> {
554 match result {
555 Ok(length) => {
556 buffer.mark_plaintext(length);
557 buffer.plaintext_mut()
558 }
559 Err(error) => {
560 buffer.clear();
561 Err(error)
562 }
563 }
564}
565
566#[inline]
567fn validate_layout(context: &MessageContext, segment: SegmentLayout) -> Result<()> {
568 if segment.parameters() == context.parameters {
569 Ok(())
570 } else {
571 Err(Error::InvalidParameters)
572 }
573}
574
575#[derive(Debug)]
584pub struct EncryptionState {
585 context: Arc<MessageContext>,
586 keys: KeyCache,
587 nonces: NonceGenerator,
588}
589
590impl EncryptionState {
591 #[must_use]
593 pub fn provider(&self) -> Provider {
594 self.context.provider
595 }
596
597 #[must_use]
599 pub fn parameters(&self) -> Parameters {
600 self.context.parameters
601 }
602
603 #[must_use]
606 pub fn into_shared(self) -> SharedEncryptionContext {
607 let Self { context, .. } = self;
608 SharedEncryptionContext { context }
609 }
610
611 pub fn encrypt_segment(&mut self, plaintext: &[u8], segment: SegmentLayout) -> Result<Vec<u8>> {
619 self.validate_plaintext_layout(plaintext.len(), segment)?;
620 self.encrypt_segment_at(plaintext, segment.position(), segment.kind())
621 }
622
623 #[inline]
635 pub fn encrypt_segment_into(
636 &mut self,
637 plaintext: &[u8],
638 segment: SegmentLayout,
639 output: &mut [u8],
640 ) -> Result<usize> {
641 self.validate_plaintext_layout(plaintext.len(), segment)?;
642 self.encrypt_segment_into_at(plaintext, segment.position(), segment.kind(), output)
643 }
644
645 #[inline]
656 pub fn encrypt_segment_in_place<'a>(
657 &mut self,
658 buffer: &'a mut SegmentBuffer,
659 segment: SegmentLayout,
660 ) -> Result<&'a [u8]> {
661 self.validate_plaintext_layout(buffer.plaintext_length()?, segment)?;
662 self.encrypt_segment_in_place_at(buffer, segment.position(), segment.kind())
663 }
664
665 pub(crate) fn encrypt_segment_in_place_at<'a>(
666 &mut self,
667 buffer: &'a mut SegmentBuffer,
668 position: u64,
669 kind: SegmentKind,
670 ) -> Result<&'a [u8]> {
671 if !buffer.matches(self.parameters()) {
672 return Err(Error::InvalidParameters);
673 }
674
675 let plaintext_length = buffer.plaintext_length()?;
676 let result = self.encrypt_segment_in_place_raw_at(
677 buffer.raw_mut(),
678 plaintext_length,
679 position,
680 kind,
681 );
682
683 match result {
684 Ok(written) => {
685 buffer.mark_ciphertext(written);
686 buffer.ciphertext()
687 }
688 Err(error) => {
689 buffer.clear();
692 Err(error)
693 }
694 }
695 }
696
697 pub fn encrypt_segment_in_place_raw(
711 &mut self,
712 buffer: &mut [u8],
713 segment: SegmentLayout,
714 ) -> Result<usize> {
715 validate_layout(&self.context, segment)?;
716 let plaintext_length = segment.plaintext_length();
717
718 self.encrypt_segment_in_place_raw_at(
719 buffer,
720 plaintext_length,
721 segment.position(),
722 segment.kind(),
723 )
724 }
725
726 pub(crate) fn encrypt_segment_at(
727 &mut self,
728 plaintext: &[u8],
729 position: u64,
730 kind: SegmentKind,
731 ) -> Result<Vec<u8>> {
732 let required = ciphertext_segment_size(&self.context, plaintext.len(), kind)?;
733 let mut output = vec![0u8; required];
734 self.encrypt_segment_into_at(plaintext, position, kind, &mut output)?;
735 Ok(output)
736 }
737
738 pub(crate) fn encrypt_segment_into_at(
739 &mut self,
740 plaintext: &[u8],
741 position: u64,
742 kind: SegmentKind,
743 output: &mut [u8],
744 ) -> Result<usize> {
745 encrypt_segment_into_inner(
746 &self.context,
747 &mut self.keys,
748 &mut self.nonces,
749 plaintext,
750 position,
751 kind,
752 output,
753 )
754 }
755
756 pub(crate) fn encrypt_segment_in_place_raw_at(
757 &mut self,
758 buffer: &mut [u8],
759 plaintext_length: usize,
760 position: u64,
761 kind: SegmentKind,
762 ) -> Result<usize> {
763 encrypt_segment_in_place_inner(
764 &self.context,
765 &mut self.keys,
766 &mut self.nonces,
767 buffer,
768 plaintext_length,
769 position,
770 kind,
771 )
772 }
773
774 fn validate_plaintext_layout(&self, actual: usize, segment: SegmentLayout) -> Result<()> {
775 validate_layout(&self.context, segment)?;
776 let expected = segment.plaintext_length();
777
778 if actual == expected {
779 Ok(())
780 } else {
781 Err(Error::InvalidPlaintextLength {
782 actual,
783 required: LengthRequirement::Exactly(expected),
784 })
785 }
786 }
787}
788
789#[derive(Clone, Debug)]
795pub struct SharedEncryptionContext {
796 context: Arc<MessageContext>,
797}
798
799impl SharedEncryptionContext {
800 #[must_use]
802 pub fn provider(&self) -> Provider {
803 self.context.provider
804 }
805
806 #[must_use]
808 pub fn parameters(&self) -> Parameters {
809 self.context.parameters
810 }
811
812 #[must_use]
815 pub fn fork(&self) -> EncryptionState {
816 EncryptionState {
817 context: Arc::clone(&self.context),
818 keys: KeyCache::empty(),
819 nonces: NonceGenerator::new(ProviderRng::new(self.context.provider)),
820 }
821 }
822}
823
824#[derive(Debug)]
832pub struct DecryptionState {
833 context: Arc<MessageContext>,
834 keys: KeyCache,
835}
836
837impl DecryptionState {
838 #[must_use]
840 pub fn provider(&self) -> Provider {
841 self.context.provider
842 }
843
844 #[must_use]
846 pub fn parameters(&self) -> Parameters {
847 self.context.parameters
848 }
849
850 #[must_use]
853 pub fn into_shared(self) -> SharedDecryptionContext {
854 let Self { context, .. } = self;
855 SharedDecryptionContext { context }
856 }
857
858 pub fn decrypt_segment(
866 &mut self,
867 ciphertext_segment: &[u8],
868 segment: SegmentLayout,
869 ) -> Result<Vec<u8>> {
870 self.validate_ciphertext_layout(ciphertext_segment.len(), segment)?;
871 self.decrypt_segment_at(ciphertext_segment, segment.position(), segment.kind())
872 }
873
874 #[inline]
886 pub fn decrypt_segment_into(
887 &mut self,
888 ciphertext_segment: &[u8],
889 segment: SegmentLayout,
890 output: &mut [u8],
891 ) -> Result<usize> {
892 self.validate_ciphertext_layout(ciphertext_segment.len(), segment)?;
893 self.decrypt_segment_into_at(
894 ciphertext_segment,
895 segment.position(),
896 segment.kind(),
897 output,
898 )
899 }
900
901 #[inline]
914 pub fn decrypt_segment_in_place<'a>(
915 &mut self,
916 buffer: &'a mut SegmentBuffer,
917 segment: SegmentLayout,
918 ) -> Result<&'a mut [u8]> {
919 self.validate_ciphertext_layout(buffer.ciphertext_length()?, segment)?;
920 self.decrypt_segment_in_place_at(buffer, segment.position(), segment.kind())
921 }
922
923 pub(crate) fn decrypt_segment_in_place_at<'a>(
924 &mut self,
925 buffer: &'a mut SegmentBuffer,
926 position: u64,
927 kind: SegmentKind,
928 ) -> Result<&'a mut [u8]> {
929 if !buffer.matches(self.parameters()) {
930 return Err(Error::InvalidParameters);
931 }
932 let ciphertext_length = buffer.ciphertext_length()?;
933 let result = self
934 .decrypt_segment_in_place_raw_at(
935 &mut buffer.raw_mut()[..ciphertext_length],
936 position,
937 kind,
938 )
939 .map(|plaintext| plaintext.len());
940 finish_in_place_decrypt(buffer, result)
941 }
942
943 pub(crate) fn decrypt_segment_in_place_at_framed<'a>(
946 &mut self,
947 buffer: &'a mut SegmentBuffer,
948 position: u64,
949 framing: SegmentFraming,
950 ) -> Result<&'a mut [u8]> {
951 if !buffer.matches(self.parameters()) {
952 return Err(Error::InvalidParameters);
953 }
954 let ciphertext_length = buffer.ciphertext_length()?;
955 let expected = framing.ciphertext_length();
956 if ciphertext_length != expected {
957 return Err(Error::InvalidCiphertextLength {
958 actual: ciphertext_length,
959 required: LengthRequirement::Exactly(expected),
960 });
961 }
962 let result = open_segment_in_place(
963 &self.context,
964 &mut self.keys,
965 &mut buffer.raw_mut()[..ciphertext_length],
966 position,
967 framing.kind(),
968 framing.plaintext_length(),
969 )
970 .map(|plaintext| plaintext.len());
971 finish_in_place_decrypt(buffer, result)
972 }
973
974 pub fn decrypt_segment_in_place_raw<'a>(
988 &mut self,
989 ciphertext_segment: &'a mut [u8],
990 segment: SegmentLayout,
991 ) -> Result<&'a mut [u8]> {
992 validate_layout(&self.context, segment)?;
993 let required = segment.ciphertext_length();
994 if ciphertext_segment.len() < required {
995 return Err(Error::InvalidCiphertextLength {
996 actual: ciphertext_segment.len(),
997 required: LengthRequirement::AtLeast(required),
998 });
999 }
1000 self.decrypt_segment_in_place_raw_at(
1001 &mut ciphertext_segment[..required],
1002 segment.position(),
1003 segment.kind(),
1004 )
1005 }
1006
1007 pub(crate) fn decrypt_segment_at(
1008 &mut self,
1009 ciphertext_segment: &[u8],
1010 position: u64,
1011 kind: SegmentKind,
1012 ) -> Result<Vec<u8>> {
1013 let plaintext_length = validate_segment(&self.context, ciphertext_segment, kind)?;
1014 let mut output = Zeroizing::new(vec![0u8; plaintext_length]);
1017 decrypt_segment_into_inner(
1018 &self.context,
1019 &mut self.keys,
1020 ciphertext_segment,
1021 position,
1022 kind,
1023 plaintext_length,
1024 &mut output,
1025 )?;
1026 Ok(core::mem::take(&mut *output))
1027 }
1028
1029 pub(crate) fn decrypt_segment_at_framed(
1032 &mut self,
1033 ciphertext_segment: &[u8],
1034 position: u64,
1035 framing: SegmentFraming,
1036 ) -> Result<Vec<u8>> {
1037 let mut output = Zeroizing::new(vec![0u8; framing.plaintext_length()]);
1038 self.decrypt_segment_into_at_framed(ciphertext_segment, position, framing, &mut output)?;
1039 Ok(core::mem::take(&mut *output))
1040 }
1041
1042 pub(crate) fn decrypt_segment_into_at(
1043 &mut self,
1044 ciphertext_segment: &[u8],
1045 position: u64,
1046 kind: SegmentKind,
1047 output: &mut [u8],
1048 ) -> Result<usize> {
1049 let plaintext_length = validate_segment(&self.context, ciphertext_segment, kind)?;
1050 decrypt_segment_into_inner(
1051 &self.context,
1052 &mut self.keys,
1053 ciphertext_segment,
1054 position,
1055 kind,
1056 plaintext_length,
1057 output,
1058 )
1059 }
1060
1061 pub(crate) fn decrypt_segment_into_at_framed(
1062 &mut self,
1063 ciphertext_segment: &[u8],
1064 position: u64,
1065 framing: SegmentFraming,
1066 output: &mut [u8],
1067 ) -> Result<usize> {
1068 let expected = framing.ciphertext_length();
1069 if ciphertext_segment.len() != expected {
1070 return Err(Error::InvalidCiphertextLength {
1071 actual: ciphertext_segment.len(),
1072 required: LengthRequirement::Exactly(expected),
1073 });
1074 }
1075 decrypt_segment_into_inner(
1076 &self.context,
1077 &mut self.keys,
1078 ciphertext_segment,
1079 position,
1080 framing.kind(),
1081 framing.plaintext_length(),
1082 output,
1083 )
1084 }
1085
1086 pub(crate) fn decrypt_segment_in_place_raw_at<'a>(
1087 &mut self,
1088 ciphertext_segment: &'a mut [u8],
1089 position: u64,
1090 kind: SegmentKind,
1091 ) -> Result<&'a mut [u8]> {
1092 decrypt_segment_in_place_inner(
1093 &self.context,
1094 &mut self.keys,
1095 ciphertext_segment,
1096 position,
1097 kind,
1098 )
1099 }
1100
1101 fn validate_ciphertext_layout(&self, actual: usize, segment: SegmentLayout) -> Result<()> {
1102 validate_layout(&self.context, segment)?;
1103 let expected = segment.ciphertext_length();
1104 if actual == expected {
1105 Ok(())
1106 } else {
1107 Err(Error::InvalidCiphertextLength {
1108 actual,
1109 required: LengthRequirement::Exactly(expected),
1110 })
1111 }
1112 }
1113}
1114
1115#[derive(Clone, Debug)]
1121pub struct SharedDecryptionContext {
1122 context: Arc<MessageContext>,
1123}
1124
1125impl SharedDecryptionContext {
1126 #[must_use]
1128 pub fn provider(&self) -> Provider {
1129 self.context.provider
1130 }
1131
1132 #[must_use]
1134 pub fn parameters(&self) -> Parameters {
1135 self.context.parameters
1136 }
1137
1138 #[must_use]
1140 pub fn fork(&self) -> DecryptionState {
1141 DecryptionState {
1142 context: Arc::clone(&self.context),
1143 keys: KeyCache::empty(),
1144 }
1145 }
1146}
1147
1148pub fn start_encryption(
1155 key: &Key,
1156 aad: &[u8],
1157 parameters: Parameters,
1158) -> Result<(EncryptionState, Header)> {
1159 let provider = key.provider()?;
1160 let mut rng = ProviderRng::new(provider);
1161 let mut floe_iv = [0u8; FLOE_IV_LENGTH];
1162 rng.fill(&mut floe_iv)?;
1163
1164 let encoded = parameters.encode();
1165 let mut header_tag = derive_header_tag(provider, key, &encoded, &floe_iv, aad)?;
1166 let message_key = derive_message_key(provider, key, &encoded, &floe_iv, aad)?;
1167
1168 let header = Header::from_fields(&encoded, &floe_iv, &header_tag);
1169 header_tag.zeroize();
1170
1171 let context = Arc::new(MessageContext::new(
1172 provider,
1173 parameters,
1174 message_key,
1175 floe_iv,
1176 aad,
1177 ));
1178 let keys = KeyCache::new(&context)?;
1179 let nonces = NonceGenerator::new(rng);
1180
1181 Ok((
1182 EncryptionState {
1183 context,
1184 keys,
1185 nonces,
1186 },
1187 header,
1188 ))
1189}
1190
1191pub fn start_decryption(
1199 key: &Key,
1200 aad: &[u8],
1201 parameters: Parameters,
1202 header: &Header,
1203) -> Result<DecryptionState> {
1204 let provider = key.provider()?;
1205 start_decryption_with_provider(key, provider, aad, parameters, header)
1206}
1207
1208fn start_decryption_with_provider(
1209 key: &Key,
1210 provider: Provider,
1211 aad: &[u8],
1212 parameters: Parameters,
1213 header: &Header,
1214) -> Result<DecryptionState> {
1215 let encoded = parameters.encode();
1216
1217 if header.encoded_parameters() != &encoded {
1218 return Err(Error::InvalidHeaderParameters);
1219 }
1220
1221 let floe_iv = *header.floe_iv();
1222
1223 let mut expected_tag = derive_header_tag(provider, key, &encoded, &floe_iv, aad)?;
1224 let tag_matches: bool = expected_tag.as_slice().ct_eq(header.tag()).into();
1225 expected_tag.zeroize();
1226
1227 if !tag_matches {
1228 return Err(Error::InvalidHeaderTag);
1229 }
1230
1231 let message_key = derive_message_key(provider, key, &encoded, &floe_iv, aad)?;
1232 let context = Arc::new(MessageContext::new(
1233 provider,
1234 parameters,
1235 message_key,
1236 floe_iv,
1237 aad,
1238 ));
1239 let keys = KeyCache::new(&context)?;
1240
1241 Ok(DecryptionState { context, keys })
1242}
1243
1244pub fn start_decryption_inferred(
1253 key: &Key,
1254 aad: &[u8],
1255 header: &Header,
1256) -> Result<DecryptionState> {
1257 let provider = key.provider()?;
1258 let parameters = header.unverified_parameters()?;
1259 start_decryption_with_provider(key, provider, aad, parameters, header)
1260}
1261
1262fn derive_header_tag(
1263 provider: Provider,
1264 key: &Key,
1265 encoded: &[u8; ENCODED_PARAMETERS_LENGTH],
1266 floe_iv: &[u8; FLOE_IV_LENGTH],
1267 aad: &[u8],
1268) -> Result<[u8; HEADER_TAG_LENGTH]> {
1269 let info: [&[u8]; 4] = [encoded, floe_iv, HEADER_TAG_PURPOSE, aad];
1270 provider.kdf_expand::<HEADER_TAG_LENGTH>(key.as_bytes(), &info)
1271}
1272
1273fn derive_message_key(
1274 provider: Provider,
1275 key: &Key,
1276 encoded: &[u8; ENCODED_PARAMETERS_LENGTH],
1277 floe_iv: &[u8; FLOE_IV_LENGTH],
1278 aad: &[u8],
1279) -> Result<SecretBytes<48>> {
1280 let info: [&[u8]; 4] = [encoded, floe_iv, MESSAGE_KEY_PURPOSE, aad];
1281 Ok(SecretBytes(
1282 provider.kdf_expand::<48>(key.as_bytes(), &info)?,
1283 ))
1284}
1285
1286fn derive_segment_key(
1287 provider: Provider,
1288 parameters: Parameters,
1289 message_key: &SecretBytes<48>,
1290 floe_iv: &[u8; FLOE_IV_LENGTH],
1291 aad: &[u8],
1292 masked_position: u64,
1293) -> Result<AeadKey> {
1294 let encoded = parameters.encode();
1295 let position_bytes = masked_position.to_be_bytes();
1296 let info: [&[u8]; 5] = [&encoded, floe_iv, SEGMENT_KEY_PURPOSE, &position_bytes, aad];
1297 let mut key_material = provider.kdf_expand::<32>(message_key.expose_bytes(), &info)?;
1298 let key = AeadKey::new(provider, &key_material);
1299 key_material.zeroize();
1300 key
1301}
1302
1303#[cfg(test)]
1304mod tests {
1305 use std::collections::HashSet;
1306
1307 use rayon::prelude::*;
1308
1309 use super::*;
1310 use crate::key::test_key;
1311 use crate::{decrypt, encrypt};
1312
1313 #[test]
1314 fn inferred_decryption_uses_header_declared_parameters() {
1315 let plaintext = b"header-selected parameters";
1317 let ciphertext = encrypt(
1318 &test_key(),
1319 b"header inference",
1320 Parameters::SEGMENT_1_MIB,
1321 plaintext,
1322 )
1323 .unwrap();
1324
1325 let header = Header::try_from(&ciphertext[..Header::LEN]).unwrap();
1327
1328 assert_eq!(Header::LEN, HEADER_LENGTH);
1331 assert_eq!(
1332 header.unverified_parameters().unwrap(),
1333 Parameters::SEGMENT_1_MIB
1334 );
1335
1336 assert_eq!(
1339 start_decryption_inferred(&test_key(), b"header inference", &header)
1340 .unwrap()
1341 .parameters(),
1342 Parameters::SEGMENT_1_MIB
1343 );
1344 assert_eq!(
1345 decrypt(&test_key(), b"header inference", &ciphertext).unwrap(),
1346 plaintext
1347 );
1348 }
1349
1350 #[test]
1351 fn tampered_header_parameters_fail_header_authentication() {
1352 let ciphertext = encrypt(
1355 &test_key(),
1356 b"header inference",
1357 Parameters::SEGMENT_1_MIB,
1358 b"header-selected parameters",
1359 )
1360 .unwrap();
1361 let mut changed_parameters = ciphertext.clone();
1362 changed_parameters[..ENCODED_PARAMETERS_LENGTH]
1363 .copy_from_slice(&Parameters::SEGMENT_4_KIB.encode());
1364
1365 let changed_header = Header::try_from(&changed_parameters[..Header::LEN]).unwrap();
1367
1368 assert_eq!(
1371 changed_header.unverified_parameters().unwrap(),
1372 Parameters::SEGMENT_4_KIB
1373 );
1374 assert_eq!(
1375 decrypt(&test_key(), b"header inference", &changed_parameters),
1376 Err(Error::InvalidHeaderTag)
1377 );
1378 }
1379
1380 #[test]
1381 fn unsupported_header_parameters_rejected_before_authentication() {
1382 let (_, header) =
1385 start_encryption(&test_key(), b"header inference", Parameters::SEGMENT_1_MIB).unwrap();
1386 let mut unsupported = <[u8; Header::LEN]>::from(header);
1387 unsupported[0] = 1;
1388 let unsupported = Header::from(unsupported);
1389
1390 assert_eq!(
1393 unsupported.unverified_parameters(),
1394 Err(Error::InvalidHeaderParameters)
1395 );
1396 assert!(matches!(
1397 start_decryption_inferred(&test_key(), b"header inference", &unsupported),
1398 Err(Error::InvalidHeaderParameters)
1399 ));
1400 }
1401
1402 #[test]
1403 fn final_segment_prefix_must_equal_actual_segment_length() {
1404 let parameters = Parameters::SEGMENT_4_KIB;
1411 let (mut encryption, header) =
1412 start_encryption(&test_key(), b"forged final prefix", parameters).unwrap();
1413 let layout = parameters.plaintext_layout(4).unwrap();
1414 let mut segment = encryption
1415 .encrypt_segment(b"last", layout.final_segment())
1416 .unwrap();
1417 let true_length = u32::try_from(segment.len()).unwrap();
1418 let forged = true_length | 0x0001_0000;
1419 segment[..SEGMENT_PREFIX_LENGTH].copy_from_slice(&forged.to_be_bytes());
1420
1421 let mut decryption =
1423 start_decryption(&test_key(), b"forged final prefix", parameters, &header).unwrap();
1424 let error = decryption
1425 .decrypt_segment_at(&segment, 0, SegmentKind::Final)
1426 .unwrap_err();
1427
1428 assert!(matches!(
1430 error,
1431 Error::InvalidCiphertextLength {
1432 actual,
1433 required: LengthRequirement::Exactly(required),
1434 } if actual == segment.len() && required == segment.len() + 0x1_0000
1435 ));
1436 }
1437
1438 #[test]
1439 fn random_access_segments_decrypt_out_of_order() {
1440 let parameters = Parameters::SEGMENT_4_KIB;
1442 let full = vec![0x5a; parameters.plaintext_segment_length()];
1443 let final_plaintext = b"final";
1444 let layout = parameters
1445 .plaintext_layout(u64::try_from(full.len() + final_plaintext.len()).unwrap())
1446 .unwrap();
1447 let segment_zero_layout = layout.segment_for_position(0).unwrap();
1448 let segment_one_layout = layout.segment_for_position(1).unwrap();
1449 let (mut encryption, header) =
1450 start_encryption(&test_key(), b"random access", parameters).unwrap();
1451 let segment_zero = encryption
1452 .encrypt_segment(&full, segment_zero_layout)
1453 .unwrap();
1454 let segment_one = encryption
1455 .encrypt_segment(final_plaintext, segment_one_layout)
1456 .unwrap();
1457
1458 let mut decryption =
1460 start_decryption(&test_key(), b"random access", parameters, &header).unwrap();
1461
1462 assert_eq!(
1464 decryption
1465 .decrypt_segment(&segment_one, segment_one_layout)
1466 .unwrap(),
1467 final_plaintext
1468 );
1469 assert_eq!(
1470 decryption
1471 .decrypt_segment(&segment_zero, segment_zero_layout)
1472 .unwrap(),
1473 full
1474 );
1475 }
1476
1477 #[test]
1478 fn failed_in_place_operations_zeroize_buffer() {
1479 let parameters = Parameters::SEGMENT_4_KIB;
1482 let (mut encryption, header) =
1483 start_encryption(&test_key(), b"buffer wipe", parameters).unwrap();
1484 let layout = parameters.plaintext_layout(5).unwrap();
1485 let mut buffer = SegmentBuffer::new(parameters);
1486 buffer
1487 .prepare_plaintext(5)
1488 .unwrap()
1489 .copy_from_slice(b"hello");
1490 let mut segment = encryption
1491 .encrypt_segment_in_place(&mut buffer, layout.final_segment())
1492 .unwrap()
1493 .to_vec();
1494
1495 let last = segment.len() - 1;
1497 segment[last] ^= 1;
1498 let mut decryption =
1499 start_decryption(&test_key(), b"buffer wipe", parameters, &header).unwrap();
1500 buffer
1501 .prepare_ciphertext(segment.len())
1502 .unwrap()
1503 .copy_from_slice(&segment);
1504 assert_eq!(
1505 decryption
1506 .decrypt_segment_in_place(&mut buffer, layout.final_segment())
1507 .unwrap_err(),
1508 Error::AuthenticationFailed
1509 );
1510
1511 assert!(buffer.raw_mut().iter().all(|&byte| byte == 0));
1513 assert_eq!(buffer.plaintext(), Err(Error::InvalidBufferState));
1514 assert_eq!(buffer.ciphertext(), Err(Error::InvalidBufferState));
1515
1516 buffer
1518 .prepare_plaintext(5)
1519 .unwrap()
1520 .copy_from_slice(b"hello");
1521 assert_eq!(
1522 encryption
1523 .encrypt_segment_in_place_at(&mut buffer, AEAD_MAX_SEGMENTS, SegmentKind::Final)
1524 .unwrap_err(),
1525 Error::SegmentLimit
1526 );
1527
1528 assert!(buffer.raw_mut().iter().all(|&byte| byte == 0));
1530 }
1531
1532 #[test]
1533 fn states_and_shared_contexts_cross_thread_boundaries() {
1534 fn assert_send<T: Send>() {}
1536 fn assert_sync<T: Sync>() {}
1537
1538 assert_send::<EncryptionState>();
1541 assert_send::<DecryptionState>();
1542 assert_send::<SharedEncryptionContext>();
1543 assert_sync::<SharedEncryptionContext>();
1544 assert_send::<SharedDecryptionContext>();
1545 assert_sync::<SharedDecryptionContext>();
1546 }
1547
1548 #[test]
1549 fn parallel_contexts_create_independent_states() {
1550 let parameters = Parameters::SEGMENT_4_KIB;
1552 let segment_length = parameters.plaintext_segment_length();
1553 let plaintext_segments: Vec<Vec<u8>> = (0..8)
1554 .map(|position| {
1555 let length = if position == 7 { 17 } else { segment_length };
1556 vec![u8::try_from(position).unwrap(); length]
1557 })
1558 .collect();
1559 let layout = parameters
1560 .plaintext_layout(
1561 plaintext_segments
1562 .iter()
1563 .map(|segment| u64::try_from(segment.len()).unwrap())
1564 .sum(),
1565 )
1566 .unwrap();
1567
1568 let (encryption, header) =
1570 start_encryption(&test_key(), b"parallel states", parameters).unwrap();
1571 let encryption = encryption.into_shared();
1572 assert_eq!(encryption.parameters(), parameters);
1573 let encrypted_segments: Vec<Vec<u8>> = plaintext_segments
1574 .par_iter()
1575 .enumerate()
1576 .map_init(
1577 || encryption.fork(),
1578 |state, (position, plaintext)| {
1579 assert_eq!(state.parameters(), parameters);
1580 let segment = layout
1581 .segment_for_position(u64::try_from(position).unwrap())
1582 .unwrap();
1583 state.encrypt_segment(plaintext, segment)
1584 },
1585 )
1586 .collect::<crate::Result<_>>()
1587 .unwrap();
1588
1589 let decryption =
1591 start_decryption(&test_key(), b"parallel states", parameters, &header).unwrap();
1592 let decryption = decryption.into_shared();
1593 assert_eq!(decryption.parameters(), parameters);
1594 let decrypted_segments: Vec<Vec<u8>> = encrypted_segments
1595 .par_iter()
1596 .enumerate()
1597 .map_init(
1598 || decryption.fork(),
1599 |state, (position, encrypted)| {
1600 assert_eq!(state.parameters(), parameters);
1601 let segment = layout
1602 .segment_for_position(u64::try_from(position).unwrap())
1603 .unwrap();
1604 state.decrypt_segment(encrypted, segment)
1605 },
1606 )
1607 .collect::<crate::Result<_>>()
1608 .unwrap();
1609
1610 assert_eq!(decrypted_segments, plaintext_segments);
1612 }
1613
1614 #[test]
1615 fn rotation_and_position_boundaries_match_specification() {
1616 const ROTATION_INTERVAL: u64 = 1 << 20;
1617
1618 let parameters = Parameters::SEGMENT_4_KIB;
1621 let (mut encryption, header) =
1622 start_encryption(&test_key(), b"position boundaries", parameters).unwrap();
1623 let before_rotation = encryption
1624 .encrypt_segment_at(b"before", ROTATION_INTERVAL - 1, SegmentKind::Final)
1625 .unwrap();
1626 let after_rotation = encryption
1627 .encrypt_segment_at(b"after", ROTATION_INTERVAL, SegmentKind::Final)
1628 .unwrap();
1629 let last_position = encryption
1630 .encrypt_segment_at(b"last", AEAD_MAX_SEGMENTS - 1, SegmentKind::Final)
1631 .unwrap();
1632
1633 assert_eq!(
1635 encryption.encrypt_segment_at(b"past", AEAD_MAX_SEGMENTS, SegmentKind::Final),
1636 Err(Error::SegmentLimit)
1637 );
1638
1639 let mut decryption =
1641 start_decryption(&test_key(), b"position boundaries", parameters, &header).unwrap();
1642
1643 assert_eq!(
1646 decryption
1647 .decrypt_segment_at(&before_rotation, ROTATION_INTERVAL - 1, SegmentKind::Final,)
1648 .unwrap(),
1649 b"before"
1650 );
1651 assert_eq!(
1652 decryption
1653 .decrypt_segment_at(&after_rotation, ROTATION_INTERVAL, SegmentKind::Final)
1654 .unwrap(),
1655 b"after"
1656 );
1657 assert_eq!(
1658 decryption
1659 .decrypt_segment_at(&last_position, AEAD_MAX_SEGMENTS - 1, SegmentKind::Final,)
1660 .unwrap(),
1661 b"last"
1662 );
1663 assert_eq!(
1664 decryption.decrypt_segment_at(&last_position, AEAD_MAX_SEGMENTS, SegmentKind::Final,),
1665 Err(Error::SegmentLimit)
1666 );
1667 }
1668
1669 #[test]
1670 fn batched_nonces_remain_unique_across_refills() {
1671 let parameters = Parameters::SEGMENT_4_KIB;
1673 let plaintext = vec![0x5a; parameters.plaintext_segment_length()];
1674 let mut encrypted = vec![0u8; parameters.ciphertext_segment_length()];
1675 let (mut encryption, _) =
1676 start_encryption(&test_key(), b"nonce batches", parameters).unwrap();
1677 let mut nonces = HashSet::new();
1678
1679 let positions = u64::try_from(2 * NONCE_BATCH_SIZE + 2).unwrap();
1680 for position in 0..positions {
1681 encryption
1683 .encrypt_segment_into_at(
1684 &plaintext,
1685 position,
1686 SegmentKind::NonFinal,
1687 &mut encrypted,
1688 )
1689 .unwrap();
1690
1691 let nonce: [u8; AEAD_IV_LENGTH] = encrypted
1693 [SEGMENT_PREFIX_LENGTH..SEGMENT_PREFIX_LENGTH + AEAD_IV_LENGTH]
1694 .try_into()
1695 .unwrap();
1696 assert!(
1697 nonces.insert(nonce),
1698 "nonce repeated at position {position}"
1699 );
1700 }
1701 }
1702
1703 #[test]
1704 fn segment_layouts_from_other_parameter_sets_rejected() {
1705 let parameters = Parameters::SEGMENT_4_KIB;
1708 let (mut encryption, _) = start_encryption(&test_key(), b"", parameters).unwrap();
1709 let wrong_profile_segment = Parameters::SEGMENT_1_MIB
1710 .plaintext_layout(3)
1711 .unwrap()
1712 .segment_for_position(0)
1713 .unwrap();
1714
1715 assert_eq!(
1718 encryption.encrypt_segment(b"abc", wrong_profile_segment),
1719 Err(Error::InvalidParameters)
1720 );
1721 }
1722
1723 #[test]
1724 fn plaintext_length_must_match_segment_layout() {
1725 let parameters = Parameters::SEGMENT_4_KIB;
1727 let segment = parameters
1728 .plaintext_layout(3)
1729 .unwrap()
1730 .segment_for_position(0)
1731 .unwrap();
1732 let (mut encryption, _) = start_encryption(&test_key(), b"", parameters).unwrap();
1733
1734 assert_eq!(
1737 encryption.encrypt_segment(b"ab", segment),
1738 Err(Error::InvalidPlaintextLength {
1739 actual: 2,
1740 required: LengthRequirement::Exactly(3),
1741 })
1742 );
1743 }
1744
1745 #[test]
1746 fn undersized_output_buffers_rejected_before_encryption() {
1747 let parameters = Parameters::SEGMENT_4_KIB;
1749 let segment = parameters
1750 .plaintext_layout(3)
1751 .unwrap()
1752 .segment_for_position(0)
1753 .unwrap();
1754 let (mut encryption, _) = start_encryption(&test_key(), b"", parameters).unwrap();
1755 let mut too_small = [0u8; SEGMENT_OVERHEAD + 2];
1756
1757 assert!(matches!(
1760 encryption.encrypt_segment_into(
1761 b"abc",
1762 segment,
1763 &mut too_small[..SEGMENT_OVERHEAD + 2]
1764 ),
1765 Err(Error::OutputTooSmall { .. })
1766 ));
1767 }
1768
1769 #[test]
1770 fn into_apis_write_exact_segment_lengths() {
1771 let parameters = Parameters::SEGMENT_4_KIB;
1773 let segment = parameters
1774 .plaintext_layout(3)
1775 .unwrap()
1776 .segment_for_position(0)
1777 .unwrap();
1778 let (mut encryption, header) = start_encryption(&test_key(), b"", parameters).unwrap();
1779
1780 let mut encrypted = [0u8; SEGMENT_OVERHEAD + 3];
1782 let encrypted_length = encryption
1783 .encrypt_segment_into(b"abc", segment, &mut encrypted)
1784 .unwrap();
1785
1786 assert_eq!(encrypted_length, SEGMENT_OVERHEAD + 3);
1789 let mut decryption = start_decryption(&test_key(), b"", parameters, &header).unwrap();
1790 let mut plaintext = [0u8; 3];
1791 assert_eq!(
1792 decryption
1793 .decrypt_segment_into(&encrypted[..encrypted_length], segment, &mut plaintext,)
1794 .unwrap(),
1795 3
1796 );
1797 assert_eq!(&plaintext, b"abc");
1798 }
1799
1800 #[test]
1801 fn segment_buffers_round_trip_in_place() {
1802 let parameters = Parameters::SEGMENT_4_KIB;
1804 let segment = parameters
1805 .plaintext_layout(3)
1806 .unwrap()
1807 .segment_for_position(0)
1808 .unwrap();
1809 let (mut encryption, header) = start_encryption(&test_key(), b"", parameters).unwrap();
1810 let mut in_place = SegmentBuffer::new(parameters);
1811 in_place
1812 .prepare_plaintext(3)
1813 .unwrap()
1814 .copy_from_slice(b"abc");
1815
1816 assert_eq!(
1818 encryption
1819 .encrypt_segment_in_place(&mut in_place, segment)
1820 .unwrap()
1821 .len(),
1822 SEGMENT_OVERHEAD + 3
1823 );
1824 let mut decryption = start_decryption(&test_key(), b"", parameters, &header).unwrap();
1825
1826 assert_eq!(
1828 decryption
1829 .decrypt_segment_in_place(&mut in_place, segment)
1830 .unwrap(),
1831 b"abc"
1832 );
1833 }
1834
1835 #[test]
1836 fn in_place_decryption_rejects_tampered_ciphertext() {
1837 let parameters = Parameters::SEGMENT_4_KIB;
1839 let segment = parameters
1840 .plaintext_layout(3)
1841 .unwrap()
1842 .segment_for_position(0)
1843 .unwrap();
1844 let (mut encryption, header) = start_encryption(&test_key(), b"", parameters).unwrap();
1845 let mut in_place = SegmentBuffer::new(parameters);
1846 in_place
1847 .prepare_plaintext(3)
1848 .unwrap()
1849 .copy_from_slice(b"abc");
1850 encryption
1851 .encrypt_segment_in_place(&mut in_place, segment)
1852 .unwrap();
1853
1854 let mut tampered = SegmentBuffer::new(parameters);
1855 tampered
1856 .prepare_ciphertext(SEGMENT_OVERHEAD + 3)
1857 .unwrap()
1858 .copy_from_slice(in_place.ciphertext().unwrap());
1859 *tampered
1860 .prepare_ciphertext(SEGMENT_OVERHEAD + 3)
1861 .unwrap()
1862 .last_mut()
1863 .unwrap() ^= 1;
1864
1865 let mut decryption = start_decryption(&test_key(), b"", parameters, &header).unwrap();
1868 assert_eq!(
1869 decryption.decrypt_segment_in_place(&mut tampered, segment),
1870 Err(Error::AuthenticationFailed)
1871 );
1872 }
1873
1874 #[test]
1875 fn segment_position_is_authenticated() {
1876 let parameters = Parameters::SEGMENT_4_KIB;
1878 let (mut encryption, header) = start_encryption(&test_key(), b"", parameters).unwrap();
1879 let segment_bytes = encryption
1880 .encrypt_segment_at(b"data", 5, SegmentKind::Final)
1881 .unwrap();
1882
1883 let mut decryption = start_decryption(&test_key(), b"", parameters, &header).unwrap();
1886 assert_eq!(
1887 decryption.decrypt_segment_at(&segment_bytes, 6, SegmentKind::Final),
1888 Err(Error::AuthenticationFailed)
1889 );
1890 }
1891
1892 #[test]
1893 fn final_indicator_is_authenticated() {
1894 let parameters = Parameters::SEGMENT_4_KIB;
1897 let (mut encryption, header) = start_encryption(&test_key(), b"", parameters).unwrap();
1898 let segment_bytes = encryption
1899 .encrypt_segment_at(b"data", 5, SegmentKind::Final)
1900 .unwrap();
1901 let mut forged_non_final = vec![0u8; parameters.ciphertext_segment_length()];
1902 forged_non_final[..4].copy_from_slice(&u32::MAX.to_be_bytes());
1903 forged_non_final[4..4 + segment_bytes.len() - 4].copy_from_slice(&segment_bytes[4..]);
1904
1905 let mut decryption = start_decryption(&test_key(), b"", parameters, &header).unwrap();
1908 assert_eq!(
1909 decryption.decrypt_segment_at(&forged_non_final, 5, SegmentKind::NonFinal),
1910 Err(Error::AuthenticationFailed)
1911 );
1912 }
1913
1914 fn raw_encrypted_segment(
1919 payload: &[u8],
1920 trailing_plaintext: u64,
1921 ) -> (Vec<u8>, SegmentLayout, DecryptionState) {
1922 let parameters = Parameters::SEGMENT_4_KIB;
1923 let total = length_usize_to_u64(payload.len()) + trailing_plaintext;
1924 let segment = parameters
1925 .plaintext_layout(total)
1926 .unwrap()
1927 .segment_for_position(0)
1928 .unwrap();
1929 assert_eq!(segment.plaintext_length(), payload.len());
1930 let (mut encryption, header) = start_encryption(&test_key(), b"raw", parameters).unwrap();
1931 let mut storage = vec![0u8; segment.ciphertext_length()];
1932 storage[SEGMENT_PAYLOAD_OFFSET..SEGMENT_PAYLOAD_OFFSET + payload.len()]
1933 .copy_from_slice(payload);
1934 let written = encryption
1935 .encrypt_segment_in_place_raw(&mut storage, segment)
1936 .unwrap();
1937 assert_eq!(written, segment.ciphertext_length());
1938 let decryption = start_decryption(&test_key(), b"raw", parameters, &header).unwrap();
1939 (storage, segment, decryption)
1940 }
1941
1942 #[test]
1943 fn raw_in_place_final_segment_round_trips() {
1944 let (mut storage, segment, mut decryption) = raw_encrypted_segment(b"hello", 0);
1946
1947 let prefix = u32::from_be_bytes(storage[..SEGMENT_PREFIX_LENGTH].try_into().unwrap());
1949 assert_eq!(prefix, u32::try_from(storage.len()).unwrap());
1950
1951 let plaintext = decryption
1954 .decrypt_segment_in_place_raw(&mut storage, segment)
1955 .unwrap();
1956 assert_eq!(&plaintext[..], b"hello");
1957 }
1958
1959 #[test]
1960 fn raw_in_place_non_final_segment_round_trips() {
1961 let parameters = Parameters::SEGMENT_4_KIB;
1963 let full = vec![0x5a; parameters.plaintext_segment_length()];
1964 let (mut storage, segment, mut decryption) = raw_encrypted_segment(&full, 5);
1965
1966 assert_eq!(storage.len(), parameters.ciphertext_segment_length());
1968 let prefix = u32::from_be_bytes(storage[..SEGMENT_PREFIX_LENGTH].try_into().unwrap());
1969 assert_eq!(prefix, u32::MAX);
1970
1971 let plaintext = decryption
1974 .decrypt_segment_in_place_raw(&mut storage, segment)
1975 .unwrap();
1976 assert_eq!(&plaintext[..], &full[..]);
1977 }
1978
1979 #[test]
1980 fn raw_in_place_encryption_rejects_short_storage() {
1981 let parameters = Parameters::SEGMENT_4_KIB;
1983 let segment = parameters.plaintext_layout(5).unwrap().final_segment();
1984 let required = segment.ciphertext_length();
1985 let (mut encryption, _header) = start_encryption(&test_key(), b"raw", parameters).unwrap();
1986 let mut storage = vec![0u8; required - 1];
1987
1988 assert_eq!(
1990 encryption.encrypt_segment_in_place_raw(&mut storage, segment),
1991 Err(Error::OutputTooSmall {
1992 actual: required - 1,
1993 required,
1994 })
1995 );
1996 }
1997
1998 #[test]
1999 fn raw_in_place_decryption_rejects_short_storage() {
2000 let parameters = Parameters::SEGMENT_4_KIB;
2002 let segment = parameters.plaintext_layout(5).unwrap().final_segment();
2003 let required = segment.ciphertext_length();
2004 let (_, header) = start_encryption(&test_key(), b"raw", parameters).unwrap();
2005 let mut decryption = start_decryption(&test_key(), b"raw", parameters, &header).unwrap();
2006 let mut storage = vec![0u8; required - 1];
2007
2008 assert!(matches!(
2010 decryption.decrypt_segment_in_place_raw(&mut storage, segment),
2011 Err(Error::InvalidCiphertextLength {
2012 actual,
2013 required: LengthRequirement::AtLeast(at_least),
2014 }) if actual == required - 1 && at_least == required
2015 ));
2016 }
2017
2018 #[test]
2019 fn raw_in_place_apis_reject_layout_from_another_parameter_set() {
2020 let parameters = Parameters::SEGMENT_4_KIB;
2022 let foreign = Parameters::SEGMENT_1_MIB
2023 .plaintext_layout(5)
2024 .unwrap()
2025 .final_segment();
2026 let (mut encryption, header) = start_encryption(&test_key(), b"raw", parameters).unwrap();
2027 let mut decryption = start_decryption(&test_key(), b"raw", parameters, &header).unwrap();
2028 let mut storage = vec![0u8; foreign.ciphertext_length()];
2029
2030 assert_eq!(
2033 encryption.encrypt_segment_in_place_raw(&mut storage, foreign),
2034 Err(Error::InvalidParameters)
2035 );
2036 assert!(matches!(
2037 decryption.decrypt_segment_in_place_raw(&mut storage, foreign),
2038 Err(Error::InvalidParameters)
2039 ));
2040 }
2041
2042 #[test]
2043 fn raw_in_place_decryption_rejects_forged_final_prefix() {
2044 let (mut storage, segment, mut decryption) = raw_encrypted_segment(b"hello", 0);
2046
2047 let mut forged = storage.clone();
2050 let declared = u32::try_from(segment.ciphertext_length()).unwrap() + 1;
2051 forged[..SEGMENT_PREFIX_LENGTH].copy_from_slice(&declared.to_be_bytes());
2052 assert!(matches!(
2053 decryption.decrypt_segment_in_place_raw(&mut forged, segment),
2054 Err(Error::InvalidCiphertextLength {
2055 actual,
2056 required: LengthRequirement::Exactly(required),
2057 }) if actual == segment.ciphertext_length()
2058 && required == segment.ciphertext_length() + 1
2059 ));
2060
2061 assert_eq!(
2063 &decryption
2064 .decrypt_segment_in_place_raw(&mut storage, segment)
2065 .unwrap()[..],
2066 b"hello"
2067 );
2068 }
2069
2070 #[test]
2071 fn raw_in_place_non_final_decryption_rejects_corrupt_prefix() {
2072 let full = vec![0x5a; Parameters::SEGMENT_4_KIB.plaintext_segment_length()];
2074 let (mut storage, segment, mut decryption) = raw_encrypted_segment(&full, 5);
2075 storage[..SEGMENT_PREFIX_LENGTH].fill(0);
2076
2077 assert!(matches!(
2080 decryption.decrypt_segment_in_place_raw(&mut storage, segment),
2081 Err(Error::InvalidSegmentPrefix)
2082 ));
2083 }
2084
2085 #[test]
2086 fn in_place_wrappers_reject_buffers_from_another_parameter_set() {
2087 let parameters = Parameters::SEGMENT_4_KIB;
2089 let segment = parameters.plaintext_layout(3).unwrap().final_segment();
2090 let (mut encryption, header) = start_encryption(&test_key(), b"raw", parameters).unwrap();
2091 let mut decryption = start_decryption(&test_key(), b"raw", parameters, &header).unwrap();
2092 let mut foreign = SegmentBuffer::new(Parameters::SEGMENT_64_B);
2093
2094 foreign
2097 .prepare_plaintext(3)
2098 .unwrap()
2099 .copy_from_slice(b"abc");
2100 assert_eq!(
2101 encryption.encrypt_segment_in_place(&mut foreign, segment),
2102 Err(Error::InvalidParameters)
2103 );
2104
2105 foreign.prepare_ciphertext(SEGMENT_OVERHEAD + 3).unwrap();
2108 assert!(matches!(
2109 decryption.decrypt_segment_in_place(&mut foreign, segment),
2110 Err(Error::InvalidParameters)
2111 ));
2112 }
2113
2114 #[test]
2115 fn in_place_decryption_rejects_prepared_length_disagreeing_with_layout() {
2116 let parameters = Parameters::SEGMENT_4_KIB;
2118 let segment = parameters.plaintext_layout(3).unwrap().final_segment();
2119 let (_, header) = start_encryption(&test_key(), b"raw", parameters).unwrap();
2120 let mut decryption = start_decryption(&test_key(), b"raw", parameters, &header).unwrap();
2121 let mut buffer = SegmentBuffer::new(parameters);
2122 buffer.prepare_ciphertext(SEGMENT_OVERHEAD + 4).unwrap();
2123
2124 assert!(matches!(
2127 decryption.decrypt_segment_in_place(&mut buffer, segment),
2128 Err(Error::InvalidCiphertextLength {
2129 actual,
2130 required: LengthRequirement::Exactly(required),
2131 }) if actual == SEGMENT_OVERHEAD + 4 && required == SEGMENT_OVERHEAD + 3
2132 ));
2133 }
2134}