cocoon 0.3.2

A simple protected container with strong encryption and format validation.
Documentation
use aes_gcm::{
    aead::{generic_array::GenericArray, KeyInit},
    AeadInPlace, Aes256Gcm,
};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use chacha20poly1305::ChaCha20Poly1305;
use rand::{rngs::StdRng, RngCore, SeedableRng};
#[cfg(feature = "std")]
use std::io::{Read, Write};
use zeroize::Zeroizing;

use super::{
    error::Error,
    format::MiniFormatPrefix,
    header::{CocoonCipher, CocoonConfig, CocoonKdf, MiniCocoonHeader},
    kdf::{self, KEY_SIZE},
};

/// The size of the cocoon prefix which appears in detached form in [`MiniCocoon::encrypt`].
pub const MINI_PREFIX_SIZE: usize = MiniFormatPrefix::SERIALIZE_SIZE;

/// This is a mini cocoon for a convenient and cool encryption.
pub struct MiniCocoon {
    key: Zeroizing<[u8; KEY_SIZE]>,
    rng: StdRng,
    config: CocoonConfig,
}

/// Stores data securely inside of a simple encrypted container ("mini cocoon").
///
/// # Basic Usage
/// ```
/// # use cocoon::{MiniCocoon, Error};
/// #
/// # fn main() -> Result<(), Error> {
/// let cocoon = MiniCocoon::from_key(b"0123456789abcdef0123456789abcdef", &[0; 32]);
///
/// let wrapped = cocoon.wrap(b"my secret data")?;
/// assert_ne!(&wrapped, b"my secret data");
///
/// let unwrapped = cocoon.unwrap(&wrapped)?;
/// assert_eq!(unwrapped, b"my secret data");
///
/// # Ok(())
/// # }
/// ```
///
/// Scroll down to [Features and Methods Mapping](#features-and-methods-mapping), and also see
/// crate's documentation for more use cases.
///
/// # Default Configuration
/// | Option                      | Value                          |
/// |-----------------------------|--------------------------------|
/// | [Cipher](CocoonCipher)      | Chacha20Poly1305               |
/// | [Key derivation](CocoonKdf) | PBKDF2 with 100 000 iterations |
///
/// * Cipher can be customized using [`MiniCocoon::with_cipher`] method.
/// * Key derivation (KDF): only PBKDF2 is supported.
///
/// # Features and Methods Mapping
///
/// _Note: It is maybe not a complete list of API methods. Please, refer to the current
/// documentation below to get familiarized with the full set of methods._
///
/// | Method ↓ / Feature →          | `std` | `alloc` | "no_std" |
/// |-------------------------------|:-----:|:-------:|:--------:|
/// | [`MiniCocoon::from_key`]      | ✔️    | ✔️      | ✔️      |
/// | [`MiniCocoon::from_password`] | ✔️    | ✔️      | ✔️      |
/// | [`MiniCocoon::encrypt`]       | ✔️    | ✔️      | ✔️      |
/// | [`MiniCocoon::decrypt`]       | ✔️    | ✔️      | ✔️      |
/// | [`MiniCocoon::wrap`]          | ✔️    | ✔️      | ❌      |
/// | [`MiniCocoon::unwrap`]        | ✔️    | ✔️      | ❌      |
/// | [`MiniCocoon::dump`]          | ✔️    | ❌      | ❌      |
/// | [`MiniCocoon::parse`]         | ✔️    | ❌      | ❌      |
impl MiniCocoon {
    /// Creates a new [`MiniCocoon`] with a symmetric key seeding a random generator
    /// using a given `seed` buffer.
    ///
    /// * `key` - a symmetric key of length 32
    /// * `seed` - 32 random bytes to initialize an internal random generator
    ///
    /// # Examples
    /// ```
    /// use cocoon::MiniCocoon;
    /// use rand::Rng;
    ///
    /// // Seed can be obtained by any cryptographically secure random generator.
    /// // ThreadRng is used as an example.
    /// let seed = rand::thread_rng().gen::<[u8; 32]>();
    ///
    /// // Key must be 32 bytes of length. Let it be another 32 random bytes.
    /// let key = rand::thread_rng().gen::<[u8; 32]>();
    ///
    /// let cocoon = MiniCocoon::from_key(&key, &seed);
    /// ```
    pub fn from_key(key: &[u8], seed: &[u8]) -> Self {
        let mut k = [0u8; KEY_SIZE];
        let mut s = [0u8; KEY_SIZE];

        k.copy_from_slice(key);
        s.copy_from_slice(seed);

        let key = Zeroizing::new(k);
        let rng = StdRng::from_seed(s);

        MiniCocoon {
            key,
            rng,
            config: CocoonConfig::default(),
        }
    }

