Web Cryptography Rust Samples

Web Rust cryptography examples including hash calculation, symmetric encryption, and Base64 encoding

💻 Hash Calculation rust

🟢 simple ⭐⭐

Calculate MD5, SHA-1, SHA-256, and SHA-512 hashes using sha2 and md5 crates

⏱️ 20 min 🏷️ rust, web, cryptography
Prerequisites: Basic Rust, sha2 crate, md5 crate
// Web Rust Hash Calculation Examples
// Calculate various hash values for data integrity and security
//
// Add to Cargo.toml:
// [dependencies]
// sha2 = "0.10"
// md5 = "0.7"
// hex = "0.4"

use sha2::{Sha256, Sha512, Digest};
use md5::{Md5 as Md5Hash};

// 1. MD5 Hash

/// Calculate MD5 hash of string
fn calculate_md5_string(input: &str) -> String {
    let mut hasher = Md5Hash::new();
    hasher.update(input.as_bytes());
    let result = hasher.finalize();
    format!("{:x}", result)
}

/// Calculate MD5 hash of bytes
fn calculate_md5_bytes(data: &[u8]) -> String {
    let mut hasher = Md5Hash::new();
    hasher.update(data);
    let result = hasher.finalize();
    format!("{:x}", result)
}

// 2. SHA-1 Hash (using sha2)

/// Calculate SHA-1 hash
fn calculate_sha1(input: &str) -> String {
    use sha2::Sha1;
    let mut hasher = Sha1::new();
    hasher.update(input.as_bytes());
    let result = hasher.finalize();
    format!("{:x}", result)
}

// 3. SHA-256 Hash

/// Calculate SHA-256 hash of string
fn calculate_sha256_string(input: &str) -> String {
    let mut hasher = Sha256::new();
    hasher.update(input.as_bytes());
    let result = hasher.finalize();
    format!("{:x}", result)
}

/// Calculate SHA-256 hash of bytes
fn calculate_sha256_bytes(data: &[u8]) -> String {
    let mut hasher = Sha256::new();
    hasher.update(data);
    let result = hasher.finalize();
    format!("{:x}", result)
}

/// Calculate SHA-256 hash of file
fn calculate_sha256_file(path: &str) -> Result<String, std::io::Error> {
    use std::io::Read;
    let mut file = std::fs::File::open(path)?;
    let mut hasher = Sha256::new();
    let mut buffer = [0u8; 8192];

    loop {
        let n = file.read(&mut buffer)?;
        if n == 0 {
            break;
        }
        hasher.update(&buffer[..n]);
    }

    Ok(format!("{:x}", hasher.finalize()))
}

// 4. SHA-512 Hash

/// Calculate SHA-512 hash of string
fn calculate_sha512_string(input: &str) -> String {
    let mut hasher = Sha512::new();
    hasher.update(input.as_bytes());
    let result = hasher.finalize();
    format!("{:x}", result)
}

/// Calculate SHA-512 hash of bytes
fn calculate_sha512_bytes(data: &[u8]) -> String {
    let mut hasher = Sha512::new();
    hasher.update(data);
    let result = hasher.finalize();
    format!("{:x}", result)
}

// 5. Hash with Salt

/// Hash password with salt using SHA-256
fn hash_password_with_salt(password: &str, salt: &str) -> String {
    let mut hasher = Sha256::new();
    hasher.update(password.as_bytes());
    hasher.update(salt.as_bytes());
    let result = hasher.finalize();
    format!("{:x}", result)
}

/// Generate random salt
fn generate_salt() -> String {
    use rand::Rng;
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ                            abcdefghijklmnopqrstuvwxyz                            0123456789";
    let mut rng = rand::thread_rng();
    (0..32)
        .map(|_| {
            let idx = rng.gen_range(0..CHARSET.len());
            CHARSET[idx] as char
        })
        .collect()
}

/// Hash password with auto-generated salt
fn hash_password(password: &str) -> (String, String) {
    let salt = generate_salt();
    let hash = hash_password_with_salt(password, &salt);
    (hash, salt)
}

// 6. Hash Verification

