nydus_utils/
crypt.rs

1// Copyright (C) 2022-2023 Alibaba Cloud. All rights reserved.
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use std::alloc::{alloc, Layout};
6use std::borrow::Cow;
7use std::convert::TryFrom;
8use std::fmt::{self, Debug, Formatter};
9use std::io::Error;
10use std::str::FromStr;
11use std::sync::Arc;
12
13use openssl::{rand, symm};
14
15// The length of the data unit to be encrypted.
16pub const DATA_UNIT_LENGTH: usize = 16;
17// The length of thd iv (Initialization Vector) to do AES-XTS encryption.
18pub const AES_XTS_IV_LENGTH: usize = 16;
19// The length of the key to do AES-128-XTS encryption.
20pub const AES_128_XTS_KEY_LENGTH: usize = 32;
21// The length of the key to do AES-256-XTS encryption.
22pub const AES_256_XTS_KEY_LENGTH: usize = 64;
23// The length of the key to do AES-256-GCM encryption.
24pub const AES_256_GCM_KEY_LENGTH: usize = 32;
25
26// The padding magic end.
27pub const PADDING_MAGIC_END: [u8; 2] = [0x78, 0x90];
28// DATA_UNIT_LENGTH + length of PADDING_MAGIC_END.
29pub const PADDING_LENGTH: usize = 18;
30// Openssl rejects keys with identical first and second halves for xts.
31// Use a default key for such cases.
32const DEFAULT_CE_KEY: [u8; 32] = [
33    0xac, 0xed, 0x14, 0x69, 0x94, 0x23, 0x1e, 0xca, 0x44, 0x8c, 0xed, 0x2f, 0x6b, 0x40, 0x0c, 0x00,
34    0xfd, 0xbb, 0x3f, 0xac, 0xdd, 0xc7, 0xd9, 0xee, 0x83, 0xf6, 0x5c, 0xd9, 0x3c, 0xaa, 0x28, 0x7c,
35];
36const DEFAULT_CE_KEY_64: [u8; 64] = [
37    0xac, 0xed, 0x14, 0x69, 0x94, 0x23, 0x1e, 0xca, 0x44, 0x8c, 0xed, 0x2f, 0x6b, 0x40, 0x0c, 0x00,
38    0xfd, 0xbb, 0x3f, 0xac, 0xdd, 0xc7, 0xd9, 0xee, 0x83, 0xf6, 0x5c, 0xd9, 0x3c, 0xaa, 0x28, 0x7c,
39    0xfd, 0xbb, 0x3f, 0xac, 0xdd, 0xc7, 0xd9, 0xee, 0x83, 0xf6, 0x5c, 0xd9, 0x3c, 0xaa, 0x28, 0x7c,
40    0xac, 0xed, 0x14, 0x69, 0x94, 0x23, 0x1e, 0xca, 0x44, 0x8c, 0xed, 0x2f, 0x6b, 0x40, 0x0c, 0x00,
41];
42
43/// Supported cipher algorithms.
44#[repr(u32)]
45#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
46pub enum Algorithm {
47    #[default]
48    None = 0,
49    Aes128Xts = 1,
50    Aes256Xts = 2,
51    Aes256Gcm = 3,
52}
53
54impl Algorithm {
55    /// Create a new cipher object.
56    pub fn new_cipher(&self) -> Result<Cipher, Error> {
57        match self {
58            Algorithm::None => Ok(Cipher::None),
59            Algorithm::Aes128Xts => {
60                let cipher = symm::Cipher::aes_128_xts();
61                Ok(Cipher::Aes128Xts(cipher))
62            }
63            Algorithm::Aes256Xts => {
64                let cipher = symm::Cipher::aes_256_xts();
65                Ok(Cipher::Aes256Xts(cipher))
66            }
67            Algorithm::Aes256Gcm => {
68                let cipher = symm::Cipher::aes_256_gcm();
69                Ok(Cipher::Aes256Gcm(cipher))
70            }
71        }
72    }
73
74    /// Check whether data encryption is enabled or not.
75    pub fn is_encryption_enabled(&self) -> bool {
76        *self != Algorithm::None
77    }
78
79    /// Check whether algorithm is AEAD.
80    pub fn is_aead(&self) -> bool {
81        match self {
82            Algorithm::None => false,
83            Algorithm::Aes128Xts => false,
84            Algorithm::Aes256Xts => false,
85            Algorithm::Aes256Gcm => true,
86        }
87    }
88
89    /// Get size of tag associated with encrypted data.
90    pub fn tag_size(&self) -> usize {
91        match self {
92            Algorithm::None => 0,
93            Algorithm::Aes128Xts => 0,
94            Algorithm::Aes256Xts => 0,
95            Algorithm::Aes256Gcm => 12,
96        }
97    }
98
99    /// Get key size of the encryption algorithm.
100    pub fn key_length(&self) -> usize {
101        match self {
102            Algorithm::None => 0,
103            Algorithm::Aes128Xts => AES_128_XTS_KEY_LENGTH,
104            Algorithm::Aes256Xts => AES_256_XTS_KEY_LENGTH,
105            Algorithm::Aes256Gcm => AES_256_GCM_KEY_LENGTH,
106        }
107    }
108}
109
110impl fmt::Display for Algorithm {
111    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112        write!(f, "{:?}", self)
113    }
114}
115
116impl FromStr for Algorithm {
117    type Err = Error;
118
119    fn from_str(s: &str) -> Result<Self, Self::Err> {
120        match s {
121            "none" => Ok(Self::None),
122            "aes128xts" => Ok(Self::Aes128Xts),
123            "aes256xts" => Ok(Self::Aes256Xts),
124            "aes256gcm" => Ok(Self::Aes256Gcm),
125            _ => Err(einval!("cypher algorithm should be none or aes_gcm")),
126        }
127    }
128}
129
130impl TryFrom<u32> for Algorithm {
131    type Error = ();
132
133    fn try_from(value: u32) -> Result<Self, Self::Error> {
134        if value == Algorithm::None as u32 {
135            Ok(Algorithm::None)
136        } else if value == Algorithm::Aes128Xts as u32 {
137            Ok(Algorithm::Aes128Xts)
138        } else if value == Algorithm::Aes256Xts as u32 {
139            Ok(Algorithm::Aes256Xts)
140        } else if value == Algorithm::Aes256Gcm as u32 {
141            Ok(Algorithm::Aes256Gcm)
142        } else {
143            Err(())
144        }
145    }
146}
147
148impl TryFrom<u64> for Algorithm {
149    type Error = ();
150
151    fn try_from(value: u64) -> Result<Self, Self::Error> {
152        if value == Algorithm::None as u64 {
153            Ok(Algorithm::None)
154        } else if value == Algorithm::Aes128Xts as u64 {
155            Ok(Algorithm::Aes128Xts)
156        } else if value == Algorithm::Aes256Xts as u64 {
157            Ok(Algorithm::Aes256Xts)
158        } else if value == Algorithm::Aes256Gcm as u64 {
159            Ok(Algorithm::Aes256Gcm)
160        } else {
161            Err(())
162        }
163    }
164}
165
166/// Cipher object to encrypt/decrypt data.
167#[derive(Default)]
168pub enum Cipher {
169    #[default]
170    None,
171    Aes128Xts(symm::Cipher),
172    Aes256Xts(symm::Cipher),
173    Aes256Gcm(symm::Cipher),
174}
175
176impl Debug for Cipher {
177    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
178        match self {
179            Cipher::None => write!(f, "cipher: none"),
180            Cipher::Aes128Xts(_) => write!(f, "cypher: aes128_xts"),
181            Cipher::Aes256Xts(_) => write!(f, "cypher: aes256_xts"),
182            Cipher::Aes256Gcm(_) => write!(f, "cipher: aes256_gcm"),
183        }
184    }
185}
186
187impl Cipher {
188    /// Encrypt plaintext with optional IV and return the encrypted data.
189    ///
190    /// For XTS, the caller needs to ensure that the top half of key is not identical to the
191    /// bottom half of the key, otherwise the encryption will fail.
192    pub fn encrypt<'a>(
193        &self,
194        key: &[u8],
195        iv: Option<&[u8]>,
196        data: &'a [u8],
197    ) -> Result<Cow<'a, [u8]>, Error> {
198        match self {
199            Cipher::None => Ok(Cow::from(data)),
200            Cipher::Aes128Xts(cipher) => {
201                assert_eq!(key.len(), AES_128_XTS_KEY_LENGTH);
202                let mut buf;
203                let data = if data.len() >= DATA_UNIT_LENGTH {
204                    data
205                } else {
206                    // CMS (Cryptographic Message Syntax).
207                    // This pads with the same value as the number of padding bytes
208                    // and appends the magic padding end.
209                    let val = (DATA_UNIT_LENGTH - data.len()) as u8;
210                    buf = [val; PADDING_LENGTH];
211                    buf[..data.len()].copy_from_slice(data);
212                    buf[DATA_UNIT_LENGTH..PADDING_LENGTH].copy_from_slice(&PADDING_MAGIC_END);
213                    &buf
214                };
215                Self::cipher(*cipher, symm::Mode::Encrypt, key, iv, data)
216                    .map(Cow::from)
217                    .map_err(|e| eother!(format!("failed to encrypt data, {}", e)))
218            }
219            Cipher::Aes256Xts(cipher) => {
220                assert_eq!(key.len(), AES_256_XTS_KEY_LENGTH);
221                let mut buf;
222                let data = if data.len() >= DATA_UNIT_LENGTH {
223                    data
224                } else {
225                    let val = (DATA_UNIT_LENGTH - data.len()) as u8;
226                    buf = [val; PADDING_LENGTH];
227                    buf[..data.len()].copy_from_slice(data);
228                    buf[DATA_UNIT_LENGTH..PADDING_LENGTH].copy_from_slice(&PADDING_MAGIC_END);
229                    &buf
230                };
231                Self::cipher(*cipher, symm::Mode::Encrypt, key, iv, data)
232                    .map(Cow::from)
233                    .map_err(|e| eother!(format!("failed to encrypt data, {}", e)))
234            }
235            Cipher::Aes256Gcm(_cipher) => {
236                Err(einval!("Cipher::encrypt() doesn't support Aes256Gcm"))
237            }
238        }
239    }
240
241    /// Decrypt encrypted data with optional IV and return the decrypted data.
242    pub fn decrypt(&self, key: &[u8], iv: Option<&[u8]>, data: &[u8]) -> Result<Vec<u8>, Error> {
243        let mut data = match self {
244            Cipher::None => Ok(data.to_vec()),
245            Cipher::Aes128Xts(cipher) => Self::cipher(*cipher, symm::Mode::Decrypt, key, iv, data)
246                .map_err(|e| eother!(format!("failed to decrypt data, {}", e))),
247            Cipher::Aes256Xts(cipher) => Self::cipher(*cipher, symm::Mode::Decrypt, key, iv, data)
248                .map_err(|e| eother!(format!("failed to decrypt data, {}", e))),
249            Cipher::Aes256Gcm(_cipher) => {
250                Err(einval!("Cipher::decrypt() doesn't support Aes256Gcm"))
251            }
252        }?;
253
254        // Trim possible padding.
255        if data.len() == PADDING_LENGTH
256            && data[PADDING_LENGTH - PADDING_MAGIC_END.len()..PADDING_LENGTH] == PADDING_MAGIC_END
257        {
258            let val = data[DATA_UNIT_LENGTH - 1] as usize;
259            if val < DATA_UNIT_LENGTH {
260                data.truncate(DATA_UNIT_LENGTH - val);
261            } else {
262                return Err(einval!(format!(
263                    "Cipher::decrypt: invalid padding data, value {}",
264                    val,
265                )));
266            }
267        };
268
269        Ok(data)
270    }
271
272    /// Encrypt plaintext and return the ciphertext with authentication tag.
273    pub fn encrypt_aead(
274        &self,
275        key: &[u8],
276        iv: Option<&[u8]>,
277        data: &[u8],
278        tag: &mut [u8],
279    ) -> Result<Vec<u8>, Error> {
280        match self {
281            Cipher::Aes256Gcm(cipher) => symm::encrypt_aead(*cipher, key, iv, &[], data, tag)
282                .map_err(|e| eother!(format!("failed to encrypt data, {}", e))),
283            _ => Err(einval!("invalid algorithm for encrypt_aead()")),
284        }
285    }
286
287    /// Decrypt plaintext and return the encrypted data with authentication tag.
288    pub fn decrypt_aead(
289        &self,
290        key: &[u8],
291        iv: Option<&[u8]>,
292        data: &[u8],
293        tag: &[u8],
294    ) -> Result<Vec<u8>, Error> {
295        match self {
296            Cipher::Aes256Gcm(cipher) => symm::decrypt_aead(*cipher, key, iv, &[], data, tag)
297                .map_err(|e| eother!(format!("failed to encrypt data, {}", e))),
298            _ => Err(einval!("invalid algorithm for decrypt_aead()")),
299        }
300    }
301
302    /// Get size of tag associated with encrypted data.
303    pub fn tag_size(&self) -> usize {
304        match self {
305            Cipher::Aes256Gcm(_) => 12,
306            _ => 0,
307        }
308    }
309
310    /// Get size of ciphertext from size of plaintext.
311    pub fn encrypted_size(&self, plaintext_size: usize) -> usize {
312        match self {
313            Cipher::None => plaintext_size,
314            Cipher::Aes128Xts(_) | Cipher::Aes256Xts(_) => {
315                if plaintext_size < DATA_UNIT_LENGTH {
316                    DATA_UNIT_LENGTH
317                } else {
318                    plaintext_size
319                }
320            }
321            Cipher::Aes256Gcm(_) => {
322                assert!(plaintext_size.checked_add(12).is_some());
323                plaintext_size + 12
324            }
325        }
326    }
327
328    /// Tweak key for XTS mode.
329    pub fn tweak_key_for_xts(key: &[u8]) -> Cow<[u8]> {
330        let len = key.len() >> 1;
331        if key[..len] == key[len..] {
332            let mut buf = if key[len] == 0xa5 {
333                vec![0x5a; key.len()]
334            } else {
335                vec![0xa5; key.len()]
336            };
337            buf[len..].copy_from_slice(&key[len..]);
338            Cow::from(buf)
339        } else {
340            Cow::from(key)
341        }
342    }
343
344    fn cipher(
345        t: symm::Cipher,
346        mode: symm::Mode,
347        key: &[u8],
348        iv: Option<&[u8]>,
349        data: &[u8],
350    ) -> Result<Vec<u8>, Error> {
351        let mut c = symm::Crypter::new(t, mode, key, iv)?;
352        let mut out = alloc_buf(data.len() + t.block_size());
353        let count = c.update(data, &mut out)?;
354        let rest = c.finalize(&mut out[count..])?;
355        out.truncate(count + rest);
356        Ok(out)
357    }
358
359    pub fn generate_random_key(cipher_algo: Algorithm) -> Result<Vec<u8>, Error> {
360        let length = cipher_algo.key_length();
361        let mut buf = vec![0u8; length];
362        if let Err(e) = rand::rand_bytes(&mut buf) {
363            Err(eother!(format!(
364                "failed to generate key for {}, {}",
365                cipher_algo, e
366            )))
367        } else {
368            Ok(Self::tweak_key_for_xts(&buf).to_vec())
369        }
370    }
371
372    pub fn generate_random_iv() -> Result<Vec<u8>, Error> {
373        let mut buf = vec![0u8; AES_XTS_IV_LENGTH];
374        if let Err(e) = rand::rand_bytes(&mut buf) {
375            Err(eother!(format!("failed to generate iv, {}", e)))
376        } else {
377            Ok(buf)
378        }
379    }
380}
381
382/// Struct to provide context information for data encryption/decryption.
383#[derive(Default, Debug, Clone)]
384pub struct CipherContext {
385    key: Vec<u8>,
386    iv: Vec<u8>,
387    convergent_encryption: bool,
388    cipher_algo: Algorithm,
389}
390
391impl CipherContext {
392    /// Create a new instance of [CipherContext].
393    pub fn new(
394        key: Vec<u8>,
395        iv: Vec<u8>,
396        convergent_encryption: bool,
397        cipher_algo: Algorithm,
398    ) -> Result<Self, Error> {
399        let key_length = key.len();
400        if key_length != cipher_algo.key_length() {
401            return Err(einval!(format!(
402                "invalid key length {} for {} encryption",
403                key_length, cipher_algo
404            )));
405        } else if key[0..key_length >> 1] == key[key_length >> 1..key_length] {
406            return Err(einval!("invalid symmetry key for encryption"));
407        }
408
409        Ok(CipherContext {
410            key,
411            iv,
412            convergent_encryption,
413            cipher_algo,
414        })
415    }
416
417    /// Generate context information from data for encryption/decryption.
418    pub fn generate_cipher_meta<'a>(&'a self, data: &'a [u8]) -> (&'a [u8], Vec<u8>) {
419        let length = data.len();
420        assert_eq!(length, self.cipher_algo.key_length());
421        let iv = vec![0u8; AES_XTS_IV_LENGTH];
422        if self.convergent_encryption {
423            if length == AES_128_XTS_KEY_LENGTH && data[0..length >> 1] == data[length >> 1..length]
424            {
425                (&DEFAULT_CE_KEY, iv)
426            } else if length == AES_256_XTS_KEY_LENGTH
427                && data[0..length >> 1] == data[length >> 1..length]
428            {
429                (&DEFAULT_CE_KEY_64, iv)
430            } else {
431                (data, iv)
432            }
433        } else {
434            (&self.key, iv)
435        }
436    }
437
438    /// Get context information for meta data encryption/decryption.
439    pub fn get_cipher_meta(&self) -> (&[u8], &[u8]) {
440        (&self.key, &self.iv)
441    }
442}
443
444/// A customized buf allocator that avoids zeroing
445fn alloc_buf(size: usize) -> Vec<u8> {
446    assert!(size < isize::MAX as usize);
447    let layout = Layout::from_size_align(size, 0x1000)
448        .unwrap()
449        .pad_to_align();
450    let ptr = unsafe { alloc(layout) };
451    unsafe { Vec::from_raw_parts(ptr, size, layout.size()) }
452}
453
454// Encrypt data with Cipher and CipherContext.
455pub fn encrypt_with_context<'a>(
456    data: &'a [u8],
457    cipher_obj: &Arc<Cipher>,
458    cipher_ctx: &Option<CipherContext>,
459    encrypted: bool,
460) -> Result<Cow<'a, [u8]>, Error> {
461    if encrypted {
462        if let Some(cipher_ctx) = cipher_ctx {
463            let (key, iv) = cipher_ctx.get_cipher_meta();
464            Ok(cipher_obj.encrypt(key, Some(iv), data)?)
465        } else {
466            Err(einval!("the encrypt context can not be none"))
467        }
468    } else {
469        Ok(Cow::Borrowed(data))
470    }
471}
472
473// Decrypt data with Cipher and CipherContext.
474pub fn decrypt_with_context<'a>(
475    data: &'a [u8],
476    cipher_obj: &Arc<Cipher>,
477    cipher_ctx: &Option<CipherContext>,
478    encrypted: bool,
479) -> Result<Cow<'a, [u8]>, Error> {
480    if encrypted {
481        if let Some(cipher_ctx) = cipher_ctx {
482            let (key, iv) = cipher_ctx.get_cipher_meta();
483            Ok(Cow::from(cipher_obj.decrypt(key, Some(iv), data)?))
484        } else {
485            Err(einval!("the decrypt context can not be none"))
486        }
487    } else {
488        Ok(Cow::Borrowed(data))
489    }
490}
491
492#[cfg(test)]
493mod tests {
494    use super::*;
495
496    #[test]
497    fn test_aes_128_xts_encrypt() {
498        let mut key = [0xcu8; 32];
499        key[31] = 0xa;
500
501        let cipher = Algorithm::Aes128Xts.new_cipher().unwrap();
502        assert_eq!(cipher.encrypted_size(1), 16);
503        assert_eq!(cipher.encrypted_size(16), 16);
504        assert_eq!(cipher.encrypted_size(17), 17);
505
506        let ciphertext1 = cipher
507            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"1")
508            .unwrap();
509        let ciphertext2 = cipher
510            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"1")
511            .unwrap();
512        assert_eq!(ciphertext1, ciphertext2);
513        assert_eq!(ciphertext2.len(), PADDING_LENGTH);
514
515        let ciphertext3 = cipher
516            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"11111111111111111")
517            .unwrap();
518        assert_eq!(ciphertext3.len(), 17);
519
520        let ciphertext4 = cipher
521            .encrypt(key.as_slice(), Some(&[1u8; 16]), b"11111111111111111")
522            .unwrap();
523        assert_eq!(ciphertext4.len(), 17);
524        assert_ne!(ciphertext4, ciphertext3);
525
526        let ciphertext5 = cipher
527            .encrypt(key.as_slice(), Some(&[1u8; 16]), b"21111111111111111")
528            .unwrap();
529        assert_eq!(ciphertext5.len(), 17);
530        assert_ne!(ciphertext5, ciphertext4);
531    }
532
533    #[test]
534    fn test_aes_256_xts_encrypt() {
535        let mut key = [0xcu8; 64];
536        key[31] = 0xa;
537
538        let cipher = Algorithm::Aes256Xts.new_cipher().unwrap();
539        let ciphertext1 = cipher
540            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"1")
541            .unwrap();
542        let ciphertext2 = cipher
543            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"1")
544            .unwrap();
545        assert_eq!(ciphertext1, ciphertext2);
546        assert_eq!(ciphertext2.len(), PADDING_LENGTH);
547
548        let ciphertext3 = cipher
549            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"11111111111111111")
550            .unwrap();
551        assert_eq!(ciphertext3.len(), 17);
552
553        let ciphertext4 = cipher
554            .encrypt(key.as_slice(), Some(&[1u8; 16]), b"11111111111111111")
555            .unwrap();
556        assert_eq!(ciphertext4.len(), 17);
557        assert_ne!(ciphertext4, ciphertext3);
558
559        let ciphertext5 = cipher
560            .encrypt(key.as_slice(), Some(&[1u8; 16]), b"21111111111111111")
561            .unwrap();
562        assert_eq!(ciphertext5.len(), 17);
563        assert_ne!(ciphertext5, ciphertext4);
564    }
565
566    #[test]
567    fn test_aes_128_xts_decrypt() {
568        let mut key = [0xcu8; 32];
569        key[31] = 0xa;
570
571        let cipher = Algorithm::Aes128Xts.new_cipher().unwrap();
572        let ciphertext1 = cipher
573            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"1")
574            .unwrap();
575        let plaintext1 = cipher
576            .decrypt(key.as_slice(), Some(&[0u8; 16]), &ciphertext1)
577            .unwrap();
578        assert_eq!(&plaintext1, b"1");
579
580        let ciphertext2 = cipher
581            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"11111111111111111")
582            .unwrap();
583        let plaintext2 = cipher
584            .decrypt(key.as_slice(), Some(&[0u8; 16]), &ciphertext2)
585            .unwrap();
586        assert_eq!(&plaintext2, b"11111111111111111");
587
588        let ciphertext3 = cipher
589            .encrypt(key.as_slice(), Some(&[1u8; 16]), b"11111111111111111")
590            .unwrap();
591        let plaintext3 = cipher
592            .decrypt(key.as_slice(), Some(&[1u8; 16]), &ciphertext3)
593            .unwrap();
594        assert_eq!(&plaintext3, b"11111111111111111");
595    }
596
597    #[test]
598    fn test_aes_256_xts_decrypt() {
599        let mut key = [0xcu8; 64];
600        key[31] = 0xa;
601
602        let cipher = Algorithm::Aes256Xts.new_cipher().unwrap();
603        let ciphertext1 = cipher
604            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"1")
605            .unwrap();
606        let plaintext1 = cipher
607            .decrypt(key.as_slice(), Some(&[0u8; 16]), &ciphertext1)
608            .unwrap();
609        assert_eq!(&plaintext1, b"1");
610
611        let ciphertext2 = cipher
612            .encrypt(key.as_slice(), Some(&[0u8; 16]), b"11111111111111111")
613            .unwrap();
614        let plaintext2 = cipher
615            .decrypt(key.as_slice(), Some(&[0u8; 16]), &ciphertext2)
616            .unwrap();
617        assert_eq!(&plaintext2, b"11111111111111111");
618
619        let ciphertext3 = cipher
620            .encrypt(key.as_slice(), Some(&[1u8; 16]), b"11111111111111111")
621            .unwrap();
622        let plaintext3 = cipher
623            .decrypt(key.as_slice(), Some(&[1u8; 16]), &ciphertext3)
624            .unwrap();
625        assert_eq!(&plaintext3, b"11111111111111111");
626    }
627
628    #[test]
629    fn test_aes_256_gcm() {
630        let key = [0xcu8; 32];
631        let mut tag = vec![0u8; 12];
632
633        let cipher = Algorithm::Aes256Gcm.new_cipher().unwrap();
634        assert_eq!(cipher.tag_size(), 12);
635        assert_eq!(cipher.encrypted_size(1), 13);
636
637        let ciphertext1 = cipher
638            .encrypt_aead(key.as_slice(), Some(&[0u8; 16]), b"1", &mut tag)
639            .unwrap();
640        assert_eq!(ciphertext1.len(), 1);
641        assert_eq!(tag.len(), 12);
642        let plaintext1 = cipher
643            .decrypt_aead(key.as_slice(), Some(&[0u8; 16]), &ciphertext1, &tag)
644            .unwrap();
645        assert_eq!(&plaintext1, b"1");
646
647        let ciphertext2 = cipher
648            .encrypt_aead(
649                key.as_slice(),
650                Some(&[0u8; 16]),
651                b"11111111111111111",
652                &mut tag,
653            )
654            .unwrap();
655        assert_eq!(ciphertext2.len(), 17);
656        assert_eq!(tag.len(), 12);
657        let plaintext2 = cipher
658            .decrypt_aead(key.as_slice(), Some(&[0u8; 16]), &ciphertext2, &tag)
659            .unwrap();
660        assert_eq!(&plaintext2, b"11111111111111111");
661
662        let ciphertext3 = cipher
663            .encrypt_aead(
664                key.as_slice(),
665                Some(&[1u8; 16]),
666                b"11111111111111111",
667                &mut tag,
668            )
669            .unwrap();
670        assert_ne!(ciphertext3, ciphertext2);
671        assert_eq!(ciphertext3.len(), 17);
672        assert_eq!(tag.len(), 12);
673        let plaintext3 = cipher
674            .decrypt_aead(key.as_slice(), Some(&[1u8; 16]), &ciphertext3, &tag)
675            .unwrap();
676        assert_eq!(&plaintext3, b"11111111111111111");
677    }
678
679    #[test]
680    fn test_tweak_key_for_xts() {
681        let buf = vec![0x0; 32];
682        let buf2 = Cipher::tweak_key_for_xts(&buf);
683        assert_eq!(buf2[0], 0xa5);
684        assert_eq!(buf2[16], 0x0);
685
686        let buf = vec![0xa5; 32];
687        let buf2 = Cipher::tweak_key_for_xts(&buf);
688        assert_eq!(buf2[0], 0x5a);
689        assert_eq!(buf2[16], 0xa5);
690    }
691
692    #[test]
693    fn test_attribute() {
694        let none = Algorithm::None.new_cipher().unwrap();
695        let aes128xts = Algorithm::Aes128Xts.new_cipher().unwrap();
696        let aes256xts = Algorithm::Aes256Xts.new_cipher().unwrap();
697        let aes256gcm = Algorithm::Aes256Gcm.new_cipher().unwrap();
698
699        assert!(!Algorithm::None.is_encryption_enabled());
700        assert!(Algorithm::Aes128Xts.is_encryption_enabled());
701        assert!(Algorithm::Aes256Xts.is_encryption_enabled());
702        assert!(Algorithm::Aes256Gcm.is_encryption_enabled());
703
704        assert!(!Algorithm::None.is_aead());
705        assert!(!Algorithm::Aes128Xts.is_aead());
706        assert!(!Algorithm::Aes256Xts.is_aead());
707        assert!(Algorithm::Aes256Gcm.is_aead());
708
709        assert_eq!(Algorithm::None.tag_size(), 0);
710        assert_eq!(Algorithm::Aes128Xts.tag_size(), 0);
711        assert_eq!(Algorithm::Aes256Xts.tag_size(), 0);
712        assert_eq!(Algorithm::Aes256Gcm.tag_size(), 12);
713
714        assert_eq!(Algorithm::None.key_length(), 0);
715        assert_eq!(Algorithm::Aes128Xts.key_length(), AES_128_XTS_KEY_LENGTH);
716        assert_eq!(Algorithm::Aes256Xts.key_length(), AES_256_XTS_KEY_LENGTH);
717        assert_eq!(Algorithm::Aes256Gcm.key_length(), AES_256_GCM_KEY_LENGTH);
718
719        print!("{}", Algorithm::Aes128Xts);
720        assert!(Algorithm::from_str("none").is_ok());
721        assert!(Algorithm::from_str("aes128xts").is_ok());
722        assert!(Algorithm::from_str("aes256xts").is_ok());
723        assert!(Algorithm::from_str("aes256gcm").is_ok());
724        assert!(Algorithm::from_str("non-exist").is_err());
725
726        assert!(Algorithm::try_from(Algorithm::None as u32).is_ok());
727        assert!(Algorithm::try_from(Algorithm::Aes128Xts as u32).is_ok());
728        assert!(Algorithm::try_from(Algorithm::Aes256Xts as u32).is_ok());
729        assert!(Algorithm::try_from(Algorithm::Aes256Gcm as u32).is_ok());
730        assert!(Algorithm::try_from(u32::MAX).is_err());
731
732        assert!(Algorithm::try_from(Algorithm::None as u64).is_ok());
733        assert!(Algorithm::try_from(Algorithm::Aes128Xts as u64).is_ok());
734        assert!(Algorithm::try_from(Algorithm::Aes256Xts as u64).is_ok());
735        assert!(Algorithm::try_from(Algorithm::Aes256Gcm as u64).is_ok());
736        assert!(Algorithm::try_from(u64::MAX).is_err());
737
738        println!("{:?},{:?},{:?},{:?}", none, aes128xts, aes256xts, aes256gcm);
739    }
740
741    #[test]
742    fn test_crypt_with_context() {
743        let error_key = [0xcu8, 64];
744        let symmetry_key = [0xcu8, 32];
745        let mut key = [0xcu8; 32];
746        key[31] = 0xa;
747        let iv = [0u8; 16];
748        let data = b"11111111111111111";
749        // create with mismatch key length and algo
750        assert!(
751            CipherContext::new(error_key.to_vec(), iv.to_vec(), true, Algorithm::Aes128Xts)
752                .is_err()
753        );
754        // create with symmetry key
755        assert!(CipherContext::new(
756            symmetry_key.to_vec(),
757            iv.to_vec(),
758            true,
759            Algorithm::Aes128Xts
760        )
761        .is_err());
762
763        // test context is none
764        let ctx =
765            CipherContext::new(key.to_vec(), iv.to_vec(), false, Algorithm::Aes128Xts).unwrap();
766        let obj = Arc::new(Algorithm::Aes128Xts.new_cipher().unwrap());
767        assert!(encrypt_with_context(data, &obj, &None, true).is_err());
768        assert!(decrypt_with_context(b"somedata", &obj, &None, true).is_err());
769
770        // test encrypted is false
771        let no_change = encrypt_with_context(data, &obj, &Some(ctx.clone()), false).unwrap();
772        assert_eq!(no_change.clone().into_owned(), data);
773        let bind = no_change.into_owned();
774        let plain_text_no_change =
775            decrypt_with_context(&bind, &obj, &Some(ctx.clone()), false).unwrap();
776        assert_eq!(plain_text_no_change.into_owned(), data);
777
778        // test normal encrypt and decrypt
779        let encrypt_text = encrypt_with_context(data, &obj, &Some(ctx.clone()), true).unwrap();
780        let bind = encrypt_text.into_owned();
781        let plain_text = decrypt_with_context(&bind, &obj, &Some(ctx), true).unwrap();
782        assert_eq!(&plain_text.into_owned(), data);
783    }
784
785    fn test_gen_key(convergent_encryption: bool) {
786        let mut key = [0xcu8; 32];
787        key[31] = 0xa;
788        let iv = [0u8; 16];
789        let data = b"11111111111111111";
790        let ctx = CipherContext::new(
791            key.to_vec(),
792            iv.to_vec(),
793            convergent_encryption,
794            Algorithm::Aes128Xts,
795        )
796        .unwrap();
797        let obj = Arc::new(Algorithm::Aes128Xts.new_cipher().unwrap());
798        let (gen_key, gen_iv) = ctx.generate_cipher_meta(&key);
799        let ciphertext = obj.encrypt(gen_key, Some(&gen_iv), data).unwrap();
800        let plaintext = obj.decrypt(gen_key, Some(&gen_iv), &ciphertext).unwrap();
801        assert_eq!(&plaintext, data);
802    }
803
804    #[test]
805    fn test_generate_cipher_meta() {
806        test_gen_key(true);
807        test_gen_key(false);
808    }
809}