    /// Creates a new [`MiniCocoon`] with a password. Under the hood, an encryption key is created
    /// from the password using PBKDF2 algorithm.
    ///
    /// * `password` - a password of any length
    /// * `seed` - 32 random bytes to initialize an internal random generator
    ///
    /// # Examples
    /// ```
    /// use cocoon::MiniCocoon;
    /// use rand::Rng;
    ///
    /// // Seed can be obtained by any cryptographically secure random generator.
    /// // ThreadRng is used as an example.
    /// let seed = rand::thread_rng().gen::<[u8; 32]>();
    ///
    /// let cocoon = MiniCocoon::from_password(b"my password", &seed);
    /// ```
    pub fn from_password(password: &[u8], seed: &[u8]) -> Self {
        let config = CocoonConfig::default();
        let key = match config.kdf() {
            CocoonKdf::Pbkdf2 => kdf::pbkdf2::derive(&seed, password, config.kdf_iterations()),
        };

        let mut s = [0u8; KEY_SIZE];
        s.copy_from_slice(seed);

        let rng = StdRng::from_seed(s);

        MiniCocoon { key, rng, config }
    }

    /// Sets an encryption algorithm to wrap data on.
    ///
    /// # Examples
    /// ```
    /// use cocoon::{MiniCocoon, CocoonCipher};
    /// use rand::Rng;
    ///
    /// let seed = rand::thread_rng().gen::<[u8; 32]>();
    /// let key = rand::thread_rng().gen::<[u8; 32]>();
    ///
    /// let cocoon = MiniCocoon::from_key(&key, &seed).with_cipher(CocoonCipher::Chacha20Poly1305);
    /// cocoon.wrap(b"my secret data");
    /// ```
    pub fn with_cipher(mut self, cipher: CocoonCipher) -> Self {
        self.config = self.config.with_cipher(cipher);
        self
    }

    /// Wraps data to an encrypted container.
    ///
    /// * `data` - a sensitive user data
    ///
    /// Examples:
    /// ```
    /// # use cocoon::{MiniCocoon, Error};
    /// # use rand::Rng;
    /// #
    /// # fn main() -> Result<(), Error> {
    /// let seed = rand::thread_rng().gen::<[u8; 32]>();
    /// let cocoon = MiniCocoon::from_password(b"password", &seed);
    ///
    /// let wrapped = cocoon.wrap(b"my secret data")?;
    /// assert_ne!(&wrapped, b"my secret data");
    ///
    /// # Ok(())
    /// # }
    /// ```
    #[cfg(feature = "alloc")]
    #[cfg_attr(docs_rs, doc(cfg(any(feature = "alloc", feature = "std"))))]
    pub fn wrap(&self, data: &[u8]) -> Result<Vec<u8>, Error> {
        // Allocation is needed because there is no way to prefix encrypted
        // data with a header without an allocation. It means that we need
        // to copy data at least once. It's necessary to avoid any further copying.
        let mut container = Vec::with_capacity(MINI_PREFIX_SIZE + data.len());
        container.extend_from_slice(&[0; MINI_PREFIX_SIZE]);
        container.extend_from_slice(data);

        let body = &mut container[MINI_PREFIX_SIZE..];

        // Encrypt in place and get a prefix part.
        let detached_prefix = self.encrypt(body)?;

        container[..MINI_PREFIX_SIZE].copy_from_slice(&detached_prefix);

        Ok(container)
    }

