Skip to main content

happy_cracking/crypto/
bitrot.rs

1use anyhow::{Context, Result};
2use clap::Subcommand;
3
4#[derive(Subcommand)]
5pub enum BitrotAction {
6    #[command(about = "Rotate bits left")]
7    Rotl {
8        #[arg(help = "Input hex string")]
9        input: String,
10        #[arg(short, long, default_value = "1", help = "Number of bits to rotate")]
11        bits: u32,
12        #[arg(short, long, default_value = "8", help = "Bit width (8, 16, 32)")]
13        width: u32,
14    },
15    #[command(about = "Rotate bits right")]
16    Rotr {
17        #[arg(help = "Input hex string")]
18        input: String,
19        #[arg(short, long, default_value = "1", help = "Number of bits to rotate")]
20        bits: u32,
21        #[arg(short, long, default_value = "8", help = "Bit width (8, 16, 32)")]
22        width: u32,
23    },
24}
25
26pub fn run(action: BitrotAction) -> Result<()> {
27    match action {
28        BitrotAction::Rotl { input, bits, width } => {
29            let data = hex::decode(input.trim()).context("Failed to decode input hex")?;
30            let result = rotate_left(&data, bits, width)?;
31            println!("{}", hex::encode(&result));
32        }
33        BitrotAction::Rotr { input, bits, width } => {
34            let data = hex::decode(input.trim()).context("Failed to decode input hex")?;
35            let result = rotate_right(&data, bits, width)?;
36            println!("{}", hex::encode(&result));
37        }
38    }
39    Ok(())
40}
41
42pub fn rotate_left(data: &[u8], bits: u32, width: u32) -> Result<Vec<u8>> {
43    match width {
44        8 => Ok(rotate_left_8(data, bits)),
45        16 => rotate_left_16(data, bits),
46        32 => rotate_left_32(data, bits),
47        _ => anyhow::bail!("Unsupported bit width: {} (must be 8, 16, or 32)", width),
48    }
49}
50
51pub fn rotate_right(data: &[u8], bits: u32, width: u32) -> Result<Vec<u8>> {
52    match width {
53        8 => Ok(rotate_right_8(data, bits)),
54        16 => rotate_right_16(data, bits),
55        32 => rotate_right_32(data, bits),
56        _ => anyhow::bail!("Unsupported bit width: {} (must be 8, 16, or 32)", width),
57    }
58}
59
60fn rotate_left_8(data: &[u8], bits: u32) -> Vec<u8> {
61    data.iter().map(|&b| b.rotate_left(bits)).collect()
62}
63
64fn rotate_right_8(data: &[u8], bits: u32) -> Vec<u8> {
65    data.iter().map(|&b| b.rotate_right(bits)).collect()
66}
67
68fn rotate_left_16(data: &[u8], bits: u32) -> Result<Vec<u8>> {
69    if !data.len().is_multiple_of(2) {
70        anyhow::bail!("Data length must be a multiple of 2 for 16-bit rotation");
71    }
72    let mut result = Vec::with_capacity(data.len());
73    for chunk in data.chunks(2) {
74        let val = u16::from_be_bytes([chunk[0], chunk[1]]);
75        let rotated = val.rotate_left(bits);
76        result.extend_from_slice(&rotated.to_be_bytes());
77    }
78    Ok(result)
79}
80
81fn rotate_right_16(data: &[u8], bits: u32) -> Result<Vec<u8>> {
82    if !data.len().is_multiple_of(2) {
83        anyhow::bail!("Data length must be a multiple of 2 for 16-bit rotation");
84    }
85    let mut result = Vec::with_capacity(data.len());
86    for chunk in data.chunks(2) {
87        let val = u16::from_be_bytes([chunk[0], chunk[1]]);
88        let rotated = val.rotate_right(bits);
89        result.extend_from_slice(&rotated.to_be_bytes());
90    }
91    Ok(result)
92}
93
94fn rotate_left_32(data: &[u8], bits: u32) -> Result<Vec<u8>> {
95    if !data.len().is_multiple_of(4) {
96        anyhow::bail!("Data length must be a multiple of 4 for 32-bit rotation");
97    }
98    let shift = bits % 32;
99    let mut result = Vec::with_capacity(data.len());
100    for chunk in data.chunks(4) {
101        let val = u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
102        let rotated = val.rotate_left(shift);
103        result.extend_from_slice(&rotated.to_be_bytes());
104    }
105    Ok(result)
106}
107
108fn rotate_right_32(data: &[u8], bits: u32) -> Result<Vec<u8>> {
109    if !data.len().is_multiple_of(4) {
110        anyhow::bail!("Data length must be a multiple of 4 for 32-bit rotation");
111    }
112    let shift = bits % 32;
113    let mut result = Vec::with_capacity(data.len());
114    for chunk in data.chunks(4) {
115        let val = u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
116        let rotated = val.rotate_right(shift);
117        result.extend_from_slice(&rotated.to_be_bytes());
118    }
119    Ok(result)
120}