1use aes::Aes256;
6use aes::cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit};
7use anyhow::anyhow;
8use async_trait::async_trait;
9use chacha20::cipher::{KeyIvInit, StreamCipher as _, StreamCipherSeek};
10use chacha20::{self, ChaCha20};
11use fprint::TypeFingerprint;
12use futures::TryStreamExt as _;
13use futures::stream::FuturesUnordered;
14use serde::de::{Error as SerdeError, Visitor};
15use serde::{Deserialize, Deserializer, Serialize, Serializer};
16use std::collections::BTreeMap;
17use storage_xts::{Tweak, XtsCtsProcessor};
18use zerocopy::IntoBytes;
19use zx_status as zx;
20
21mod cipher;
22pub mod ff1;
23
24pub use cipher::fscrypt_ino_lblk32::{
25 FscryptInoLblk32FileCipher, FscryptSoftwareInoLblk32FileCipher,
26};
27pub use cipher::fscrypt_ino_lblk64::{FscryptInoLblk64DirCipher, FscryptInoLblk64FileCipher};
28pub use cipher::fxfs::FxfsCipher;
29pub use cipher::{
30 Cipher, CipherHolder, CipherSet, FindKeyResult, KeyType, MutPtrByteSlice, PtrByteSlice,
31 key_to_cipher,
32};
33pub use fidl_fuchsia_fxfs::{
34 EmptyStruct, FscryptKeyIdentifier, FscryptKeyIdentifierAndNonce, ObjectType, WrappedKey,
35};
36
37pub use cipher::FSCRYPT_PADDING;
38pub const FXFS_KEY_SIZE: usize = 256 / 8;
39pub const FXFS_WRAPPED_KEY_SIZE: usize = FXFS_KEY_SIZE + 16;
40
41#[derive(Debug)]
44pub struct UnwrappedKey {
45 key: Vec<u8>,
46 slot: Option<u8>,
48}
49impl UnwrappedKey {
50 pub fn new(key: Vec<u8>) -> Self {
51 Self { key, slot: None }
52 }
53
54 pub fn new_with_slot(key: Vec<u8>, slot: Option<u8>) -> Self {
55 Self { key, slot }
56 }
57
58 pub fn slot(&self) -> Option<u8> {
59 self.slot
60 }
61}
62impl std::ops::Deref for UnwrappedKey {
63 type Target = Vec<u8>;
64 fn deref(&self) -> &Self::Target {
65 &self.key
66 }
67}
68impl std::ops::DerefMut for UnwrappedKey {
69 fn deref_mut(&mut self) -> &mut Self::Target {
70 &mut self.key
71 }
72}
73
74#[repr(transparent)]
76#[derive(Clone, Debug, PartialEq)]
77pub struct WrappedKeyBytes(pub [u8; FXFS_WRAPPED_KEY_SIZE]);
78impl Default for WrappedKeyBytes {
79 fn default() -> Self {
80 Self([0u8; FXFS_WRAPPED_KEY_SIZE])
81 }
82}
83impl TryFrom<Vec<u8>> for WrappedKeyBytes {
84 type Error = anyhow::Error;
85
86 fn try_from(buf: Vec<u8>) -> Result<Self, Self::Error> {
87 Ok(Self(buf.try_into().map_err(|_| anyhow!("wrapped key wrong length"))?))
88 }
89}
90impl From<[u8; FXFS_WRAPPED_KEY_SIZE]> for WrappedKeyBytes {
91 fn from(buf: [u8; FXFS_WRAPPED_KEY_SIZE]) -> Self {
92 Self(buf)
93 }
94}
95impl TypeFingerprint for WrappedKeyBytes {
96 fn fingerprint() -> String {
97 "WrappedKeyBytes".to_owned()
98 }
99}
100
101impl std::ops::Deref for WrappedKeyBytes {
102 type Target = [u8; FXFS_WRAPPED_KEY_SIZE];
103 fn deref(&self) -> &Self::Target {
104 &self.0
105 }
106}
107
108impl std::ops::DerefMut for WrappedKeyBytes {
109 fn deref_mut(&mut self) -> &mut Self::Target {
110 &mut self.0
111 }
112}
113
114impl Serialize for WrappedKeyBytes {
117 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
118 where
119 S: Serializer,
120 {
121 serializer.serialize_bytes(&self[..])
122 }
123}
124
125impl<'de> Deserialize<'de> for WrappedKeyBytes {
126 fn deserialize<D>(deserializer: D) -> Result<WrappedKeyBytes, D::Error>
127 where
128 D: Deserializer<'de>,
129 {
130 struct WrappedKeyVisitor;
131
132 impl<'d> Visitor<'d> for WrappedKeyVisitor {
133 type Value = WrappedKeyBytes;
134
135 fn expecting(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
136 formatter.write_str("Expected wrapped keys to be 48 bytes")
137 }
138
139 fn visit_bytes<E>(self, bytes: &[u8]) -> Result<WrappedKeyBytes, E>
140 where
141 E: SerdeError,
142 {
143 self.visit_byte_buf(bytes.to_vec())
144 }
145
146 fn visit_byte_buf<E>(self, bytes: Vec<u8>) -> Result<WrappedKeyBytes, E>
147 where
148 E: SerdeError,
149 {
150 let orig_len = bytes.len();
151 let bytes: [u8; FXFS_WRAPPED_KEY_SIZE] =
152 bytes.try_into().map_err(|_| SerdeError::invalid_length(orig_len, &self))?;
153 Ok(WrappedKeyBytes::from(bytes))
154 }
155 }
156 deserializer.deserialize_byte_buf(WrappedKeyVisitor)
157 }
158}
159
160fn reject_legacy_key<'de, D: Deserializer<'de>>(_: D) -> Result<FxfsKey, D::Error> {
161 Err(SerdeError::custom("LegacyFxfs keys are no longer supported"))
162}
163
164#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
166pub enum EncryptionKey {
167 LegacyFxfs(#[serde(deserialize_with = "reject_legacy_key")] FxfsKey),
169 FscryptInoLblk32File {
175 key_identifier: [u8; 16],
176 },
177 FscryptInoLblk32Dir {
178 key_identifier: [u8; 16],
179 nonce: [u8; 16],
180 },
181 Fxfs(FxfsKey),
183 FscryptInoLblk64File {
184 key_identifier: [u8; 16],
185 },
186 FscryptInoLblk64Dir {
187 key_identifier: [u8; 16],
188 nonce: [u8; 16],
189 },
190}
191
192impl EncryptionKey {
193 pub fn wrapping_key_id(&self) -> Option<WrappingKeyId> {
194 match self {
195 EncryptionKey::LegacyFxfs(_) => unreachable!(),
196 EncryptionKey::Fxfs(key) => Some(key.wrapping_key_id),
197 EncryptionKey::FscryptInoLblk32File { key_identifier }
198 | EncryptionKey::FscryptInoLblk32Dir { key_identifier, .. }
199 | EncryptionKey::FscryptInoLblk64File { key_identifier }
200 | EncryptionKey::FscryptInoLblk64Dir { key_identifier, .. } => Some(*key_identifier),
201 }
202 }
203}
204
205impl<'a> arbitrary::Arbitrary<'a> for EncryptionKey {
206 fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
207 Ok(match u.int_in_range(0..=4)? {
208 0 => EncryptionKey::FscryptInoLblk32File { key_identifier: u.arbitrary()? },
209 1 => EncryptionKey::FscryptInoLblk32Dir {
210 key_identifier: u.arbitrary()?,
211 nonce: u.arbitrary()?,
212 },
213 2 => EncryptionKey::Fxfs(u.arbitrary()?),
214 3 => EncryptionKey::FscryptInoLblk64File { key_identifier: u.arbitrary()? },
215 4 => EncryptionKey::FscryptInoLblk64Dir {
216 key_identifier: u.arbitrary()?,
217 nonce: u.arbitrary()?,
218 },
219 _ => unreachable!(),
220 })
221 }
222}
223
224impl From<EncryptionKey> for WrappedKey {
225 fn from(value: EncryptionKey) -> Self {
226 match value {
227 EncryptionKey::LegacyFxfs(_) => unreachable!(),
228 EncryptionKey::Fxfs(key) => WrappedKey::Fxfs(key.into()),
229 EncryptionKey::FscryptInoLblk32File { key_identifier } => {
230 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier })
231 }
232 EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce } => {
233 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
234 key_identifier,
235 nonce,
236 })
237 }
238 EncryptionKey::FscryptInoLblk64File { key_identifier } => {
239 WrappedKey::FscryptInoLblk64File(FscryptKeyIdentifier { key_identifier })
240 }
241 EncryptionKey::FscryptInoLblk64Dir { key_identifier, nonce } => {
242 WrappedKey::FscryptInoLblk64Dir(FscryptKeyIdentifierAndNonce {
243 key_identifier,
244 nonce,
245 })
246 }
247 }
248 }
249}
250
251impl From<&EncryptionKey> for KeyType {
252 fn from(value: &EncryptionKey) -> Self {
253 match value {
254 EncryptionKey::LegacyFxfs(_) => unreachable!(),
255 EncryptionKey::Fxfs(_) => KeyType::Fxfs,
256 EncryptionKey::FscryptInoLblk32File { .. } => KeyType::FscryptInoLblk32File,
257 EncryptionKey::FscryptInoLblk32Dir { .. } => KeyType::FscryptInoLblk32Dir,
258 EncryptionKey::FscryptInoLblk64File { .. } => KeyType::FscryptInoLblk64File,
259 EncryptionKey::FscryptInoLblk64Dir { .. } => KeyType::FscryptInoLblk64Dir,
260 }
261 }
262}
263
264impl TryFrom<WrappedKey> for EncryptionKey {
265 type Error = zx::Status;
266
267 fn try_from(value: WrappedKey) -> Result<Self, Self::Error> {
268 Ok(match value {
269 WrappedKey::Fxfs(fidl_fuchsia_fxfs::FxfsKey { wrapping_key_id, wrapped_key }) => {
270 EncryptionKey::Fxfs(FxfsKey { wrapping_key_id, key: WrappedKeyBytes(wrapped_key) })
271 }
272 WrappedKey::FscryptInoLblk32File(FscryptKeyIdentifier { key_identifier }) => {
273 EncryptionKey::FscryptInoLblk32File { key_identifier }
274 }
275 WrappedKey::FscryptInoLblk32Dir(FscryptKeyIdentifierAndNonce {
276 key_identifier,
277 nonce,
278 }) => EncryptionKey::FscryptInoLblk32Dir { key_identifier, nonce },
279 WrappedKey::FscryptInoLblk64File(FscryptKeyIdentifier { key_identifier }) => {
280 EncryptionKey::FscryptInoLblk64File { key_identifier }
281 }
282 WrappedKey::FscryptInoLblk64Dir(FscryptKeyIdentifierAndNonce {
283 key_identifier,
284 nonce,
285 }) => EncryptionKey::FscryptInoLblk64Dir { key_identifier, nonce },
286 _ => return Err(zx::Status::NOT_SUPPORTED),
287 })
288 }
289}
290
291#[derive(Clone, Default, Debug, Serialize, Deserialize, TypeFingerprint, PartialEq)]
294pub struct FxfsKey {
295 pub wrapping_key_id: WrappingKeyId,
298 pub key: WrappedKeyBytes,
304}
305
306pub type WrappingKeyId = [u8; 16];
307
308impl From<FxfsKey> for fidl_fuchsia_fxfs::FxfsKey {
309 fn from(value: FxfsKey) -> Self {
310 fidl_fuchsia_fxfs::FxfsKey {
311 wrapping_key_id: value.wrapping_key_id,
312 wrapped_key: value.key.0,
313 }
314 }
315}
316
317impl<'a> arbitrary::Arbitrary<'a> for FxfsKey {
318 fn arbitrary(_u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
319 return Ok(FxfsKey::default());
321 }
322}
323
324pub struct StreamCipher(ChaCha20);
328
329impl StreamCipher {
330 pub fn new(key: &UnwrappedKey, offset: u64) -> Self {
331 let mut cipher = Self(ChaCha20::new(
332 &chacha20::Key::try_from(&key[..]).expect("Invalid StreamCipher key length"),
333 &[0; 12].into(),
334 ));
335 cipher.0.seek(offset);
336 cipher
337 }
338
339 pub fn encrypt(&mut self, buffer: &mut [u8]) {
340 fxfs_trace::duration!("StreamCipher::encrypt", "len" => buffer.len());
341 self.0.apply_keystream(buffer);
342 }
343
344 pub fn decrypt(&mut self, buffer: &mut [u8]) {
345 fxfs_trace::duration!("StreamCipher::decrypt", "len" => buffer.len());
346 self.0.apply_keystream(buffer);
347 }
348
349 pub fn offset(&self) -> u64 {
350 self.0.current_pos()
351 }
352
353 pub fn key_is_new(&self) -> bool {
354 0 == self.0.current_pos()
355 }
356}
357
358pub struct JournalXtsCipher {
360 key: Aes256,
361 aligned_buf: Vec<u128>,
363 tweak: u64,
364 key_start_tweak: u64,
365}
366
367impl JournalXtsCipher {
368 pub fn new(key: &UnwrappedKey, tweak: u64) -> Self {
369 Self {
370 key: Aes256::new(key.as_slice().try_into().expect("Invalid key length")),
371 aligned_buf: Vec::new(),
372 tweak,
373 key_start_tweak: tweak,
374 }
375 }
376
377 pub fn encrypt(&mut self, buffer: &[u8]) -> Vec<u8> {
380 let out_len = std::cmp::max(buffer.len(), 16);
381 let mut out_buf = vec![0u8; out_len];
382 let mut tweak = Tweak::new(self.tweak as u128);
383 self.key.encrypt_block(tweak.as_mut_bytes().try_into().unwrap());
384 if buffer.as_ptr().cast::<u128>().is_aligned()
385 && buffer.len() >= 16
386 && out_buf.as_ptr().cast::<u128>().is_aligned()
387 {
388 let slice = PtrByteSlice::from(buffer);
389 let out_slice = MutPtrByteSlice::from(&mut out_buf[..]);
390 self.key.encrypt_with_backend(XtsCtsProcessor::new(tweak, slice, out_slice));
391 } else {
392 self.aligned_buf.resize(out_len.div_ceil(16), 0u128);
393 let aligned_bytes = &mut self.aligned_buf.as_mut_bytes()[..out_len];
394 if buffer.len() < 16 {
395 aligned_bytes.fill(0);
396 }
397 aligned_bytes[..buffer.len()].copy_from_slice(buffer);
398 let slice = MutPtrByteSlice::from(&mut *aligned_bytes);
399 self.key.encrypt_with_backend(XtsCtsProcessor::new_in_place(tweak, slice));
400 out_buf.copy_from_slice(&aligned_bytes[..out_len]);
401 }
402 self.tweak += 1;
403 out_buf
404 }
405
406 pub fn decrypt(&mut self, buffer: &mut [u8]) {
409 assert!(buffer.len() >= 16);
410 let len = buffer.len();
411 let mut tweak = Tweak::new(self.tweak as u128);
412 self.key.encrypt_block(tweak.as_mut_bytes().try_into().unwrap());
413
414 if buffer.as_ptr().cast::<u128>().is_aligned() {
415 let slice = MutPtrByteSlice::from(buffer);
416 self.key.decrypt_with_backend(XtsCtsProcessor::new_in_place(tweak, slice));
417 } else {
418 self.aligned_buf.resize(buffer.len().div_ceil(16), 0u128);
419 let aligned_bytes = &mut self.aligned_buf.as_mut_bytes()[..len];
420 aligned_bytes.copy_from_slice(buffer);
421 let slice = MutPtrByteSlice::from(aligned_bytes);
422 self.key.decrypt_with_backend(XtsCtsProcessor::new_in_place(tweak, slice));
423 buffer.copy_from_slice(&self.aligned_buf.as_bytes()[..len]);
424 }
425 self.tweak += 1;
426 }
427
428 pub fn current_tweak(&self) -> u64 {
429 self.tweak
430 }
431
432 pub fn key_is_new(&self) -> bool {
433 self.tweak - self.key_start_tweak == 0
434 }
435}
436
437pub enum JournalCipher {
438 ChaCha20(StreamCipher),
439 Aes256Xts(Box<JournalXtsCipher>),
440}
441
442impl JournalCipher {
443 pub fn new_chacha20(key: &UnwrappedKey, offset: u64) -> Self {
444 JournalCipher::ChaCha20(StreamCipher::new(key, offset))
445 }
446
447 pub fn new_aes256_xts(key: &UnwrappedKey, current_tweak: u64) -> Self {
448 JournalCipher::Aes256Xts(Box::new(JournalXtsCipher::new(key, current_tweak)))
449 }
450
451 pub fn encrypt(&mut self, buffer: &[u8]) -> Vec<u8> {
452 match self {
453 JournalCipher::ChaCha20(_) => unreachable!(),
454 JournalCipher::Aes256Xts(c) => c.encrypt(buffer),
455 }
456 }
457
458 pub fn decrypt(&mut self, buffer: &mut [u8]) {
459 match self {
460 JournalCipher::ChaCha20(c) => c.decrypt(buffer),
461 JournalCipher::Aes256Xts(c) => c.decrypt(buffer),
462 }
463 }
464
465 pub fn sequence_number(&self) -> u64 {
466 match self {
467 JournalCipher::ChaCha20(c) => c.offset(),
468 JournalCipher::Aes256Xts(c) => c.current_tweak(),
469 }
470 }
471
472 pub fn key_is_new(&self) -> bool {
474 match self {
475 JournalCipher::ChaCha20(c) => c.key_is_new(),
476 JournalCipher::Aes256Xts(c) => c.key_is_new(),
477 }
478 }
479}
480
481pub enum KeyPurpose {
484 Data,
486 Metadata,
488}
489
490impl TryFrom<fidl_fuchsia_fxfs::KeyPurpose> for KeyPurpose {
491 type Error = zx::Status;
492
493 fn try_from(purpose: fidl_fuchsia_fxfs::KeyPurpose) -> Result<Self, Self::Error> {
494 match purpose {
495 fidl_fuchsia_fxfs::KeyPurpose::Data => Ok(KeyPurpose::Data),
496 fidl_fuchsia_fxfs::KeyPurpose::Metadata => Ok(KeyPurpose::Metadata),
497 _ => Err(zx::Status::INVALID_ARGS),
498 }
499 }
500}
501
502impl From<KeyPurpose> for fidl_fuchsia_fxfs::KeyPurpose {
503 fn from(purpose: KeyPurpose) -> Self {
504 match purpose {
505 KeyPurpose::Data => fidl_fuchsia_fxfs::KeyPurpose::Data,
506 KeyPurpose::Metadata => fidl_fuchsia_fxfs::KeyPurpose::Metadata,
507 }
508 }
509}
510
511pub enum WrappingKey {
514 Aes256GcmSiv([u8; 32]),
516 Fscrypt([u8; 64]),
518}
519impl From<[u8; 32]> for WrappingKey {
520 fn from(value: [u8; 32]) -> Self {
521 WrappingKey::Aes256GcmSiv(value)
522 }
523}
524impl From<[u8; 64]> for WrappingKey {
525 fn from(value: [u8; 64]) -> Self {
526 WrappingKey::Fscrypt(value)
527 }
528}
529
530#[async_trait]
538pub trait Crypt: Send + Sync {
539 async fn create_key(
544 &self,
545 owner: u64,
546 purpose: KeyPurpose,
547 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status>;
548
549 async fn create_key_with_id(
554 &self,
555 owner: u64,
556 wrapping_key_id: WrappingKeyId,
557 object_type: ObjectType,
558 flags: fidl_fuchsia_io::FscryptPolicyFlags,
559 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status>;
560
561 async fn unwrap_key(
567 &self,
568 wrapped_key: &WrappedKey,
569 owner: u64,
570 ) -> Result<UnwrappedKey, zx::Status>;
571
572 async fn unwrap_keys(
577 &self,
578 keys: &[(u64, EncryptionKey)],
579 owner: u64,
580 ) -> Result<CipherSet, zx::Status> {
581 let futures: FuturesUnordered<_> = keys
582 .iter()
583 .map(|(key_id, key)| {
584 let key_id = *key_id;
585 let wrapped_key = WrappedKey::from(key.clone());
586 let owner = owner;
587 async move {
588 match self.unwrap_key(&wrapped_key, owner).await {
589 Ok(unwrapped_key) => cipher::key_to_cipher(key, &unwrapped_key)
590 .map(|c| (key_id, cipher::CipherHolder::Cipher(c))),
591 Err(zx::Status::UNAVAILABLE) => {
592 Ok((key_id, cipher::CipherHolder::Unavailable))
593 }
594 Err(e) => Err(e),
595 }
596 }
597 })
598 .collect();
599 let result = futures.try_collect::<BTreeMap<u64, _>>().await?;
600 Ok(result.into())
601 }
602}
603
604#[cfg(test)]
605mod tests {
606 use super::{JournalCipher, JournalXtsCipher, StreamCipher, UnwrappedKey};
607 use zerocopy::IntoBytes;
608
609 #[test]
610 fn test_journal_xts_cipher_roundtrip() {
611 let key = UnwrappedKey::new(vec![0x42; 32]);
612 let mut enc = JournalXtsCipher::new(&key, 0);
613 let mut dec = JournalXtsCipher::new(&key, 0);
614
615 let buf_short = vec![1, 2, 3, 4, 5];
617 let mut enc_short = enc.encrypt(&buf_short);
618 assert_eq!(enc_short.len(), 16);
619 dec.decrypt(&mut enc_short);
620 assert_eq!(&enc_short[..5], &[1, 2, 3, 4, 5]);
621 assert_eq!(&enc_short[5..], &[0; 11]);
622 assert_eq!(enc.current_tweak(), 1);
623 assert_eq!(dec.current_tweak(), 1);
624
625 let buf_16 = vec![7u8; 16];
627 let mut enc_16 = enc.encrypt(&buf_16);
628 assert_eq!(enc_16.len(), 16);
629 dec.decrypt(&mut enc_16);
630 assert_eq!(enc_16, vec![7u8; 16]);
631 assert_eq!(enc.current_tweak(), 2);
632 assert_eq!(dec.current_tweak(), 2);
633
634 let buf_25: Vec<u8> = (0..25).collect();
636 let mut enc_25 = enc.encrypt(&buf_25);
637 assert_eq!(enc_25.len(), 25);
638 dec.decrypt(&mut enc_25);
639 assert_eq!(enc_25, (0..25).collect::<Vec<u8>>());
640 assert_eq!(enc.current_tweak(), 3);
641 assert_eq!(dec.current_tweak(), 3);
642 }
643
644 #[test]
645 fn test_journal_cipher_enum() {
646 let key = UnwrappedKey::new(vec![0x33; 32]);
647 let mut enc = JournalCipher::new_aes256_xts(&key, 0);
648 let mut dec = JournalCipher::new_aes256_xts(&key, 0);
649
650 let buf = vec![9u8; 20];
651 let mut enc_buf = enc.encrypt(&buf);
652 assert_eq!(enc_buf.len(), 20);
653 dec.decrypt(&mut enc_buf);
654 assert_eq!(enc_buf, vec![9u8; 20]);
655 assert_eq!(enc.sequence_number(), 1);
656 }
657
658 #[test]
659 fn test_stream_cipher_offset() {
660 let key = UnwrappedKey::new(vec![
661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
662 25, 26, 27, 28, 29, 30, 31, 32,
663 ]);
664 let mut cipher1 = StreamCipher::new(&key, 0);
665 let mut p1 = [1, 2, 3, 4];
666 let mut c1 = p1.clone();
667 cipher1.encrypt(&mut c1);
668
669 let mut cipher2 = StreamCipher::new(&key, 1);
670 let p2 = [5, 6, 7, 8];
671 let mut c2 = p2.clone();
672 cipher2.encrypt(&mut c2);
673
674 let xor_fn = |buf1: &mut [u8], buf2| {
675 for (b1, b2) in buf1.iter_mut().zip(buf2) {
676 *b1 ^= b2;
677 }
678 };
679
680 xor_fn(&mut c1, &c2);
683 xor_fn(&mut p1, &p2);
684 assert_ne!(c1, p1);
685 }
686
687 #[test]
688 fn test_journal_xts_cipher_aligned_and_unaligned_allocations() {
689 let key = UnwrappedKey::new(vec![0x5a; 32]);
690 let test_lengths = [1, 5, 16, 25];
691 let backing_size: usize = test_lengths.iter().max().unwrap() + 1;
693 let mut backing_vector = vec![0u128; backing_size.div_ceil(16)];
695
696 for &len in &test_lengths {
697 let plaintext = vec![42u8; len];
698 let mut expected_plaintext = plaintext.clone();
699 if expected_plaintext.len() < 16 {
700 expected_plaintext.resize(16, 0);
701 }
702
703 {
705 let buf = &mut backing_vector.as_mut_bytes()[..len];
706 assert!(buf.as_ptr().cast::<u128>().is_aligned());
707 buf.copy_from_slice(plaintext.as_slice());
708 let mut encrypted = {
709 let mut enc = JournalXtsCipher::new(&key, 13);
710 enc.encrypt(buf)
711 };
712 {
713 let mut dec = JournalXtsCipher::new(&key, 13);
714 dec.decrypt(&mut encrypted);
715 }
716 assert_eq!(encrypted, expected_plaintext);
717 }
718
719 {
721 let buf = &mut backing_vector.as_mut_bytes()[1..1 + len];
722 assert!(!buf.as_ptr().cast::<u128>().is_aligned());
723 buf.copy_from_slice(plaintext.as_slice());
724 let mut encrypted = {
725 let mut enc = JournalXtsCipher::new(&key, 13);
726 enc.encrypt(buf)
727 };
728 {
729 let mut dec = JournalXtsCipher::new(&key, 13);
730 dec.decrypt(&mut encrypted);
731 }
732 assert_eq!(encrypted, expected_plaintext);
733 }
734 }
735 }
736}