/// Verify password against hash
fn verify_password(password: &str, salt: &str, hash: &str) -> bool {
    let computed_hash = hash_password_with_salt(password, salt);
    computed_hash == hash
}

// 7. Multiple Hashing (Iterated)

/// Hash with multiple iterations (key stretching)
fn hash_iterations(data: &str, iterations: usize) -> String {
    let mut current = data.to_string();
    for _ in 0..iterations {
        current = calculate_sha256_string(&current);
    }
    current
}

// 8. HMAC (Hash-based Message Authentication Code)

/// Calculate HMAC-SHA256
fn calculate_hmac_sha256(message: &str, key: &str) -> String {
    use hmac::{Hmac, Mac};
    type HmacSha256 = Hmac<Sha256>;

    let mut mac = HmacSha256::new_from_slice(key.as_bytes()).expect("HMAC key length error");
    mac.update(message.as_bytes());
    let result = mac.finalize();
    format!("{:x}", result.into_bytes())
}

// 9. Hash Comparison

/// Constant-time hash comparison to prevent timing attacks
fn hash_equals(hash1: &str, hash2: &str) -> bool {
    use subtle::ConstantTimeEq;
    hash1.as_bytes().ct_eq(hash2.as_bytes()).into()
}

// 10. Checksum

/// Calculate simple checksum
fn calculate_checksum(data: &[u8]) -> u8 {
    data.iter().fold(0u8, |acc, &b| acc.wrapping_add(b))
}

/// Calculate CRC32 checksum
fn calculate_crc32(data: &[u8]) -> u32 {
    let mut crc: u32 = 0xFFFFFFFF;
    for &byte in data {
        crc ^= byte as u32;
        for _ in 0..8 {
            if crc & 1 != 0 {
                crc = (crc >> 1) ^ 0xEDB88320;
            } else {
                crc >>= 1;
            }
        }
    }
    !crc
}

// 11. Batch Hashing

/// Hash multiple strings
fn hash_multiple_strings(strings: &[&str]) -> Vec<String> {
    strings.iter()
        .map(|s| calculate_sha256_string(s))
        .collect()
}

/// Find hash collisions (simple check)
fn find_hash_collisions(strings: &[&str]) -> Vec<(String, String, String)> {
    use std::collections::HashMap;
    let mut hash_map: HashMap<String, Vec<&str>> = HashMap::new();

    for &s in strings {
        let hash = calculate_sha256_string(s);
        hash_map.entry(hash).or_insert_with(Vec::new).push(s);
    }

    hash_map.into_iter()
        .filter(|(_, v)| v.len() > 1)
        .flat_map(|(hash, strings)| {
            strings.iter().map(move |s| (s.to_string(), hash.clone()))
        })
        .collect::<Vec<_>>()
        .chunks(2)
        .map(|c| {
            if c.len() == 2 {
                (c[0].0.clone(), c[1].0.clone(), c[0].1.clone())
            } else {
                (String::new(), String::new(), String::new())
            }
        })
        .collect()
}

