///
#[allow(warnings)]
#[cfg(feature = "crypto")]
pub mod crypto {
    /// AES
    /// ```ignore
    ///let data = "this is data".as_bytes();
    ///let enc_data = doe::crypto::aes::aes_ecb_encrypt("12345678123456781234567812345678".as_bytes(),"1234567812345678".as_bytes(),data).unwrap();
    ///let dec_data = doe::crypto::aes::aes_ecb_decrypt("12345678123456781234567812345678".as_bytes(),"1234567812345678".as_bytes(),&enc_data).unwrap();
    ///println!("data:{:?}",&data);
    ///println!("enc_data:{:?}",&enc_data);
    ///println!("dec_data:{:?}",&dec_data);
    /// ```
    ///
    pub mod aes {
        /// AES ECB Encrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_ecb_encrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Ecb};
            use rand::Rng;
            use std::str;
            type Aes256Ecb = Ecb<Aes256, Pkcs7>;
            let cipher = Aes256Ecb::new_from_slices(key, iv).unwrap();
            let enc_data = cipher.encrypt_vec(data);
            Ok(enc_data)
        }
        /// AES ECB Decrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_ecb_decrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Ecb};
            use rand::Rng;
            use std::str;
            type Aes256Ecb = Ecb<Aes256, Pkcs7>;
            let cipher = Aes256Ecb::new_from_slices(key, iv).unwrap();
            cipher
                .decrypt_vec(data)
                .map(|enc_data| Ok(enc_data))
                .unwrap_or_else(|_| Err("aes_ecb_decrypt error".to_string()))
        }
        /// AES CBC Encrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_cbc_encrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Cbc};
            use rand::Rng;
            use std::str;
            type Aes256Cbc = Cbc<Aes256, Pkcs7>;
            let cipher = Aes256Cbc::new_from_slices(key, iv).unwrap();
            let enc_data = cipher.encrypt_vec(data);
            Ok(enc_data)
        }
        /// AES CBC Decrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_cbc_decrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Cbc};
            use rand::Rng;
            use std::str;
            type Aes256Cbc = Cbc<Aes256, Pkcs7>;
            let cipher = Aes256Cbc::new_from_slices(key, iv).unwrap();
            cipher
                .decrypt_vec(data)
                .map(|enc_data| Ok(enc_data))
                .unwrap_or_else(|_| Err("aes_cbc_decrypt error".to_string()))
        }
        /// AES CBF Encrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///

        pub fn aes_cfb_encrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Cfb};
            use rand::Rng;
            use std::str;
            type Aes256Cfb = Cfb<Aes256, Pkcs7>;
            let cipher = Aes256Cfb::new_from_slices(key, iv).unwrap();
            let enc_data = cipher.encrypt_vec(data);
            Ok(enc_data)
        }
        /// AES CBF Decrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_cfb_decrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Cfb};
            use rand::Rng;
            use std::str;
            type Aes256Cfb = Cfb<Aes256, Pkcs7>;
            let cipher = Aes256Cfb::new_from_slices(key, iv).unwrap();
            cipher
                .decrypt_vec(data)
                .map(|enc_data| Ok(enc_data))
                .unwrap_or_else(|_| Err("aes_cbc_decrypt error".to_string()))
        }
        /// AES OBF Encrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_ofb_encrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Ofb};
            use rand::Rng;
            use std::str;
            type Aes256Ofb = Ofb<Aes256, Pkcs7>;
            let cipher = Aes256Ofb::new_from_slices(key, iv).unwrap();
            let enc_data = cipher.encrypt_vec(data);
            Ok(enc_data)
        }
        /// AES OBF Decrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_ofb_decrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::Aes256;
            use block_modes::block_padding::Pkcs7;
            use block_modes::{BlockMode, Ofb};
            use rand::Rng;
            use std::str;
            type Aes256Ofb = Ofb<Aes256, Pkcs7>;
            let cipher = Aes256Ofb::new_from_slices(key, iv).unwrap();
            cipher
                .decrypt_vec(data)
                .map(|enc_data| Ok(enc_data))
                .unwrap_or_else(|_| Err("aes_cbc_decrypt error".to_string()))
        }
        /// AES IGE Encrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 32 bytes
        ///
        /// data must be 16*n bytes
        ///
        pub fn aes_ige_encrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::cipher::generic_array::typenum::U16;
            use aes::cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt};
            use aes::Aes256;
            use aes::NewBlockCipher;
            let cipher = Aes256::new(GenericArray::from_slice(key));
            let mut prev_block: GenericArray<u8, U16> =
                GenericArray::from_slice(&iv[..16]).to_owned();
            let mut prev_prev_block: GenericArray<u8, U16> =
                GenericArray::from_slice(&iv[16..]).to_owned();

            let mut ciphertext = Vec::with_capacity(data.len());

            for chunk in data.chunks(16) {
                let mut block = GenericArray::clone_from_slice(chunk);
                for i in 0..16 {
                    block[i] ^= prev_block[i] ^ prev_prev_block[i];
                }
                cipher.encrypt_block(&mut block);
                for i in 0..16 {
                    block[i] ^= prev_block[i];
                }
                ciphertext.extend_from_slice(&block);
                prev_prev_block.copy_from_slice(&prev_block);
                prev_block.copy_from_slice(&block);
            }

            Ok(ciphertext)
        }
        /// AES IGE Decrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 32 bytes
        ///
        /// data must be 16*n bytes
        ///
        pub fn aes_ige_decrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::cipher::generic_array::typenum::U16;
            use aes::cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt};
            use aes::Aes256;
            use aes::NewBlockCipher;
            let cipher = Aes256::new(GenericArray::from_slice(key));
            let mut prev_block: &GenericArray<u8, U16> = GenericArray::from_slice(&iv[..16]);
            let mut prev_prev_block: &GenericArray<u8, U16> = GenericArray::from_slice(&iv[16..]);

            let mut plaintext = Vec::with_capacity(data.len());

            for chunk in data.chunks(16) {
                let mut block = GenericArray::clone_from_slice(chunk);
                for i in 0..16 {
                    block[i] ^= prev_block[i];
                }
                cipher.decrypt_block(&mut block);
                for i in 0..16 {
                    block[i] ^= prev_block[i] ^ prev_prev_block[i];
                }
                plaintext.extend_from_slice(&block);
                prev_prev_block = prev_block;
                prev_block = chunk.try_into().unwrap();
            }

            Ok(plaintext)
        }
        /// AES CTR Encrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_ctr_encrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::cipher::NewCipher;
            use aes::cipher::StreamCipher;
            use aes::cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt};
            use aes::Aes256;
            use ctr::Ctr128BE;
            use rand::Rng;
            use std::str;
            type Aes256Ctr = Ctr128BE<Aes256>;
            let mut cipher = Aes256Ctr::new(
                &GenericArray::from_slice(key),
                &GenericArray::from_slice(iv),
            );
            let mut ciphertext = data.to_vec();
            cipher.apply_keystream(&mut ciphertext);
            Ok(ciphertext)
        }
        /// AES CTR Decrypt
        ///
        /// key must be 32 bytes
        ///
        /// iv must be 16 bytes
        ///
        pub fn aes_ctr_decrypt(key: &[u8], iv: &[u8], data: &[u8]) -> Result<Vec<u8>, String> {
            use aes::cipher::NewCipher;
            use aes::cipher::StreamCipher;
            use aes::cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt};
            use aes::Aes256;
            use ctr::Ctr128BE;
            use rand::Rng;
            use std::str;
            type Aes256Ctr = Ctr128BE<Aes256>;
            let mut cipher = Aes256Ctr::new(
                &GenericArray::from_slice(key),
                &GenericArray::from_slice(iv),
            );
            let mut ciphertext = data.to_vec();
            cipher.apply_keystream(&mut ciphertext);
            Ok(ciphertext)
        }
    }
    ///RSA example
    ///```ignore
    ///let priv_key = doe::crypto::rsa::gen_priv_key(2048);
    ///let pub_key = doe::crypto::rsa::gen_pub_key(&priv_key);
    ///let data = b"hello world";
    ///let enc_data = doe::crypto::rsa::encrypt(&pub_key, data).unwrap();
    ///let dec_data = doe::crypto::rsa::decrypt(&priv_key, &enc_data).unwrap();
    ///assert_eq!(data, dec_data.as_slice());
    /// ```
    ///
    pub mod rsa {
        ///RSA example
        ///```ignore
        ///let priv_key = doe::crypto::rsa::gen_priv_key(2048);
        ///let pub_key = doe::crypto::rsa::gen_pub_key(&priv_key);
        ///let data = b"hello world";
        ///let enc_data = doe::crypto::rsa::encrypt(&pub_key, data).unwrap();
        ///let dec_data = doe::crypto::rsa::decrypt(&priv_key, &enc_data).unwrap();
        ///assert_eq!(data, dec_data.as_slice());
        /// ```
        ///
        pub fn gen_priv_key(bits: usize) -> rsa::RsaPrivateKey {
            use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
            let mut rng = rand::thread_rng();
            RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key")
        }
        ///RSA example
        ///```ignore
        ///let priv_key = doe::crypto::rsa::gen_priv_key(2048);
        ///let pub_key = doe::crypto::rsa::gen_pub_key(&priv_key);
        ///let data = b"hello world";
        ///let enc_data = doe::crypto::rsa::encrypt(&pub_key, data).unwrap();
        ///let dec_data = doe::crypto::rsa::decrypt(&priv_key, &enc_data).unwrap();
        ///assert_eq!(data, dec_data.as_slice());
        /// ```
        ///
        pub fn gen_pub_key(priv_key: &rsa::RsaPrivateKey) -> rsa::RsaPublicKey {
            use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
            RsaPublicKey::from(priv_key)
        }
        ///RSA example
        ///```ignore
        ///let priv_key = doe::crypto::rsa::gen_priv_key(2048);
        ///let pub_key = doe::crypto::rsa::gen_pub_key(&priv_key);
        ///let data = b"hello world";
        ///let enc_data = doe::crypto::rsa::encrypt(&pub_key, data).unwrap();
        ///let dec_data = doe::crypto::rsa::decrypt(&priv_key, &enc_data).unwrap();
        ///assert_eq!(data, dec_data.as_slice());
        /// ```
        ///
        pub fn encrypt(pub_key: &rsa::RsaPublicKey, data: &[u8]) -> Result<Vec<u8>, String> {
            use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
            let mut rng = rand::thread_rng();
            pub_key
                .encrypt(&mut rng, Pkcs1v15Encrypt, &data[..])
                .map(|enc_data| Ok(enc_data))
                .unwrap_or_else(|_| Err("encrypt error".to_string()))
        }
        ///RSA example
        ///```ignore
        ///let priv_key = doe::crypto::rsa::gen_priv_key(2048);
        ///let pub_key = doe::crypto::rsa::gen_pub_key(&priv_key);
        ///let data = b"hello world";
        ///let enc_data = doe::crypto::rsa::encrypt(&pub_key, data).unwrap();
        ///let dec_data = doe::crypto::rsa::decrypt(&priv_key, &enc_data).unwrap();
        ///assert_eq!(data, dec_data.as_slice());
        /// ```
        ///
        pub fn decrypt(priv_key: &rsa::RsaPrivateKey, enc_data: &[u8]) -> Result<Vec<u8>, String> {
            use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
            priv_key
                .decrypt(Pkcs1v15Encrypt, &enc_data)
                .map(|enc_data| Ok(enc_data))
                .unwrap_or_else(|_| Err("decrypt error".to_string()))
        }
    }
    pub mod sha1 {
        /// not secure
        pub fn sha1(data: &[u8]) -> String {
            use sha1::{Digest, Sha1};
            let mut hasher = Sha1::new();
            hasher.update(data);
            let result = hasher.finalize();
            hex::encode(result)
        }
    }
    pub mod sha2 {
        pub fn sha_224(data: &[u8]) -> String {
            use sha2::{Digest, Sha224};
            let mut hasher = Sha224::new();
            hasher.update(data);
            let result = hasher.finalize();
            hex::encode(result)
        }
        fn sha_256(data: &[u8]) -> String {
            use sha2::{Digest, Sha256};
            let mut hasher = Sha256::new();
            hasher.update(data);
            let result = hasher.finalize();
            hex::encode(result)
        }
        fn sha_512_224(data: &[u8]) -> String {
            use sha2::{Digest, Sha512_224};
            let mut hasher = Sha512_224::new();
            hasher.update(data);
            let result = hasher.finalize();
            hex::encode(result)
        }
        fn sha_512_256(data: &[u8]) -> String {
            use sha2::{Digest, Sha512_256};
            let mut hasher = Sha512_256::new();
            hasher.update(data);
            let result = hasher.finalize();
            hex::encode(result)
        }
        fn sha_384(data: &[u8]) -> String {
            use sha2::{Digest, Sha384};
            let mut hasher = Sha384::new();
            hasher.update(data);
            let result = hasher.finalize();
            hex::encode(result)
        }
        pub fn sha_512(data: &[u8]) -> String {
            use sha2::{Digest, Sha512};
            let mut hasher = Sha512::new();
            hasher.update(data);
            let result = hasher.finalize().to_vec();
            hex::encode_upper(result)
        }
    }
    pub mod sha3 {
        use sha1::digest::ExtendableOutput;

        pub fn sha_224(data: &[u8]) -> String {
            use sha3::{Digest, Sha3_224};
            let mut hasher = Sha3_224::new();
            hasher.update(data);
            let result = hasher.finalize().to_vec();
            hex::encode_upper(result)
        }
        pub fn sha_256(data: &[u8]) -> String {
            use sha3::{Digest, Sha3_256};
            let mut hasher = Sha3_256::new();
            hasher.update(data);
            let result = hasher.finalize().to_vec();
            hex::encode_upper(result)
        }

        pub fn sha_384(data: &[u8]) -> String {
            use sha3::{Digest, Sha3_384};
            let mut hasher = Sha3_384::new();
            hasher.update(data);
            let result = hasher.finalize().to_vec();
            hex::encode_upper(result)
        }

        pub fn sha_512(data: &[u8]) -> String {
            use sha3::{Digest, Sha3_512};
            let mut hasher = Sha3_512::new();
            hasher.update(data);
            let result = hasher.finalize().to_vec();
            hex::encode_upper(result)
        }
        pub fn shake_128(data: &[u8]) -> String {
            use sha3::{
                digest::{ExtendableOutput, Update, XofReader},
                Shake128,
            };
            let mut hasher = Shake128::default();
            hasher.update(data);
            let mut reader = hasher.finalize_xof();
            // 128 bytes of output
            let mut result = [0u8; 128];
            reader.read(&mut result);
            hex::encode_upper(result)
        }
        pub fn shake_256(data: &[u8]) -> String {
            use sha3::{
                digest::{ExtendableOutput, Update, XofReader},
                Shake256,
            };
            let mut hasher = Shake256::default();
            hasher.update(data);
            let mut reader = hasher.finalize_xof();
            // 256 bytes of output
            let mut result = [0u8; 256];
            reader.read(&mut result);
            hex::encode_upper(result)
        }
    }

    pub fn md5(data: &[u8]) -> String {
        use md5::compute;
        let result = compute(data);
        result
            .to_vec()
            .iter()
            .map(|x| format!("{:02x}", x))
            .collect::<String>()
    }
    /// in defalut 32 bytes
    pub fn blake3(data: &[u8]) -> String {
        let hasher = blake3::hash(data);
        hex::encode_upper(hasher.as_bytes())
    }
    /// can set the output size
    pub fn blake3_xof(data: &[u8], size: usize) -> String {
        let hasher = blake3::Hasher::new();
        let mut reader = hasher.finalize_xof();
        let mut result = vec![0u8; size];
        reader.fill(&mut result);
        hex::encode_upper(result)
    }
}
#[cfg(feature = "crypto")]
pub use crypto::*;