    /// Encrypts data in place, taking ownership over the buffer, and dumps the container
    /// into [`File`](std::fs::File), [`Cursor`](std::io::Cursor), or any other writer.
    /// * `data` - a sensitive data inside of [`Vec`] to be encrypted in place
    /// * `writer` - [`File`](std::fs::File), [`Cursor`](`std::io::Cursor`), or any other output
    ///
    /// A data is going to be encrypted in place and stored in a file using the "mini cocoon"
    /// [format](#format).
    ///
    /// # Examples
    /// ```
    /// # use cocoon::{MiniCocoon, Error};
    /// # use rand::Rng;
    /// # use std::io::Cursor;
    /// #
    /// # fn main() -> Result<(), Error> {
    /// let key = [ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
    ///            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32];
    /// let seed = rand::thread_rng().gen::<[u8; 32]>();
    ///
    /// let cocoon = MiniCocoon::from_key(&key, &seed);
    /// # let mut file = Cursor::new(vec![0; 150]);
    ///
    /// let mut data = b"my secret data".to_vec();
    ///
    /// cocoon.dump(data, &mut file)?;
    /// # assert_ne!(file.get_ref(), b"my secret data");
    ///
    /// # Ok(())
    /// # }
    #[cfg(feature = "std")]
    #[cfg_attr(docs_rs, doc(cfg(feature = "std")))]
    pub fn dump(&self, mut data: Vec<u8>, writer: &mut impl Write) -> Result<(), Error> {
        let detached_prefix = self.encrypt(&mut data)?;

        writer.write_all(&detached_prefix)?;
        writer.write_all(&data)?;

        Ok(())
    }

    /// Encrypts data in place and returns a detached prefix of the container.
    ///
    /// The prefix is needed to decrypt data with [`MiniCocoon::decrypt`].
    /// This method doesn't use memory allocation and it is suitable in the build
    /// with no [`std`] and no [`alloc`].
    ///
    /// <img src="../../../images/cocoon_detached_prefix.svg" />
    ///
    /// # Examples
    /// ```
    /// # use cocoon::{MiniCocoon, Error};
    /// #
    /// # fn main() -> Result<(), Error> {
    /// let cocoon = MiniCocoon::from_password(b"password", &[1; 32]);
    ///
    /// let mut data = "my secret data".to_owned().into_bytes();
    ///
    /// let detached_prefix = cocoon.encrypt(&mut data)?;
    /// assert_ne!(data, b"my secret data");
    /// # Ok(())
    /// # }
    /// ```
    pub fn encrypt(&self, data: &mut [u8]) -> Result<[u8; MINI_PREFIX_SIZE], Error> {
        let mut rng = self.rng.clone();

        let mut nonce = [0u8; 12];
        rng.fill_bytes(&mut nonce);

        let header = MiniCocoonHeader::new(nonce, data.len());
        let prefix = MiniFormatPrefix::new(header);

        let nonce = GenericArray::from_slice(&nonce);
        let key = GenericArray::clone_from_slice(self.key.as_ref());

        let tag: [u8; 16] = match self.config.cipher() {
            CocoonCipher::Chacha20Poly1305 => {
                let cipher = ChaCha20Poly1305::new(&key);
                cipher.encrypt_in_place_detached(nonce, &prefix.prefix(), data)
            }
            CocoonCipher::Aes256Gcm => {
                let cipher = Aes256Gcm::new(&key);
                cipher.encrypt_in_place_detached(nonce, &prefix.prefix(), data)
            }
        }
        .map_err(|_| Error::Cryptography)?
        .into();

        Ok(prefix.serialize(&tag))
    }

    /// Unwraps data from the encrypted container (see [`MiniCocoon::wrap`]).
    ///
    /// # Examples
    /// ```
    /// # use cocoon::{MiniCocoon, Error};
    /// # use rand::Rng;
    /// #
    /// # fn main() -> Result<(), Error> {
    /// let key = b"0123456789abcdef0123456789abcdef";
    /// let seed = rand::thread_rng().gen::<[u8; 32]>();
    ///
    /// let cocoon = MiniCocoon::from_key(key, &seed);
    ///
    /// # let wrapped = cocoon.wrap(b"my secret data")?;
    /// # assert_ne!(&wrapped, b"my secret data");
    /// #
    /// let unwrapped = cocoon.unwrap(&wrapped)?;
    /// assert_eq!(unwrapped, b"my secret data");
    ///
    /// # Ok(())
    /// # }
    /// ```
    #[cfg(feature = "alloc")]
    #[cfg_attr(docs_rs, doc(cfg(any(feature = "alloc", feature = "std"))))]
    pub fn unwrap(&self, container: &[u8]) -> Result<Vec<u8>, Error> {
        let prefix = MiniFormatPrefix::deserialize(container)?;
        let header = prefix.header();

        if container.len() < MINI_PREFIX_SIZE + header.data_length() {
            return Err(Error::TooShort);
        }

        let mut body = Vec::with_capacity(header.data_length());
        body.extend_from_slice(&container[MINI_PREFIX_SIZE..MINI_PREFIX_SIZE + body.capacity()]);

        self.decrypt_parsed(&mut body, &prefix)?;

        Ok(body)
    }