// Usage Examples
fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Web Rust Hash Calculation Examples ===\n");

    let test_string = "Hello, World!";
    let test_bytes = b"Hello, World!";

    // 1. MD5
    println!("--- 1. MD5 Hash ---");
    println!("MD5 of '{}': {}", test_string, calculate_md5_string(test_string));
    println!("MD5 of bytes: {}", calculate_md5_bytes(test_bytes));

    // 2. SHA-1
    println!("\n--- 2. SHA-1 Hash ---");
    println!("SHA-1 of '{}': {}", test_string, calculate_sha1(test_string));

    // 3. SHA-256
    println!("\n--- 3. SHA-256 Hash ---");
    println!("SHA-256 of '{}': {}", test_string, calculate_sha256_string(test_string));
    println!("SHA-256 of bytes: {}", calculate_sha256_bytes(test_bytes));

    // 4. SHA-512
    println!("\n--- 4. SHA-512 Hash ---");
    println!("SHA-512 of '{}': {}", test_string, calculate_sha512_string(test_string));
    println!("SHA-512 of bytes: {}", calculate_sha512_bytes(test_bytes));

    // 5. Password hashing with salt
    println!("\n--- 5. Password Hashing with Salt ---");
    let password = "secure_password_123";
    let (hash, salt) = hash_password(password);
    println!("Password: {}", password);
    println!("Salt: {}", salt);
    println!("Hash: {}", hash);

    // 6. Verify password
    println!("\n--- 6. Verify Password ---");
    let is_valid = verify_password(password, &salt, &hash);
    println!("Password verification: {}", is_valid);
    let is_invalid = verify_password("wrong_password", &salt, &hash);
    println!("Wrong password verification: {}", is_invalid);

    // 7. Iterated hashing
    println!("\n--- 7. Iterated Hashing ---");
    let iterated = hash_iterations(test_string, 1000);
    println!("Hash after 1000 iterations: {}", iterated);

    // 8. HMAC
    println!("\n--- 8. HMAC-SHA256 ---");
    let message = "Important message";
    let key = "secret_key";
    let hmac = calculate_hmac_sha256(message, key);
    println!("HMAC of '{}' with key '{}': {}", message, key, hmac);

    // 9. Hash comparison
    println!("\n--- 9. Hash Comparison ---");
    let hash1 = calculate_sha256_string("test");
    let hash2 = calculate_sha256_string("test");
    let hash3 = calculate_sha256_string("different");
    println!("hash1 vs hash2: {}", hash_equals(&hash1, &hash2));
    println!("hash1 vs hash3: {}", hash_equals(&hash1, &hash3));

    // 10. Checksums
    println!("\n--- 10. Checksums ---");
    let checksum = calculate_checksum(test_bytes);
    println!("Simple checksum: {}", checksum);
    let crc32 = calculate_crc32(test_bytes);
    println!("CRC32: {:08x}", crc32);

    // 11. Batch hashing
    println!("\n--- 11. Batch Hashing ---");
    let strings = vec!["hello", "world", "rust"];
    let hashes = hash_multiple_strings(&strings);
    for (s, h) in strings.iter().zip(hashes.iter()) {
        println!("SHA256 of '{}': {}", s, h);
    }

    println!("\n=== All Hash Calculation Examples Completed ===");
    Ok(())
}

💻 Base64 Encoding rust

🟢 simple ⭐⭐

Encode and decode data using Base64 encoding with standard and URL-safe variants

⏱️ 15 min 🏷️ rust, web, cryptography
Prerequisites: Basic Rust, base64 crate
// Web Rust Base64 Encoding Examples
// Base64 encoding and decoding operations
//
// Add to Cargo.toml:
// [dependencies]
// base64 = "0.21"

use base64::{Engine as _, engine::general_purpose};

// 1. Standard Base64 Encoding

/// Encode bytes to standard Base64
fn encode_base64(data: &[u8]) -> String {
    general_purpose::STANDARD.encode(data)
}

/// Decode Base64 to bytes
fn decode_base64(encoded: &str) -> Result<Vec<u8>, base64::DecodeError> {
    general_purpose::STANDARD.decode(encoded)
}

/// Encode string to Base64
fn encode_string_base64(input: &str) -> String {
    encode_base64(input.as_bytes())
}

// 2. URL-Safe Base64 Encoding

/// Encode bytes to URL-safe Base64
fn encode_base64_url_safe(data: &[u8]) -> String {
    general_purpose::URL_SAFE.encode(data)
}

/// Decode URL-safe Base64
fn decode_base64_url_safe(encoded: &str) -> Result<Vec<u8>, base64::DecodeError> {
    general_purpose::URL_SAFE.decode(encoded)
}

// 3. Base64 without Padding

/// Encode without padding (no '=' characters)
fn encode_base64_no_pad(data: &[u8]) -> String {
    general_purpose::STANDARD_NO_PAD.encode(data)
}

/// Decode Base64 without padding
fn decode_base64_no_pad(encoded: &str) -> Result<Vec<u8>, base64::DecodeError> {
    general_purpose::STANDARD_NO_PAD.decode(encoded)
}

// 4. Base64 with Custom Configuration

