happy_cracking/crypto/
bitrot.rs1use 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}