    /// Parses container from the reader (file, cursor, etc.), validates format,
    /// allocates memory and places decrypted data there.
    ///
    /// * `reader` - [`File`](std::fs::File), [`Cursor`](`std::io::Cursor`), or any other input
    ///
    /// # Examples
    /// ```
    /// # use cocoon::{MiniCocoon, Error};
    /// # use rand::Rng;
    /// # use std::io::Cursor;
    /// #
    /// # fn main() -> Result<(), Error> {
    /// let key = b"0123456789abcdef0123456789abcdef";
    /// let seed = rand::thread_rng().gen::<[u8; 32]>();
    ///
    /// let cocoon = MiniCocoon::from_key(key, &seed);
    /// # let mut file = Cursor::new(vec![0; 150]);
    /// #
    /// # let mut data = b"my secret data".to_vec();
    /// #
    /// # cocoon.dump(data, &mut file)?;
    /// # assert_ne!(file.get_ref(), b"my secret data");
    /// #
    /// # file.set_position(0);
    ///
    /// let data = cocoon.parse(&mut file)?;
    /// assert_eq!(&data, b"my secret data");
    ///
    /// # Ok(())
    /// # }
    /// ```
    #[cfg(feature = "std")]
    #[cfg_attr(docs_rs, doc(cfg(feature = "std")))]
    pub fn parse(&self, reader: &mut impl Read) -> Result<Vec<u8>, Error> {
        let prefix = MiniFormatPrefix::deserialize_from(reader)?;
        let mut body = Vec::with_capacity(prefix.header().data_length());
        body.resize(body.capacity(), 0);

        // Too short error can be thrown right from here.
        reader.read_exact(&mut body)?;

        self.decrypt_parsed(&mut body, &prefix)?;

        Ok(body)
    }

    /// Decrypts data in place using the parts returned by [`MiniCocoon::encrypt`] method.
    ///
    /// The method doesn't use memory allocation and is suitable for "no std" and "no alloc" build.
    ///
    /// # Examples
    /// ```
    /// # use cocoon::{MiniCocoon, Error};
    /// #
    /// # fn main() -> Result<(), Error> {
    /// let mut data = "my secret data".to_owned().into_bytes();
    /// let cocoon = MiniCocoon::from_password(b"password", &[0; 32]);
    ///
    /// let detached_prefix = cocoon.encrypt(&mut data)?;
    /// assert_ne!(data, b"my secret data");
    ///
    /// cocoon.decrypt(&mut data, &detached_prefix)?;
    /// assert_eq!(data, b"my secret data");
    /// #
    /// # Ok(())
    /// # }
    /// ```
    pub fn decrypt(&self, data: &mut [u8], detached_prefix: &[u8]) -> Result<(), Error> {
        let prefix = MiniFormatPrefix::deserialize(detached_prefix)?;

        self.decrypt_parsed(data, &prefix)
    }

    fn decrypt_parsed(
        &self,
        data: &mut [u8],
        detached_prefix: &MiniFormatPrefix,
    ) -> Result<(), Error> {
        let mut nonce = [0u8; 12];

        let header = detached_prefix.header();

        if data.len() < header.data_length() {
            return Err(Error::TooShort);
        }

        let data = &mut data[..header.data_length()];

        nonce.copy_from_slice(header.nonce());

        let nonce = GenericArray::from_slice(&nonce);
        let master_key = GenericArray::clone_from_slice(self.key.as_ref());
        let tag = GenericArray::from_slice(&detached_prefix.tag());

        match self.config.cipher() {
            CocoonCipher::Chacha20Poly1305 => {
                let cipher = ChaCha20Poly1305::new(&master_key);
                cipher.decrypt_in_place_detached(nonce, &detached_prefix.prefix(), data, tag)
            }
            CocoonCipher::Aes256Gcm => {
                let cipher = Aes256Gcm::new(&master_key);
                cipher.decrypt_in_place_detached(nonce, &detached_prefix.prefix(), data, tag)
            }
        }
        .map_err(|_| Error::Cryptography)?;

        Ok(())
    }
}