/// Encode with custom configuration
fn encode_base64_custom(data: &[u8], url_safe: bool, pad: bool) -> String {
    use base64::engine::Config;

    let config = Config::new()
        .with_encode_padding(pad);

    if url_safe {
        base64::engine::GeneralPurpose::new(
            &base64::alphabet::URL_SAFE,
            config
        ).encode(data)
    } else {
        base64::engine::GeneralPurpose::new(
            &base64::alphabet::STANDARD,
            config
        ).encode(data)
    }
}

// 5. Binary Data Encoding

/// Encode binary file to Base64
fn encode_file_to_base64(path: &str) -> Result<String, std::io::Error> {
    use std::io::Read;
    let mut file = std::fs::File::open(path)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;
    Ok(encode_base64(&buffer))
}

/// Decode Base64 and write to file
fn decode_base64_to_file(encoded: &str, output_path: &str) -> Result<(), std::io::Error> {
    use std::io::Write;
    let decoded = decode_base64(encoded)?;
    let mut file = std::fs::File::create(output_path)?;
    file.write_all(&decoded)?;
    Ok(())
}

// 6. Stream Encoding

/// Encode data in chunks
fn encode_chunks(data: &[u8], chunk_size: usize) -> Vec<String> {
    data.chunks(chunk_size)
        .map(|chunk| encode_base64(chunk))
        .collect()
}

/// Decode multiple Base64 strings
fn decode_multiple(encoded_strings: &[&str]) -> Result<Vec<u8>, base64::DecodeError> {
    let mut result = Vec::new();
    for encoded in encoded_strings {
        result.extend(decode_base64(encoded)?);
    }
    Ok(result)
}

// 7. Base64 for URLs

/// Encode data for use in URL parameters
fn encode_for_url(data: &[u8]) -> String {
    // Remove padding and use URL-safe alphabet
    let encoded = encode_base64_url_safe(data);
    encoded.trim_end_matches('=').to_string()
}

/// Decode URL parameter
fn decode_from_url(encoded: &str) -> Result<Vec<u8>, base64::DecodeError> {
    // Add padding back if needed
    let padded = if encoded.len() % 4 != 0 {
        let padding = 4 - (encoded.len() % 4);
        format!("{}{}", encoded, "=".repeat(padding))
    } else {
        encoded.to_string()
    };
    decode_base64_url_safe(&padded)
}

// 8. Validation

/// Check if string is valid Base64
fn is_valid_base64(s: &str) -> bool {
    decode_base64(s).is_ok()
}

/// Check if string is valid URL-safe Base64
fn is_valid_base64_url(s: &str) -> bool {
    decode_base64_url_safe(s).is_ok()
}

// 9. Base64 Length Calculation

/// Calculate encoded length from data length
fn calculate_encoded_length(data_len: usize, with_padding: bool) -> usize {
    let encoded_len = ((data_len + 2) / 3) * 4;
    if with_padding {
        encoded_len
    } else {
        encoded_len - (data_len % 3).min(2)
    }
}

/// Calculate decoded length from encoded string
fn calculate_decoded_length(encoded_len: usize) -> usize {
    (encoded_len * 3) / 4
}

// 10. Hash Encoding

/// Encode binary hash to Base64 for display
fn encode_hash_to_base64(hash: &[u8]) -> String {
    encode_base64(hash)
}

/// Create Base64-encoded SHA256 hash
fn hash_and_encode_base64(data: &[u8]) -> String {
    use sha2::{Sha256, Digest};
    let mut hasher = Sha256::new();
    hasher.update(data);
    let hash = hasher.finalize();
    encode_base64(&hash)
}

// 11. Comparison

/// Compare two Base64 strings (constant-time)
fn base64_equals(encoded1: &str, encoded2: &str) -> Result<bool, base64::DecodeError> {
    use subtle::ConstantTimeEq;
    let bytes1 = decode_base64(encoded1)?;
    let bytes2 = decode_base64(encoded2)?;
    Ok(bytes1.ct_eq(&bytes2).into())
}

// 12. Common Use Cases

/// Encode credentials for Basic Auth
fn encode_basic_auth(username: &str, password: &str) -> String {
    let credentials = format!("{}:{}", username, password);
    encode_string_base64(&credentials)
}

