happy-cracking 0.3.0

A fast, comprehensive CTF toolkit for cryptographic encoding/decoding, classic ciphers, hash operations, and analysis tools
Documentation
use anyhow::Result;
use clap::Subcommand;
use md5::Md5;
use sha1::Sha1;
use sha2::{Digest, Sha256, Sha512};

#[derive(Subcommand)]
pub enum HmacAction {
    #[command(about = "HMAC-MD5")]
    Md5 {
        #[arg(help = "Input message")]
        input: String,
        #[arg(short, long, help = "HMAC key")]
        key: String,
    },
    #[command(about = "HMAC-SHA1")]
    Sha1 {
        #[arg(help = "Input message")]
        input: String,
        #[arg(short, long, help = "HMAC key")]
        key: String,
    },
    #[command(about = "HMAC-SHA256")]
    Sha256 {
        #[arg(help = "Input message")]
        input: String,
        #[arg(short, long, help = "HMAC key")]
        key: String,
    },
    #[command(about = "HMAC-SHA512")]
    Sha512 {
        #[arg(help = "Input message")]
        input: String,
        #[arg(short, long, help = "HMAC key")]
        key: String,
    },
}

pub fn run(action: HmacAction) -> Result<()> {
    match action {
        HmacAction::Md5 { input, key } => {
            println!("{}", hmac_md5(key.as_bytes(), input.as_bytes()));
        }
        HmacAction::Sha1 { input, key } => {
            println!("{}", hmac_sha1(key.as_bytes(), input.as_bytes()));
        }
        HmacAction::Sha256 { input, key } => {
            println!("{}", hmac_sha256(key.as_bytes(), input.as_bytes()));
        }
        HmacAction::Sha512 { input, key } => {
            println!("{}", hmac_sha512(key.as_bytes(), input.as_bytes()));
        }
    }
    Ok(())
}

fn hmac<D: Digest>(key: &[u8], message: &[u8], block_size: usize) -> Vec<u8> {
    let actual_key = if key.len() > block_size {
        let mut hasher = D::new();
        hasher.update(key);
        hasher.finalize().to_vec()
    } else {
        key.to_vec()
    };

    let mut padded_key = vec![0u8; block_size];
    padded_key[..actual_key.len()].copy_from_slice(&actual_key);

    let ipad: Vec<u8> = padded_key.iter().map(|&k| k ^ 0x36).collect();
    let opad: Vec<u8> = padded_key.iter().map(|&k| k ^ 0x5c).collect();

    let mut inner_hasher = D::new();
    inner_hasher.update(&ipad);
    inner_hasher.update(message);
    let inner_hash = inner_hasher.finalize();

    let mut outer_hasher = D::new();
    outer_hasher.update(&opad);
    outer_hasher.update(&inner_hash);
    outer_hasher.finalize().to_vec()
}

pub fn hmac_md5(key: &[u8], message: &[u8]) -> String {
    hex::encode(hmac::<Md5>(key, message, 64))
}

pub fn hmac_sha1(key: &[u8], message: &[u8]) -> String {
    hex::encode(hmac::<Sha1>(key, message, 64))
}

pub fn hmac_sha256(key: &[u8], message: &[u8]) -> String {
    hex::encode(hmac::<Sha256>(key, message, 64))
}

pub fn hmac_sha512(key: &[u8], message: &[u8]) -> String {
    hex::encode(hmac::<Sha512>(key, message, 128))
}