#[cfg(test)]
mod test {
    use std::fs::File;
    use std::io::Cursor;

    use super::*;

    #[test]
    fn mini_cocoon_create() {
        MiniCocoon::from_password(b"password", &[0; 32]);
        MiniCocoon::from_key(&[1; 32], &[0; 32]);
    }

    #[test]
    fn mini_cocoon_encrypt() {
        let cocoon = MiniCocoon::from_password(b"password", &[0; 32]);
        let mut data = "my secret data".to_owned().into_bytes();

        let detached_prefix = cocoon.encrypt(&mut data).unwrap();

        assert_eq!(
            &[
                155, 244, 154, 106, 7, 85, 249, 83, 129, 31, 206, 18, 0, 0, 0, 0, 0, 0, 0, 14, 88,
                114, 102, 98, 71, 228, 153, 231, 144, 157, 177, 113, 160, 209, 154, 83
            ][..],
            &detached_prefix[..]
        );

        assert_eq!(
            &[98, 34, 35, 62, 28, 121, 71, 223, 170, 151, 215, 104, 52, 187],
            &data[..]
        );
    }

    #[test]
    fn mini_cocoon_encrypt_aes() {
        let cocoon =
            MiniCocoon::from_password(b"password", &[0; 32]).with_cipher(CocoonCipher::Aes256Gcm);
        let mut data = "my secret data".to_owned().into_bytes();

        let detached_prefix = cocoon.encrypt(&mut data).unwrap();

        assert_eq!(
            &[
                155, 244, 154, 106, 7, 85, 249, 83, 129, 31, 206, 18, 0, 0, 0, 0, 0, 0, 0, 14, 95,
                1, 247, 191, 121, 127, 53, 49, 59, 241, 134, 122, 122, 207, 110, 138
            ][..],
            &detached_prefix[..]
        );

        assert_eq!(
            &[41, 58, 226, 219, 28, 132, 21, 216, 165, 46, 246, 120, 10, 92],
            &data[..]
        );
    }

    #[test]
    fn mini_cocoon_decrypt() {
        let detached_prefix = [
            118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 0, 0, 0, 0, 0, 0, 0, 14, 159,
            31, 100, 63, 43, 219, 99, 46, 201, 213, 205, 233, 174, 235, 43, 24,
        ];
        let mut data = [
            224, 50, 239, 254, 30, 140, 44, 135, 217, 94, 127, 67, 78, 31,
        ];
        let cocoon = MiniCocoon::from_password(b"password", &[0; 32]);

        cocoon
            .decrypt(&mut data, &detached_prefix)
            .expect("Decrypted data");

        assert_eq!(b"my secret data", &data);
    }

    #[test]
    fn mini_cocoon_decrypt_aes() {
        let detached_prefix = [
            118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 0, 0, 0, 0, 0, 0, 0, 14, 165,
            83, 248, 230, 121, 148, 146, 253, 98, 153, 208, 174, 129, 31, 162, 13,
        ];
        let mut data = [
            178, 119, 26, 64, 67, 5, 235, 21, 238, 150, 245, 172, 197, 114,
        ];
        let cocoon =
            MiniCocoon::from_password(b"password", &[0; 32]).with_cipher(CocoonCipher::Aes256Gcm);

        cocoon
            .decrypt(&mut data, &detached_prefix)
            .expect("Decrypted data");

        assert_eq!(b"my secret data", &data);
    }

    #[test]
    fn mini_cocoon_wrap() {
        let cocoon = MiniCocoon::from_password(b"password", &[0; 32]);
        let wrapped = cocoon.wrap(b"data").expect("Wrapped container");

        assert_eq!(wrapped[wrapped.len() - 4..], [107, 58, 119, 44]);
    }