/// Encode JSON for URL transmission
fn encode_json_for_url<T: serde::Serialize>(data: &T) -> Result<String, Box<dyn std::error::Error>> {
    let json = serde_json::to_string(data)?;
    Ok(encode_for_url(json.as_bytes()))
}

/// Decode JSON from URL transmission
fn decode_json_from_url<T: for<'de> serde::Deserialize<'de>>(
    encoded: &str
) -> Result<T, Box<dyn std::error::Error>> {
    let decoded = decode_from_url(encoded)?;
    let json_str = String::from_utf8(decoded)?;
    let data = serde_json::from_str(&json_str)?;
    Ok(data)
}

// Usage Examples
fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Web Rust Base64 Encoding Examples ===\n");

    let test_data = b"Hello, World!";
    let test_string = "Hello, Base64!";

    // 1. Standard encoding
    println!("--- 1. Standard Base64 Encoding ---");
    let encoded = encode_base64(test_data);
    println!("Encoded: {}", encoded);
    let decoded = decode_base64(&encoded)?;
    println!("Decoded: {}", String::from_utf8(decoded)?);

    // 2. String encoding
    println!("\n--- 2. String Encoding ---");
    let encoded_str = encode_string_base64(test_string);
    println!("Encoded string: {}", encoded_str);

    // 3. URL-safe encoding
    println!("\n--- 3. URL-Safe Encoding ---");
    let url_data = b"data with/slashes+and=equals";
    let url_encoded = encode_base64_url_safe(url_data);
    println!("URL-safe encoded: {}", url_encoded);
    let url_decoded = decode_base64_url_safe(&url_encoded)?;
    println!("URL-safe decoded: {}", String::from_utf8(url_decoded)?);

    // 4. No padding
    println!("\n--- 4. Encoding Without Padding ---");
    let no_pad = encode_base64_no_pad(test_data);
    println!("No padding: {}", no_pad);
    println!("Standard:    {}", encoded);

    // 5. Chunked encoding
    println!("\n--- 5. Chunked Encoding ---");
    let large_data = b"This is a longer piece of data that will be encoded in chunks";
    let chunks = encode_chunks(large_data, 10);
    println!("Encoded in {} chunks:", chunks.len());
    for (i, chunk) in chunks.iter().enumerate() {
        println!("  Chunk {}: {}", i + 1, chunk);
    }

    // 6. URL encoding
    println!("\n--- 6. URL Encoding ---");
    let url_safe_data = b"safe for url";
    let url_encoded_data = encode_for_url(url_safe_data);
    println!("URL encoded: {}", url_encoded_data);
    let url_decoded_data = decode_from_url(&url_encoded_data)?;
    println!("URL decoded: {}", String::from_utf8(url_decoded_data)?);

    // 7. Validation
    println!("\n--- 7. Validation ---");
    println!("Is valid Base64: {}", is_valid_base64(&encoded));
    println!("Is invalid valid: {}", !is_valid_base64("invalid@base64!"));

    // 8. Length calculations
    println!("\n--- 8. Length Calculations ---");
    let data_len = test_data.len();
    println!("Original length: {}", data_len);
    println!("Encoded length (with padding): {}", calculate_encoded_length(data_len, true));
    println!("Encoded length (no padding): {}", calculate_encoded_length(data_len, false));
    println!("Actual encoded length: {}", encoded.len());

    // 9. Hash encoding
    println!("\n--- 9. Hash Encoding ---");
    let hash_encoded = hash_and_encode_base64(test_data);
    println!("SHA256 as Base64: {}", hash_encoded);

    // 10. Basic auth
    println!("\n--- 10. Basic Auth ---");
    let auth = encode_basic_auth("alice", "secret123");
    println!("Basic auth header: Basic {}", auth);

    // 11. JSON in URL
    println!("\n--- 11. JSON URL Encoding ---");
    #[derive(serde::Serialize, Deserialize, Debug)]
    struct Data {
        name: String,
        value: i32,
    }
    let json_data = Data {
        name: "Test".to_string(),
        value: 42,
    };
    let json_encoded = encode_json_for_url(&json_data)?;
    println!("JSON URL encoded: {}", json_encoded);
    let json_decoded: Data = decode_json_from_url(&json_encoded)?;
    println!("JSON decoded: {:?}", json_decoded);

    // 12. Comparison
    println!("\n--- 12. Base64 Comparison ---");
    let encoded1 = encode_base64(b"test");
    let encoded2 = encode_base64(b"test");
    let encoded3 = encode_base64(b"different");
    println!("encoded1 == encoded2: {}", base64_equals(&encoded1, &encoded2)?);
    println!("encoded1 == encoded3: {}", base64_equals(&encoded1, &encoded3)?);

    println!("\n=== All Base64 Encoding Examples Completed ===");
    Ok(())
}