    #[test]
    fn mini_cocoon_wrap_unwrap() {
        let cocoon = MiniCocoon::from_key(&[1; 32], &[0; 32]);
        let wrapped = cocoon.wrap(b"data").expect("Wrapped container");
        let original = cocoon.unwrap(&wrapped).expect("Unwrapped container");

        assert_eq!(original, b"data");
    }

    #[test]
    fn mini_cocoon_wrap_unwrap_corrupted() {
        let cocoon = MiniCocoon::from_key(&[1; 32], &[0; 32]);
        let mut wrapped = cocoon.wrap(b"data").expect("Wrapped container");

        let last = wrapped.len() - 1;
        wrapped[last] = wrapped[last] + 1;
        cocoon.unwrap(&wrapped).expect_err("Unwrapped container");
    }

    #[test]
    fn mini_cocoon_unwrap_larger_is_ok() {
        let cocoon = MiniCocoon::from_key(&[1; 32], &[0; 32]);
        let mut wrapped = cocoon.wrap(b"data").expect("Wrapped container");

        wrapped.push(0);
        let original = cocoon.unwrap(&wrapped).expect("Unwrapped container");

        assert_eq!(original, b"data");
    }

    #[test]
    fn mini_cocoon_unwrap_too_short() {
        let cocoon = MiniCocoon::from_key(&[1; 32], &[0; 32]);
        let mut wrapped = cocoon.wrap(b"data").expect("Wrapped container");

        wrapped.pop();
        cocoon.unwrap(&wrapped).expect_err("Too short");
    }

    #[test]
    fn cocoon_decrypt_wrong_sizes() {
        let detached_prefix = [
            118, 184, 224, 173, 160, 241, 61, 144, 64, 93, 106, 229, 0, 0, 0, 0, 0, 0, 0, 14, 165,
            83, 248, 230, 121, 148, 146, 253, 98, 153, 208, 174, 129, 31, 162, 13,
        ];
        let mut data = [
            178, 119, 26, 64, 67, 5, 235, 21, 238, 150, 245, 172, 197, 114, 0,
        ];
        let cocoon =
            MiniCocoon::from_password(b"password", &[0; 32]).with_cipher(CocoonCipher::Aes256Gcm);

        cocoon
            .decrypt(&mut data, &detached_prefix)
            .expect("Decrypted data");

        assert_eq!(b"my secret data\0", &data);

        cocoon
            .decrypt(&mut data[..4], &detached_prefix)
            .expect_err("Too short");
    }

    #[test]
    fn mini_cocoon_dump_parse() {
        let buf = vec![0; 100];
        let mut file = Cursor::new(buf);
        let cocoon = MiniCocoon::from_key(&[1; 32], &[0; 32]);

        // Prepare data inside of `Vec` container.
        let data = b"my data".to_vec();

        cocoon.dump(data, &mut file).expect("Dumped container");
        assert_ne!(b"my data", file.get_ref().as_slice());

        // "Re-open" the file.
        file.set_position(0);

        let original = cocoon.parse(&mut file).expect("Parsed container");
        assert_eq!(b"my data", original.as_slice());
    }

    #[test]
    fn mini_cocoon_dump_io_error() {
        File::create("target/read_only.txt").expect("Test file");
        let mut file = File::open("target/read_only.txt").expect("Test file");

        let cocoon = MiniCocoon::from_key(&[1; 32], &[0; 32]);

        // Prepare data inside of `Vec` container.
        let data = b"my data".to_vec();

        match cocoon.dump(data, &mut file) {
            Err(e) => match e {
                Error::Io(_) => (),
                _ => panic!("Only unexpected I/O error is expected :)"),
            },
            _ => panic!("Success is not expected"),
        }
    }

    #[test]
    fn mini_cocoon_parse_io_error() {
        File::create("target/read_only.txt").expect("Test file");
        let mut file = File::open("target/read_only.txt").expect("Test file");

        let cocoon = MiniCocoon::from_key(&[1; 32], &[0; 32]);

        match cocoon.parse(&mut file) {
            Err(e) => match e {
                Error::TooShort => (),
                _ => panic!("TooShort is expected for an empty file"),
            },
            _ => panic!("Success is not expected"),
        }
    }
}