💻 Symmetric Encryption rust

🟡 intermediate ⭐⭐⭐⭐

Encrypt and decrypt data using AES with GCM mode

⏱️ 30 min 🏷️ rust, web, cryptography, encryption
Prerequisites: Intermediate Rust, aes-gcm crate
// Web Rust Symmetric Encryption Examples
// AES encryption and decryption with GCM mode
//
// Add to Cargo.toml:
// [dependencies]
// aes-gcm = "0.10"
// rand = "0.8"
// hex = "0.4"

use aes_gcm::{
    Aes256Gcm,
    Key,
    Nonce,
    aead::{Aead, AeadCore, KeyInit, OsRng},
};
use rand::Rng;

// 1. Key Generation

/// Generate random 256-bit key for AES-256
fn generate_key() -> [u8; 32] {
    Aes256Gcm::generate_key().into()
}

/// Generate key from password using PBKDF2
fn key_from_password(password: &str, salt: &[u8; 32], iterations: u32) -> [u8; 32] {
    use pbkdf2::pbkdf2_hmac;
    use sha2::Sha256;

    let mut key_bytes = [0u8; 32];
    pbkdf2_hmac::<Sha256>(
        password.as_bytes(),
        salt,
        iterations,
        &mut key_bytes,
    );
    key_bytes
}

// 2. Nonce Generation

/// Generate random nonce for AES-GCM
fn generate_nonce() -> [u8; 12] {
    Aes256Gcm::generate_nonce().into()
}

/// Create nonce from counter (for testing)
fn nonce_from_counter(counter: u64) -> [u8; 12] {
    let mut nonce = [0u8; 12];
    nonce[4..].copy_from_slice(&counter.to_be_bytes());
    nonce
}

// 3. AES-GCM Encryption

/// Encrypt data using AES-256-GCM
fn encrypt_aes256_gcm(
    key: &[u8; 32],
    nonce: &[u8; 12],
    plaintext: &[u8],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
    let nonce = Nonce::from_slice(nonce);

    let ciphertext = cipher.encrypt(nonce, plaintext)?;
    Ok(ciphertext)
}

/// Encrypt string using AES-256-GCM
fn encrypt_string_aes256_gcm(
    key: &[u8; 32],
    nonce: &[u8; 12],
    plaintext: &str,
) -> Result<String, Box<dyn std::error::Error>> {
    let ciphertext = encrypt_aes256_gcm(key, nonce, plaintext.as_bytes())?;
    Ok(hex::encode(ciphertext))
}

// 4. AES-GCM Decryption

/// Decrypt data using AES-256-GCM
fn decrypt_aes256_gcm(
    key: &[u8; 32],
    nonce: &[u8; 12],
    ciphertext: &[u8],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
    let nonce = Nonce::from_slice(nonce);

    let plaintext = cipher.decrypt(nonce, ciphertext)?;
    Ok(plaintext)
}

/// Decrypt hex-encoded string using AES-256-GCM
fn decrypt_string_aes256_gcm(
    key: &[u8; 32],
    nonce: &[u8; 12],
    ciphertext_hex: &str,
) -> Result<String, Box<dyn std::error::Error>> {
    let ciphertext = hex::decode(ciphertext_hex)?;
    let plaintext_bytes = decrypt_aes256_gcm(key, nonce, &ciphertext)?;
    Ok(String::from_utf8(plaintext_bytes)?)
}

// 5. Encryption with Associated Data (AAD)

/// Encrypt with additional authenticated data
fn encrypt_with_aad(
    key: &[u8; 32],
    nonce: &[u8; 12],
    plaintext: &[u8],
    aad: &[u8],
) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
    let nonce = Nonce::from_slice(nonce);

    let ciphertext = cipher.encrypt(nonce, plaintext)?;
    Ok(ciphertext)
}

// 6. Complete Encryption Structure

/// Encrypted message with nonce
#[derive(Debug)]
struct EncryptedMessage {
    nonce: [u8; 12],
    ciphertext: Vec<u8>,
}

/// Encrypt and return message with nonce
fn encrypt_message(key: &[u8; 32], plaintext: &str) -> EncryptedMessage {
    let nonce = generate_nonce();
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
    let nonce_obj = Nonce::from_slice(&nonce);

    let ciphertext = cipher.encrypt(nonce_obj, plaintext.as_bytes()).unwrap();

    EncryptedMessage { nonce, ciphertext }
}

/// Decrypt message with embedded nonce
fn decrypt_message(key: &[u8; 32], message: EncryptedMessage) -> Result<String, Box<dyn std::error::Error>> {
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
    let nonce = Nonce::from_slice(&message.nonce);

    let plaintext = cipher.decrypt(nonce, message.ciphertext.as_slice())?;
    Ok(String::from_utf8(plaintext)?)
}

// 7. File Encryption

/// Encrypt file contents
fn encrypt_file(
    key: &[u8; 32],
    input_path: &str,
    output_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    use std::io::Read;
    use std::io::Write;

    // Read input file
    let mut file = std::fs::File::open(input_path)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;

    // Encrypt
    let nonce = generate_nonce();
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
    let nonce_obj = Nonce::from_slice(&nonce);
    let ciphertext = cipher.encrypt(nonce_obj, buffer.as_slice())?;

    // Write nonce + ciphertext to output
    let mut output = std::fs::File::create(output_path)?;
    output.write_all(&nonce)?;
    output.write_all(&ciphertext)?;

    Ok(())
}

/// Decrypt file contents
fn decrypt_file(
    key: &[u8; 32],
    input_path: &str,
    output_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    use std::io::Read;
    use std::io::Write;

    // Read input file
    let mut file = std::fs::File::open(input_path)?;
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)?;

    // Extract nonce (first 12 bytes)
    let mut nonce = [0u8; 12];
    nonce.copy_from_slice(&buffer[..12]);
    let ciphertext = &buffer[12..];

    // Decrypt
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
    let nonce_obj = Nonce::from_slice(&nonce);
    let plaintext = cipher.decrypt(nonce_obj, ciphertext)?;

    // Write to output
    let mut output = std::fs::File::create(output_path)?;
    output.write_all(&plaintext)?;

    Ok(())
}

// 8. Stream Encryption (Chunked)

/// Encrypt data in chunks
fn encrypt_chunked(
    key: &[u8; 32],
    data: &[u8],
    chunk_size: usize,
) -> Result<Vec<(Vec<u8>, [u8; 12])>, Box<dyn std::error::Error>> {
    let mut results = Vec::new();

    for chunk in data.chunks(chunk_size) {
        let nonce = generate_nonce();
        let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
        let nonce_obj = Nonce::from_slice(&nonce);

        let ciphertext = cipher.encrypt(nonce_obj, chunk)?;
        results.push((ciphertext, nonce));
    }

    Ok(results)
}

// 9. Key Derivation

/// Derive encryption key from passphrase
struct EncryptionKey {
    key: [u8; 32],
    salt: [u8; 32],
}

impl EncryptionKey {
    fn new(passphrase: &str) -> Self {
        let mut salt = [0u8; 32];
        let mut rng = rand::thread_rng();
        rng.fill(&mut salt);

        let key = key_from_password(passphrase, &salt, 100_000);
        EncryptionKey { key, salt }
    }

    fn from_salt(passphrase: &str, salt: [u8; 32]) -> Self {
        let key = key_from_password(passphrase, &salt, 100_000);
        EncryptionKey { key, salt }
    }
}

// 10. Password-Based Encryption

/// Encrypt with password
fn encrypt_with_password(
    password: &str,
    plaintext: &str,
) -> Result<(String, [u8; 32], [u8; 12]), Box<dyn std::error::Error>> {
    let enc_key = EncryptionKey::new(password);
    let nonce = generate_nonce();
    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(&enc_key.key));
    let nonce_obj = Nonce::from_slice(&nonce);

    let ciphertext = cipher.encrypt(nonce_obj, plaintext.as_bytes())?;
    Ok((hex::encode(ciphertext), enc_key.salt, nonce))
}

/// Decrypt with password
fn decrypt_with_password(
    password: &str,
    ciphertext_hex: &str,
    salt: [u8; 32],
    nonce: [u8; 12],
) -> Result<String, Box<dyn std::error::Error>> {
    let enc_key = EncryptionKey::from_salt(password, salt);
    let ciphertext = hex::decode(ciphertext_hex)?;

    let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(&enc_key.key));
    let nonce_obj = Nonce::from_slice(&nonce);

    let plaintext = cipher.decrypt(nonce_obj, ciphertext.as_slice())?;
    Ok(String::from_utf8(plaintext)?)
}

// Usage Examples
fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("=== Web Rust Symmetric Encryption Examples ===\n");

    // 1. Generate key
    println!("--- 1. Key Generation ---");
    let key = generate_key();
    println!("Generated key: {}", hex::encode(key));

    // 2. Generate nonce
    println!("\n--- 2. Nonce Generation ---");
    let nonce = generate_nonce();
    println!("Generated nonce: {}", hex::encode(nonce));

    // 3. Encrypt string
    println!("\n--- 3. Encrypt String ---");
    let plaintext = "Secret message!";
    let encrypted = encrypt_string_aes256_gcm(&key, &nonce, plaintext)?;
    println!("Plaintext: {}", plaintext);
    println!("Encrypted: {}", encrypted);

    // 4. Decrypt string
    println!("\n--- 4. Decrypt String ---");
    let decrypted = decrypt_string_aes256_gcm(&key, &nonce, &encrypted)?;
    println!("Decrypted: {}", decrypted);

    // 5. Complete message encryption
    println!("\n--- 5. Complete Message ---");
    let message = encrypt_message(&key, "Hello, secure world!");
    println!("Encrypted message: {:?}", message);
    let decrypted_msg = decrypt_message(&key, message)?;
    println!("Decrypted message: {}", decrypted_msg);

    // 6. Password-based encryption
    println!("\n--- 6. Password-Based Encryption ---");
    let password = "my_secure_password";
    let secret = "This is a secret message";

    let (encrypted_pwd, salt, nonce_pwd) = encrypt_with_password(password, secret)?;
    println!("Password-encrypted: {}", encrypted_pwd);
    println!("Salt: {}", hex::encode(salt));
    println!("Nonce: {}", hex::encode(nonce_pwd));

    let decrypted_pwd = decrypt_with_password(password, &encrypted_pwd, salt, nonce_pwd)?;
    println!("Decrypted: {}", decrypted_pwd);

    // 7. Key from password
    println!("\n--- 7. Key Derivation ---");
    let user_password = "user_password_123";
    let user_salt = [0u8; 32]; // In practice, generate random salt
    let derived_key = key_from_password(user_password, &user_salt, 100_000);
    println!("Derived key: {}", hex::encode(derived_key));

    // 8. Encrypt large data
    println!("\n--- 8. Large Data Encryption ---");
    let large_data = "A".repeat(10000);
    let large_encrypted = encrypt_string_aes256_gcm(&key, &nonce, &large_data)?;
    println!("Encrypted {} bytes to {}", large_data.len(), large_encrypted.len());

    // 9. Chunked encryption
    println!("\n--- 9. Chunked Encryption ---");
    let test_data = b"This is some test data that will be encrypted in chunks";
    let chunks = encrypt_chunked(&key, test_data, 10)?;
    println!("Encrypted into {} chunks", chunks.len());

    // 10. Verify data integrity
    println!("\n--- 10. Data Integrity ---");
    let original = "Important data to protect";
    let enc = encrypt_message(&key, original)?;
    let dec = decrypt_message(&key, enc)?;
    println!("Original matches decrypted: {}", original == dec);

    println!("\n=== All Symmetric Encryption Examples Completed ===");
    Ok(())
}